diff --git a/apps/apps_container.cpp b/apps/apps_container.cpp index c352f44c4..af3904fbb 100644 --- a/apps/apps_container.cpp +++ b/apps/apps_container.cpp @@ -5,11 +5,13 @@ #include #include #include +#include extern "C" { #include } +using namespace Poincare; using namespace Shared; AppsContainer * AppsContainer::sharedAppsContainer() { @@ -199,7 +201,7 @@ bool AppsContainer::processEvent(Ion::Events::Event event) { // Warning: if the window is dirtied, you need to call window()->redraw() if (event == Ion::Events::USBPlug) { if (Ion::USB::isPlugged()) { - if (GlobalPreferences::sharedGlobalPreferences()->examMode() == GlobalPreferences::ExamMode::Activate) { + if (GlobalPreferences::sharedGlobalPreferences()->examMode()) { displayExamModePopUp(false); window()->redraw(); } else { @@ -244,6 +246,9 @@ bool AppsContainer::switchTo(App::Snapshot * snapshot) { void AppsContainer::run() { window()->setFrame(KDRect(0, 0, Ion::Display::Width, Ion::Display::Height)); + if (GlobalPreferences::sharedGlobalPreferences()->examMode()) { + activateExamMode(); + } refreshPreferences(); /* ExceptionCheckpoint stores the value of the stack pointer when setjump is @@ -319,7 +324,7 @@ void AppsContainer::shutdownDueToLowBattery() { } while (Ion::Battery::level() == Ion::Battery::Charge::EMPTY) { Ion::Backlight::setBrightness(0); - if (GlobalPreferences::sharedGlobalPreferences()->examMode() == GlobalPreferences::ExamMode::Deactivate) { + if (!GlobalPreferences::sharedGlobalPreferences()->examMode()) { /* Unless the LED is lit up for the exam mode, switch off the LED. IF the * low battery event happened during the Power-On Self-Test, a LED might * have stayed lit up. */ @@ -352,6 +357,26 @@ void AppsContainer::redrawWindow(bool force) { m_window.redraw(force); } +void AppsContainer::activateExamMode() { + reset(); + Preferences * preferences = Preferences::sharedPreferences(); + switch ((int)preferences->colorOfLED()) { + case 0: + Ion::LED::setColor(KDColorWhite); + break; + case 1: + Ion::LED::setColor(KDColorGreen); + break; + case 2: + Ion::LED::setColor(KDColorBlue); + break; + case 3: + Ion::LED::setColor(KDColorYellow); + break; + } + Ion::LED::setBlinking(1000, 0.1f); +} + void AppsContainer::examDeactivatingPopUpIsDismissed() { if (Ion::USB::isPlugged()) { Ion::USB::enable(); diff --git a/apps/apps_container.h b/apps/apps_container.h index 87c0adea6..da9250aed 100644 --- a/apps/apps_container.h +++ b/apps/apps_container.h @@ -46,6 +46,7 @@ public: void setShiftAlphaStatus(Ion::Events::ShiftAlphaStatus newStatus); OnBoarding::PopUpController * promptController(); void redrawWindow(bool force = false); + void activateExamMode(); // Exam pop-up controller delegate void examDeactivatingPopUpIsDismissed() override; // Ion::StorageDelegate diff --git a/apps/calculation/calculation_store.cpp b/apps/calculation/calculation_store.cpp index 3e68f79c5..b493ccf91 100644 --- a/apps/calculation/calculation_store.cpp +++ b/apps/calculation/calculation_store.cpp @@ -92,7 +92,7 @@ ExpiringPointer CalculationStore::push(const char * text, Context * // Compute and serialize the outputs { Expression outputs[] = {Expression(), Expression()}; - PoincareHelpers::ParseAndSimplifyAndApproximate(inputSerialization, &(outputs[0]), &(outputs[1]), context, GlobalPreferences::sharedGlobalPreferences()->examMode() == GlobalPreferences::ExamMode::Activate ? Preferences::sharedPreferences()->isExamSymbolic() : true); // Symbolic computation + PoincareHelpers::ParseAndSimplifyAndApproximate(inputSerialization, &(outputs[0]), &(outputs[1]), context, GlobalPreferences::sharedGlobalPreferences()->examMode() ? Preferences::sharedPreferences()->isExamSymbolic() : true); // Symbolic computation for (int i = 0; i < 2; i++) { if (!serializeExpression(outputs[i], nextSerializationLocation, &newCalculationsLocation)) { /* If the exat/approximate output does not fit in the store (event if the diff --git a/apps/exam_pop_up_controller.cpp b/apps/exam_pop_up_controller.cpp index 8d4f25c65..72661159e 100644 --- a/apps/exam_pop_up_controller.cpp +++ b/apps/exam_pop_up_controller.cpp @@ -16,10 +16,8 @@ ExamPopUpController::ExamPopUpController(ExamPopUpControllerDelegate * delegate) } void ExamPopUpController::setActivatingExamMode(bool activatingExamMode) { - if (m_isActivatingExamMode != activatingExamMode) { - m_isActivatingExamMode = activatingExamMode; - m_contentView.setMessages(activatingExamMode); - } + m_isActivatingExamMode = activatingExamMode; + m_contentView.setMessages(activatingExamMode); } View * ExamPopUpController::view() { @@ -55,27 +53,10 @@ ExamPopUpController::ContentView::ContentView(Responder * parentResponder) : }, parentResponder), KDFont::SmallFont), m_okButton(parentResponder, I18n::Message::Ok, Invocation([](void * context, void * sender) { ExamPopUpController * controller = (ExamPopUpController *)context; - GlobalPreferences::ExamMode nextExamMode = controller->isActivatingExamMode() ? GlobalPreferences::ExamMode::Activate : GlobalPreferences::ExamMode::Deactivate; - GlobalPreferences::sharedGlobalPreferences()->setExamMode(nextExamMode); - Preferences * preferences = Preferences::sharedPreferences(); + GlobalPreferences::sharedGlobalPreferences()->setExamMode(controller->isActivatingExamMode()); AppsContainer * container = AppsContainer::sharedAppsContainer(); if (controller->isActivatingExamMode()) { - container->reset(); - switch ((int)preferences->colorOfLED()) { - case 0: - Ion::LED::setColor(KDColorWhite); - break; - case 1: - Ion::LED::setColor(KDColorGreen); - break; - case 2: - Ion::LED::setColor(KDColorBlue); - break; - case 3: - Ion::LED::setColor(KDColorYellow); - break; - } - Ion::LED::setBlinking(1000, 0.1f); + container->activateExamMode(); } else { Ion::LED::setColor(KDColorBlack); Ion::LED::updateColorWithPlugAndCharge(); diff --git a/apps/global_preferences.cpp b/apps/global_preferences.cpp index f509b7a65..b78102ba9 100644 --- a/apps/global_preferences.cpp +++ b/apps/global_preferences.cpp @@ -5,6 +5,22 @@ GlobalPreferences * GlobalPreferences::sharedGlobalPreferences() { return &globalPreferences; } +bool GlobalPreferences::examMode() const { + if (m_examMode == ExamMode::Unknown) { + m_examMode = (ExamMode)Ion::ExamMode::FetchExamMode(); + } + assert((int)m_examMode == 0 || (int)m_examMode == 1); + return (bool)m_examMode; +} + +void GlobalPreferences::setExamMode(bool activateExamMode) { + if (((bool)examMode()) == activateExamMode) { + return; + } + Ion::ExamMode::ToggleExamMode(); + m_examMode = (ExamMode)activateExamMode; +} + void GlobalPreferences::setBrightnessLevel(int brightnessLevel) { if (m_brightnessLevel != brightnessLevel) { brightnessLevel = brightnessLevel < 0 ? 0 : brightnessLevel; diff --git a/apps/global_preferences.h b/apps/global_preferences.h index 201957ab2..3e3c75feb 100644 --- a/apps/global_preferences.h +++ b/apps/global_preferences.h @@ -5,15 +5,11 @@ class GlobalPreferences { public: - enum class ExamMode { - Activate, - Deactivate - }; static GlobalPreferences * sharedGlobalPreferences(); I18n::Language language() const { return m_language; } void setLanguage(I18n::Language language) { m_language = language; } - ExamMode examMode() const { return m_examMode; } - void setExamMode(ExamMode examMode) { m_examMode = examMode; } + bool examMode() const; + void setExamMode(bool activateExamMode); bool showPopUp() const { return m_showPopUp; } void setShowPopUp(bool showPopUp) { m_showPopUp = showPopUp; } int brightnessLevel() const { return m_brightnessLevel; } @@ -22,11 +18,18 @@ public: private: GlobalPreferences() : m_language(I18n::Language::EN), - m_examMode(ExamMode::Deactivate), + m_examMode(ExamMode::Unknown), m_showPopUp(true), m_brightnessLevel(Ion::Backlight::MaxBrightness) {} I18n::Language m_language; - ExamMode m_examMode; + enum class ExamMode : uint8_t { + Deactivate = 0, + Activate = 1, + Unknown = 2 + }; + static_assert((uint8_t)GlobalPreferences::ExamMode::Deactivate == 0, "GlobalPreferences::setExamMode and examMode() are not right"); + static_assert((uint8_t)GlobalPreferences::ExamMode::Activate == 1, "GlobalPreferences::setExamMode and examMode() are not right"); + mutable ExamMode m_examMode; bool m_showPopUp; int m_brightnessLevel; }; diff --git a/apps/on_boarding/logo_controller.cpp b/apps/on_boarding/logo_controller.cpp index 197a29e7b..91ea5173e 100644 --- a/apps/on_boarding/logo_controller.cpp +++ b/apps/on_boarding/logo_controller.cpp @@ -1,5 +1,7 @@ #include "logo_controller.h" #include "power_on_self_test.h" +#include +#include #include namespace OnBoarding { @@ -45,6 +47,11 @@ void LogoController::viewWillAppear() { void LogoController::viewDidDisappear() { if (m_didPerformTests) { Ion::LED::setColor(m_previousLEDColor); + /* TODO: instead of setting again the exam mode, put the previous led color + * AND BLINKING.*/ + if (GlobalPreferences::sharedGlobalPreferences()->examMode()) { + AppsContainer::sharedAppsContainer()->activateExamMode(); + } } ViewController::viewDidDisappear(); } diff --git a/apps/settings/base.de.i18n b/apps/settings/base.de.i18n index 7caa733b4..d86c25dc5 100644 --- a/apps/settings/base.de.i18n +++ b/apps/settings/base.de.i18n @@ -7,8 +7,8 @@ EditionLinear = "Linear " Edition2D = "Natürlich " ComplexFormat = "Komplex" ExamMode = "Testmodus" -ActivateExamMode = "Start Testmodus" -ExamModeActive = "Testmodus: aktiv" +ActivateExamMode = "Starten Testmodus" +ExamModeActive = "Wieder starten Testmodus" About = "Über" Degrees = "Grad " Gradians = "Gone " diff --git a/apps/settings/base.en.i18n b/apps/settings/base.en.i18n index 0d0421143..1d710c354 100644 --- a/apps/settings/base.en.i18n +++ b/apps/settings/base.en.i18n @@ -8,7 +8,7 @@ Edition2D = "Natural " ComplexFormat = "Complex format" ExamMode = "Exam mode" ActivateExamMode = "Activate exam mode" -ExamModeActive = "Exam mode: active" +ExamModeActive = "Reactivate exam mode" About = "About" Degrees = "Degrees " Gradians = "Gradians " diff --git a/apps/settings/base.es.i18n b/apps/settings/base.es.i18n index 57ce54c7c..a75ad3912 100644 --- a/apps/settings/base.es.i18n +++ b/apps/settings/base.es.i18n @@ -8,7 +8,7 @@ Edition2D = "Natural " ComplexFormat = "Forma compleja" ExamMode = "Modo examen" ActivateExamMode = "Activar el modo examen" -ExamModeActive = "Modo examen: activo" +ExamModeActive = "Reactivar el modo examen" About = "Acerca" Degrees = "Grados " Gradians = "Gradianes " diff --git a/apps/settings/base.fr.i18n b/apps/settings/base.fr.i18n index de3d3be95..511a0ae2a 100644 --- a/apps/settings/base.fr.i18n +++ b/apps/settings/base.fr.i18n @@ -8,7 +8,7 @@ Edition2D = "Naturelle " ComplexFormat = "Forme complexe" ExamMode = "Mode examen" ActivateExamMode = "Activer le mode examen" -ExamModeActive = "Mode examen: actif" +ExamModeActive = "Réactiver le mode examen" About = "À propos" Degrees = "Degrés " Gradians = "Grades " diff --git a/apps/settings/base.pt.i18n b/apps/settings/base.pt.i18n index ca2d855aa..2f1ccf928 100644 --- a/apps/settings/base.pt.i18n +++ b/apps/settings/base.pt.i18n @@ -6,9 +6,9 @@ EditionMode = "Formato escrita " EditionLinear = "Em linha " Edition2D = "Natural " ComplexFormat = "Complexos" -ExamMode = "Modo de Exame" -ActivateExamMode = "Inicio modo de exame" -ExamModeActive = "Modo de exame : ativo" +ExamMode = "Modo de exame" +ActivateExamMode = "Ativar o modo de exame" +ExamModeActive = "Reativar o modo de exame" About = "Acerca" Degrees = "Graus " Gradians = "Grados " diff --git a/apps/settings/sub_menu/exam_mode_controller.cpp b/apps/settings/sub_menu/exam_mode_controller.cpp index b293081e0..d2d90c7b2 100644 --- a/apps/settings/sub_menu/exam_mode_controller.cpp +++ b/apps/settings/sub_menu/exam_mode_controller.cpp @@ -28,9 +28,6 @@ bool ExamModeController::handleEvent(Ion::Events::Event event) { I18n::Message childLabel = m_messageTreeModel->children(selectedRow())->label(); if (event == Ion::Events::OK || event == Ion::Events::EXE || event == Ion::Events::Right) { if (childLabel == I18n::Message::ActivateExamMode || childLabel == I18n::Message::ExamModeActive) { - if (GlobalPreferences::sharedGlobalPreferences()->examMode() == GlobalPreferences::ExamMode::Activate) { - return false; - } AppsContainer::sharedAppsContainer()->displayExamModePopUp(true); return true; } @@ -81,7 +78,7 @@ void ExamModeController::willDisplayCellForIndex(HighlightCell * cell, int index GenericSubController::willDisplayCellForIndex(cell, index); I18n::Message thisLabel = m_messageTreeModel->children(index)->label(); - if (GlobalPreferences::sharedGlobalPreferences()->examMode() == GlobalPreferences::ExamMode::Activate && (thisLabel == I18n::Message::ActivateExamMode || thisLabel == I18n::Message::ExamModeActive)) { + if (GlobalPreferences::sharedGlobalPreferences()->examMode() && (thisLabel == I18n::Message::ActivateExamMode || thisLabel == I18n::Message::ExamModeActive)) { MessageTableCell * myCell = (MessageTableCell *)cell; myCell->setMessage(I18n::Message::ExamModeActive); } diff --git a/apps/title_bar_view.cpp b/apps/title_bar_view.cpp index 577d02b62..d1f2ce4de 100644 --- a/apps/title_bar_view.cpp +++ b/apps/title_bar_view.cpp @@ -71,7 +71,7 @@ void TitleBarView::layoutSubviews() { m_preferenceView.setFrame(KDRect(Metric::TitleBarExternHorizontalMargin, 0, m_preferenceView.minimalSizeForOptimalDisplay().width(), bounds().height())); KDSize batterySize = m_batteryView.minimalSizeForOptimalDisplay(); m_batteryView.setFrame(KDRect(bounds().width() - batterySize.width() - Metric::TitleBarExternHorizontalMargin, (bounds().height()- batterySize.height())/2, batterySize)); - if (GlobalPreferences::sharedGlobalPreferences()->examMode() == GlobalPreferences::ExamMode::Activate) { + if (GlobalPreferences::sharedGlobalPreferences()->examMode()) { m_examModeIconView.setFrame(KDRect(k_examIconMargin, (bounds().height() - k_examIconHeight)/2, k_examIconWidth, k_examIconHeight)); } else { m_examModeIconView.setFrame(KDRectZero); diff --git a/ion/include/ion.h b/ion/include/ion.h index e30d36cb9..8cba01dec 100644 --- a/ion/include/ion.h +++ b/ion/include/ion.h @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include diff --git a/ion/include/ion/exam_mode.h b/ion/include/ion/exam_mode.h new file mode 100644 index 000000000..ef0c5c92b --- /dev/null +++ b/ion/include/ion/exam_mode.h @@ -0,0 +1,13 @@ +#ifndef ION_EXAM_MODE_H +#define ION_EXAM_MODE_H + +namespace Ion { +namespace ExamMode { + +bool FetchExamMode(); +void ToggleExamMode(); + +} +} + +#endif diff --git a/ion/src/blackbox/Makefile b/ion/src/blackbox/Makefile index 2ac36a1aa..a47729da9 100644 --- a/ion/src/blackbox/Makefile +++ b/ion/src/blackbox/Makefile @@ -17,6 +17,7 @@ ion_src += $(addprefix ion/src/shared/, \ dummy/battery.cpp \ dummy/display.cpp \ dummy/events_modifier.cpp \ + dummy/exam_mode.cpp \ dummy/fcc_id.cpp \ dummy/led.cpp \ dummy/keyboard.cpp \ diff --git a/ion/src/device/n0100/drivers/config/flash.h b/ion/src/device/n0100/drivers/config/internal_flash.h similarity index 79% rename from ion/src/device/n0100/drivers/config/flash.h rename to ion/src/device/n0100/drivers/config/internal_flash.h index aa23e3135..002ed92ce 100644 --- a/ion/src/device/n0100/drivers/config/flash.h +++ b/ion/src/device/n0100/drivers/config/internal_flash.h @@ -1,11 +1,11 @@ -#ifndef ION_DEVICE_N0100_CONFIG_FLASH_H -#define ION_DEVICE_N0100_CONFIG_FLASH_H +#ifndef ION_DEVICE_N0100_CONFIG_INTERNAL_FLASH_H +#define ION_DEVICE_N0100_CONFIG_INTERNAL_FLASH_H #include namespace Ion { namespace Device { -namespace Flash { +namespace InternalFlash { namespace Config { constexpr static uint32_t StartAddress = 0x08000000; diff --git a/ion/src/device/n0100/drivers/reset.cpp b/ion/src/device/n0100/drivers/reset.cpp index c64afb379..9bcc93695 100644 --- a/ion/src/device/n0100/drivers/reset.cpp +++ b/ion/src/device/n0100/drivers/reset.cpp @@ -1,5 +1,5 @@ #include -#include "config/flash.h" +#include "config/internal_flash.h" namespace Ion { namespace Device { @@ -10,7 +10,7 @@ void coreWhilePlugged() { * might be plugged in. Doing a full core reset would result in the device * entering the ST DFU bootloader. By performing a jump-reset, we mimic the * core reset without entering ST bootloader.*/ - jump(Flash::Config::StartAddress); + jump(InternalFlash::Config::StartAddress); } } diff --git a/ion/src/device/n0100/flash.ld b/ion/src/device/n0100/flash.ld index db1fc8d2a..6c449809a 100644 --- a/ion/src/device/n0100/flash.ld +++ b/ion/src/device/n0100/flash.ld @@ -9,14 +9,16 @@ * This will let us use shortcuts such as ">FLASH" to ask for a given section to * be stored in Flash. */ MEMORY { - FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K + FLASH_FIRST_SECTOR (rx) : ORIGIN = 0x08000000, LENGTH = 16K + FLASH_SECOND_SECTOR (rx) : ORIGIN = (0x08000000 + 16K), LENGTH = 16K + FLASH_LAST_SECTORS (rx) : ORIGIN = (0x08000000 + 32K), LENGTH = (1024K - 32K) SRAM (rw) : ORIGIN = 0x20000000, LENGTH = 256K } STACK_SIZE = 32K; SECTIONS { - .isr_vector_table ORIGIN(FLASH) : { + .isr_vector_table ORIGIN(FLASH_FIRST_SECTOR) : { /* When booting, the STM32F412 fetches the content of address 0x0, and * extracts from it various key infos: the initial value of the PC register * (program counter), the initial value of the stack pointer, and various @@ -31,30 +33,37 @@ SECTIONS { * convenient: using function pointers, we can easily point to the service * routine for each interrupt. */ KEEP(*(.isr_vector_table)) - } >FLASH + } >FLASH_FIRST_SECTOR .header : { KEEP(*(.header)) - } >FLASH + } >FLASH_FIRST_SECTOR + + .exam_mode_persistence ORIGIN(FLASH_SECOND_SECTOR): { + _exam_mode_persistence_start = .; + /* Note: We don't increment "." here, we set it. */ + . = (ORIGIN(FLASH_SECOND_SECTOR) + LENGTH(FLASH_SECOND_SECTOR)); + _exam_mode_persistence_end = .; + } >FLASH_SECOND_SECTOR .text : { . = ALIGN(4); *(.text) *(.text.*) - } >FLASH + } >FLASH_LAST_SECTORS .init_array : { . = ALIGN(4); _init_array_start = .; KEEP (*(.init_array*)) _init_array_end = .; - } >FLASH + } >FLASH_LAST_SECTORS .rodata : { . = ALIGN(4); *(.rodata) *(.rodata.*) - } >FLASH + } >FLASH_LAST_SECTORS .data : { /* The data section is written to Flash but linked as if it were in RAM. @@ -75,7 +84,7 @@ SECTIONS { *(.data) *(.data.*) _data_section_end_ram = .; - } >SRAM AT> FLASH + } >SRAM AT> FLASH_LAST_SECTORS .bss : { /* The bss section contains data for all uninitialized variables diff --git a/ion/src/device/n0110/drivers/board.cpp b/ion/src/device/n0110/drivers/board.cpp index c605a4add..55fe11131 100644 --- a/ion/src/device/n0110/drivers/board.cpp +++ b/ion/src/device/n0110/drivers/board.cpp @@ -35,10 +35,36 @@ void initMPU() { // 2. MPU settings // 2.1 Configure a MPU region for the FMC memory area - // This is needed for interfacing with the LCD - MPU.RNR()->setREGION(0x00); + /* This is needed for interfacing with the LCD + * We define the whole FMC memory bank 1 as strongly ordered, non-executable + * and not accessible. We define the FMC command and data addresses as + * writeable non-cachable, non-buffereable and non shareable. */ + int sector = 0; + MPU.RNR()->setREGION(sector++); MPU.RBAR()->setADDR(0x60000000); - MPU.RASR()->setSIZE(MPU::RASR::RegionSize::_32MB); + MPU.RASR()->setSIZE(MPU::RASR::RegionSize::_256MB); + MPU.RASR()->setAP(MPU::RASR::AccessPermission::NoAccess); + MPU.RASR()->setXN(true); + MPU.RASR()->setTEX(2); + MPU.RASR()->setS(0); + MPU.RASR()->setC(0); + MPU.RASR()->setB(0); + MPU.RASR()->setENABLE(true); + + MPU.RNR()->setREGION(sector++); + MPU.RBAR()->setADDR(0x60000000); + MPU.RASR()->setSIZE(MPU::RASR::RegionSize::_32B); + MPU.RASR()->setXN(true); + MPU.RASR()->setAP(MPU::RASR::AccessPermission::RW); + MPU.RASR()->setTEX(2); + MPU.RASR()->setS(0); + MPU.RASR()->setC(0); + MPU.RASR()->setB(0); + MPU.RASR()->setENABLE(true); + + MPU.RNR()->setREGION(sector++); + MPU.RBAR()->setADDR(0x60000000+0x20000); + MPU.RASR()->setSIZE(MPU::RASR::RegionSize::_32B); MPU.RASR()->setXN(true); MPU.RASR()->setAP(MPU::RASR::AccessPermission::RW); MPU.RASR()->setTEX(2); @@ -56,7 +82,7 @@ void initMPU() { * strongly ordered, non-executable and not accessible. Plus, we define the * Quad-SPI region corresponding to the Expternal Chip as executable and * fully accessible (AN4861). */ - MPU.RNR()->setREGION(0x01); + MPU.RNR()->setREGION(sector++); MPU.RBAR()->setADDR(0x90000000); MPU.RASR()->setSIZE(MPU::RASR::RegionSize::_256MB); MPU.RASR()->setAP(MPU::RASR::AccessPermission::NoAccess); @@ -67,7 +93,7 @@ void initMPU() { MPU.RASR()->setB(0); MPU.RASR()->setENABLE(true); - MPU.RNR()->setREGION(0x02); + MPU.RNR()->setREGION(sector++); MPU.RBAR()->setADDR(0x90000000); MPU.RASR()->setSIZE(MPU::RASR::RegionSize::_8MB); MPU.RASR()->setAP(MPU::RASR::AccessPermission::RW); diff --git a/ion/src/device/n0110/drivers/config/flash.h b/ion/src/device/n0110/drivers/config/internal_flash.h similarity index 75% rename from ion/src/device/n0110/drivers/config/flash.h rename to ion/src/device/n0110/drivers/config/internal_flash.h index 2c50a8fcf..fc494c00d 100644 --- a/ion/src/device/n0110/drivers/config/flash.h +++ b/ion/src/device/n0110/drivers/config/internal_flash.h @@ -1,11 +1,11 @@ -#ifndef ION_DEVICE_N0110_CONFIG_FLASH_H -#define ION_DEVICE_N0110_CONFIG_FLASH_H +#ifndef ION_DEVICE_N0110_CONFIG_INTERNAL_FLASH_H +#define ION_DEVICE_N0110_CONFIG_INTERNAL_FLASH_H #include namespace Ion { namespace Device { -namespace Flash { +namespace InternalFlash { namespace Config { constexpr static uint32_t StartAddress = 0x08000000; diff --git a/ion/src/device/n0110/flash.ld b/ion/src/device/n0110/flash.ld index f6edcc8db..42ac5350a 100644 --- a/ion/src/device/n0110/flash.ld +++ b/ion/src/device/n0110/flash.ld @@ -12,7 +12,8 @@ MEMORY { INTERNAL_FLASH (rx) : ORIGIN = 0x00200000, LENGTH = 64K SRAM (rw) : ORIGIN = 0x20000000, LENGTH = 256K - EXTERNAL_FLASH (rx) : ORIGIN = 0x90000000, LENGTH = 8M + EXTERNAL_FLASH_FIRST_SECTOR (rx) : ORIGIN = 0x90000000, LENGTH = 4K + EXTERNAL_FLASH_NEXT_SECTORS (rx) : ORIGIN = (0x90000000 + 4K), LENGTH = (8M - 4K) /* ITCM (rwx) : ORIGIN = 0x00000000, LENGTH = 16K DTCM (rwx) : ORIGIN = 0x20000000, LENGTH = 64K @@ -55,6 +56,13 @@ SECTIONS { *(.text._ZL22jump_to_external_flashv) } >INTERNAL_FLASH + .exam_mode_persistence ORIGIN(EXTERNAL_FLASH_FIRST_SECTOR): { + _exam_mode_persistence_start = .; + /* Note: We don't increment "." here, we set it. */ + . = (ORIGIN(EXTERNAL_FLASH_FIRST_SECTOR) + LENGTH(EXTERNAL_FLASH_FIRST_SECTOR)); + _exam_mode_persistence_end = .; + } >EXTERNAL_FLASH_FIRST_SECTOR + /* Use boot routine and required dependencies */ /* We're relying on symbols being in their own sub-section. On GCC, this is * done with -fdata-sections -ffunction-sections */ @@ -120,12 +128,12 @@ SECTIONS { . = ALIGN(4); *(.text) *(.text.*) - } >EXTERNAL_FLASH + } >EXTERNAL_FLASH_NEXT_SECTORS .rodata.external : { *(.rodata) *(.rodata.*) - } >EXTERNAL_FLASH + } >EXTERNAL_FLASH_NEXT_SECTORS .init_array : { . = ALIGN(4); @@ -202,3 +210,8 @@ NOCROSSREFS_TO(.text.external .isr_vector_table); NOCROSSREFS_TO(.rodata.external .isr_vector_table); NOCROSSREFS_TO(.text.external .header); NOCROSSREFS_TO(.rodata.external .header); + +NOCROSSREFS_TO(.exam_mode_persistence .text.internal); +NOCROSSREFS_TO(.exam_mode_persistence .rodata.internal); +NOCROSSREFS_TO(.exam_mode_persistence .isr_vector_table); +NOCROSSREFS_TO(.exam_mode_persistence .header); diff --git a/ion/src/device/shared/drivers/Makefile b/ion/src/device/shared/drivers/Makefile index 6def5933e..2b3b71efb 100644 --- a/ion/src/device/shared/drivers/Makefile +++ b/ion/src/device/shared/drivers/Makefile @@ -6,8 +6,10 @@ ion_device_src += $(addprefix ion/src/device/shared/drivers/, \ crc32.cpp \ display.cpp \ events_keyboard_platform.cpp \ + exam_mode.cpp \ external_flash.cpp \ flash.cpp \ + internal_flash.cpp \ keyboard.cpp \ led.cpp \ power.cpp\ diff --git a/ion/src/device/shared/drivers/exam_mode.cpp b/ion/src/device/shared/drivers/exam_mode.cpp new file mode 100644 index 000000000..3096ad526 --- /dev/null +++ b/ion/src/device/shared/drivers/exam_mode.cpp @@ -0,0 +1,74 @@ +#include +#include "flash.h" +#include + +namespace Ion { +namespace ExamMode { + +extern "C" { + extern char _exam_mode_persistence_start; + extern char _exam_mode_persistence_end; +} + +/* The exam mode is written in flash so that it is resilient to resets. + * We erase the dedicated flash sector (all bits written to 1) and, upon + * activating or deactivating the exam mode we write one bit to 0. To determine + * if we are in exam mode, we count the number of leading 0 bits. If it is even, + * the exam mode is deactivated, if it is odd, the exam mode is activated. */ + +/* significantExamModeAddress returns the first uint32_t * in the exam mode + * flash sector that does not point to 0. If this flash sector has only 0s, it + * is erased (to 1) and significantExamModeAddress returns the start of the + * sector. */ + +uint32_t * SignificantExamModeAddress() { + uint32_t * persitence_start = (uint32_t *)&_exam_mode_persistence_start; + uint32_t * persitence_end = (uint32_t *)&_exam_mode_persistence_end; + while (persitence_start < persitence_end && *persitence_start == 0x0) { + // Skip even number of zero bits + persitence_start++; + } + if (persitence_start == persitence_end) { + assert(Ion::Device::Flash::SectorAtAddress((uint32_t)&_exam_mode_persistence_start) >= 0); + Ion::Device::Flash::EraseSector(Ion::Device::Flash::SectorAtAddress((uint32_t)&_exam_mode_persistence_start)); + return (uint32_t *)&_exam_mode_persistence_start; + } + return persitence_start; +} + +size_t firstOneBit(int i, size_t size) { + int minShift = 0; + int maxShift = size; + while (maxShift > minShift+1) { + int shift = (minShift + maxShift)/2; + int shifted = i >> shift; + if (shifted == 0) { + maxShift = shift; + } else { + minShift = shift; + } + } + return maxShift; +} + +bool FetchExamMode() { + uint32_t * readingAddress = SignificantExamModeAddress(); + size_t numberOfLeading0 = 32 - firstOneBit(*readingAddress, 32); + return numberOfLeading0 % 2 == 1; +} + +void ToggleExamMode() { + uint32_t * writingAddress = SignificantExamModeAddress(); + assert(*writingAddress != 0); + // Compute the new value with one bit switched + uint8_t numberOfLeadingZeroes = 32 - firstOneBit(*writingAddress, 32); + /* When writing in flash, we can only switch a 1 to a 0. If we want to switch + * the fifth bit in a byte, we can thus write "11110111". */ + uint32_t newValue = ~(1 << (31 - numberOfLeadingZeroes)); + + // Write the value in flash + Ion::Device::Flash::WriteMemory((uint8_t *)writingAddress, (uint8_t *)&newValue, sizeof(uint32_t)); +} + +} +} diff --git a/ion/src/device/shared/drivers/external_flash.cpp b/ion/src/device/shared/drivers/external_flash.cpp index d482aac98..10404c7c2 100644 --- a/ion/src/device/shared/drivers/external_flash.cpp +++ b/ion/src/device/shared/drivers/external_flash.cpp @@ -402,7 +402,7 @@ void MassErase() { set_as_memory_mapped(); } -void EraseSector(int i) { +void __attribute__((noinline)) EraseSector(int i) { assert(i >= 0 && i < Config::NumberOfSectors); unset_memory_mapped_mode(); unlockFlash(); @@ -413,7 +413,7 @@ void EraseSector(int i) { set_as_memory_mapped(); } -void WriteMemory(uint8_t * destination, const uint8_t * source, size_t length) { +void __attribute__((noinline)) WriteMemory(uint8_t * destination, const uint8_t * source, size_t length) { if (Config::NumberOfSectors == 0) { return; } diff --git a/ion/src/device/shared/drivers/flash.cpp b/ion/src/device/shared/drivers/flash.cpp index 2ae24eb97..6f569cd89 100644 --- a/ion/src/device/shared/drivers/flash.cpp +++ b/ion/src/device/shared/drivers/flash.cpp @@ -1,253 +1,53 @@ #include "flash.h" -#include -#include +#include "external_flash.h" +#include "internal_flash.h" +#include +#include #include namespace Ion { namespace Device { namespace Flash { -using namespace Regs; - -static inline void wait() { - /* Issue a DSB instruction to guarantee the completion of a previous access - * to FLASH_CR register or data write operation. (RM0431) */ - Cache::dsb(); - // Wait for pending Flash operations to complete - while (FLASH.SR()->getBSY()) { - } -} - -static void open() { - // Unlock the Flash configuration register if needed - if (FLASH.CR()->getLOCK()) { - FLASH.KEYR()->set(0x45670123); - FLASH.KEYR()->set(0xCDEF89AB); - } - assert(FLASH.CR()->getLOCK() == false); - - // Set the programming parallelism - FLASH.CR()->setPSIZE(MemoryAccessWidth); -} - -static void close() { - // Clear error flags - class FLASH::SR sr(0); - // Error flags are cleared by writing 1 - sr.setERSERR(true); - sr.setPGPERR(true); - sr.setPGAERR(true); - sr.setWRPERR(true); - sr.setEOP(true); - FLASH.SR()->set(sr); - - // Lock the Flash configuration register - assert(!FLASH.CR()->getMER()); - assert(!FLASH.CR()->getSER()); - assert(!FLASH.CR()->getPG()); - FLASH.CR()->setLOCK(true); - - // Purge Data and instruction cache -#if REGS_FLASH_CONFIG_ART - if (FLASH.ACR()->getARTEN()) { - FLASH.ACR()->setARTEN(false); - FLASH.ACR()->setARTRST(true); - FLASH.ACR()->setARTRST(false); - FLASH.ACR()->setARTEN(true); - } -#else - if (FLASH.ACR()->getDCEN()) { - FLASH.ACR()->setDCEN(false); - FLASH.ACR()->setDCRST(true); - FLASH.ACR()->setDCRST(false); - FLASH.ACR()->setDCEN(true); - } - if (FLASH.ACR()->getICEN()) { - FLASH.ACR()->setICEN(false); - FLASH.ACR()->setICRST(true); - FLASH.ACR()->setICRST(false); - FLASH.ACR()->setICEN(true); - } -#endif -} - -// Compile-time log2 -static inline constexpr size_t clog2(size_t input) { - return (input == 1) ? 0 : clog2(input/2)+1; -} - -// Align a pointer to a given type's boundaries -// Returns a value that is lower or equal to input -template -static inline T * align(void * input) { - size_t k = clog2(sizeof(T)); - return reinterpret_cast(reinterpret_cast(input) & ~((1< -static inline T eat(void * ptr) { - T * pointer = *reinterpret_cast(ptr); - T result = *pointer; - *reinterpret_cast(ptr) = pointer+1; - return result; -} - -static inline ptrdiff_t byte_offset(void * p1, void * p2) { - return reinterpret_cast(p2) - reinterpret_cast(p1); -} - -template -static inline T min(T i, T j) { - return (i| - * |-- HeaderDelta ->| - */ - - MemoryAccessType * alignedDestination = align(destination); - ptrdiff_t headerDelta = byte_offset(alignedDestination, destination); - assert(headerDelta >= 0 && headerDelta < static_cast(sizeof(MemoryAccessType))); - - if (headerDelta > 0) { - // At this point, alignedDestination < destination - // We'll then retrieve the current value at alignedDestination, fill it with - // bytes from source, and write it back at alignedDestination. - - // First, retrieve the current value at alignedDestination - MemoryAccessType header = *alignedDestination; - - // Then copy headerLength bytes from source and put them in the header - uint8_t * headerStart = reinterpret_cast(&header); - // Here's where source data shall start being copied in the header - uint8_t * headerDataStart = headerStart + headerDelta; - // And here's where it should end - uint8_t * headerDataEnd = min( - headerStart + sizeof(MemoryAccessType), // Either at the end of the header - headerDataStart + length // or whenever src runs out of data - ); - for (uint8_t * h = headerDataStart; h(&source); - } - - // Then eventually write the header back into the aligned destination - *alignedDestination++ = header; - wait(); - } - - /* Step 2 - Copy the bulk of the data - * At this point, we can use aligned MemoryAccessType pointers. */ - - MemoryAccessType * lastAlignedDestination = align(destination + length); - while (alignedDestination < lastAlignedDestination) { - *alignedDestination++ = eat(&source); - wait(); - } - - /* Step 3 - Copy a footer if needed - * Some unaligned data can be pending at the end. Let's take care of it like - * we did for the header. - * - * _alignedDst _Destination+length - * | | - * --+--------+--------+--------+--------+--------+--------+-- - * | || | | | || | - *---+--------+--------+--------+--------+--------+--------+-- - * |<------------ Footer ------------->| - * |- footerLength ->| - */ - - ptrdiff_t footerLength = byte_offset(alignedDestination, destination + length); - assert(footerLength < static_cast(sizeof(MemoryAccessType))); - if (footerLength > 0) { - assert(alignedDestination == lastAlignedDestination); - - // First, retrieve the current value at alignedDestination - MemoryAccessType footer = *alignedDestination; - - /* Then copy footerLength bytes from source and put them at the beginning of - * the footer */ - uint8_t * footerPointer = reinterpret_cast(&footer); - for (ptrdiff_t i=0; i(&source); - } - - // Then eventually write the footer back into the aligned destination - *alignedDestination = footer; - wait(); - } +int TotalNumberOfSectors() { + return InternalFlash::Config::NumberOfSectors + ExternalFlash::Config::NumberOfSectors; } int SectorAtAddress(uint32_t address) { - for (int i = 0; i < Config::NumberOfSectors; i++) { - if (address >= Config::SectorAddresses[i] && address < Config::SectorAddresses[i+1]) { - return i; - } + if (address >= InternalFlash::Config::StartAddress + && address <= InternalFlash::Config::EndAddress) + { + return InternalFlash::SectorAtAddress(address); + } + if (address >= ExternalFlash::Config::StartAddress + && address <= ExternalFlash::Config::EndAddress) + { + return InternalFlash::Config::NumberOfSectors + ExternalFlash::SectorAtAddress(address - ExternalFlash::Config::StartAddress); } return -1; } void MassErase() { - open(); - FLASH.CR()->setMER(true); - FLASH.CR()->setSTRT(true); - wait(); - FLASH.CR()->setMER(false); - close(); + InternalFlash::MassErase(); + ExternalFlash::MassErase(); } void EraseSector(int i) { - assert(i >= 0 && i < Config::NumberOfSectors); - open(); - FLASH.CR()->setSNB(i); - FLASH.CR()->setSER(true); - FLASH.CR()->setSTRT(true); - wait(); - FLASH.CR()->setSNB(0); - FLASH.CR()->setSER(false); - close(); + assert(i >= 0 && i < TotalNumberOfSectors()); + if (i < InternalFlash::Config::NumberOfSectors) { + InternalFlash::EraseSector(i); + } else { + ExternalFlash::EraseSector(i - InternalFlash::Config::NumberOfSectors); + } } void WriteMemory(uint8_t * destination, uint8_t * source, size_t length) { - open(); - FLASH.CR()->setPG(true); - flash_memcpy(destination, source, length); - FLASH.CR()->setPG(false); - close(); + assert(SectorAtAddress((uint32_t)destination) >= 0); + if (SectorAtAddress((uint32_t)destination) < InternalFlash::Config::NumberOfSectors) { + InternalFlash::WriteMemory(destination, source, length); + } else { + ExternalFlash::WriteMemory(destination - ExternalFlash::Config::StartAddress, source, length); + } } } diff --git a/ion/src/device/shared/drivers/flash.h b/ion/src/device/shared/drivers/flash.h index ebb3ffc4f..4e61b1fa9 100644 --- a/ion/src/device/shared/drivers/flash.h +++ b/ion/src/device/shared/drivers/flash.h @@ -2,24 +2,19 @@ #define ION_DEVICE_SHARED_FLASH_H #include -#include +#include namespace Ion { namespace Device { namespace Flash { -void MassErase(); - +int TotalNumberOfSectors(); int SectorAtAddress(uint32_t address); + +void MassErase(); void EraseSector(int i); - void WriteMemory(uint8_t * destination, uint8_t * source, size_t length); -/* The Device is powered by a 2.8V LDO. This allows us to perform writes to the - * Flash 32 bits at once. */ -constexpr Regs::FLASH::CR::PSIZE MemoryAccessWidth = Regs::FLASH::CR::PSIZE::X32; -typedef uint32_t MemoryAccessType; - } } } diff --git a/ion/src/device/shared/drivers/internal_flash.cpp b/ion/src/device/shared/drivers/internal_flash.cpp new file mode 100644 index 000000000..9ff5e1432 --- /dev/null +++ b/ion/src/device/shared/drivers/internal_flash.cpp @@ -0,0 +1,256 @@ +#include "internal_flash.h" +#include +#include +#include + +namespace Ion { +namespace Device { +namespace InternalFlash { + +using namespace Regs; + +static inline void wait() { + /* Issue a DSB instruction to guarantee the completion of a previous access + * to FLASH_CR register or data write operation. (RM0431) */ + Cache::dsb(); + // Wait for pending Flash operations to complete + while (FLASH.SR()->getBSY()) { + } +} + +static void open() { + // Unlock the Flash configuration register if needed + if (FLASH.CR()->getLOCK()) { + FLASH.KEYR()->set(0x45670123); + FLASH.KEYR()->set(0xCDEF89AB); + } + assert(FLASH.CR()->getLOCK() == false); + + // Set the programming parallelism + FLASH.CR()->setPSIZE(MemoryAccessWidth); +} + +static void close() { + // Clear error flags + class FLASH::SR sr(0); + // Error flags are cleared by writing 1 + sr.setERSERR(true); + sr.setPGPERR(true); + sr.setPGAERR(true); + sr.setWRPERR(true); + sr.setEOP(true); + FLASH.SR()->set(sr); + + // Lock the Flash configuration register + assert(!FLASH.CR()->getMER()); + assert(!FLASH.CR()->getSER()); + assert(!FLASH.CR()->getPG()); + FLASH.CR()->setLOCK(true); + + // Purge Data and instruction cache +#if REGS_FLASH_CONFIG_ART + if (FLASH.ACR()->getARTEN()) { + FLASH.ACR()->setARTEN(false); + FLASH.ACR()->setARTRST(true); + FLASH.ACR()->setARTRST(false); + FLASH.ACR()->setARTEN(true); + } +#else + if (FLASH.ACR()->getDCEN()) { + FLASH.ACR()->setDCEN(false); + FLASH.ACR()->setDCRST(true); + FLASH.ACR()->setDCRST(false); + FLASH.ACR()->setDCEN(true); + } + if (FLASH.ACR()->getICEN()) { + FLASH.ACR()->setICEN(false); + FLASH.ACR()->setICRST(true); + FLASH.ACR()->setICRST(false); + FLASH.ACR()->setICEN(true); + } +#endif +} + +// Compile-time log2 +static inline constexpr size_t clog2(size_t input) { + return (input == 1) ? 0 : clog2(input/2)+1; +} + +// Align a pointer to a given type's boundaries +// Returns a value that is lower or equal to input +template +static inline T * align(void * input) { + size_t k = clog2(sizeof(T)); + return reinterpret_cast(reinterpret_cast(input) & ~((1< +static inline T eat(void * ptr) { + T * pointer = *reinterpret_cast(ptr); + T result = *pointer; + *reinterpret_cast(ptr) = pointer+1; + return result; +} + +static inline ptrdiff_t byte_offset(void * p1, void * p2) { + return reinterpret_cast(p2) - reinterpret_cast(p1); +} + +template +static inline T min(T i, T j) { + return (i| + * |-- HeaderDelta ->| + */ + + MemoryAccessType * alignedDestination = align(destination); + ptrdiff_t headerDelta = byte_offset(alignedDestination, destination); + assert(headerDelta >= 0 && headerDelta < static_cast(sizeof(MemoryAccessType))); + + if (headerDelta > 0) { + // At this point, alignedDestination < destination + // We'll then retrieve the current value at alignedDestination, fill it with + // bytes from source, and write it back at alignedDestination. + + // First, retrieve the current value at alignedDestination + MemoryAccessType header = *alignedDestination; + + // Then copy headerLength bytes from source and put them in the header + uint8_t * headerStart = reinterpret_cast(&header); + // Here's where source data shall start being copied in the header + uint8_t * headerDataStart = headerStart + headerDelta; + // And here's where it should end + uint8_t * headerDataEnd = min( + headerStart + sizeof(MemoryAccessType), // Either at the end of the header + headerDataStart + length // or whenever src runs out of data + ); + for (uint8_t * h = headerDataStart; h(&source); + } + + // Then eventually write the header back into the aligned destination + *alignedDestination++ = header; + wait(); + } + + /* Step 2 - Copy the bulk of the data + * At this point, we can use aligned MemoryAccessType pointers. */ + + MemoryAccessType * lastAlignedDestination = align(destination + length); + while (alignedDestination < lastAlignedDestination) { + *alignedDestination++ = eat(&source); + wait(); + } + + /* Step 3 - Copy a footer if needed + * Some unaligned data can be pending at the end. Let's take care of it like + * we did for the header. + * + * _alignedDst _Destination+length + * | | + * --+--------+--------+--------+--------+--------+--------+-- + * | || | | | || | + *---+--------+--------+--------+--------+--------+--------+-- + * |<------------ Footer ------------->| + * |- footerLength ->| + */ + + ptrdiff_t footerLength = byte_offset(alignedDestination, destination + length); + assert(footerLength < static_cast(sizeof(MemoryAccessType))); + if (footerLength > 0) { + assert(alignedDestination == lastAlignedDestination); + + // First, retrieve the current value at alignedDestination + MemoryAccessType footer = *alignedDestination; + + /* Then copy footerLength bytes from source and put them at the beginning of + * the footer */ + uint8_t * footerPointer = reinterpret_cast(&footer); + for (ptrdiff_t i=0; i(&source); + } + + // Then eventually write the footer back into the aligned destination + *alignedDestination = footer; + wait(); + } +} + +int SectorAtAddress(uint32_t address) { + for (int i = 0; i < Config::NumberOfSectors; i++) { + if (address >= Config::SectorAddresses[i] && address < Config::SectorAddresses[i+1]) { + return i; + } + } + return -1; +} + +void MassErase() { + open(); + FLASH.CR()->setMER(true); + FLASH.CR()->setSTRT(true); + wait(); + FLASH.CR()->setMER(false); + close(); +} + + +void EraseSector(int i) { + assert(i >= 0 && i < Config::NumberOfSectors); + open(); + FLASH.CR()->setSNB(i); + FLASH.CR()->setSER(true); + FLASH.CR()->setSTRT(true); + wait(); + FLASH.CR()->setSNB(0); + FLASH.CR()->setSER(false); + close(); +} + +void WriteMemory(uint8_t * destination, uint8_t * source, size_t length) { + open(); + FLASH.CR()->setPG(true); + flash_memcpy(destination, source, length); + FLASH.CR()->setPG(false); + close(); +} + +} +} +} diff --git a/ion/src/device/shared/drivers/internal_flash.h b/ion/src/device/shared/drivers/internal_flash.h new file mode 100644 index 000000000..befe83b3e --- /dev/null +++ b/ion/src/device/shared/drivers/internal_flash.h @@ -0,0 +1,27 @@ +#ifndef ION_DEVICE_SHARED_INTERNAL_FLASH_H +#define ION_DEVICE_SHARED_INTERNAL_FLASH_H + +#include +#include + +namespace Ion { +namespace Device { +namespace InternalFlash { + +void MassErase(); + +int SectorAtAddress(uint32_t address); +void EraseSector(int i); + +void WriteMemory(uint8_t * destination, uint8_t * source, size_t length); + +/* The Device is powered by a 2.8V LDO. This allows us to perform writes to the + * Flash 32 bits at once. */ +constexpr Regs::FLASH::CR::PSIZE MemoryAccessWidth = Regs::FLASH::CR::PSIZE::X32; +typedef uint32_t MemoryAccessType; + +} +} +} + +#endif diff --git a/ion/src/device/shared/usb/Makefile b/ion/src/device/shared/usb/Makefile index cf2f0cbf7..df9d1f6c2 100644 --- a/ion/src/device/shared/usb/Makefile +++ b/ion/src/device/shared/usb/Makefile @@ -55,6 +55,7 @@ dfu_src += $(addprefix ion/src/device/shared/drivers/, \ events_keyboard_platform.cpp \ external_flash.cpp \ flash.cpp \ + internal_flash.cpp \ keyboard.cpp \ led.cpp \ power.cpp\ diff --git a/ion/src/device/shared/usb/dfu_interface.cpp b/ion/src/device/shared/usb/dfu_interface.cpp index c221dae35..5316f7b46 100644 --- a/ion/src/device/shared/usb/dfu_interface.cpp +++ b/ion/src/device/shared/usb/dfu_interface.cpp @@ -1,18 +1,12 @@ #include "dfu_interface.h" -#include #include #include -#include -#include -#include #include namespace Ion { namespace Device { namespace USB { -using namespace Ion::Device::Regs; - static inline uint32_t minUint32T(uint32_t x, uint32_t y) { return x < y ? x : y; } void DFUInterface::StatusData::push(Channel * c) const { @@ -188,7 +182,7 @@ void DFUInterface::eraseCommand(uint8_t * transferBuffer, uint16_t transferBuffe if (transferBufferLength == 1) { // Mass erase - m_erasePage = Flash::Config::NumberOfSectors + ExternalFlash::Config::NumberOfSectors; + m_erasePage = Flash::TotalNumberOfSectors(); return; } @@ -200,11 +194,8 @@ void DFUInterface::eraseCommand(uint8_t * transferBuffer, uint16_t transferBuffe + (transferBuffer[3] << 16) + (transferBuffer[4] << 24); - if (eraseAddress >= Flash::Config::StartAddress && eraseAddress <= Flash::Config::EndAddress) { - m_erasePage = Flash::SectorAtAddress(eraseAddress); - } else if (eraseAddress >= ExternalFlash::Config::StartAddress && eraseAddress <= ExternalFlash::Config::EndAddress) { - m_erasePage = Flash::Config::NumberOfSectors + ExternalFlash::SectorAtAddress(eraseAddress - ExternalFlash::Config::StartAddress); - } else { + m_erasePage = Flash::SectorAtAddress(eraseAddress); + if (m_erasePage < 0) { // Unrecognized sector m_state = State::dfuERROR; m_status = Status::errTARGET; @@ -218,13 +209,10 @@ void DFUInterface::eraseMemoryIfNeeded() { return; } - if (m_erasePage == Flash::Config::NumberOfSectors + ExternalFlash::Config::NumberOfSectors) { + if (m_erasePage == Flash::TotalNumberOfSectors()) { Flash::MassErase(); - ExternalFlash::MassErase(); - } else if (m_erasePage < Flash::Config::NumberOfSectors) { - Flash::EraseSector(m_erasePage); } else { - ExternalFlash::EraseSector(m_erasePage - Flash::Config::NumberOfSectors); + Flash::EraseSector(m_erasePage); } /* Put an out of range value in m_erasePage to indicate that no erase is @@ -235,15 +223,12 @@ void DFUInterface::eraseMemoryIfNeeded() { } void DFUInterface::writeOnMemory() { - if (m_writeAddress >= Flash::Config::StartAddress && m_writeAddress <= Flash::Config::EndAddress) { - // Write to the Flash memory - Flash::WriteMemory(reinterpret_cast(m_writeAddress), m_largeBuffer, m_largeBufferLength); - } else if (m_writeAddress >= k_sramStartAddress && m_writeAddress <= k_sramEndAddress) { + if (m_writeAddress >= k_sramStartAddress && m_writeAddress <= k_sramEndAddress) { // Write on SRAM // FIXME We should check that we are not overriding the current instructions. memcpy((void *)m_writeAddress, m_largeBuffer, m_largeBufferLength); - } else if (m_writeAddress >= ExternalFlash::Config::StartAddress && m_writeAddress <= ExternalFlash::Config::EndAddress) { - ExternalFlash::WriteMemory(reinterpret_cast(m_writeAddress) - ExternalFlash::Config::StartAddress, m_largeBuffer, m_largeBufferLength); + } else if (Flash::SectorAtAddress(m_writeAddress) >= 0) { + Flash::WriteMemory(reinterpret_cast(m_writeAddress), m_largeBuffer, m_largeBufferLength); } else { // Invalid write address m_largeBufferLength = 0; diff --git a/ion/src/device/shared/usb/stack/device.cpp b/ion/src/device/shared/usb/stack/device.cpp index c0b72dc9e..294b647e1 100644 --- a/ion/src/device/shared/usb/stack/device.cpp +++ b/ion/src/device/shared/usb/stack/device.cpp @@ -1,5 +1,5 @@ #include "device.h" -#include +#include #include #include @@ -92,7 +92,7 @@ void Device::detach() { } void Device::leave(uint32_t leaveAddress) { - if (leaveAddress == Ion::Device::Flash::Config::StartAddress) { + if (leaveAddress == Ion::Device::InternalFlash::Config::StartAddress) { Ion::Device::Reset::coreWhilePlugged(); } else { Ion::Device::Reset::jump(leaveAddress); diff --git a/ion/src/shared/dummy/exam_mode.cpp b/ion/src/shared/dummy/exam_mode.cpp new file mode 100644 index 000000000..02d78e591 --- /dev/null +++ b/ion/src/shared/dummy/exam_mode.cpp @@ -0,0 +1,14 @@ +#include + +namespace Ion { +namespace ExamMode { + +bool FetchExamMode() { + return false; +} + +void ToggleExamMode() { +} + +} +} diff --git a/ion/src/simulator/Makefile b/ion/src/simulator/Makefile index e7511833d..74ae93666 100644 --- a/ion/src/simulator/Makefile +++ b/ion/src/simulator/Makefile @@ -10,6 +10,7 @@ ion_src += $(addprefix ion/src/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 \