mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-18 16:27:34 +01:00
[Upstream] Merged epsilon 15.5
This commit is contained in:
8
.github/workflows/ci-workflow.yml
vendored
8
.github/workflows/ci-workflow.yml
vendored
@@ -129,6 +129,8 @@ jobs:
|
||||
submodules: 'recursive'
|
||||
- run: pacman -S --noconfirm mingw-w64-x86_64-gcc mingw-w64-x86_64-freetype mingw-w64-x86_64-pkg-config make mingw-w64-x86_64-python3 mingw-w64-x86_64-libjpeg-turbo mingw-w64-x86_64-libpng
|
||||
- run: make -j2 PLATFORM=simulator
|
||||
- run: make -j2 PLATFORM=simulator test.exe
|
||||
- run: cmd /c output\release\simulator\windows\test.exe --headless
|
||||
- uses: actions/upload-artifact@master
|
||||
with:
|
||||
name: epsilon-windows.exe
|
||||
@@ -143,6 +145,8 @@ jobs:
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
- run: make -j2 PLATFORM=simulator TARGET=web
|
||||
- run: make -j2 PLATFORM=simulator TARGET=web test.js
|
||||
- run: node output/release/simulator/web/test.js --headless
|
||||
- uses: actions/upload-artifact@master
|
||||
with:
|
||||
name: epsilon-web.zip
|
||||
@@ -155,6 +159,8 @@ jobs:
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
- run: make -j2 PLATFORM=simulator
|
||||
- run: make -j2 PLATFORM=simulator test.bin
|
||||
- run: output/release/simulator/linux/test.bin --headless
|
||||
- uses: actions/upload-artifact@master
|
||||
with:
|
||||
name: epsilon-linux.bin
|
||||
@@ -168,6 +174,8 @@ jobs:
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
- run: make -j2 PLATFORM=simulator
|
||||
- run: make -j2 PLATFORM=simulator ARCH=x86_64 test.bin
|
||||
- run: output/release/simulator/macos/x86_64/test.bin --headless
|
||||
- uses: actions/upload-artifact@master
|
||||
with:
|
||||
name: epsilon-macos.zip
|
||||
|
||||
@@ -85,9 +85,6 @@ language_preferences = apps/language_preferences.csv
|
||||
SFLAGS += -I$(BUILD_DIR)
|
||||
|
||||
i18n_files += $(addprefix apps/language_,$(addsuffix .universal.i18n, $(EPSILON_I18N)))
|
||||
ifeq ($(EPSILON_GETOPT),1)
|
||||
i18n_files += $(addprefix apps/language_,$(addsuffix _iso6391.universal.i18n, $(EPSILON_I18N)))
|
||||
endif
|
||||
|
||||
i18n_files += $(call i18n_with_universal_for,shared)
|
||||
i18n_files += $(call i18n_with_universal_for,toolbox)
|
||||
@@ -97,7 +94,7 @@ $(eval $(call rule_for, \
|
||||
I18N, \
|
||||
apps/i18n.cpp, \
|
||||
$(i18n_files), \
|
||||
$$(PYTHON) apps/i18n.py --codepoints $(code_points) --countrypreferences $(country_preferences) --languagepreferences $(language_preferences) --header $$(subst .cpp,.h,$$@) --implementation $$@ --locales $$(EPSILON_I18N) --countries $$(EPSILON_COUNTRIES) --files $$^ --generateISO6391locales $$(EPSILON_GETOPT), \
|
||||
$$(PYTHON) apps/i18n.py --codepoints $(code_points) --countrypreferences $(country_preferences) --languagepreferences $(language_preferences) --header $$(subst .cpp,.h,$$@) --implementation $$@ --locales $$(EPSILON_I18N) --countries $$(EPSILON_COUNTRIES) --files $$^, \
|
||||
global \
|
||||
))
|
||||
|
||||
@@ -113,6 +110,8 @@ $(call object_for,$(apps_src) $(tests_src)): $(BUILD_DIR)/apps/i18n.h
|
||||
$(call object_for,$(apps_src) $(tests_src)): $(BUILD_DIR)/apps/home/apps_layout.h
|
||||
$(call object_for,$(apps_src) $(tests_src)): $(BUILD_DIR)/python/port/genhdr/qstrdefs.generated.h
|
||||
|
||||
$(call object_for,$(apps_src)): $(BUILD_DIR)/apps/home/apps_layout.h
|
||||
|
||||
apps_tests_src = $(app_calculation_test_src) $(app_code_test_src) $(app_graph_test_src) $(app_probability_test_src) $(app_regression_test_src) $(app_sequence_test_src) $(app_shared_test_src) $(app_statistics_test_src) $(app_settings_test_src) $(app_solver_test_src)
|
||||
|
||||
apps_tests_src += $(addprefix apps/,\
|
||||
|
||||
17
apps/i18n.py
17
apps/i18n.py
@@ -23,13 +23,9 @@ parser.add_argument('--codepoints', help='the code_points.h file')
|
||||
parser.add_argument('--countrypreferences', help='the country_preferences.csv file')
|
||||
parser.add_argument('--languagepreferences', help='the language_preferences.csv file')
|
||||
parser.add_argument('--files', nargs='+', help='an i18n file')
|
||||
parser.add_argument('--generateISO6391locales', type=int, nargs='+', help='whether to generate the ISO6391 codes for the languages (for instance "en" for english)')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
def generate_ISO6391():
|
||||
return args.generateISO6391locales[0] == 1
|
||||
|
||||
def has_glyph(glyph):
|
||||
return glyph in codepoints
|
||||
|
||||
@@ -196,13 +192,6 @@ def print_header(data, path, locales, countries):
|
||||
lambda arg: arg.upper(),
|
||||
" Message::Language")
|
||||
|
||||
if generate_ISO6391():
|
||||
print_block_from_list(f,
|
||||
"constexpr const Message LanguageISO6391Names[NumberOfLanguages] = {\n",
|
||||
locales,
|
||||
lambda arg: arg.upper(),
|
||||
" Message::LanguageISO6391")
|
||||
|
||||
# Countries enumeration
|
||||
print_block_from_list(f,
|
||||
"enum class Country : uint8_t {\n",
|
||||
@@ -236,6 +225,12 @@ def print_header(data, path, locales, countries):
|
||||
f.write(line[:-2] + "),\n")
|
||||
f.write("};\n\n")
|
||||
|
||||
# Language ISO639-1 codes
|
||||
f.write("constexpr const char * LanguageISO6391Codes[NumberOfLanguages] = {\n");
|
||||
for locale in locales:
|
||||
f.write(" \"" + locale + "\",\n")
|
||||
f.write("};\n\n")
|
||||
|
||||
f.write("}\n\n")
|
||||
f.write("#endif\n")
|
||||
f.close()
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
LanguageISO6391DE = "de"
|
||||
@@ -1 +0,0 @@
|
||||
LanguageISO6391EN = "en"
|
||||
@@ -1 +0,0 @@
|
||||
LanguageISO6391ES = "es"
|
||||
@@ -1 +0,0 @@
|
||||
LanguageISO6391FR = "fr"
|
||||
@@ -1 +0,0 @@
|
||||
LanguageISO6391IT = "it"
|
||||
@@ -1 +0,0 @@
|
||||
LanguageISO6391NL = "nl"
|
||||
@@ -1 +0,0 @@
|
||||
LanguageISO6391PT = "pt"
|
||||
@@ -19,6 +19,10 @@ void ion_main(int argc, const char * const argv[]) {
|
||||
#else
|
||||
|
||||
void ion_main(int argc, const char * const argv[]) {
|
||||
/* Lock OTP on older devices to prevent garbage being written where the PCB
|
||||
* version is read. */
|
||||
Ion::Board::lockUnlockedPCBVersion();
|
||||
|
||||
// Initialize Poincare::TreePool::sharedPool
|
||||
Poincare::Init();
|
||||
|
||||
@@ -36,7 +40,7 @@ void ion_main(int argc, const char * const argv[]) {
|
||||
continue;
|
||||
}
|
||||
for (int j = 0; j < I18n::NumberOfLanguages; j++) {
|
||||
if (strcmp(requestedLanguageId, I18n::translate(I18n::LanguageISO6391Names[j])) == 0) {
|
||||
if (strcmp(requestedLanguageId, I18n::LanguageISO6391Codes[j]) == 0) {
|
||||
GlobalPreferences::sharedGlobalPreferences()->setLanguage((I18n::Language)j);
|
||||
GlobalPreferences::sharedGlobalPreferences()->setCountry(I18n::DefaultCountryForLanguage[j]);
|
||||
break;
|
||||
|
||||
@@ -48,11 +48,15 @@ bool AboutController::handleEvent(Ion::Events::Event event) {
|
||||
if (!(event == Ion::Events::Right)) {
|
||||
if (childLabel == I18n::Message::SoftwareVersion) {
|
||||
MessageTableCellWithBuffer * myCell = (MessageTableCellWithBuffer *)m_selectableTableView.selectedCell();
|
||||
if (strcmp(myCell->accessoryText(), Ion::patchLevel()) == 0) {
|
||||
const char * currentText = myCell->accessoryText();
|
||||
if (strcmp(currentText, Ion::patchLevel()) == 0) {
|
||||
myCell->setAccessoryText(Ion::pcbVersion());
|
||||
} else if (strcmp(currentText, Ion::pcbVersion()) == 0) {
|
||||
myCell->setAccessoryText(Ion::softwareVersion());
|
||||
return true;
|
||||
} else {
|
||||
assert(strcmp(currentText, Ion::softwareVersion()) == 0);
|
||||
myCell->setAccessoryText(Ion::patchLevel());
|
||||
}
|
||||
myCell->setAccessoryText(Ion::patchLevel());
|
||||
return true;
|
||||
}
|
||||
if (childLabel == I18n::Message::OmegaVersion) {
|
||||
|
||||
@@ -4,7 +4,7 @@ PLATFORM ?= device
|
||||
DEBUG ?= 0
|
||||
|
||||
HOME_DISPLAY_EXTERNALS ?= 1
|
||||
EPSILON_VERSION ?= 15.3.1
|
||||
EPSILON_VERSION ?= 15.5.0
|
||||
OMEGA_VERSION ?= 1.22.0
|
||||
# OMEGA_USERNAME ?= N/A
|
||||
OMEGA_STATE ?= dev
|
||||
@@ -13,7 +13,6 @@ SUBMODULES_APPS = atomic rpn
|
||||
EPSILON_I18N ?= en fr nl pt it de es hu
|
||||
EPSILON_COUNTRIES ?= WW CA DE ES FR GB IT NL PT US
|
||||
EPSILON_GETOPT ?= 0
|
||||
EPSILON_TELEMETRY ?= 0
|
||||
ESCHER_LOG_EVENTS_BINARY ?= 0
|
||||
THEME_NAME ?= omega_light
|
||||
THEME_REPO ?= local
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
TOOLCHAIN ?= host-gcc
|
||||
USE_LIBA ?= 0
|
||||
ION_KEYBOARD_LAYOUT = layout_B2
|
||||
EXE = bin
|
||||
EXE = bin
|
||||
|
||||
EPSILON_TELEMETRY ?= 0
|
||||
@@ -2,6 +2,8 @@ MODEL ?= n0110
|
||||
USE_LIBA = 1
|
||||
EXE = elf
|
||||
|
||||
EPSILON_TELEMETRY ?= 0
|
||||
|
||||
BUILD_DIR := $(BUILD_DIR)/$(MODEL)
|
||||
|
||||
$(BUILD_DIR)/python/port/port.o: CXXFLAGS += -DMP_PORT_USE_STACK_SYMBOLS=1
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
TOOLCHAIN ?= arm-gcc-m4f
|
||||
ION_KEYBOARD_LAYOUT = layout_B2
|
||||
PCB_LATEST = 0
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
TOOLCHAIN ?= arm-gcc-m7f
|
||||
ION_KEYBOARD_LAYOUT = layout_B3
|
||||
PCB_LATEST = 343 # PCB version 3.43
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
TOOLCHAIN = host-gcc
|
||||
EXE = bin
|
||||
|
||||
EPSILON_SIMULATOR_HAS_LIBPNG = 1
|
||||
EPSILON_TELEMETRY ?= 0
|
||||
|
||||
@@ -3,11 +3,10 @@ EXE = bin
|
||||
|
||||
APPLE_PLATFORM = macos
|
||||
APPLE_PLATFORM_MIN_VERSION = 10.10
|
||||
EPSILON_TELEMETRY ?= 0
|
||||
|
||||
ARCHS = x86_64
|
||||
|
||||
EPSILON_SIMULATOR_HAS_LIBPNG = 1
|
||||
|
||||
ifdef ARCH
|
||||
BUILD_DIR := $(BUILD_DIR)/$(ARCH)
|
||||
else
|
||||
|
||||
@@ -8,13 +8,4 @@ TARGET ?= $(HOST)
|
||||
|
||||
BUILD_DIR := $(BUILD_DIR)/$(TARGET)
|
||||
|
||||
EPSILON_SIMULATOR_HAS_LIBPNG ?= 0
|
||||
|
||||
include build/platform.simulator.$(TARGET).mak
|
||||
|
||||
SFLAGS += -DEPSILON_SIMULATOR_HAS_LIBPNG=$(EPSILON_SIMULATOR_HAS_LIBPNG)
|
||||
|
||||
ifeq ($(EPSILON_SIMULATOR_HAS_LIBPNG),1)
|
||||
SFLAGS += `libpng-config --cflags`
|
||||
LDFLAGS += `libpng-config --ldflags`
|
||||
endif
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
TOOLCHAIN = emscripten
|
||||
EXE = js
|
||||
|
||||
HANDY_TARGETS_EXTENSIONS += zip
|
||||
EPSILON_TELEMETRY ?= 0
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
TOOLCHAIN = windows
|
||||
EXE = exe
|
||||
|
||||
EPSILON_TELEMETRY ?= 0
|
||||
|
||||
@@ -14,7 +14,7 @@ $(eval $(call rule_for, \
|
||||
|
||||
$(eval $(call rule_for, \
|
||||
CPP, %, %.inc, \
|
||||
$$(CPP) -P $$< $$@, \
|
||||
$$(CPP) $$(addprefix -I,$$(dir $$^)) -P $$< $$@, \
|
||||
global \
|
||||
))
|
||||
|
||||
@@ -60,6 +60,12 @@ $(eval $(call rule_for, \
|
||||
global \
|
||||
))
|
||||
|
||||
$(eval $(call rule_for, \
|
||||
ZIP, %.zip, , \
|
||||
rm -rf $$(basename $$@) && mkdir -p $$(basename $$@) && cp $$^ $$(basename $$@) && zip -r -9 -j $$@ $$(basename $$@) > /dev/null && rm -rf $$(basename $$@), \
|
||||
global \
|
||||
))
|
||||
|
||||
ifdef EXE
|
||||
ifeq ($(OS),Windows_NT)
|
||||
# Work around command-line length limit
|
||||
|
||||
@@ -54,21 +54,3 @@ $(BUILD_DIR)/bench.ram.$(EXE): LDFLAGS += -Lion/src/$(PLATFORM)/bench
|
||||
$(BUILD_DIR)/bench.ram.$(EXE): LDSCRIPT = ion/src/$(PLATFORM)/shared/ram.ld
|
||||
$(BUILD_DIR)/bench.flash.$(EXE): $(call flavored_object_for,$(bench_src),consoleuart usbxip)
|
||||
$(BUILD_DIR)/bench.flash.$(EXE): LDSCRIPT = ion/src/$(PLATFORM)/$(MODEL)/internal_flash.ld
|
||||
|
||||
.PHONY: %.two_binaries
|
||||
%.two_binaries: %.elf
|
||||
@echo "Building an internal and an external binary for $<"
|
||||
$(Q) $(OBJCOPY) -O binary -j .text.external -j .rodata.external -j .exam_mode_buffer $< $(basename $<).external.bin
|
||||
$(Q) $(OBJCOPY) -O binary -R .text.external -R .rodata.external -R .exam_mode_buffer $< $(basename $<).internal.bin
|
||||
@echo "Padding $(basename $<).external.bin and $(basename $<).internal.bin"
|
||||
$(Q) printf "\xFF\xFF\xFF\xFF" >> $(basename $<).external.bin
|
||||
$(Q) printf "\xFF\xFF\xFF\xFF" >> $(basename $<).internal.bin
|
||||
|
||||
.PHONY: binpack
|
||||
binpack: $(BUILD_DIR)/flasher.light.bin $(BUILD_DIR)/epsilon.onboarding.two_binaries
|
||||
rm -rf $(BUILD_DIR)/binpack
|
||||
mkdir -p $(BUILD_DIR)/binpack
|
||||
cp $(BUILD_DIR)/flasher.light.bin $(BUILD_DIR)/binpack
|
||||
cp $(BUILD_DIR)/epsilon.onboarding.internal.bin $(BUILD_DIR)/epsilon.onboarding.external.bin $(BUILD_DIR)/binpack
|
||||
cd $(BUILD_DIR) && for binary in flasher.light.bin epsilon.onboarding.internal.bin epsilon.onboarding.external.bin; do shasum -a 256 -b binpack/$${binary} > binpack/$${binary}.sha256;done
|
||||
cd $(BUILD_DIR) && tar cvfz binpack-$(MODEL)-`git rev-parse HEAD | head -c 7`.tgz binpack/*
|
||||
|
||||
@@ -20,3 +20,38 @@ $(BUILD_DIR)/test.external_flash.write.$(EXE): $(BUILD_DIR)/quiz/src/test_ion_ex
|
||||
fi
|
||||
$(Q) $(PYTHON) build/device/dfu.py -u $(word 1,$^)
|
||||
|
||||
.PHONY: %.two_binaries
|
||||
%.two_binaries: %.elf
|
||||
@echo "Building an internal and an external binary for $<"
|
||||
$(Q) $(OBJCOPY) -O binary -j .text.external -j .rodata.external -j .exam_mode_buffer $(BUILD_DIR)/$< $(BUILD_DIR)/$(basename $<).external.bin
|
||||
$(Q) $(OBJCOPY) -O binary -R .text.external -R .rodata.external -R .exam_mode_buffer $(BUILD_DIR)/$< $(BUILD_DIR)/$(basename $<).internal.bin
|
||||
@echo "Padding $(basename $<).external.bin and $(basename $<).internal.bin"
|
||||
$(Q) printf "\xFF\xFF\xFF\xFF" >> $(BUILD_DIR)/$(basename $<).external.bin
|
||||
$(Q) printf "\xFF\xFF\xFF\xFF" >> $(BUILD_DIR)/$(basename $<).internal.bin
|
||||
|
||||
USE_IN_FACTORY := 1
|
||||
|
||||
.PHONY: binpack
|
||||
binpack:
|
||||
ifndef USE_IN_FACTORY
|
||||
@echo "CAUTION: You are building a binpack."
|
||||
@echo "You must specify where this binpack will be used."
|
||||
@echo "Please set the USE_IN_FACTORY environment variable to either:"
|
||||
@echo " - 0 for use in diagnostic"
|
||||
@echo " - 1 for use in production"
|
||||
@exit -1
|
||||
endif
|
||||
rm -rf output/binpack
|
||||
mkdir -p output/binpack
|
||||
$(MAKE) clean
|
||||
$(MAKE) IN_FACTORY=$(USE_IN_FACTORY) $(BUILD_DIR)/flasher.light.bin
|
||||
cp $(BUILD_DIR)/flasher.light.bin output/binpack
|
||||
$(MAKE) IN_FACTORY=$(USE_IN_FACTORY) $(BUILD_DIR)/bench.flash.bin
|
||||
$(MAKE) IN_FACTORY=$(USE_IN_FACTORY) $(BUILD_DIR)/bench.ram.bin
|
||||
cp $(BUILD_DIR)/bench.ram.bin $(BUILD_DIR)/bench.flash.bin output/binpack
|
||||
$(MAKE) IN_FACTORY=$(USE_IN_FACTORY) epsilon.official.onboarding.update.two_binaries
|
||||
cp $(BUILD_DIR)/epsilon.official.onboarding.update.internal.bin $(BUILD_DIR)/epsilon.official.onboarding.update.external.bin output/binpack
|
||||
$(MAKE) clean
|
||||
cd output && for binary in flasher.light.bin bench.flash.bin bench.ram.bin epsilon.official.onboarding.update.internal.bin epsilon.official.onboarding.update.external.bin; do shasum -a 256 -b binpack/$${binary} > binpack/$${binary}.sha256;done
|
||||
cd output && tar cvfz binpack-`git rev-parse HEAD | head -c 7`.tgz binpack
|
||||
rm -rf output/binpack
|
||||
|
||||
@@ -1,8 +1 @@
|
||||
# Headless targets
|
||||
$(eval $(call rule_for_epsilon_flavor,headless))
|
||||
HANDY_TARGETS += epsilon.headless
|
||||
|
||||
$(BUILD_DIR)/test.headless.$(EXE): $(call flavored_object_for,$(test_runner_src),headless)
|
||||
HANDY_TARGETS += test.headless
|
||||
|
||||
-include build/targets.simulator.$(TARGET).mak
|
||||
|
||||
@@ -1 +1,13 @@
|
||||
$(BUILD_DIR)/test.headless.js: EMSCRIPTEN_MODULARIZE = 0
|
||||
$(BUILD_DIR)/test.js: EMSCRIPTEN_MODULARIZE = 0
|
||||
|
||||
HANDY_TARGETS += htmlpack htmlpack.official
|
||||
HANDY_TARGETS_EXTENSIONS += zip
|
||||
|
||||
htmlpack_targets = .\
|
||||
.official. \
|
||||
|
||||
define rule_htmlpack
|
||||
$$(BUILD_DIR)/htmlpack$(1)zip: $$(addprefix $$(BUILD_DIR)/ion/src/simulator/web/,calculator.html calculator.css) $$(BUILD_DIR)/epsilon$(1)js ion/src/simulator/web/calculator.js
|
||||
endef
|
||||
|
||||
$(foreach target,$(htmlpack_targets),$(eval $(call rule_htmlpack,$(target))))
|
||||
|
||||
@@ -25,7 +25,6 @@ initializer_list = $(shell echo $(1) | sed "s/\(.\)/'\1',/g")0
|
||||
$(call object_for,ion/src/shared/platform_info.cpp): SFLAGS += -DPATCH_LEVEL="$(call initializer_list,$(PATCH_LEVEL))" -DEPSILON_VERSION="$(call initializer_list,$(EPSILON_VERSION))" -DOMEGA_VERSION="$(call initializer_list,$(OMEGA_VERSION))" -DOMEGA_USERNAME="$(call initializer_list,$(OMEGA_USERNAME))"
|
||||
|
||||
ion_src += $(addprefix ion/src/shared/, \
|
||||
console_display.cpp:+consoledisplay \
|
||||
console_line.cpp \
|
||||
crc32_eat_byte.cpp \
|
||||
decompress.cpp \
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <ion/backlight.h>
|
||||
#include <ion/battery.h>
|
||||
#include <ion/board.h>
|
||||
#include <ion/clipboard.h>
|
||||
#include <ion/console.h>
|
||||
#include <ion/display.h>
|
||||
@@ -37,6 +38,7 @@ const char * softwareVersion();
|
||||
const char * omegaVersion();
|
||||
const char * patchLevel();
|
||||
const char * fccId();
|
||||
const char * pcbVersion();
|
||||
|
||||
// CRC32 : non xor-ed, non reversed, direct, polynomial 4C11DB7
|
||||
uint32_t crc32Word(const uint32_t * data, size_t length); // Only accepts whole 32bit values
|
||||
|
||||
12
ion/include/ion/board.h
Normal file
12
ion/include/ion/board.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#ifndef ION_BOARD_H
|
||||
#define ION_BOARD_H
|
||||
|
||||
namespace Ion {
|
||||
namespace Board {
|
||||
|
||||
void lockUnlockedPCBVersion();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -53,6 +53,18 @@ enum class ShiftAlphaStatus {
|
||||
// Timeout is decremented
|
||||
Event getEvent(int * timeout);
|
||||
|
||||
#if ION_EVENTS_JOURNAL
|
||||
class Journal {
|
||||
public:
|
||||
virtual void pushEvent(Event e) = 0;
|
||||
virtual Event popEvent() = 0;
|
||||
virtual bool isEmpty() = 0;
|
||||
};
|
||||
|
||||
void replayFrom(Journal * l);
|
||||
void logTo(Journal * l);
|
||||
#endif
|
||||
|
||||
ShiftAlphaStatus shiftAlphaStatus();
|
||||
void setShiftAlphaStatus(ShiftAlphaStatus s);
|
||||
void removeShift();
|
||||
|
||||
@@ -12,7 +12,9 @@ endif
|
||||
|
||||
ion_src += ion/src/shared/collect_registers.cpp
|
||||
|
||||
ION_DEVICE_SFLAGS = -Iion/src/device/$(MODEL) -Iion/src/device/shared
|
||||
IN_FACTORY ?= 0
|
||||
|
||||
ION_DEVICE_SFLAGS = -Iion/src/device/$(MODEL) -Iion/src/device/shared -DPCB_LATEST=$(PCB_LATEST) -DIN_FACTORY=$(IN_FACTORY)
|
||||
|
||||
$(call object_for,$(ion_device_src) $(ion_device_flasher_src) $(ion_device_bench_src)): SFLAGS += $(ION_DEVICE_SFLAGS)
|
||||
|
||||
|
||||
@@ -29,4 +29,5 @@ ion_device_bench_src += $(addprefix ion/src/device/bench/command/, \
|
||||
standby.cpp \
|
||||
usb_plugged.cpp \
|
||||
vblank.cpp \
|
||||
write_pcb_version.cpp \
|
||||
)
|
||||
|
||||
@@ -31,6 +31,7 @@ constexpr CommandHandler handles[] = {
|
||||
CommandHandler("STANDBY", Command::Standby),
|
||||
CommandHandler("USB_PLUGGED", Command::USBPlugged),
|
||||
CommandHandler("VBLANK", Command::VBlank),
|
||||
CommandHandler("WRITE_PCB_VERSION", Command::WritePCBVersion),
|
||||
CommandHandler(nullptr, nullptr)
|
||||
};
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ void LCDPins(const char * input);
|
||||
void LCDTiming(const char * input);
|
||||
void LED(const char * input);
|
||||
void MCUSerial(const char * input);
|
||||
void WritePCBVersion(const char * input);
|
||||
void Ping(const char * input);
|
||||
void Print(const char * input);
|
||||
void ScreenID(const char * input);
|
||||
|
||||
34
ion/src/device/bench/command/write_pcb_version.cpp
Normal file
34
ion/src/device/bench/command/write_pcb_version.cpp
Normal file
@@ -0,0 +1,34 @@
|
||||
#include "command.h"
|
||||
#include <drivers/board.h>
|
||||
|
||||
namespace Ion {
|
||||
namespace Device {
|
||||
namespace Bench {
|
||||
namespace Command {
|
||||
|
||||
void WritePCBVersion(const char * input) {
|
||||
if (input != nullptr) {
|
||||
reply(sSyntaxError);
|
||||
return;
|
||||
}
|
||||
|
||||
/* When running the bench for a diagnostic, we must absolutely not write the
|
||||
* OTP, as N0110 built prior to the PCB revision would still have their OTP
|
||||
* blank and unlocked. */
|
||||
#if IN_FACTORY
|
||||
Board::writePCBVersion(PCB_LATEST);
|
||||
/* Read directly from memory, as when IN_FACTORY is true, the method
|
||||
* pcbVersion always returns PCB_LATEST. */
|
||||
if (Board::readPCBVersionInMemory() != PCB_LATEST) {
|
||||
reply(sKO);
|
||||
return;
|
||||
}
|
||||
Board::lockPCBVersion();
|
||||
#endif
|
||||
reply(sOK);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
ion_device_src += $(addprefix ion/src/device/n0100/drivers/, \
|
||||
board.cpp \
|
||||
external_flash.cpp \
|
||||
led.cpp \
|
||||
power.cpp \
|
||||
reset.cpp \
|
||||
usb.cpp \
|
||||
)
|
||||
|
||||
LDSCRIPT ?= ion/src/device/n0100/flash.ld
|
||||
|
||||
@@ -231,6 +231,23 @@ void shutdownClocks(bool keepLEDAwake) {
|
||||
RCC.AHB1ENR()->set(ahb1enr);
|
||||
}
|
||||
|
||||
/* The following methods regarding PCB version are dummy implementations.
|
||||
* Handling the PCB version is only necessary on the N0110. */
|
||||
|
||||
PCBVersion pcbVersion() {
|
||||
return PCB_LATEST;
|
||||
}
|
||||
|
||||
PCBVersion readPCBVersionInMemory() {
|
||||
return PCB_LATEST;
|
||||
}
|
||||
|
||||
void writePCBVersion(PCBVersion) {}
|
||||
|
||||
void lockPCBVersion() {}
|
||||
|
||||
bool pcbVersionIsLocked() { return true; }
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
18
ion/src/device/n0100/drivers/external_flash.cpp
Normal file
18
ion/src/device/n0100/drivers/external_flash.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
#include <drivers/external_flash.h>
|
||||
|
||||
namespace Ion {
|
||||
namespace Device {
|
||||
namespace ExternalFlash {
|
||||
|
||||
void init() {}
|
||||
void shutdown() {}
|
||||
|
||||
void MassErase() {}
|
||||
int SectorAtAddress(uint32_t) { return 0; }
|
||||
void EraseSector(int) {}
|
||||
void WriteMemory(uint8_t *, const uint8_t *, size_t) {}
|
||||
void JDECid(uint8_t *, uint8_t *, uint8_t *) {}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
14
ion/src/device/n0100/drivers/usb.cpp
Normal file
14
ion/src/device/n0100/drivers/usb.cpp
Normal file
@@ -0,0 +1,14 @@
|
||||
#include <drivers/usb.h>
|
||||
#include <drivers/config/usb.h>
|
||||
|
||||
namespace Ion {
|
||||
namespace Device {
|
||||
namespace USB {
|
||||
|
||||
void initVbus() {
|
||||
Config::VbusPin.init();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
ion_device_src += $(addprefix ion/src/device/n0110/drivers/, \
|
||||
board.cpp \
|
||||
cache.cpp \
|
||||
external_flash.cpp \
|
||||
led.cpp \
|
||||
power.cpp \
|
||||
reset.cpp \
|
||||
usb.cpp \
|
||||
)
|
||||
|
||||
LDSCRIPT ?= ion/src/device/n0110/flash.ld
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#include <drivers/board.h>
|
||||
#include <drivers/cache.h>
|
||||
#include <drivers/internal_flash.h>
|
||||
#include <drivers/config/clocks.h>
|
||||
#include <drivers/config/internal_flash.h>
|
||||
#include <drivers/external_flash.h>
|
||||
#include <regs/regs.h>
|
||||
#include <ion.h>
|
||||
@@ -372,6 +374,44 @@ void shutdownClocks(bool keepLEDAwake) {
|
||||
RCC.AHB1ENR()->set(ahb1enr);
|
||||
}
|
||||
|
||||
constexpr int k_pcbVersionOTPIndex = 0;
|
||||
|
||||
/* As we want the PCB versions to be in ascending order chronologically, and
|
||||
* because the OTP are initialized with 1s, we store the bitwise-not of the
|
||||
* version number. This way, devices with blank OTP are considered version 0. */
|
||||
|
||||
PCBVersion pcbVersion() {
|
||||
#if IN_FACTORY
|
||||
/* When flashing for the first time, we want all systems that depend on the
|
||||
* PCB version to function correctly before flashing the PCB version. This
|
||||
* way, flashing the PCB version can be done last. */
|
||||
return PCB_LATEST;
|
||||
#else
|
||||
PCBVersion version = readPCBVersionInMemory();
|
||||
return (version == k_alternateBlankVersion ? 0 : version);
|
||||
#endif
|
||||
}
|
||||
|
||||
PCBVersion readPCBVersionInMemory() {
|
||||
return ~(*reinterpret_cast<const PCBVersion *>(InternalFlash::Config::OTPAddress(k_pcbVersionOTPIndex)));
|
||||
}
|
||||
|
||||
void writePCBVersion(PCBVersion version) {
|
||||
uint8_t * destination = reinterpret_cast<uint8_t *>(InternalFlash::Config::OTPAddress(k_pcbVersionOTPIndex));
|
||||
PCBVersion formattedVersion = ~version;
|
||||
InternalFlash::WriteMemory(destination, reinterpret_cast<uint8_t *>(&formattedVersion), sizeof(formattedVersion));
|
||||
}
|
||||
|
||||
void lockPCBVersion() {
|
||||
uint8_t * destination = reinterpret_cast<uint8_t *>(InternalFlash::Config::OTPLockAddress(k_pcbVersionOTPIndex));
|
||||
uint8_t zero = 0;
|
||||
InternalFlash::WriteMemory(destination, &zero, sizeof(zero));
|
||||
}
|
||||
|
||||
bool pcbVersionIsLocked() {
|
||||
return *reinterpret_cast<const uint8_t *>(InternalFlash::Config::OTPLockAddress(k_pcbVersionOTPIndex)) == 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,13 @@ constexpr static uint32_t SectorAddresses[NumberOfSectors+1] = {
|
||||
0x08010000
|
||||
};
|
||||
|
||||
constexpr static uint32_t OTPStartAddress = 0x1FF07800;
|
||||
constexpr static uint32_t OTPLocksAddress = 0x1FF07A00;
|
||||
constexpr static int NumberOfOTPBlocks = 16;
|
||||
constexpr static uint32_t OTPBlockSize = 0x20;
|
||||
constexpr uint32_t OTPAddress(int block) { return OTPStartAddress + block * OTPBlockSize; };
|
||||
constexpr uint32_t OTPLockAddress(int block) { return OTPLocksAddress + block; }
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,14 @@ namespace Config {
|
||||
|
||||
using namespace Regs;
|
||||
|
||||
/* On the STM32F730, PA9 does not actually support alternate function 10.
|
||||
* However, because of the wiring of the USB connector on old N0110, detection
|
||||
* of when the device is plugged required the use of this undocumented setting.
|
||||
* After the revision of the USB connector and ESD protection, we can now
|
||||
* follow the specification and configure the Vbus pin as a floating-input GPIO.
|
||||
*/
|
||||
constexpr static AFGPIOPin VbusPin = AFGPIOPin(GPIOA, 9, GPIO::AFR::AlternateFunction::AF10, GPIO::PUPDR::Pull::None, GPIO::OSPEEDR::OutputSpeed::Fast);
|
||||
|
||||
constexpr static AFGPIOPin DmPin = AFGPIOPin(GPIOA, 11, GPIO::AFR::AlternateFunction::AF10, GPIO::PUPDR::Pull::None, GPIO::OSPEEDR::OutputSpeed::Fast);
|
||||
constexpr static AFGPIOPin DpPin = AFGPIOPin(GPIOA, 12, GPIO::AFR::AlternateFunction::AF10, GPIO::PUPDR::Pull::None, GPIO::OSPEEDR::OutputSpeed::Fast);
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "external_flash.h"
|
||||
#include <drivers/external_flash.h>
|
||||
#include <drivers/cache.h>
|
||||
#include <drivers/config/external_flash.h>
|
||||
#include <drivers/config/clocks.h>
|
||||
#include <ion/timing.h>
|
||||
@@ -9,9 +10,9 @@ namespace ExternalFlash {
|
||||
|
||||
using namespace Regs;
|
||||
|
||||
/* The external flash and the Quad-SPI peripheral support
|
||||
* several operating modes, corresponding to different numbers of signals
|
||||
* used to communicate during each phase of the command sequence.
|
||||
/* The external flash and the Quad-SPI peripheral support several operating
|
||||
* modes, corresponding to different numbers of signals used to communicate
|
||||
* during each phase of the command sequence.
|
||||
*
|
||||
* Mode name for | Number of signals used during each phase:
|
||||
* external flash | Instruction | Address | Alt. bytes | Data
|
||||
@@ -23,8 +24,8 @@ using namespace Regs;
|
||||
* Quad-I/O SPI | 1 | 4 | 4 | 4
|
||||
* QPI | 4 | 4 | 4 | 4
|
||||
*
|
||||
* The external flash supports clock frequencies up to 104MHz for all instructions,
|
||||
* except for Read Data (0x03) which is supported up to 50Mhz.
|
||||
* The external flash supports clock frequencies up to 104MHz for all
|
||||
* instructions, except for Read Data (0x03) which is supported up to 50Mhz.
|
||||
*
|
||||
*
|
||||
* Quad-SPI block diagram
|
||||
@@ -37,47 +38,45 @@ using namespace Regs;
|
||||
* matrix --> | register --> FIFO | --> | |
|
||||
* +----------------------+ write +------------+
|
||||
*
|
||||
* Any data transmitted to or from the external flash memory go through a 32-byte FIFO.
|
||||
* Any data transmitted to or from the external flash memory go through a
|
||||
* 32-byte FIFO.
|
||||
*
|
||||
* Read or write operations are performed in burst mode, that is,
|
||||
* after any data byte is transmitted between the Quad-SPI and the flash memory,
|
||||
* the latter automatically increments the specified address and
|
||||
* the next byte to read or write is respectively pushed in or popped from the FIFO.
|
||||
* and so on, as long as the clock continues.
|
||||
* Read or write operations are performed in burst mode, that is, after any data
|
||||
* byte is transmitted between the Quad-SPI and the flash memory, the latter
|
||||
* automatically increments the specified address and the next byte to read or
|
||||
* write is respectively pushed in or popped from the FIFO.
|
||||
* And so on, as long as the clock continues.
|
||||
*
|
||||
* If the FIFO gets full in a read operation or
|
||||
* if the FIFO gets empty in a write operation,
|
||||
* the operation stalls and CLK stays low until firmware services the FIFO.
|
||||
*
|
||||
* If the FIFO gets full in a write operation,
|
||||
* the operation is stalled until the FIFO has enough space to accept the amount of data being written.
|
||||
* If the FIFO does not have as many bytes as requested by the read operation and if BUSY=1,
|
||||
* the operation is stalled until enough data is present or until the transfer is complete, whichever happens first. */
|
||||
* If the FIFO gets full in a write operation, the operation is stalled until
|
||||
* the FIFO has enough space to accept the amount of data being written.
|
||||
* If the FIFO does not have as many bytes as requested by the read operation
|
||||
* and if BUSY=1, the operation is stalled until enough data is present or until
|
||||
* the transfer is complete, whichever happens first. */
|
||||
|
||||
enum class Command : uint8_t {
|
||||
ReadStatusRegister1 = 0x05,
|
||||
ReadStatusRegister2 = 0x35,
|
||||
WriteStatusRegister = 0x01,
|
||||
WriteStatusRegister2 = 0x31,
|
||||
WriteEnable = 0x06,
|
||||
ReadData = 0x03,
|
||||
FastRead = 0x0B,
|
||||
FastReadQuadIO = 0xEB,
|
||||
// Program previously erased memory areas as being "0"
|
||||
PageProgram = 0x02,
|
||||
QuadPageProgram = 0x33,
|
||||
EnableQPI = 0x38,
|
||||
EnableReset = 0x66,
|
||||
Reset = 0x99,
|
||||
// Erase the whole chip or a 64-Kbyte block as being "1"
|
||||
ChipErase = 0xC7,
|
||||
Erase4KbyteBlock = 0x20,
|
||||
Erase32KbyteBlock = 0x52,
|
||||
Erase64KbyteBlock = 0xD8,
|
||||
SetReadParameters = 0xC0,
|
||||
DeepPowerDown = 0xB9,
|
||||
ReleaseDeepPowerDown = 0xAB,
|
||||
ReadJEDECID = 0x9F
|
||||
WriteStatusRegister = 0x01,
|
||||
PageProgram = 0x02, // Program previously erased memory areas as being "0"
|
||||
ReadData = 0x03,
|
||||
ReadStatusRegister1 = 0x05,
|
||||
WriteEnable = 0x06,
|
||||
Erase4KbyteBlock = 0x20,
|
||||
WriteStatusRegister2 = 0x31,
|
||||
QuadPageProgramW25Q64JV = 0x32,
|
||||
QuadPageProgramAT25F641 = 0x33,
|
||||
ReadStatusRegister2 = 0x35,
|
||||
Erase32KbyteBlock = 0x52,
|
||||
EnableReset = 0x66,
|
||||
Reset = 0x99,
|
||||
ReadJEDECID = 0x9F,
|
||||
ReleaseDeepPowerDown = 0xAB,
|
||||
DeepPowerDown = 0xB9,
|
||||
ChipErase = 0xC7, // Erase the whole chip or a 64-Kbyte block as being "1"
|
||||
Erase64KbyteBlock = 0xD8,
|
||||
FastReadQuadIO = 0xEB
|
||||
};
|
||||
|
||||
static constexpr uint8_t NumberOfAddressBitsIn64KbyteBlock = 16;
|
||||
@@ -98,53 +97,95 @@ public:
|
||||
};
|
||||
};
|
||||
|
||||
static constexpr QUADSPI::CCR::OperatingMode DefaultOperatingMode = QUADSPI::CCR::OperatingMode::Quad;
|
||||
static constexpr int ClockFrequencyDivisor = 2;
|
||||
static constexpr bool ajustNumberOfDummyCycles = Clocks::Config::AHBFrequency > (80 * ClockFrequencyDivisor);
|
||||
static constexpr int FastReadDummyCycles = (DefaultOperatingMode == QUADSPI::CCR::OperatingMode::Quad && ajustNumberOfDummyCycles) ? 4 : 2;
|
||||
class OperatingModes {
|
||||
public:
|
||||
constexpr OperatingModes(
|
||||
QUADSPI::CCR::OperatingMode instruction,
|
||||
QUADSPI::CCR::OperatingMode address,
|
||||
QUADSPI::CCR::OperatingMode data) :
|
||||
m_instructionOperatingMode(instruction),
|
||||
m_addressOperatingMode(address),
|
||||
m_dataOperatingMode(data)
|
||||
{}
|
||||
QUADSPI::CCR::OperatingMode instructionOperatingMode() const { return m_instructionOperatingMode; }
|
||||
QUADSPI::CCR::OperatingMode addressOperatingMode() const { return m_addressOperatingMode; }
|
||||
QUADSPI::CCR::OperatingMode dataOperatingMode() const { return m_dataOperatingMode; }
|
||||
private:
|
||||
QUADSPI::CCR::OperatingMode m_instructionOperatingMode;
|
||||
QUADSPI::CCR::OperatingMode m_addressOperatingMode;
|
||||
QUADSPI::CCR::OperatingMode m_dataOperatingMode;
|
||||
};
|
||||
|
||||
static void send_command_full(QUADSPI::CCR::FunctionalMode functionalMode, QUADSPI::CCR::OperatingMode operatingMode, Command c, uint8_t * address, uint32_t altBytes, size_t numberOfAltBytes, uint8_t dummyCycles, uint8_t * data, size_t dataLength);
|
||||
/* W25Q64JV does not implement QPI-4-4-4, so we always send the instructions on
|
||||
* one wire only.*/
|
||||
static constexpr OperatingModes sOperatingModes100(QUADSPI::CCR::OperatingMode::Single, QUADSPI::CCR::OperatingMode::NoData, QUADSPI::CCR::OperatingMode::NoData);
|
||||
static constexpr OperatingModes sOperatingModes101(QUADSPI::CCR::OperatingMode::Single, QUADSPI::CCR::OperatingMode::NoData, QUADSPI::CCR::OperatingMode::Single);
|
||||
static constexpr OperatingModes sOperatingModes110(QUADSPI::CCR::OperatingMode::Single, QUADSPI::CCR::OperatingMode::Single, QUADSPI::CCR::OperatingMode::NoData);
|
||||
static constexpr OperatingModes sOperatingModes111(QUADSPI::CCR::OperatingMode::Single, QUADSPI::CCR::OperatingMode::Single, QUADSPI::CCR::OperatingMode::Single);
|
||||
static constexpr OperatingModes sOperatingModes114(QUADSPI::CCR::OperatingMode::Single, QUADSPI::CCR::OperatingMode::Single, QUADSPI::CCR::OperatingMode::Quad);
|
||||
static constexpr OperatingModes sOperatingModes144(QUADSPI::CCR::OperatingMode::Single, QUADSPI::CCR::OperatingMode::Quad, QUADSPI::CCR::OperatingMode::Quad);
|
||||
|
||||
static inline void send_command(Command c, QUADSPI::CCR::OperatingMode operatingMode = DefaultOperatingMode) {
|
||||
static QUADSPI::CCR::OperatingMode sOperatingMode = QUADSPI::CCR::OperatingMode::Single;
|
||||
|
||||
static constexpr int ClockFrequencyDivisor = 2; // F(QUADSPI) = F(AHB) / ClockFrequencyDivisor
|
||||
static constexpr int FastReadQuadIODummyCycles = 4; // Must be 4 for W25Q64JV (Fig 24.A page 34) and for AT25F641 (table 7.19 page 28)
|
||||
/* According to datasheets, the CS signal should stay high (deselect the device)
|
||||
* for t_SHSL = 50ns at least.
|
||||
* -> Max of 30ns (see AT25F641 Sections 8.7 and 8.8),
|
||||
* 10ns and 50ns (see W25Q64JV Section 9.6). */
|
||||
static constexpr float ChipSelectHighTimeInNanoSeconds = 50.0f;
|
||||
|
||||
static void send_command_full(
|
||||
QUADSPI::CCR::FunctionalMode functionalMode,
|
||||
OperatingModes operatingModes,
|
||||
Command c,
|
||||
uint8_t * address,
|
||||
uint32_t altBytes,
|
||||
size_t numberOfAltBytes,
|
||||
uint8_t dummyCycles,
|
||||
uint8_t * data,
|
||||
size_t dataLength);
|
||||
|
||||
static inline void send_command(Command c) {
|
||||
send_command_full(
|
||||
QUADSPI::CCR::FunctionalMode::IndirectWrite,
|
||||
operatingMode,
|
||||
sOperatingModes100,
|
||||
c,
|
||||
reinterpret_cast<uint8_t *>(FlashAddressSpaceSize),
|
||||
0, 0,
|
||||
0,
|
||||
nullptr, 0
|
||||
);
|
||||
nullptr, 0);
|
||||
}
|
||||
|
||||
static inline void send_write_command(Command c, uint8_t * address, const uint8_t * data, size_t dataLength, QUADSPI::CCR::OperatingMode operatingMode = DefaultOperatingMode) {
|
||||
static inline void send_write_command(Command c, uint8_t * address, const uint8_t * data, size_t dataLength, OperatingModes operatingModes) {
|
||||
send_command_full(
|
||||
QUADSPI::CCR::FunctionalMode::IndirectWrite,
|
||||
operatingMode,
|
||||
operatingModes,
|
||||
c,
|
||||
address,
|
||||
0, 0,
|
||||
0,
|
||||
const_cast<uint8_t *>(data), dataLength
|
||||
);
|
||||
const_cast<uint8_t *>(data), dataLength);
|
||||
}
|
||||
|
||||
static inline void send_read_command(Command c, uint8_t * address, uint8_t * data, size_t dataLength, QUADSPI::CCR::OperatingMode operatingMode = DefaultOperatingMode) {
|
||||
static inline void send_read_command(Command c, uint8_t * address, uint8_t * data, size_t dataLength) {
|
||||
send_command_full(
|
||||
QUADSPI::CCR::FunctionalMode::IndirectRead,
|
||||
operatingMode,
|
||||
sOperatingModes101,
|
||||
c,
|
||||
address,
|
||||
0, 0,
|
||||
0,
|
||||
data, dataLength
|
||||
);
|
||||
data, dataLength);
|
||||
}
|
||||
|
||||
static inline void wait(QUADSPI::CCR::OperatingMode operatingMode = DefaultOperatingMode) {
|
||||
static inline void wait() {
|
||||
/* The DSB instruction guarantees the completion of a write operation before
|
||||
* polling the status register. */
|
||||
Cache::dsb();
|
||||
ExternalFlashStatusRegister::StatusRegister1 statusRegister1(0);
|
||||
do {
|
||||
send_read_command(Command::ReadStatusRegister1, reinterpret_cast<uint8_t *>(FlashAddressSpaceSize), reinterpret_cast<uint8_t *>(&statusRegister1), sizeof(statusRegister1), operatingMode);
|
||||
send_read_command(Command::ReadStatusRegister1, reinterpret_cast<uint8_t *>(FlashAddressSpaceSize), reinterpret_cast<uint8_t *>(&statusRegister1), sizeof(statusRegister1));
|
||||
} while (statusRegister1.getBUSY());
|
||||
}
|
||||
|
||||
@@ -160,11 +201,11 @@ static void set_as_memory_mapped() {
|
||||
* (Flash memories tend to consume more when nCS is held low.) */
|
||||
send_command_full(
|
||||
QUADSPI::CCR::FunctionalMode::MemoryMapped,
|
||||
DefaultOperatingMode,
|
||||
sOperatingModes144,
|
||||
Command::FastReadQuadIO,
|
||||
reinterpret_cast<uint8_t *>(FlashAddressSpaceSize),
|
||||
0xA0, 1,
|
||||
FastReadDummyCycles,
|
||||
FastReadQuadIODummyCycles,
|
||||
nullptr, 0
|
||||
);
|
||||
}
|
||||
@@ -174,16 +215,16 @@ static void unset_memory_mapped_mode() {
|
||||
uint8_t dummyData;
|
||||
send_command_full(
|
||||
QUADSPI::CCR::FunctionalMode::IndirectRead,
|
||||
DefaultOperatingMode,
|
||||
sOperatingModes144,
|
||||
Command::FastReadQuadIO,
|
||||
0,
|
||||
~(0xA0), 1,
|
||||
FastReadDummyCycles,
|
||||
FastReadQuadIODummyCycles,
|
||||
&dummyData, 1
|
||||
);
|
||||
}
|
||||
|
||||
static void send_command_full(QUADSPI::CCR::FunctionalMode functionalMode, QUADSPI::CCR::OperatingMode operatingMode, Command c, uint8_t * address, uint32_t altBytes, size_t numberOfAltBytes, uint8_t dummyCycles, uint8_t * data, size_t dataLength) {
|
||||
static void send_command_full(QUADSPI::CCR::FunctionalMode functionalMode, OperatingModes operatingModes, Command c, uint8_t * address, uint32_t altBytes, size_t numberOfAltBytes, uint8_t dummyCycles, uint8_t * data, size_t dataLength) {
|
||||
/* According to ST's Errata Sheet ES0360, "Wrong data can be read in
|
||||
* memory-mapped after an indirect mode operation". This is the workaround. */
|
||||
if (functionalMode == QUADSPI::CCR::FunctionalMode::MemoryMapped) {
|
||||
@@ -214,22 +255,22 @@ static void send_command_full(QUADSPI::CCR::FunctionalMode functionalMode, QUADS
|
||||
class QUADSPI::CCR ccr(0);
|
||||
ccr.setFMODE(functionalMode);
|
||||
if (data != nullptr || functionalMode == QUADSPI::CCR::FunctionalMode::MemoryMapped) {
|
||||
ccr.setDMODE(operatingMode);
|
||||
ccr.setDMODE(operatingModes.dataOperatingMode());
|
||||
}
|
||||
if (functionalMode != QUADSPI::CCR::FunctionalMode::MemoryMapped) {
|
||||
QUADSPI.DLR()->set((dataLength > 0) ? dataLength-1 : 0);
|
||||
}
|
||||
ccr.setDCYC(dummyCycles);
|
||||
if (numberOfAltBytes > 0) {
|
||||
ccr.setABMODE(operatingMode);
|
||||
ccr.setABMODE(operatingModes.addressOperatingMode()); // Seems to always be the same as address mode
|
||||
ccr.setABSIZE(static_cast<QUADSPI::CCR::Size>(numberOfAltBytes - 1));
|
||||
QUADSPI.ABR()->set(altBytes);
|
||||
}
|
||||
if (address != reinterpret_cast<uint8_t *>(FlashAddressSpaceSize) || functionalMode == QUADSPI::CCR::FunctionalMode::MemoryMapped) {
|
||||
ccr.setADMODE(operatingMode);
|
||||
ccr.setADMODE(operatingModes.addressOperatingMode());
|
||||
ccr.setADSIZE(QUADSPI::CCR::Size::ThreeBytes);
|
||||
}
|
||||
ccr.setIMODE(operatingMode);
|
||||
ccr.setIMODE(operatingModes.instructionOperatingMode());
|
||||
ccr.setINSTRUCTION(static_cast<uint8_t>(c));
|
||||
if (functionalMode == QUADSPI::CCR::FunctionalMode::MemoryMapped) {
|
||||
ccr.setSIOO(true);
|
||||
@@ -275,11 +316,8 @@ static void initQSPI() {
|
||||
// Configure controller for target device
|
||||
class QUADSPI::DCR dcr(0);
|
||||
dcr.setFSIZE(NumberOfAddressBitsInChip - 1);
|
||||
/* According to the device's datasheet (see Sections 8.7 and 8.8), the CS
|
||||
* signal should stay high (deselect the device) for t_SHSL = 30ns at least.
|
||||
* */
|
||||
constexpr int ChipSelectHighTime = (30 * Clocks::Config::AHBFrequency + ClockFrequencyDivisor * 1000 - 1) / (ClockFrequencyDivisor * 1000);
|
||||
dcr.setCSHT(ChipSelectHighTime - 1);
|
||||
constexpr int ChipSelectHighTimeCycles = (ChipSelectHighTimeInNanoSeconds * static_cast<float>(Clocks::Config::AHBFrequency)) / (static_cast<float>(ClockFrequencyDivisor) * 1000.0f) + 1.0f;
|
||||
dcr.setCSHT(ChipSelectHighTimeCycles - 1);
|
||||
dcr.setCKMODE(true);
|
||||
QUADSPI.DCR()->set(dcr);
|
||||
class QUADSPI::CR cr(0);
|
||||
@@ -288,36 +326,20 @@ static void initQSPI() {
|
||||
QUADSPI.CR()->set(cr);
|
||||
}
|
||||
|
||||
static QUADSPI::CCR::OperatingMode sOperatingMode = QUADSPI::CCR::OperatingMode::Single;
|
||||
|
||||
static void initChip() {
|
||||
// Release sleep deep
|
||||
send_command(Command::ReleaseDeepPowerDown, sOperatingMode);
|
||||
send_command(Command::ReleaseDeepPowerDown);
|
||||
Timing::usleep(3);
|
||||
|
||||
/* The chip initially expects commands in SPI mode. We need to use SPI to tell
|
||||
* it to switch to QPI. */
|
||||
if (sOperatingMode == QUADSPI::CCR::OperatingMode::Single && DefaultOperatingMode == QUADSPI::CCR::OperatingMode::Quad) {
|
||||
send_command(Command::WriteEnable, QUADSPI::CCR::OperatingMode::Single);
|
||||
* it to switch to QuadSPI/QPI. */
|
||||
if (sOperatingMode == QUADSPI::CCR::OperatingMode::Single) {
|
||||
send_command(Command::WriteEnable);
|
||||
ExternalFlashStatusRegister::StatusRegister2 statusRegister2(0);
|
||||
statusRegister2.setQE(true);
|
||||
wait(QUADSPI::CCR::OperatingMode::Single);
|
||||
send_write_command(Command::WriteStatusRegister2, reinterpret_cast<uint8_t *>(FlashAddressSpaceSize), reinterpret_cast<uint8_t *>(&statusRegister2), sizeof(statusRegister2), QUADSPI::CCR::OperatingMode::Single);
|
||||
wait(QUADSPI::CCR::OperatingMode::Single);
|
||||
send_command(Command::EnableQPI, QUADSPI::CCR::OperatingMode::Single);
|
||||
wait();
|
||||
if (ajustNumberOfDummyCycles) {
|
||||
class ReadParameters : Register8 {
|
||||
public:
|
||||
/* Parameters sent along with SetReadParameters instruction in order
|
||||
* to configure the number of dummy cycles for the QPI Read instructions. */
|
||||
using Register8::Register8;
|
||||
REGS_BOOL_FIELD_W(P5, 5);
|
||||
};
|
||||
ReadParameters readParameters(0);
|
||||
readParameters.setP5(true);
|
||||
send_write_command(Command::SetReadParameters, reinterpret_cast<uint8_t *>(FlashAddressSpaceSize), reinterpret_cast<uint8_t *>(&readParameters), sizeof(readParameters));
|
||||
}
|
||||
send_write_command(Command::WriteStatusRegister2, reinterpret_cast<uint8_t *>(FlashAddressSpaceSize), reinterpret_cast<uint8_t *>(&statusRegister2), sizeof(statusRegister2), sOperatingModes101);
|
||||
wait();
|
||||
sOperatingMode = QUADSPI::CCR::OperatingMode::Quad;
|
||||
}
|
||||
set_as_memory_mapped();
|
||||
@@ -346,10 +368,10 @@ static void shutdownChip() {
|
||||
send_command(Command::EnableReset);
|
||||
send_command(Command::Reset);
|
||||
sOperatingMode = QUADSPI::CCR::OperatingMode::Single;
|
||||
Ion::Timing::usleep(30);
|
||||
Timing::usleep(30);
|
||||
|
||||
// Sleep deep
|
||||
send_command(Command::DeepPowerDown, sOperatingMode);
|
||||
send_command(Command::DeepPowerDown);
|
||||
Timing::usleep(3);
|
||||
}
|
||||
|
||||
@@ -402,7 +424,7 @@ void unlockFlash() {
|
||||
statusRegister2.setQE(currentStatusRegister2.getQE());
|
||||
|
||||
uint8_t registers[] = {statusRegister1.get(), statusRegister2.get()};
|
||||
send_write_command(Command::WriteStatusRegister, reinterpret_cast<uint8_t *>(FlashAddressSpaceSize), reinterpret_cast<uint8_t *>(registers), sizeof(registers));
|
||||
send_write_command(Command::WriteStatusRegister, reinterpret_cast<uint8_t *>(FlashAddressSpaceSize), reinterpret_cast<uint8_t *>(registers), sizeof(registers), sOperatingModes101);
|
||||
wait();
|
||||
}
|
||||
|
||||
@@ -428,18 +450,18 @@ void __attribute__((noinline)) EraseSector(int i) {
|
||||
/* WARNING: this code assumes that the flash sectors are of increasing size:
|
||||
* first all 4K sectors, then all 32K sectors, and finally all 64K sectors. */
|
||||
if (i < Config::NumberOf4KSectors) {
|
||||
send_write_command(Command::Erase4KbyteBlock, reinterpret_cast<uint8_t *>(i << NumberOfAddressBitsIn4KbyteBlock), nullptr, 0);
|
||||
send_write_command(Command::Erase4KbyteBlock, reinterpret_cast<uint8_t *>(i << NumberOfAddressBitsIn4KbyteBlock), nullptr, 0, sOperatingModes110);
|
||||
} else if (i < Config::NumberOf4KSectors + Config::NumberOf32KSectors) {
|
||||
/* If the sector is the number Config::NumberOf4KSectors, we want to write
|
||||
* at the address 1 << NumberOfAddressBitsIn32KbyteBlock, hence the formula
|
||||
* (i - Config::NumberOf4KSectors + 1). */
|
||||
send_write_command(Command::Erase32KbyteBlock, reinterpret_cast<uint8_t *>((i - Config::NumberOf4KSectors + 1) << NumberOfAddressBitsIn32KbyteBlock), nullptr, 0);
|
||||
send_write_command(Command::Erase32KbyteBlock, reinterpret_cast<uint8_t *>((i - Config::NumberOf4KSectors + 1) << NumberOfAddressBitsIn32KbyteBlock), nullptr, 0, sOperatingModes110);
|
||||
} else {
|
||||
/* If the sector is the number
|
||||
* Config::NumberOf4KSectors - Config::NumberOf32KSectors, we want to write
|
||||
* at the address 1 << NumberOfAddressBitsIn32KbyteBlock, hence the formula
|
||||
* (i - Config::NumberOf4KSectors - Config::NumberOf32KSectors + 1). */
|
||||
send_write_command(Command::Erase64KbyteBlock, reinterpret_cast<uint8_t *>((i - Config::NumberOf4KSectors - Config::NumberOf32KSectors + 1) << NumberOfAddressBitsIn64KbyteBlock), nullptr, 0);
|
||||
send_write_command(Command::Erase64KbyteBlock, reinterpret_cast<uint8_t *>((i - Config::NumberOf4KSectors - Config::NumberOf32KSectors + 1) << NumberOfAddressBitsIn64KbyteBlock), nullptr, 0, sOperatingModes110);
|
||||
}
|
||||
wait();
|
||||
set_as_memory_mapped();
|
||||
@@ -455,7 +477,6 @@ void __attribute__((noinline)) WriteMemory(uint8_t * destination, const uint8_t
|
||||
* However, when the end of a page is reached, the addressing wraps to the beginning.
|
||||
* Hence a Page Program instruction must be issued for each page. */
|
||||
static constexpr size_t PageSize = 256;
|
||||
constexpr Command pageProgram = (DefaultOperatingMode == QUADSPI::CCR::OperatingMode::Single) ? Command::PageProgram : Command::QuadPageProgram;
|
||||
uint8_t offset = reinterpret_cast<uint32_t>(destination) & (PageSize - 1);
|
||||
size_t lengthThatFitsInPage = PageSize - offset;
|
||||
while (length > 0) {
|
||||
@@ -464,7 +485,12 @@ void __attribute__((noinline)) WriteMemory(uint8_t * destination, const uint8_t
|
||||
}
|
||||
send_command(Command::WriteEnable);
|
||||
wait();
|
||||
send_write_command(pageProgram, destination, source, lengthThatFitsInPage);
|
||||
|
||||
/* Some chips implement 0x32 only, others 0x33 only, we call both. This does
|
||||
* not seem to affect the writing. */
|
||||
send_write_command(Command::QuadPageProgramAT25F641, destination, source, lengthThatFitsInPage, sOperatingModes144);
|
||||
send_write_command(Command::QuadPageProgramW25Q64JV, destination, source, lengthThatFitsInPage, sOperatingModes114);
|
||||
|
||||
length -= lengthThatFitsInPage;
|
||||
destination += lengthThatFitsInPage;
|
||||
source += lengthThatFitsInPage;
|
||||
27
ion/src/device/n0110/drivers/usb.cpp
Normal file
27
ion/src/device/n0110/drivers/usb.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
#include <drivers/usb.h>
|
||||
#include <drivers/board.h>
|
||||
#include <drivers/config/usb.h>
|
||||
|
||||
namespace Ion {
|
||||
namespace Device {
|
||||
|
||||
using namespace Regs;
|
||||
|
||||
namespace USB {
|
||||
|
||||
bool useAlternateFunctionVbus() {
|
||||
return Board::pcbVersion() == 0;
|
||||
}
|
||||
|
||||
void initVbus() {
|
||||
if (useAlternateFunctionVbus()) {
|
||||
Config::VbusPin.init();
|
||||
} else {
|
||||
Config::VbusPin.group().MODER()->setMode(Config::VbusPin.pin(), GPIO::MODER::Mode::Input);
|
||||
Config::VbusPin.group().PUPDR()->setPull(Config::VbusPin.pin(), GPIO::PUPDR::Pull::None);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,16 +5,18 @@ ion_device_src += $(addprefix ion/src/device/shared/drivers/, \
|
||||
board.cpp \
|
||||
clipboard.cpp \
|
||||
console_uart.cpp:+consoleuart \
|
||||
console_display.cpp:+consoledisplay \
|
||||
console_dummy.cpp:-consoledisplay \
|
||||
console_dummy.cpp:-consoleuart \
|
||||
crc32.cpp \
|
||||
display.cpp \
|
||||
events_keyboard_platform.cpp \
|
||||
exam_mode.cpp \
|
||||
external_flash.cpp \
|
||||
flash.cpp \
|
||||
internal_flash.cpp \
|
||||
keyboard.cpp \
|
||||
led.cpp \
|
||||
pcb_version.cpp \
|
||||
power.cpp\
|
||||
random.cpp\
|
||||
reset.cpp \
|
||||
|
||||
@@ -94,3 +94,26 @@ void setClockFrequency(Frequency f) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace Ion {
|
||||
namespace Board {
|
||||
|
||||
using namespace Device::Board;
|
||||
|
||||
void lockUnlockedPCBVersion() {
|
||||
if (pcbVersionIsLocked()) {
|
||||
return;
|
||||
}
|
||||
/* PCB version is unlocked : the device is a N0110 that has been
|
||||
* produced prior to the pcb revision 3.43. */
|
||||
PCBVersion version = pcbVersion();
|
||||
if (version != 0) {
|
||||
/* Some garbage has been written in OTP0. We overwrite it fully, which is
|
||||
* interepreted as blank. */
|
||||
writePCBVersion(k_alternateBlankVersion);
|
||||
}
|
||||
lockPCBVersion();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef ION_DEVICE_SHARED_DRIVERS_BOARD_H
|
||||
#define ION_DEVICE_SHARED_DRIVERS_BOARD_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace Ion {
|
||||
namespace Device {
|
||||
namespace Board {
|
||||
@@ -23,6 +25,20 @@ Frequency standardFrequency();
|
||||
void setStandardFrequency(Frequency f);
|
||||
void setClockFrequency(Frequency f);
|
||||
|
||||
typedef uint32_t PCBVersion;
|
||||
/* On N0110 released before the PCB revision, OTP0 is supposed to be blank and
|
||||
* unlocked. However, such a device with something written in OTP0 will be
|
||||
* unable to configure Vbus properly. In this case, and if OTP0 is still
|
||||
* unlocked, we fully write OTP0 and treat it the same as fully blank.
|
||||
* This way, pcbVersion will be 0 if OTP0 is either 0x00000000 or 0xFFFFFFFF.*/
|
||||
constexpr PCBVersion k_alternateBlankVersion = 0xFFFFFFFF;
|
||||
|
||||
PCBVersion pcbVersion();
|
||||
PCBVersion readPCBVersionInMemory();
|
||||
void writePCBVersion(PCBVersion version);
|
||||
void lockPCBVersion();
|
||||
bool pcbVersionIsLocked();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
39
ion/src/device/shared/drivers/console_display.cpp
Normal file
39
ion/src/device/shared/drivers/console_display.cpp
Normal file
@@ -0,0 +1,39 @@
|
||||
#include "console.h"
|
||||
#include <ion/console.h>
|
||||
#include <kandinsky/ion_context.h>
|
||||
|
||||
namespace Ion {
|
||||
namespace Console {
|
||||
|
||||
char readChar() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void writeChar(char c) {
|
||||
KDIonContext::putchar(c);
|
||||
}
|
||||
|
||||
bool transmissionDone() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
namespace Ion {
|
||||
namespace Device {
|
||||
namespace Console {
|
||||
|
||||
void init() {
|
||||
}
|
||||
|
||||
void shutdown() {
|
||||
}
|
||||
|
||||
bool peerConnected() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,22 @@
|
||||
#include "console.h"
|
||||
#include <ion/console.h>
|
||||
|
||||
namespace Ion {
|
||||
namespace Console {
|
||||
|
||||
char readChar() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void writeChar(char c) {
|
||||
}
|
||||
|
||||
bool transmissionDone() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
namespace Ion {
|
||||
namespace Device {
|
||||
|
||||
25
ion/src/device/shared/drivers/pcb_version.cpp
Normal file
25
ion/src/device/shared/drivers/pcb_version.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
#include <ion.h>
|
||||
#include "board.h"
|
||||
|
||||
namespace Ion {
|
||||
|
||||
const char * pcbVersion() {
|
||||
constexpr int pcbVersionLength = 5; // xx.yy
|
||||
static char pcbVer[pcbVersionLength] = {'\0'};
|
||||
if (pcbVer[0] == '\0') {
|
||||
Device::Board::PCBVersion ver = Device::Board::pcbVersion();
|
||||
/* As PCB version only uses 4 chars, value should be at most 9999. */
|
||||
assert(ver < 10000);
|
||||
for (int i = pcbVersionLength - 1; i >= 0; i--) {
|
||||
if (i == 2) {
|
||||
pcbVer[i] = '.';
|
||||
} else {
|
||||
pcbVer[i] = '0' + ver % 10;
|
||||
ver /= 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
return pcbVer;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "serial_number.h"
|
||||
#include "board.h"
|
||||
#include <drivers/config/serial_number.h>
|
||||
#include "base64.h"
|
||||
|
||||
|
||||
@@ -65,22 +65,17 @@ void initGPIO() {
|
||||
GPIOC.MODER()->setMode(11, GPIO::MODER::Mode::Output);
|
||||
GPIOC.ODR()->set(11, false);
|
||||
|
||||
/* Configure the GPIO
|
||||
* The VBUS pin is connected to the USB VBUS port. To read if the USB is
|
||||
* plugged, the pin must be pulled down. */
|
||||
// FIXME: Understand how the Vbus pin really works!
|
||||
#if 0
|
||||
Config::VbusPin.group().MODER()->setMode(Config::VbusPin.pin(), GPIO::MODER::Mode::Input);
|
||||
Config::VbusPin.group().PUPDR()->setPull(Config::VbusPin.pin(), GPIO::PUPDR::Pull::Down);
|
||||
#else
|
||||
Config::VbusPin.init();
|
||||
#endif
|
||||
/* Configure the GPIO */
|
||||
/* The Vbus pin is connected to the USB Vbus port. Depending on the
|
||||
* hardware, it should either be configured as an AlternateFunction, or as a
|
||||
* floating Input. */
|
||||
initVbus();
|
||||
Config::DmPin.init();
|
||||
Config::DpPin.init();
|
||||
}
|
||||
|
||||
void shutdownGPIO() {
|
||||
constexpr static AFGPIOPin Pins[] = {Config::DpPin, Config::DmPin, Config::VbusPin};
|
||||
constexpr static AFGPIOPin Pins[] = { Config::DpPin, Config::DmPin, Config::VbusPin };
|
||||
for (const AFGPIOPin & p : Pins) {
|
||||
p.shutdown();
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ namespace USB {
|
||||
|
||||
void init();
|
||||
void shutdown();
|
||||
void initVbus();
|
||||
void initGPIO();
|
||||
void shutdownGPIO();
|
||||
void initOTG();
|
||||
|
||||
@@ -43,7 +43,9 @@ ion_device_dfu_src += libaxx/src/cxxabi/pure_virtual.cpp
|
||||
ion_device_dfu_src += ion/src/device/shared/usb/boot.cpp
|
||||
ion_device_dfu_src += ion/src/device/$(MODEL)/drivers/board.cpp
|
||||
ion_device_dfu_src += ion/src/device/$(MODEL)/drivers/cache.cpp
|
||||
ion_device_dfu_src += ion/src/device/$(MODEL)/drivers/external_flash.cpp
|
||||
ion_device_dfu_src += ion/src/device/$(MODEL)/drivers/reset.cpp
|
||||
ion_device_dfu_src += ion/src/device/$(MODEL)/drivers/usb.cpp
|
||||
ion_device_dfu_src += $(addprefix ion/src/device/shared/drivers/, \
|
||||
backlight.cpp \
|
||||
battery.cpp \
|
||||
@@ -53,7 +55,6 @@ ion_device_dfu_src += $(addprefix ion/src/device/shared/drivers/, \
|
||||
crc32.cpp \
|
||||
display.cpp \
|
||||
events_keyboard_platform.cpp \
|
||||
external_flash.cpp \
|
||||
flash.cpp \
|
||||
internal_flash.cpp \
|
||||
keyboard.cpp \
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
#include <ion/console.h>
|
||||
#include <kandinsky.h>
|
||||
#include <ion/display.h>
|
||||
|
||||
namespace Ion {
|
||||
namespace Console {
|
||||
|
||||
char readChar() {
|
||||
return '\0';
|
||||
}
|
||||
|
||||
static KDPoint cursor = KDPointZero;
|
||||
|
||||
void writeChar(char c) {
|
||||
char text[2] = {c, 0};
|
||||
KDContext * ctx = KDIonContext::sharedContext();
|
||||
cursor = ctx->drawString(text, cursor);
|
||||
if (cursor.y() > Ion::Display::Height) {
|
||||
cursor = KDPoint(cursor.x(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
bool transmissionDone() {
|
||||
// Always true because we flush after each writeChar
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
24
ion/src/shared/dummy/backlight.cpp
Normal file
24
ion/src/shared/dummy/backlight.cpp
Normal file
@@ -0,0 +1,24 @@
|
||||
#include <ion/backlight.h>
|
||||
|
||||
namespace Ion {
|
||||
namespace Backlight {
|
||||
|
||||
uint8_t brightness() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void setBrightness(uint8_t b) {
|
||||
}
|
||||
|
||||
void init() {
|
||||
}
|
||||
|
||||
bool isInitialized() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void shutdown() {
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
4
ion/src/shared/dummy/board.cpp
Normal file
4
ion/src/shared/dummy/board.cpp
Normal file
@@ -0,0 +1,4 @@
|
||||
#include <ion/board.h>
|
||||
|
||||
void Ion::Board::lockUnlockedPCBVersion() {
|
||||
}
|
||||
22
ion/src/shared/dummy/display.cpp
Normal file
22
ion/src/shared/dummy/display.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#include <ion/display.h>
|
||||
|
||||
namespace Ion {
|
||||
namespace Display {
|
||||
|
||||
void POSTPushMulticolor(int rootNumberTiles, int tileSize) {
|
||||
}
|
||||
|
||||
int displayUniformTilingSize10(KDColor c) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int displayColoredTilingSize10() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool waitForVBlank() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
#include <ion.h>
|
||||
#include <assert.h>
|
||||
|
||||
const char * Ion::fccId() {
|
||||
return "NA";
|
||||
@@ -7,9 +7,11 @@ KDColor getColor() {
|
||||
return KDColorBlack;
|
||||
}
|
||||
|
||||
void setColor(KDColor c) {}
|
||||
void setColor(KDColor c) {
|
||||
}
|
||||
|
||||
void setBlinking(uint16_t period, float dutyCycle) {}
|
||||
void setBlinking(uint16_t period, float dutyCycle) {
|
||||
}
|
||||
|
||||
KDColor updateColorWithPlugAndCharge() {
|
||||
return KDColorBlack;
|
||||
5
ion/src/shared/dummy/pcb_version.cpp
Normal file
5
ion/src/shared/dummy/pcb_version.cpp
Normal file
@@ -0,0 +1,5 @@
|
||||
#include <ion.h>
|
||||
|
||||
const char * Ion::pcbVersion() {
|
||||
return "00.00";
|
||||
}
|
||||
13
ion/src/shared/dummy/power.cpp
Normal file
13
ion/src/shared/dummy/power.cpp
Normal file
@@ -0,0 +1,13 @@
|
||||
#include <ion/power.h>
|
||||
|
||||
namespace Ion {
|
||||
namespace Power {
|
||||
|
||||
void suspend(bool checkIfOnOffKeyReleased) {
|
||||
}
|
||||
|
||||
void standby() {
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
27
ion/src/shared/dummy/usb.cpp
Normal file
27
ion/src/shared/dummy/usb.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
#include <ion/usb.h>
|
||||
|
||||
namespace Ion {
|
||||
namespace USB {
|
||||
|
||||
bool isPlugged() {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isEnumerated() {
|
||||
return false;
|
||||
}
|
||||
|
||||
void clearEnumerationInterrupt() {
|
||||
}
|
||||
|
||||
void DFU(bool) {
|
||||
}
|
||||
|
||||
void enable() {
|
||||
}
|
||||
|
||||
void disable() {
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -50,7 +50,11 @@ void resetLongRepetition() {
|
||||
ComputeAndSetRepetionFactor(sEventRepetitionCount);
|
||||
}
|
||||
|
||||
Event getEvent(int * timeout) {
|
||||
static Keyboard::Key keyFromState(Keyboard::State state) {
|
||||
return static_cast<Keyboard::Key>(63 - __builtin_clzll(state));
|
||||
}
|
||||
|
||||
static inline Event innerGetEvent(int * timeout) {
|
||||
assert(*timeout > delayBeforeRepeat);
|
||||
assert(*timeout > delayBetweenRepeat);
|
||||
int time = 0;
|
||||
@@ -128,5 +132,36 @@ Event getEvent(int * timeout) {
|
||||
}
|
||||
}
|
||||
|
||||
#if ION_EVENTS_JOURNAL
|
||||
|
||||
static Journal * sSourceJournal = nullptr;
|
||||
static Journal * sDestinationJournal = nullptr;
|
||||
void replayFrom(Journal * l) { sSourceJournal = l; }
|
||||
void logTo(Journal * l) { sDestinationJournal = l; }
|
||||
|
||||
Event getEvent(int * timeout) {
|
||||
if (sSourceJournal != nullptr) {
|
||||
if (sSourceJournal->isEmpty()) {
|
||||
sSourceJournal = nullptr;
|
||||
} else {
|
||||
return sSourceJournal->popEvent();
|
||||
}
|
||||
}
|
||||
Event e = innerGetEvent(timeout);
|
||||
if (sDestinationJournal != nullptr) {
|
||||
sDestinationJournal->pushEvent(e);
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
Event getEvent(int * timeout) {
|
||||
return innerGetEvent(timeout);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,31 +1,34 @@
|
||||
ion_src += $(addprefix ion/src/shared/dummy/, \
|
||||
backlight.cpp \
|
||||
board.cpp \
|
||||
battery.cpp \
|
||||
display.cpp \
|
||||
exam_mode.cpp \
|
||||
fcc_id.cpp \
|
||||
led.cpp \
|
||||
pcb_version.cpp \
|
||||
power.cpp \
|
||||
serial_number.cpp \
|
||||
stack.cpp \
|
||||
usb.cpp \
|
||||
)
|
||||
|
||||
ion_src += $(addprefix ion/src/simulator/shared/, \
|
||||
dummy/backlight.cpp \
|
||||
dummy/battery.cpp \
|
||||
dummy/display.cpp \
|
||||
dummy/exam_mode.cpp \
|
||||
dummy/fcc_id.cpp \
|
||||
dummy/led.cpp \
|
||||
dummy/serial_number.cpp \
|
||||
dummy/stack.cpp \
|
||||
dummy/usb.cpp \
|
||||
clipboard.cpp \
|
||||
console_stdio.cpp:-consoledisplay \
|
||||
console.cpp \
|
||||
rtc.cpp \
|
||||
crc32.cpp \
|
||||
display.cpp:-headless \
|
||||
display.cpp \
|
||||
events.cpp \
|
||||
events_keyboard.cpp:-headless \
|
||||
events_stdin.cpp:+headless \
|
||||
framebuffer_base.cpp \
|
||||
framebuffer_png.cpp:+headless \
|
||||
keyboard_dummy.cpp:+headless \
|
||||
keyboard_sdl.cpp:-headless \
|
||||
layout.cpp:-headless \
|
||||
main_headless.cpp:+headless \
|
||||
main_sdl.cpp:-headless \
|
||||
power.cpp \
|
||||
events_platform.cpp \
|
||||
framebuffer.cpp \
|
||||
keyboard.cpp \
|
||||
layout.cpp \
|
||||
main.cpp \
|
||||
random.cpp \
|
||||
timing.cpp \
|
||||
window.cpp \
|
||||
store_script.cpp \
|
||||
)
|
||||
|
||||
ion_simulator_assets = background.jpg horizontal_arrow.png vertical_arrow.png round.png small_squircle.png large_squircle.png
|
||||
@@ -33,3 +36,13 @@ ion_simulator_assets_paths = $(add_prefix ion/src/simulator/assets/,$(ion_simula
|
||||
|
||||
include ion/src/simulator/$(TARGET)/Makefile
|
||||
include ion/src/simulator/external/Makefile
|
||||
|
||||
SFLAGS += -DION_EVENTS_JOURNAL
|
||||
|
||||
ifeq ($(ION_SIMULATOR_FILES),1)
|
||||
ion_src += $(addprefix ion/src/simulator/shared/, \
|
||||
actions.cpp \
|
||||
state_file.cpp \
|
||||
)
|
||||
SFLAGS += -DION_SIMULATOR_FILES=1
|
||||
endif
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
ion_src += $(addprefix ion/src/simulator/android/src/cpp/, \
|
||||
images.cpp \
|
||||
haptics_enabled.cpp \
|
||||
platform_images.cpp \
|
||||
platform_language.cpp \
|
||||
)
|
||||
|
||||
ion_src += $(addprefix ion/src/simulator/shared/, \
|
||||
dummy/callback.cpp \
|
||||
dummy/language.cpp \
|
||||
dummy/journal.cpp \
|
||||
dummy/keyboard_callback.cpp \
|
||||
dummy/window_callback.cpp \
|
||||
clipboard_helper.cpp \
|
||||
haptics.cpp \
|
||||
)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "../../../shared/haptics.h"
|
||||
#include <jni.h>
|
||||
#include <SDL.h>
|
||||
#include <assert.h>
|
||||
|
||||
namespace Ion {
|
||||
namespace Simulator {
|
||||
@@ -11,8 +12,15 @@ bool isEnabled() {
|
||||
jobject activity = static_cast<jobject>(SDL_AndroidGetActivity());
|
||||
jclass j_class = env->FindClass("io/github/omega/simulator/OmegaActivity");
|
||||
jmethodID j_methodId = env->GetMethodID(j_class,"hapticFeedbackIsEnabled", "()Z");
|
||||
|
||||
return env->CallObjectMethod(activity, j_methodId);
|
||||
assert(j_methodId != 0);
|
||||
bool result = (env->CallBooleanMethod(activity, j_methodId) != JNI_FALSE);
|
||||
/* Local references are automatically deleted if a native function called from
|
||||
* Java side returns. For SDL this native function is main() itself. Therefore
|
||||
* references need to be manually deleted because otherwise the references
|
||||
* will first be cleaned if main() returns (application exit). */
|
||||
env->DeleteLocalRef(j_class);
|
||||
env->DeleteLocalRef(activity);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,8 +2,13 @@
|
||||
#include <SDL.h>
|
||||
#include <jni.h>
|
||||
#include <android/bitmap.h>
|
||||
#include <assert.h>
|
||||
|
||||
SDL_Texture * IonSimulatorLoadImage(SDL_Renderer * renderer, const char * identifier) {
|
||||
namespace Ion {
|
||||
namespace Simulator {
|
||||
namespace Platform {
|
||||
|
||||
SDL_Texture * loadImage(SDL_Renderer * renderer, const char * identifier) {
|
||||
JNIEnv * env = static_cast<JNIEnv *>(SDL_AndroidGetJNIEnv());
|
||||
jobject activity = static_cast<jobject>(SDL_AndroidGetActivity());
|
||||
|
||||
@@ -13,6 +18,7 @@ SDL_Texture * IonSimulatorLoadImage(SDL_Renderer * renderer, const char * identi
|
||||
"retrieveBitmapAsset",
|
||||
"(Ljava/lang/String;)Landroid/graphics/Bitmap;"
|
||||
);
|
||||
assert(j_methodId != 0);
|
||||
|
||||
jstring j_identifier = env->NewStringUTF(identifier);
|
||||
|
||||
@@ -45,6 +51,14 @@ SDL_Texture * IonSimulatorLoadImage(SDL_Renderer * renderer, const char * identi
|
||||
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
|
||||
|
||||
AndroidBitmap_unlockPixels(env, j_bitmap);
|
||||
|
||||
// See comment in haptics_enabled.cpp
|
||||
env->DeleteLocalRef(j_bitmap);
|
||||
env->DeleteLocalRef(j_identifier);
|
||||
env->DeleteLocalRef(j_class);
|
||||
env->DeleteLocalRef(activity);
|
||||
return texture;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
37
ion/src/simulator/android/src/cpp/platform_language.cpp
Normal file
37
ion/src/simulator/android/src/cpp/platform_language.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
#include "../../../shared/platform.h"
|
||||
#include <jni.h>
|
||||
#include <assert.h>
|
||||
|
||||
namespace Ion {
|
||||
namespace Simulator {
|
||||
namespace Platform {
|
||||
|
||||
const char * languageCode() {
|
||||
static char buffer[4] = {0};
|
||||
if (buffer[0] == 0) {
|
||||
JNIEnv * env = static_cast<JNIEnv *>(SDL_AndroidGetJNIEnv());
|
||||
jobject activity = static_cast<jobject>(SDL_AndroidGetActivity());
|
||||
|
||||
jclass j_class = env->FindClass("com/numworks/calculator/EpsilonActivity");
|
||||
jmethodID j_methodId = env->GetMethodID(
|
||||
j_class,
|
||||
"retrieveLanguage",
|
||||
"()Ljava/lang/String;"
|
||||
);
|
||||
assert(j_methodId != 0);
|
||||
|
||||
jstring j_language = static_cast<jstring>(env->CallObjectMethod(activity, j_methodId));
|
||||
const char * language = env->GetStringUTFChars(j_language, nullptr);
|
||||
memcpy(buffer, language, 4);
|
||||
buffer[3] = 0;
|
||||
env->ReleaseStringUTFChars(j_language, language);
|
||||
env->DeleteLocalRef(j_language);
|
||||
env->DeleteLocalRef(j_class);
|
||||
env->DeleteLocalRef(activity);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
66
ion/src/simulator/android/src/cpp/telemetry.cpp
Normal file
66
ion/src/simulator/android/src/cpp/telemetry.cpp
Normal file
@@ -0,0 +1,66 @@
|
||||
#include "../../../shared/telemetry.h"
|
||||
#include <jni.h>
|
||||
#include <SDL.h>
|
||||
#include <assert.h>
|
||||
|
||||
static inline JNIEnv * AndroidJNI() {
|
||||
return static_cast<JNIEnv *>(SDL_AndroidGetJNIEnv());
|
||||
}
|
||||
|
||||
static inline jobject AndroidActivity() {
|
||||
return static_cast<jobject>(SDL_AndroidGetActivity());
|
||||
}
|
||||
|
||||
static inline jstring JS(const char * s, JNIEnv * env) {
|
||||
return env->NewStringUTF(s);
|
||||
}
|
||||
|
||||
namespace Ion {
|
||||
namespace Simulator {
|
||||
namespace Telemetry {
|
||||
|
||||
void init() {
|
||||
JNIEnv * env = AndroidJNI();
|
||||
|
||||
jclass j_class = env->FindClass("com/numworks/calculator/EpsilonActivity");
|
||||
jmethodID j_methodId = env->GetMethodID(j_class,"telemetryInit", "()V");
|
||||
assert(j_methodId != 0);
|
||||
|
||||
env->CallVoidMethod(AndroidActivity(), j_methodId);
|
||||
env->DeleteLocalRef(j_class);
|
||||
}
|
||||
|
||||
void shutdown() {
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace Ion {
|
||||
namespace Telemetry {
|
||||
|
||||
void reportScreen(const char * screenName) {
|
||||
JNIEnv * env = AndroidJNI();
|
||||
|
||||
jclass j_class = env->FindClass("com/numworks/calculator/EpsilonActivity");
|
||||
jmethodID j_methodId = env->GetMethodID(j_class, "telemetryScreen", "(Ljava/lang/String;)V");
|
||||
assert(j_methodId != 0);
|
||||
|
||||
env->CallVoidMethod(AndroidActivity(), j_methodId, JS(screenName, env));
|
||||
env->DeleteLocalRef(j_class);
|
||||
}
|
||||
|
||||
void reportEvent(const char * category, const char * action, const char * label) {
|
||||
JNIEnv * env = AndroidJNI();
|
||||
|
||||
jclass j_class = env->FindClass("com/numworks/calculator/EpsilonActivity");
|
||||
jmethodID j_methodId = env->GetMethodID(j_class, "telemetryEvent", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
|
||||
assert(j_methodId != 0);
|
||||
|
||||
env->CallVoidMethod(AndroidActivity(), j_methodId, JS(category, env), JS(action, env), JS(label, env));
|
||||
env->DeleteLocalRef(j_class);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -25,13 +25,6 @@ public class OmegaActivity extends SDLActivity {
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String[] getArguments() {
|
||||
Locale currentLocale = getResources().getConfiguration().locale;
|
||||
String[] arguments = {"--language", currentLocale.getLanguage()};
|
||||
return arguments;
|
||||
}
|
||||
|
||||
public Bitmap retrieveBitmapAsset(String identifier) {
|
||||
Bitmap bitmap = null;
|
||||
try {
|
||||
@@ -44,6 +37,10 @@ public class OmegaActivity extends SDLActivity {
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
public String retrieveLanguage() {
|
||||
return getResources().getConfiguration().locale.getLanguage();
|
||||
}
|
||||
|
||||
public boolean hapticFeedbackIsEnabled() {
|
||||
ContentResolver contentResolver = SDL.getContext().getContentResolver();
|
||||
int val = Settings.System.getInt(contentResolver, Settings.System.HAPTIC_FEEDBACK_ENABLED, 0);
|
||||
|
||||
@@ -51,7 +51,12 @@ class HIDDeviceUSB implements HIDDevice {
|
||||
public String getSerialNumber() {
|
||||
String result = null;
|
||||
if (Build.VERSION.SDK_INT >= 21) {
|
||||
result = mDevice.getSerialNumber();
|
||||
try {
|
||||
result = mDevice.getSerialNumber();
|
||||
}
|
||||
catch (SecurityException exception) {
|
||||
//Log.w(TAG, "App permissions mean we cannot get serial number for device " + getDeviceName() + " message: " + exception.getMessage());
|
||||
}
|
||||
}
|
||||
if (result == null) {
|
||||
result = "";
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
ion_src += $(addprefix ion/src/simulator/ios/, \
|
||||
images.m \
|
||||
)
|
||||
|
||||
ion_src += $(addprefix ion/src/simulator/shared/, \
|
||||
apple/language.m \
|
||||
dummy/callback.cpp \
|
||||
apple/platform_images.mm \
|
||||
apple/platform_language.mm \
|
||||
dummy/haptics_enabled.cpp \
|
||||
dummy/journal.cpp \
|
||||
dummy/keyboard_callback.cpp \
|
||||
dummy/window_callback.cpp \
|
||||
clipboard_helper.cpp \
|
||||
haptics.cpp \
|
||||
)
|
||||
@@ -31,6 +30,9 @@ LDFLAGS += -framework CoreData
|
||||
LDFLAGS += -Lion/src/simulator/ios/GoogleAnalyticsServices
|
||||
endif
|
||||
|
||||
LDFLAGS += -framework MobileCoreServices
|
||||
LDFLAGS += -framework ImageIO
|
||||
|
||||
ifndef ARCH
|
||||
|
||||
# App resources
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
#include "../shared/platform.h"
|
||||
|
||||
#include <SDL.h>
|
||||
#include <UIKit/UIKit.h>
|
||||
|
||||
SDL_Texture * IonSimulatorLoadImage(SDL_Renderer * renderer, const char * identifier) {
|
||||
CGImageRef cgImage = [[UIImage imageNamed:[NSString stringWithUTF8String:identifier]] CGImage];
|
||||
if (cgImage == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
size_t width = CGImageGetWidth(cgImage);
|
||||
size_t height = CGImageGetHeight(cgImage);
|
||||
|
||||
|
||||
size_t bytesPerPixel = 4;
|
||||
size_t bytesPerRow = bytesPerPixel * width;
|
||||
size_t bitsPerComponent = 8;
|
||||
|
||||
size_t size = height * width * bytesPerPixel;
|
||||
void * bitmapData = malloc(size);
|
||||
memset(bitmapData, 0, size);
|
||||
|
||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
CGContextRef context = CGBitmapContextCreate(
|
||||
bitmapData, width, height,
|
||||
bitsPerComponent, bytesPerRow, colorSpace,
|
||||
kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big
|
||||
);
|
||||
|
||||
CGContextDrawImage(context, CGRectMake(0, 0, width, height), cgImage);
|
||||
|
||||
CGContextRelease(context);
|
||||
CGColorSpaceRelease(colorSpace);
|
||||
|
||||
SDL_Texture * texture = SDL_CreateTexture(
|
||||
renderer,
|
||||
SDL_PIXELFORMAT_ABGR8888,
|
||||
SDL_TEXTUREACCESS_STATIC,
|
||||
width,
|
||||
height
|
||||
);
|
||||
|
||||
SDL_UpdateTexture(
|
||||
texture,
|
||||
NULL,
|
||||
bitmapData,
|
||||
bytesPerPixel * width
|
||||
);
|
||||
|
||||
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
|
||||
|
||||
free(bitmapData);
|
||||
|
||||
return texture;
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
# The following lines allow us to use our own SDL_config.h
|
||||
ION_SIMULATOR_FILES = 1
|
||||
|
||||
# The following lines allow us to use our own SDL_config.h
|
||||
# First, make sure an error is raised if we ever use the standard SDL_config.h
|
||||
SFLAGS += -DUSING_GENERATED_CONFIG_H
|
||||
# Then use our very own include dir if either SDL.h or SDL_config.h are included
|
||||
@@ -8,18 +9,26 @@ SFLAGS += -DUSING_GENERATED_CONFIG_H
|
||||
SFLAGS += -Iion/src/simulator/linux/include
|
||||
|
||||
ion_src += $(addprefix ion/src/simulator/linux/, \
|
||||
images.cpp \
|
||||
language.cpp \
|
||||
assets.s \
|
||||
platform_files.cpp \
|
||||
platform_images.cpp \
|
||||
platform_language.cpp \
|
||||
)
|
||||
|
||||
SFLAGS += $(shell pkg-config libpng libjpeg --cflags)
|
||||
LDFLAGS += $(shell pkg-config libpng libjpeg --libs)
|
||||
|
||||
ion_src += $(addprefix ion/src/simulator/shared/, \
|
||||
dummy/callback.cpp \
|
||||
dummy/haptics_enabled.cpp \
|
||||
dummy/keyboard_callback.cpp \
|
||||
dummy/window_callback.cpp \
|
||||
actions.cpp \
|
||||
clipboard_helper.cpp \
|
||||
collect_registers_x86_64.s \
|
||||
collect_registers.cpp \
|
||||
haptics.cpp \
|
||||
journal.cpp \
|
||||
state_file.cpp \
|
||||
)
|
||||
|
||||
ifeq ($(EPSILON_TELEMETRY),1)
|
||||
@@ -27,17 +36,15 @@ ion_src += ion/src/simulator/shared/dummy/telemetry_init.cpp
|
||||
ion_src += ion/src/shared/telemetry_console.cpp
|
||||
endif
|
||||
|
||||
LDFLAGS += -ljpeg
|
||||
|
||||
$(eval $(call rule_for, \
|
||||
INCBIN, \
|
||||
ion/src/simulator/linux/assets.s ion/src/simulator/linux/images.h, \
|
||||
ion/src/simulator/linux/assets.s ion/src/simulator/linux/platform_images.h, \
|
||||
$(ion_simulator_assets_paths), \
|
||||
$$(PYTHON) ion/src/simulator/linux/incbin.py $(ion_simulator_assets) -o $$@, \
|
||||
global \
|
||||
))
|
||||
|
||||
$(call object_for,ion/src/simulator/linux/images.cpp): $(BUILD_DIR)/ion/src/simulator/linux/images.h
|
||||
$(call object_for,ion/src/simulator/linux/platform_images.cpp): $(BUILD_DIR)/ion/src/simulator/linux/platform_images.h
|
||||
|
||||
# The header is refered to as <ion/src/simulator/linux/images.h> so make sure it's findable this way
|
||||
SFLAGS += -I$(BUILD_DIR)
|
||||
# The header is refered to as <ion/src/simulator/linux/platform_images.h> so make sure it's findable this way
|
||||
$(call object_for,ion/src/simulator/linux/platform_images.cpp): SFLAGS += -I$(BUILD_DIR)
|
||||
|
||||
21
ion/src/simulator/linux/platform_files.cpp
Normal file
21
ion/src/simulator/linux/platform_files.cpp
Normal file
@@ -0,0 +1,21 @@
|
||||
#include "../shared/platform.h"
|
||||
|
||||
namespace Ion {
|
||||
namespace Simulator {
|
||||
namespace Platform {
|
||||
|
||||
const char * filePathForReading(const char * extension) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char * filePathForWriting(const char * extension) {
|
||||
static char path[64];
|
||||
if (snprintf(path, sizeof(path), "/tmp/epsilon.%s", extension) < 0) {
|
||||
return nullptr;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,16 @@
|
||||
#include "../shared/platform.h"
|
||||
|
||||
#include <SDL.h>
|
||||
#include <assert.h>
|
||||
#include <jpeglib.h>
|
||||
#include <png.h>
|
||||
#include <assert.h>
|
||||
#include <SDL.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <ion/src/simulator/linux/images.h>
|
||||
#include <ion/src/simulator/linux/platform_images.h>
|
||||
|
||||
namespace Ion {
|
||||
namespace Simulator {
|
||||
namespace Platform {
|
||||
|
||||
enum class AssetFormat {
|
||||
JPG,
|
||||
@@ -95,7 +100,7 @@ bool readJPG(const unsigned char * start, size_t size, unsigned char ** bitmapDa
|
||||
return true;
|
||||
}
|
||||
|
||||
SDL_Texture * IonSimulatorLoadImage(SDL_Renderer * renderer, const char * identifier) {
|
||||
SDL_Texture * loadImage(SDL_Renderer * renderer, const char * identifier) {
|
||||
static constexpr const char * jpgExtension = ".jpg";
|
||||
static constexpr const char * pngExtension = ".png";
|
||||
|
||||
@@ -161,3 +166,55 @@ SDL_Texture * IonSimulatorLoadImage(SDL_Renderer * renderer, const char * identi
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
class RGB888Pixel {
|
||||
public:
|
||||
RGB888Pixel() {}
|
||||
RGB888Pixel(KDColor c) :
|
||||
m_red(c.red()),
|
||||
m_green(c.green()),
|
||||
m_blue(c.blue()) {
|
||||
}
|
||||
private:
|
||||
uint8_t m_red;
|
||||
uint8_t m_green;
|
||||
uint8_t m_blue;
|
||||
};
|
||||
static_assert(sizeof(RGB888Pixel) == 3, "RGB888Pixel shall be 3 bytes long");
|
||||
|
||||
void saveImage(const KDColor * pixels, int width, int height, const char * path) {
|
||||
FILE * file = fopen(path, "wb"); // Write in binary mode
|
||||
|
||||
png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
|
||||
png_infop info = png_create_info_struct(png);
|
||||
png_init_io(png, file);
|
||||
|
||||
png_set_IHDR(png, info,
|
||||
width, height,
|
||||
8, // Number of bits per channel
|
||||
PNG_COLOR_TYPE_RGB,
|
||||
PNG_INTERLACE_NONE,
|
||||
PNG_COMPRESSION_TYPE_DEFAULT,
|
||||
PNG_FILTER_TYPE_DEFAULT);
|
||||
|
||||
png_write_info(png, info);
|
||||
|
||||
RGB888Pixel * row = new RGB888Pixel[3*width];
|
||||
for (int j=0;j<height;j++) {
|
||||
for (int i=0; i<width; i++) {
|
||||
row[i] = RGB888Pixel(pixels[i+width*j]);
|
||||
}
|
||||
png_write_row(png, reinterpret_cast<png_bytep>(row));
|
||||
}
|
||||
delete row;
|
||||
|
||||
png_write_end(png, NULL);
|
||||
|
||||
png_free_data(png, info, PNG_FREE_ALL, -1); // -1 = all items
|
||||
png_destroy_write_struct(&png, nullptr);
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,11 @@
|
||||
#include "../shared/platform.h"
|
||||
|
||||
#include <locale.h>
|
||||
|
||||
char * IonSimulatorGetLanguageCode() {
|
||||
namespace Ion {
|
||||
namespace Simulator {
|
||||
namespace Platform {
|
||||
|
||||
const char * languageCode() {
|
||||
static char buffer[3] = {0};
|
||||
char * locale = setlocale(LC_ALL, "");
|
||||
if (locale[2] == '_') {
|
||||
@@ -12,3 +15,7 @@ char * IonSimulatorGetLanguageCode() {
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,41 @@
|
||||
<array>
|
||||
<string>MacOSX</string>
|
||||
</array>
|
||||
<key>CFBundleDocumentTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>Nacho MNDL file</string>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Editor</string>
|
||||
<key>LSHandlerRank</key>
|
||||
<string>Owner</string>
|
||||
<key>LSItemContentTypes</key>
|
||||
<array>
|
||||
<string>com.numworks.savefile</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
<key>UTExportedTypeDeclarations</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>UTTypeIdentifier</key>
|
||||
<string>com.numworks.savefile</string>
|
||||
<key>UTTypeConformsTo</key>
|
||||
<array>
|
||||
<string>public.data</string>
|
||||
</array>
|
||||
<key>UTTypeDescription</key>
|
||||
<string>NumWorks save file</string>
|
||||
<key>UTTypeTagSpecification</key>
|
||||
<dict>
|
||||
<key>public.filename-extension</key>
|
||||
<array>
|
||||
<string>nws</string>
|
||||
</array>
|
||||
</dict>
|
||||
</dict>
|
||||
</array>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2019 NumWorks. All rights reserved.</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
ION_SIMULATOR_FILES = 1
|
||||
|
||||
ion_src += $(addprefix ion/src/simulator/macos/, \
|
||||
images.m \
|
||||
platform_files.mm \
|
||||
)
|
||||
|
||||
ion_src += $(addprefix ion/src/simulator/shared/, \
|
||||
apple/language.m \
|
||||
dummy/callback.cpp \
|
||||
apple/platform_images.mm \
|
||||
apple/platform_language.mm \
|
||||
dummy/haptics_enabled.cpp \
|
||||
dummy/keyboard_callback.cpp \
|
||||
dummy/window_callback.cpp \
|
||||
clipboard_helper.cpp \
|
||||
collect_registers_x86_64.s \
|
||||
collect_registers.cpp \
|
||||
haptics.cpp \
|
||||
journal.cpp \
|
||||
)
|
||||
|
||||
ifeq ($(EPSILON_TELEMETRY),1)
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
#include "../shared/platform.h"
|
||||
|
||||
#include <SDL.h>
|
||||
#include <AppKit/AppKit.h>
|
||||
|
||||
SDL_Texture * IonSimulatorLoadImage(SDL_Renderer * renderer, const char * identifier) {
|
||||
NSImage * nsImage = [NSImage imageNamed:[NSString stringWithUTF8String:identifier]];
|
||||
CGImageRef cgImage = [nsImage CGImageForProposedRect:NULL
|
||||
context:NULL
|
||||
hints:0];
|
||||
if (cgImage == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
size_t width = CGImageGetWidth(cgImage);
|
||||
size_t height = CGImageGetHeight(cgImage);
|
||||
|
||||
size_t bytesPerPixel = 4;
|
||||
size_t bytesPerRow = bytesPerPixel * width;
|
||||
size_t bitsPerComponent = 8;
|
||||
|
||||
size_t size = height * width * bytesPerPixel;
|
||||
void * bitmapData = malloc(size);
|
||||
memset(bitmapData, 0, size);
|
||||
|
||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
CGContextRef context = CGBitmapContextCreate(
|
||||
bitmapData, width, height,
|
||||
bitsPerComponent, bytesPerRow, colorSpace,
|
||||
kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big
|
||||
);
|
||||
|
||||
CGContextDrawImage(context, CGRectMake(0, 0, width, height), cgImage);
|
||||
|
||||
CGContextRelease(context);
|
||||
CGColorSpaceRelease(colorSpace);
|
||||
|
||||
SDL_Texture * texture = SDL_CreateTexture(
|
||||
renderer,
|
||||
SDL_PIXELFORMAT_ABGR8888,
|
||||
SDL_TEXTUREACCESS_STATIC,
|
||||
width,
|
||||
height
|
||||
);
|
||||
|
||||
SDL_UpdateTexture(
|
||||
texture,
|
||||
NULL,
|
||||
bitmapData,
|
||||
bytesPerPixel * width
|
||||
);
|
||||
|
||||
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
|
||||
|
||||
free(bitmapData);
|
||||
|
||||
return texture;
|
||||
}
|
||||
32
ion/src/simulator/macos/platform_files.mm
Normal file
32
ion/src/simulator/macos/platform_files.mm
Normal file
@@ -0,0 +1,32 @@
|
||||
#include "../shared/platform.h"
|
||||
#include <AppKit/AppKit.h>
|
||||
|
||||
namespace Ion {
|
||||
namespace Simulator {
|
||||
namespace Platform {
|
||||
|
||||
static const char * getPath(NSSavePanel * panel, const char * extension) {
|
||||
[panel setAllowedFileTypes:[NSArray arrayWithObject:[NSString stringWithUTF8String:extension]]];
|
||||
static NSString * path = nil;
|
||||
[path release]; path = nil; // Discard previous path if any
|
||||
NSWindow * mainWindow = [[NSApplication sharedApplication] keyWindow];
|
||||
if ([panel runModal] == NSFileHandlingPanelOKButton) {
|
||||
path = [[[panel URL] path] retain];
|
||||
}
|
||||
[mainWindow makeKeyAndOrderFront:nil];
|
||||
return [path UTF8String];
|
||||
}
|
||||
|
||||
const char * filePathForReading(const char * extension) {
|
||||
NSOpenPanel * panel = [NSOpenPanel openPanel];
|
||||
return getPath(panel, extension);
|
||||
}
|
||||
|
||||
const char * filePathForWriting(const char * extension) {
|
||||
NSSavePanel * panel = [NSSavePanel savePanel];
|
||||
return getPath(panel, extension);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
43
ion/src/simulator/shared/actions.cpp
Normal file
43
ion/src/simulator/shared/actions.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
#include "actions.h"
|
||||
#include <ion/display.h>
|
||||
#include "framebuffer.h"
|
||||
#include "platform.h"
|
||||
#include "state_file.h"
|
||||
|
||||
namespace Ion {
|
||||
namespace Simulator {
|
||||
namespace Actions {
|
||||
|
||||
constexpr const char * kStateFileExtension = "nws";
|
||||
|
||||
void saveState() {
|
||||
const char * path = Platform::filePathForWriting(kStateFileExtension);
|
||||
if (path != nullptr) {
|
||||
StateFile::save(path);
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
void loadState() {
|
||||
// We would need to be able to perform a reset for this to be callable anytime
|
||||
const char * path = Platform::filePathForReading(kStateFileExtension);
|
||||
if (path != nullptr) {
|
||||
StateFile::load(path);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void takeScreenshot() {
|
||||
const char * path = Platform::filePathForWriting("png");
|
||||
if (path != nullptr) {
|
||||
Platform::saveImage(
|
||||
Framebuffer::address(),
|
||||
Display::Width, Display::Height,
|
||||
path
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
17
ion/src/simulator/shared/actions.h
Normal file
17
ion/src/simulator/shared/actions.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifndef ION_SIMULATOR_ACTIONS_H
|
||||
#define ION_SIMULATOR_ACTIONS_H
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
namespace Ion {
|
||||
namespace Simulator {
|
||||
namespace Actions {
|
||||
|
||||
void saveState();
|
||||
void takeScreenshot();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
128
ion/src/simulator/shared/apple/platform_images.mm
Normal file
128
ion/src/simulator/shared/apple/platform_images.mm
Normal file
@@ -0,0 +1,128 @@
|
||||
#include "../platform.h"
|
||||
#include <SDL.h>
|
||||
#include <TargetConditionals.h>
|
||||
#if TARGET_OS_OSX
|
||||
#include <AppKit/AppKit.h>
|
||||
#else
|
||||
#include <UIKit/UIKit.h>
|
||||
#include <MobileCoreServices/MobileCoreServices.h>
|
||||
#endif
|
||||
|
||||
namespace Ion {
|
||||
namespace Simulator {
|
||||
namespace Platform {
|
||||
|
||||
static CGContextRef createABGR8888Context(size_t width, size_t height) {
|
||||
size_t bytesPerPixel = 4;
|
||||
size_t bytesPerRow = bytesPerPixel * width;
|
||||
size_t bitsPerComponent = 8;
|
||||
|
||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
CGContextRef context = CGBitmapContextCreate(
|
||||
nullptr, // The context will allocate and take ownership of the bitmap buffer
|
||||
width, height,
|
||||
bitsPerComponent, bytesPerRow, colorSpace,
|
||||
kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big
|
||||
);
|
||||
if (colorSpace) {
|
||||
CFRelease(colorSpace);
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
SDL_Texture * loadImage(SDL_Renderer * renderer, const char * identifier) {
|
||||
CGImageRef image = nullptr;
|
||||
#if TARGET_OS_OSX
|
||||
//http://lists.libsdl.org/pipermail/commits-libsdl.org/2016-December/001235.html
|
||||
[[[NSApp windows] firstObject] setColorSpace:[NSColorSpace sRGBColorSpace]];
|
||||
|
||||
NSImage * nsImage = [NSImage imageNamed:[NSString stringWithUTF8String:identifier]];
|
||||
image = [nsImage CGImageForProposedRect:NULL context:NULL hints:0];
|
||||
#else
|
||||
image = [[UIImage imageNamed:[NSString stringWithUTF8String:identifier]] CGImage];
|
||||
#endif
|
||||
if (image == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
size_t width = CGImageGetWidth(image);
|
||||
size_t height = CGImageGetHeight(image);
|
||||
|
||||
CGContextRef context = createABGR8888Context(width, height);
|
||||
if (context == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void * argb8888Pixels = CGBitmapContextGetData(context);
|
||||
|
||||
CGContextDrawImage(context, CGRectMake(0, 0, width, height), image);
|
||||
|
||||
SDL_Texture * texture = SDL_CreateTexture(
|
||||
renderer,
|
||||
SDL_PIXELFORMAT_ABGR8888,
|
||||
SDL_TEXTUREACCESS_STATIC,
|
||||
width,
|
||||
height
|
||||
);
|
||||
|
||||
size_t bytesPerPixel = 4;
|
||||
|
||||
SDL_UpdateTexture(
|
||||
texture,
|
||||
NULL,
|
||||
argb8888Pixels,
|
||||
bytesPerPixel * width
|
||||
);
|
||||
|
||||
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
|
||||
|
||||
CGContextRelease(context);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
class ABGR8888Pixel {
|
||||
public:
|
||||
ABGR8888Pixel(KDColor c) :
|
||||
m_red(c.red()),
|
||||
m_green(c.green()),
|
||||
m_blue(c.blue()),
|
||||
m_alpha(255) {
|
||||
}
|
||||
private:
|
||||
uint8_t m_red;
|
||||
uint8_t m_green;
|
||||
uint8_t m_blue;
|
||||
uint8_t m_alpha;
|
||||
};
|
||||
static_assert(sizeof(ABGR8888Pixel) == 4, "ARGB8888Pixel shall be 4 bytes long");
|
||||
|
||||
void saveImage(const KDColor * pixels, int width, int height, const char * path) {
|
||||
CGContextRef context = createABGR8888Context(width, height);
|
||||
if (context == nullptr) {
|
||||
return;
|
||||
}
|
||||
ABGR8888Pixel * argb8888Pixels = static_cast<ABGR8888Pixel *>(CGBitmapContextGetData(context));
|
||||
for (int i=0; i<width*height; i++) {
|
||||
argb8888Pixels[i] = ABGR8888Pixel(pixels[i]);
|
||||
}
|
||||
|
||||
CGImageRef image = CGBitmapContextCreateImage(context);
|
||||
|
||||
CFURLRef url = static_cast<CFURLRef>([NSURL fileURLWithPath:[NSString stringWithUTF8String:path]]);
|
||||
|
||||
CGImageDestinationRef destination = CGImageDestinationCreateWithURL(url, kUTTypePNG, 1, NULL);
|
||||
CGImageDestinationAddImage(destination, image, nil);
|
||||
CGImageDestinationFinalize(destination);
|
||||
|
||||
if (destination) {
|
||||
CFRelease(destination);
|
||||
}
|
||||
CGImageRelease(image);
|
||||
CGContextRelease(context);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,11 @@
|
||||
|
||||
#include <Foundation/Foundation.h>
|
||||
|
||||
char * IonSimulatorGetLanguageCode() {
|
||||
namespace Ion {
|
||||
namespace Simulator {
|
||||
namespace Platform {
|
||||
|
||||
const char * languageCode() {
|
||||
static char buffer[4] = {0};
|
||||
if (buffer[0] == 0) {
|
||||
NSString * preferredLanguage = [[NSLocale preferredLanguages] firstObject];
|
||||
@@ -15,3 +19,7 @@ char * IonSimulatorGetLanguageCode() {
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
31
ion/src/simulator/shared/console.cpp
Normal file
31
ion/src/simulator/shared/console.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
#include <ion/console.h>
|
||||
#include "window.h"
|
||||
#include <kandinsky/ion_context.h>
|
||||
#include <stdio.h>
|
||||
|
||||
namespace Ion {
|
||||
namespace Console {
|
||||
|
||||
char readChar() {
|
||||
if (Simulator::Window::isHeadless()) {
|
||||
return getchar();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void writeChar(char c) {
|
||||
if (Simulator::Window::isHeadless()) {
|
||||
putchar(c);
|
||||
fflush(stdout);
|
||||
} else {
|
||||
KDIonContext::putchar(c);
|
||||
}
|
||||
}
|
||||
|
||||
bool transmissionDone() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
#include <ion/console.h>
|
||||
#include <stdio.h>
|
||||
|
||||
namespace Ion {
|
||||
namespace Console {
|
||||
|
||||
char readChar() {
|
||||
return getchar();
|
||||
}
|
||||
|
||||
void writeChar(char c) {
|
||||
putchar(c);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
bool transmissionDone() {
|
||||
// Always true because we flush after each writeChar
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,28 +1,32 @@
|
||||
#include <ion.h>
|
||||
|
||||
uint32_t crc32Helper(const uint8_t * data, size_t length, bool wordAccess) {
|
||||
namespace Ion {
|
||||
|
||||
static uint32_t crc32Helper(const uint8_t * data, size_t length, bool wordAccess) {
|
||||
size_t uint32ByteLength = sizeof(uint32_t)/sizeof(uint8_t);
|
||||
uint32_t crc = 0xFFFFFFFF;
|
||||
size_t byteLength = (wordAccess ? length * uint32ByteLength : length);
|
||||
size_t wordLength = byteLength / uint32ByteLength;
|
||||
|
||||
for (int i = 0; i < (int)wordLength; i++) {
|
||||
for (int i = 0; i < wordLength; i++) {
|
||||
// FIXME: Assumes little-endian byte order!
|
||||
for (int j = uint32ByteLength-1; j >= 0; j--) {
|
||||
// scan byte by byte to avoid alignment issue when building for emscripten platform
|
||||
crc = Ion::crc32EatByte(crc, data[i*uint32ByteLength+j]);
|
||||
crc = crc32EatByte(crc, data[i*uint32ByteLength+j]);
|
||||
}
|
||||
}
|
||||
for (int i = (int) wordLength * uint32ByteLength; i < byteLength; i++) {
|
||||
crc = Ion::crc32EatByte(crc, data[i]);
|
||||
for (int i = wordLength * uint32ByteLength; i < byteLength; i++) {
|
||||
crc = crc32EatByte(crc, data[i]);
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
uint32_t Ion::crc32Word(const uint32_t * data, size_t length) {
|
||||
return crc32Helper((const uint8_t *) data, length, true);
|
||||
uint32_t crc32Word(const uint32_t * data, size_t length) {
|
||||
return crc32Helper(reinterpret_cast<const uint8_t *>(data), length, true);
|
||||
}
|
||||
|
||||
uint32_t Ion::crc32Byte(const uint8_t * data, size_t length) {
|
||||
uint32_t crc32Byte(const uint8_t * data, size_t length) {
|
||||
return crc32Helper(data, length, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace Display {
|
||||
static SDL_Texture * sFramebufferTexture = nullptr;
|
||||
|
||||
void init(SDL_Renderer * renderer) {
|
||||
Framebuffer::setActive(true);
|
||||
Uint32 texturePixelFormat = SDL_PIXELFORMAT_RGB565;
|
||||
assert(sizeof(KDColor) == SDL_BYTESPERPIXEL(texturePixelFormat));
|
||||
sFramebufferTexture = SDL_CreateTexture(
|
||||
@@ -23,7 +24,7 @@ void init(SDL_Renderer * renderer) {
|
||||
);
|
||||
}
|
||||
|
||||
void quit() {
|
||||
void shutdown() {
|
||||
SDL_DestroyTexture(sFramebufferTexture);
|
||||
sFramebufferTexture = nullptr;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Simulator {
|
||||
namespace Display {
|
||||
|
||||
void init(SDL_Renderer * renderer);
|
||||
void quit();
|
||||
void shutdown();
|
||||
|
||||
void draw(SDL_Renderer * renderer, SDL_Rect * rect);
|
||||
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
#include <ion/backlight.h>
|
||||
|
||||
uint8_t Ion::Backlight::brightness() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Ion::Backlight::setBrightness(uint8_t b) {}
|
||||
|
||||
void Ion::Backlight::init() {}
|
||||
|
||||
bool Ion::Backlight::isInitialized() { return true; }
|
||||
|
||||
void Ion::Backlight::shutdown() {}
|
||||
@@ -1,7 +0,0 @@
|
||||
#include "../platform.h"
|
||||
|
||||
void IonSimulatorCallbackDidRefresh() {
|
||||
}
|
||||
|
||||
void IonSimulatorCallbackDidScanKeyboard() {
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
#include <ion/display.h>
|
||||
|
||||
void Ion::Display::POSTPushMulticolor(int rootNumberTiles, int tileSize) {
|
||||
}
|
||||
|
||||
int Ion::Display::displayUniformTilingSize10(KDColor c) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Ion::Display::displayColoredTilingSize10() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool Ion::Display::waitForVBlank() {
|
||||
return true;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user