From 34e6141bdb8fcbc788c8d68dd8ef18c06a0be770 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Sun, 15 Dec 2019 09:34:40 -0500 Subject: [PATCH 01/44] [ion/regs] Avoid code duplication --- ion/src/device/shared/regs/cortex.h | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/ion/src/device/shared/regs/cortex.h b/ion/src/device/shared/regs/cortex.h index b89351ebe..15d6e4ace 100644 --- a/ion/src/device/shared/regs/cortex.h +++ b/ion/src/device/shared/regs/cortex.h @@ -100,25 +100,20 @@ public: using Register32::Register32; }; - class DCISW : public Register32 { + class DCSW : public Register32 { public: - DCISW() : Register32(0) {} + DCSW() : Register32(0) {} REGS_FIELD(SET, uint16_t, 13, 5); REGS_FIELD(WAY, uint8_t, 31, 30); }; - class DCCSW : public Register32 { - public: - DCCSW() : Register32(0) {} - REGS_FIELD(SET, uint16_t, 13, 5); - REGS_FIELD(WAY, uint8_t, 31, 30); + class DCISW : public DCSW { }; - class DCCISW : public Register32 { - public: - DCCISW() : Register32(0) {} - REGS_FIELD(SET, uint16_t, 13, 5); - REGS_FIELD(WAY, uint8_t, 31, 30); + class DCCSW : public DCSW { + }; + + class DCCISW : public DCSW { }; #endif From d25346d82f2643415ed2c230002341bdf2575e26 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Sun, 15 Dec 2019 17:01:03 -0500 Subject: [PATCH 02/44] [ion/cache] Use DCSW to reduce code duplication --- ion/src/device/n0110/drivers/cache.cpp | 29 +++++++++++--------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/ion/src/device/n0110/drivers/cache.cpp b/ion/src/device/n0110/drivers/cache.cpp index af907386f..3210383d8 100644 --- a/ion/src/device/n0110/drivers/cache.cpp +++ b/ion/src/device/n0110/drivers/cache.cpp @@ -23,24 +23,19 @@ void privateCleanInvalidateDisableDCache(bool clean, bool invalidate, bool disab do { uint32_t w = ways; do { - if (clean) { - if (invalidate) { - class CORTEX::DCCISW dccisw; - dccisw.setSET(sets); - dccisw.setWAY(w); - CORTEX.DCCISW()->set(dccisw); - } else { - class CORTEX::DCCSW dccsw; - dccsw.setSET(sets); - dccsw.setWAY(w); - CORTEX.DCCSW()->set(dccsw); - } - } else if (invalidate) { - class CORTEX::DCISW dcisw; - dcisw.setSET(sets); - dcisw.setWAY(w); - CORTEX.DCISW()->set(dcisw); + class CORTEX::DCSW dcsw; + dcsw.setSET(sets); + dcsw.setWAY(w); + volatile CORTEX::DCSW * target = nullptr; + if (clean && invalidate) { + target = CORTEX.DCCISW(); + } else if (clean) { + target = CORTEX.DCCSW(); + } else { + assert(invalidate); + target = CORTEX.DCISW(); } + target->set(dcsw); __asm volatile("nop"); } while (w-- != 0); } while (sets-- != 0); From 67302a90c7fd4cd8ca91aac0350ec094fae368e3 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Sun, 15 Dec 2019 17:02:01 -0500 Subject: [PATCH 03/44] [ion/cache] Follow CMSIS' order --- ion/src/device/n0110/drivers/cache.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ion/src/device/n0110/drivers/cache.cpp b/ion/src/device/n0110/drivers/cache.cpp index 3210383d8..f14bee613 100644 --- a/ion/src/device/n0110/drivers/cache.cpp +++ b/ion/src/device/n0110/drivers/cache.cpp @@ -7,19 +7,19 @@ namespace Cache { using namespace Regs; void privateCleanInvalidateDisableDCache(bool clean, bool invalidate, bool disable) { + // Select Level 1 data cache CORTEX.CSSELR()->set(0); dsb(); - // Associativity = 6 - - uint32_t sets = CORTEX.CCSIDR()->getNUMSETS(); - uint32_t ways = CORTEX.CCSIDR()->getASSOCIATIVITY(); - + // Disable D-Cache if (disable) { CORTEX.CCR()->setDC(false); dsb(); } + uint32_t sets = CORTEX.CCSIDR()->getNUMSETS(); + uint32_t ways = CORTEX.CCSIDR()->getASSOCIATIVITY(); + do { uint32_t w = ways; do { From 273834ee84814ba543d17c6c2b8a1a4d2c3ed2fa Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Sun, 15 Dec 2019 17:13:27 -0500 Subject: [PATCH 04/44] [ion/cache] Improve cache cleaning - Avoid fetching CCSIDR twice - Use for loop instead of do/while - Only compute the target register once - Avoid an useless nop --- ion/src/device/n0110/drivers/cache.cpp | 39 +++++++++++++------------- ion/src/device/shared/regs/cortex.h | 1 + 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/ion/src/device/n0110/drivers/cache.cpp b/ion/src/device/n0110/drivers/cache.cpp index f14bee613..87b1a36f2 100644 --- a/ion/src/device/n0110/drivers/cache.cpp +++ b/ion/src/device/n0110/drivers/cache.cpp @@ -17,28 +17,29 @@ void privateCleanInvalidateDisableDCache(bool clean, bool invalidate, bool disab dsb(); } - uint32_t sets = CORTEX.CCSIDR()->getNUMSETS(); - uint32_t ways = CORTEX.CCSIDR()->getASSOCIATIVITY(); + // Pick the right DC??SW register according to invalidate/disable parameters + volatile CORTEX::DCSW * target = nullptr; + if (clean && invalidate) { + target = CORTEX.DCCISW(); + } else if (clean) { + target = CORTEX.DCCSW(); + } else { + assert(invalidate); + target = CORTEX.DCISW(); + } - do { - uint32_t w = ways; - do { + class CORTEX::CCSIDR ccsidr = CORTEX.CCSIDR()->get(); + uint32_t sets = ccsidr.getNUMSETS(); + uint32_t ways = ccsidr.getASSOCIATIVITY(); + + for (int set = sets; set >= 0; set--) { + for (int way = ways; way >= 0; way--) { class CORTEX::DCSW dcsw; - dcsw.setSET(sets); - dcsw.setWAY(w); - volatile CORTEX::DCSW * target = nullptr; - if (clean && invalidate) { - target = CORTEX.DCCISW(); - } else if (clean) { - target = CORTEX.DCCSW(); - } else { - assert(invalidate); - target = CORTEX.DCISW(); - } + dcsw.setSET(set); + dcsw.setWAY(way); target->set(dcsw); - __asm volatile("nop"); - } while (w-- != 0); - } while (sets-- != 0); + } + } dsb(); isb(); diff --git a/ion/src/device/shared/regs/cortex.h b/ion/src/device/shared/regs/cortex.h index 15d6e4ace..2c71c0fa2 100644 --- a/ion/src/device/shared/regs/cortex.h +++ b/ion/src/device/shared/regs/cortex.h @@ -72,6 +72,7 @@ public: #if REGS_CORTEX_CONFIG_CACHE class CCSIDR : public Register32 { public: + using Register32::Register32; REGS_FIELD(ASSOCIATIVITY, uint16_t, 12, 3); REGS_FIELD(NUMSETS, uint16_t, 27, 13); }; From b155af0c0dda42826bef77756522755a21d224e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 18 Dec 2019 10:55:59 +0100 Subject: [PATCH 05/44] [ion/external_flash] Finer flash sectors Instead of 128 sectors of 64K, there are now 8 sectors of 4K, 1 of 32K and 127 of 64K. This makes a more finely erasable flash, which is needed for the exam mode. --- .../n0100/drivers/config/external_flash.h | 5 ++- .../n0110/drivers/config/external_flash.h | 7 +++- ion/src/device/n0110/drivers/config/usb.h | 2 +- .../device/shared/drivers/external_flash.cpp | 36 +++++++++++++++++-- .../device/shared/drivers/external_flash.h | 7 +++- 5 files changed, 51 insertions(+), 6 deletions(-) diff --git a/ion/src/device/n0100/drivers/config/external_flash.h b/ion/src/device/n0100/drivers/config/external_flash.h index 79d39f768..2fa895a21 100644 --- a/ion/src/device/n0100/drivers/config/external_flash.h +++ b/ion/src/device/n0100/drivers/config/external_flash.h @@ -22,7 +22,10 @@ using namespace Regs; constexpr static uint32_t StartAddress = 0xFFFFFFFF; constexpr static uint32_t EndAddress = 0xFFFFFFFF; -constexpr static int NumberOfSectors = 0; +constexpr static int NumberOf4KSectors = 0; +constexpr static int NumberOf32KSectors = 0; +constexpr static int NumberOf64KSectors = 0; +constexpr static int NumberOfSectors = NumberOf4KSectors + NumberOf32KSectors + NumberOf64KSectors; constexpr static AFGPIOPin Pins[] = {}; } diff --git a/ion/src/device/n0110/drivers/config/external_flash.h b/ion/src/device/n0110/drivers/config/external_flash.h index 98c3ef9f0..f245dca20 100644 --- a/ion/src/device/n0110/drivers/config/external_flash.h +++ b/ion/src/device/n0110/drivers/config/external_flash.h @@ -22,7 +22,12 @@ using namespace Regs; constexpr static uint32_t StartAddress = 0x90000000; constexpr static uint32_t EndAddress = 0x90800000; -constexpr static int NumberOfSectors = 128; + +constexpr static int NumberOf4KSectors = 8; +constexpr static int NumberOf32KSectors = 1; +constexpr static int NumberOf64KSectors = 128 - 1; +constexpr static int NumberOfSectors = NumberOf4KSectors + NumberOf32KSectors + NumberOf64KSectors; + constexpr static AFGPIOPin Pins[] = { AFGPIOPin(GPIOB, 2, GPIO::AFR::AlternateFunction::AF9, GPIO::PUPDR::Pull::None, GPIO::OSPEEDR::OutputSpeed::Fast), AFGPIOPin(GPIOB, 6, GPIO::AFR::AlternateFunction::AF10, GPIO::PUPDR::Pull::None, GPIO::OSPEEDR::OutputSpeed::Fast), diff --git a/ion/src/device/n0110/drivers/config/usb.h b/ion/src/device/n0110/drivers/config/usb.h index 7477f0846..bbd3fa5a1 100644 --- a/ion/src/device/n0110/drivers/config/usb.h +++ b/ion/src/device/n0110/drivers/config/usb.h @@ -14,7 +14,7 @@ constexpr static AFGPIOPin VbusPin = AFGPIOPin(GPIOA, 9, GPIO::AFR::AlternateFun 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); -constexpr static const char * InterfaceStringDescriptor = "@Flash/0x08000000/04*016Kg/0x90000000/64*064Kg,64*064Kg"; +constexpr static const char * InterfaceStringDescriptor = "@Flash/0x08000000/04*016Kg/0x90000000/08*004Kg,01*032Kg,63*064Kg,64*064Kg"; } } diff --git a/ion/src/device/shared/drivers/external_flash.cpp b/ion/src/device/shared/drivers/external_flash.cpp index 10404c7c2..a2b6cfe59 100644 --- a/ion/src/device/shared/drivers/external_flash.cpp +++ b/ion/src/device/shared/drivers/external_flash.cpp @@ -71,6 +71,8 @@ enum class Command : uint8_t { 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, @@ -79,6 +81,8 @@ enum class Command : uint8_t { }; static constexpr uint8_t NumberOfAddressBitsIn64KbyteBlock = 16; +static constexpr uint8_t NumberOfAddressBitsIn32KbyteBlock = 15; +static constexpr uint8_t NumberOfAddressBitsIn4KbyteBlock = 12; class ExternalFlashStatusRegister { public: @@ -367,10 +371,23 @@ void shutdown() { } int SectorAtAddress(uint32_t address) { + /* 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. */ int i = address >> NumberOfAddressBitsIn64KbyteBlock; - if (i >= Config::NumberOfSectors) { + if (i > Config::NumberOf64KSectors) { return -1; } + if (i >= 1) { + return Config::NumberOf4KSectors + Config::NumberOf32KSectors + i - 1; + } + i = address >> NumberOfAddressBitsIn32KbyteBlock; + if (i >= 1) { + i = Config::NumberOf4KSectors + i - 1; + assert(i >= 0 && i <= Config::NumberOf32KSectors); + return i; + } + i = address >> NumberOfAddressBitsIn4KbyteBlock; + assert(i <= Config::NumberOf4KSectors); return i; } @@ -408,7 +425,22 @@ void __attribute__((noinline)) EraseSector(int i) { unlockFlash(); send_command(Command::WriteEnable); wait(); - send_write_command(Command::Erase64KbyteBlock, reinterpret_cast(i << NumberOfAddressBitsIn64KbyteBlock), nullptr, 0); + /* 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(i << NumberOfAddressBitsIn4KbyteBlock), nullptr, 0); + } 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((i - Config::NumberOf4KSectors + 1) << NumberOfAddressBitsIn32KbyteBlock), nullptr, 0); + } 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((i - Config::NumberOf4KSectors - Config::NumberOf32KSectors + 1) << NumberOfAddressBitsIn64KbyteBlock), nullptr, 0); + } wait(); set_as_memory_mapped(); } diff --git a/ion/src/device/shared/drivers/external_flash.h b/ion/src/device/shared/drivers/external_flash.h index 8a0ad3b62..f2c1ddd6f 100644 --- a/ion/src/device/shared/drivers/external_flash.h +++ b/ion/src/device/shared/drivers/external_flash.h @@ -15,7 +15,12 @@ * 2^7 64KiB blocks 0x..0000 - 0x..FFFF * 2^7 * 2 32KiB blocks 0x..0000 - 0x..7FFF or 0x..8000 - 0x..FFFF * 2^7 * 2 * 2^3 4KiB blocks 0x...000 - 0x...FFF - * 2^7 * 2 * 2^3 * 2^4 256B pages 0x....00 - 0x....FF */ + * 2^7 * 2 * 2^3 * 2^4 256B pages 0x....00 - 0x....FF + * + * To be able to erase a small sector for the exam mode, we say that the flash + * is cut into 8 + 1 + 2^7-1 = 136 sectors: 8 sectors of 4Kb, 1 sector of 32Kb + * and 2^7-1 sectors of 64Kb. These sectors are the smallest erasable units. If + * need be, we can define more sectors to erase even more finely the flash. */ namespace Ion { namespace Device { From 6a7ca3263006f94a46e3051ecbf46c027e027366 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 28 Oct 2019 11:59:53 +0100 Subject: [PATCH 06/44] [apps/home] Add messages: ForbidenAppInExamMode --- apps/home/base.de.i18n | 2 ++ apps/home/base.en.i18n | 2 ++ apps/home/base.es.i18n | 2 ++ apps/home/base.fr.i18n | 2 ++ apps/home/base.pt.i18n | 2 ++ 5 files changed, 10 insertions(+) diff --git a/apps/home/base.de.i18n b/apps/home/base.de.i18n index f762d3e57..a8f33d6cb 100644 --- a/apps/home/base.de.i18n +++ b/apps/home/base.de.i18n @@ -1,2 +1,4 @@ Apps = "Anwendungen" AppsCapital = "ANWENDUNGEN" +ForbidenAppInExamMode1 = "" +ForbidenAppInExamMode2 = "" diff --git a/apps/home/base.en.i18n b/apps/home/base.en.i18n index b7ab1ab2f..158fa3bda 100644 --- a/apps/home/base.en.i18n +++ b/apps/home/base.en.i18n @@ -1,2 +1,4 @@ Apps = "Applications" AppsCapital = "APPLICATIONS" +ForbidenAppInExamMode1 = "This application is" +ForbidenAppInExamMode2 = "forbidden in exam mode" diff --git a/apps/home/base.es.i18n b/apps/home/base.es.i18n index 7ad2abcbf..8f48d86c5 100644 --- a/apps/home/base.es.i18n +++ b/apps/home/base.es.i18n @@ -1,2 +1,4 @@ Apps = "Aplicaciones" AppsCapital = "APLICACIONES" +ForbidenAppInExamMode1 = "" +ForbidenAppInExamMode2 = "" diff --git a/apps/home/base.fr.i18n b/apps/home/base.fr.i18n index b7ab1ab2f..200c6f577 100644 --- a/apps/home/base.fr.i18n +++ b/apps/home/base.fr.i18n @@ -1,2 +1,4 @@ Apps = "Applications" AppsCapital = "APPLICATIONS" +ForbidenAppInExamMode1 = "" +ForbidenAppInExamMode2 = "" diff --git a/apps/home/base.pt.i18n b/apps/home/base.pt.i18n index aa255ea6b..2720ea295 100644 --- a/apps/home/base.pt.i18n +++ b/apps/home/base.pt.i18n @@ -1,2 +1,4 @@ Apps = "Aplicações" AppsCapital = "APLICAÇÕES" +ForbidenAppInExamMode1 = "" +ForbidenAppInExamMode2 = "" From 510151c7db9db1853431c18edf115de11137952f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 28 Oct 2019 12:01:36 +0100 Subject: [PATCH 07/44] [apps/home] Prevent from entering Python application in exam mode --- apps/home/controller.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/apps/home/controller.cpp b/apps/home/controller.cpp index c59612d7a..221ba5ec9 100644 --- a/apps/home/controller.cpp +++ b/apps/home/controller.cpp @@ -1,6 +1,7 @@ #include "controller.h" #include "app.h" #include "../apps_container.h" +#include "../global_preferences.h" extern "C" { #include } @@ -57,9 +58,15 @@ Controller::Controller(Responder * parentResponder, SelectableTableViewDataSourc bool Controller::handleEvent(Ion::Events::Event event) { if (event == Ion::Events::OK || event == Ion::Events::EXE) { AppsContainer * container = AppsContainer::sharedAppsContainer(); - bool switched = container->switchTo(container->appSnapshotAtIndex(selectionDataSource()->selectedRow()*k_numberOfColumns+selectionDataSource()->selectedColumn()+1)); - assert(switched); - (void) switched; // Silence compilation warning about unused variable. + ::App::Snapshot * selectedSnapshot = container->appSnapshotAtIndex(selectionDataSource()->selectedRow()*k_numberOfColumns+selectionDataSource()->selectedColumn()+1); + // TODO: check that we are in Dutch exam mode + if (GlobalPreferences::sharedGlobalPreferences()->examMode() && selectedSnapshot->descriptor()->name() == I18n::Message::CodeApp) { + App::app()->displayWarning(I18n::Message::ForbidenAppInExamMode1, I18n::Message::ForbidenAppInExamMode2); + } else { + bool switched = container->switchTo(selectedSnapshot); + assert(switched); + (void) switched; // Silence compilation warning about unused variable. + } return true; } From 82fb00689e025310a7d3d499279c321b3b004dc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 28 Oct 2019 15:22:54 +0100 Subject: [PATCH 08/44] [apps/settings] Message: add messages to activate Dutch exam mode --- apps/settings/base.de.i18n | 2 ++ apps/settings/base.en.i18n | 2 ++ apps/settings/base.es.i18n | 2 ++ apps/settings/base.fr.i18n | 2 ++ apps/settings/base.pt.i18n | 2 ++ 5 files changed, 10 insertions(+) diff --git a/apps/settings/base.de.i18n b/apps/settings/base.de.i18n index a9385db05..0f3e127e1 100644 --- a/apps/settings/base.de.i18n +++ b/apps/settings/base.de.i18n @@ -9,6 +9,8 @@ ComplexFormat = "Komplex" ExamMode = "Testmodus" ActivateExamMode = "Starten Testmodus" ExamModeActive = "Wieder starten Testmodus" +ActivateDutchExamMode = "" +DutchExamModeActive = "" About = "Über" Degrees = "Grad " Gradians = "Gone " diff --git a/apps/settings/base.en.i18n b/apps/settings/base.en.i18n index e5cc87cae..7f7309985 100644 --- a/apps/settings/base.en.i18n +++ b/apps/settings/base.en.i18n @@ -9,6 +9,8 @@ ComplexFormat = "Complex format" ExamMode = "Exam mode" ActivateExamMode = "Activate exam mode" ExamModeActive = "Reactivate exam mode" +ActivateDutchExamMode = "Activate Dutch exam mode" +DutchExamModeActive = "Reactivate Dutch exam mode" About = "About" Degrees = "Degrees " Gradians = "Gradians " diff --git a/apps/settings/base.es.i18n b/apps/settings/base.es.i18n index 589348d3e..aaf71e055 100644 --- a/apps/settings/base.es.i18n +++ b/apps/settings/base.es.i18n @@ -9,6 +9,8 @@ ComplexFormat = "Forma compleja" ExamMode = "Modo examen" ActivateExamMode = "Activar el modo examen" ExamModeActive = "Reactivar el modo examen" +ActivateDutchExamMode = "" +DutchExamModeActive = "" About = "Acerca" Degrees = "Grados " Gradians = "Gradianes " diff --git a/apps/settings/base.fr.i18n b/apps/settings/base.fr.i18n index 5ca04b291..e8782094c 100644 --- a/apps/settings/base.fr.i18n +++ b/apps/settings/base.fr.i18n @@ -9,6 +9,8 @@ ComplexFormat = "Forme complexe" ExamMode = "Mode examen" ActivateExamMode = "Activer le mode examen" ExamModeActive = "Réactiver le mode examen" +ActivateDutchExamMode = "" +DutchExamModeActive = "" About = "À propos" Degrees = "Degrés " Gradians = "Grades " diff --git a/apps/settings/base.pt.i18n b/apps/settings/base.pt.i18n index 6582afeff..18d8b0ca4 100644 --- a/apps/settings/base.pt.i18n +++ b/apps/settings/base.pt.i18n @@ -9,6 +9,8 @@ ComplexFormat = "Complexos" ExamMode = "Modo de exame" ActivateExamMode = "Ativar o modo de exame" ExamModeActive = "Reativar o modo de exame" +ActivateDutchExamMode = "" +DutchExamModeActive = "" About = "Acerca" Degrees = "Graus " Gradians = "Grados " From f4de842a865c8e00c82a40b92d17fca3268527f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 12 Dec 2019 11:44:13 +0100 Subject: [PATCH 09/44] [ion] Change exam mode to have 3 states (off, standard, Dutch) --- ion/include/ion/exam_mode.h | 8 +++- ion/src/device/shared/drivers/exam_mode.cpp | 48 +++++++++++++-------- ion/src/shared/dummy/exam_mode.cpp | 4 +- 3 files changed, 39 insertions(+), 21 deletions(-) diff --git a/ion/include/ion/exam_mode.h b/ion/include/ion/exam_mode.h index ef0c5c92b..801dd4d1e 100644 --- a/ion/include/ion/exam_mode.h +++ b/ion/include/ion/exam_mode.h @@ -1,11 +1,15 @@ #ifndef ION_EXAM_MODE_H #define ION_EXAM_MODE_H +extern "C" { +#include +} + namespace Ion { namespace ExamMode { -bool FetchExamMode(); -void ToggleExamMode(); +uint8_t FetchExamMode(); +void IncrementExamMode(uint8_t delta); } } diff --git a/ion/src/device/shared/drivers/exam_mode.cpp b/ion/src/device/shared/drivers/exam_mode.cpp index 19b62b4df..806729c01 100644 --- a/ion/src/device/shared/drivers/exam_mode.cpp +++ b/ion/src/device/shared/drivers/exam_mode.cpp @@ -18,14 +18,17 @@ char ones[Config::ExamModeBufferSize] /* 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. */ + * deactivating or activating standard or Dutch exam mode we write one or two + * bits to 0. To determine in which exam mode we are, we count the number of + * leading 0 bits. If it is equal to: + * - 0[3]: the exam mode is off; + * - 1[3]: the standard exam mode is activated; + * - 2[3]: the Dutch 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. */ + * flash sector that does not point to 0. If this flash sector has only 0s or + * if it has only one 1, it is erased (to 1) and significantExamModeAddress + * returns the start of the sector. */ uint32_t * SignificantExamModeAddress() { uint32_t * persitence_start = (uint32_t *)&_exam_mode_buffer_start; @@ -34,7 +37,9 @@ uint32_t * SignificantExamModeAddress() { // Skip even number of zero bits persitence_start++; } - if (persitence_start == persitence_end) { + if (persitence_start == persitence_end + // we can't toggle from 0[3] to 2[3] when there is only one 1 bit in the whole sector + || (persitence_start + 1 == persitence_end && *persitence_start == 1)) { assert(Ion::Device::Flash::SectorAtAddress((uint32_t)&_exam_mode_buffer_start) >= 0); Ion::Device::Flash::EraseSector(Ion::Device::Flash::SectorAtAddress((uint32_t)&_exam_mode_buffer_start)); return (uint32_t *)&_exam_mode_buffer_start; @@ -57,23 +62,32 @@ size_t firstOneBit(int i, size_t size) { return maxShift; } -bool FetchExamMode() { +uint8_t FetchExamMode() { uint32_t * readingAddress = SignificantExamModeAddress(); - size_t numberOfLeading0 = 32 - firstOneBit(*readingAddress, 32); - return numberOfLeading0 % 2 == 1; + // Count the number of 0[3] before reading address + uint32_t nbOfZerosBefore = ((readingAddress - (uint32_t *)&_exam_mode_buffer_start)/4 * 2) % 3; + // Count the number of 0[3] at reading address + size_t numberOfLeading0 = (32 - firstOneBit(*readingAddress, 32)) % 3; + return (nbOfZerosBefore + numberOfLeading0) % 3; } -void ToggleExamMode() { +void IncrementExamMode(uint8_t delta) { + assert(delta == 1 || delta == 2); uint32_t * writingAddress = SignificantExamModeAddress(); assert(*writingAddress != 0); - // Compute the new value with one bit switched - uint8_t numberOfLeadingZeroes = 32 - firstOneBit(*writingAddress, 32); + size_t nbOfOnes = firstOneBit(*writingAddress, 32); + // Compute the new value with two bits switched to 0. + /* We write in a uint64_t instead of uint32_t, in case there was only one bit + * left to 1 in writingAddress. */ /* 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)); - + * the fifth and sixth bit in a byte, we can thus write "11100111". */ + uint64_t deltaOnes = (1 << delta) - 1; + uint64_t newValue = ~(deltaOnes << (32 + nbOfOnes - delta)); // Write the value in flash - Ion::Device::Flash::WriteMemory((uint8_t *)writingAddress, (uint8_t *)&newValue, sizeof(uint32_t)); + /* Avoid writing out of sector */ + assert(writingAddress < (uint32_t *)&_exam_mode_buffer_end - 1 || *writingAddress > 1); + size_t writtenFlash = *writingAddress == 1 ? sizeof(uint64_t) : sizeof(uint32_t); + Ion::Device::Flash::WriteMemory((uint8_t *)writingAddress, (uint8_t *)&newValue, writtenFlash); } } diff --git a/ion/src/shared/dummy/exam_mode.cpp b/ion/src/shared/dummy/exam_mode.cpp index 02d78e591..e9a32a539 100644 --- a/ion/src/shared/dummy/exam_mode.cpp +++ b/ion/src/shared/dummy/exam_mode.cpp @@ -3,11 +3,11 @@ namespace Ion { namespace ExamMode { -bool FetchExamMode() { +uint8_t FetchExamMode() { return false; } -void ToggleExamMode() { +void IncrementExamMode(uint8_t delta) { } } From da735b93a4af731c9e56bc6608e0d56fe34380ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 12 Dec 2019 11:44:52 +0100 Subject: [PATCH 10/44] [apps] GlobalPreferences: change exam mode API --- apps/apps_container.cpp | 8 +++++--- apps/exam_pop_up_controller.cpp | 3 ++- apps/global_preferences.cpp | 18 ++++++++++------- apps/global_preferences.h | 20 ++++++++++--------- apps/home/controller.cpp | 3 +-- apps/on_boarding/logo_controller.cpp | 2 +- .../sub_menu/exam_mode_controller.cpp | 3 ++- apps/title_bar_view.cpp | 2 +- 8 files changed, 34 insertions(+), 25 deletions(-) diff --git a/apps/apps_container.cpp b/apps/apps_container.cpp index 70ac5cbde..bee6ddd4e 100644 --- a/apps/apps_container.cpp +++ b/apps/apps_container.cpp @@ -168,7 +168,8 @@ 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()) { + // TODO + if (GlobalPreferences::sharedGlobalPreferences()->isInExamMode()) { displayExamModePopUp(false); window()->redraw(); } else { @@ -213,7 +214,8 @@ void AppsContainer::run() { * and it is visible when reflashing a N0100 (there is some noise on the * screen before the logo appears). */ Ion::Display::pushRectUniform(screenRect, KDColorWhite); - if (GlobalPreferences::sharedGlobalPreferences()->examMode()) { + // TODO + if (GlobalPreferences::sharedGlobalPreferences()->isInExamMode()) { activateExamMode(); } refreshPreferences(); @@ -291,7 +293,7 @@ void AppsContainer::shutdownDueToLowBattery() { } while (Ion::Battery::level() == Ion::Battery::Charge::EMPTY) { Ion::Backlight::setBrightness(0); - if (!GlobalPreferences::sharedGlobalPreferences()->examMode()) { + if (!GlobalPreferences::sharedGlobalPreferences()->isInExamMode()) { /* 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. */ diff --git a/apps/exam_pop_up_controller.cpp b/apps/exam_pop_up_controller.cpp index 38d6d90ce..a51286e81 100644 --- a/apps/exam_pop_up_controller.cpp +++ b/apps/exam_pop_up_controller.cpp @@ -50,7 +50,8 @@ ExamPopUpController::ContentView::ContentView(Responder * parentResponder) : }, parentResponder), KDFont::SmallFont), m_okButton(parentResponder, I18n::Message::Ok, Invocation([](void * context, void * sender) { ExamPopUpController * controller = (ExamPopUpController *)context; - GlobalPreferences::sharedGlobalPreferences()->setExamMode(controller->isActivatingExamMode()); + // TODO + GlobalPreferences::sharedGlobalPreferences()->setExamMode(controller->isActivatingExamMode() ? GlobalPreferences::ExamMode::Dutch : GlobalPreferences::ExamMode::Off); AppsContainer * container = AppsContainer::sharedAppsContainer(); if (controller->isActivatingExamMode()) { container->activateExamMode(); diff --git a/apps/global_preferences.cpp b/apps/global_preferences.cpp index b78102ba9..52572a469 100644 --- a/apps/global_preferences.cpp +++ b/apps/global_preferences.cpp @@ -5,20 +5,24 @@ GlobalPreferences * GlobalPreferences::sharedGlobalPreferences() { return &globalPreferences; } -bool GlobalPreferences::examMode() const { +GlobalPreferences::ExamMode 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; + assert((int)m_examMode >= 0 && (int)m_examMode <= 2); + return m_examMode; } -void GlobalPreferences::setExamMode(bool activateExamMode) { - if (((bool)examMode()) == activateExamMode) { +void GlobalPreferences::setExamMode(ExamMode mode) { + if (examMode() == mode) { return; } - Ion::ExamMode::ToggleExamMode(); - m_examMode = (ExamMode)activateExamMode; + assert(mode != ExamMode::Unknown); + int8_t deltaMode = (int8_t)mode - (int8_t)examMode(); + deltaMode = deltaMode < 0 ? deltaMode + 3 : deltaMode; + assert(deltaMode > 0); + Ion::ExamMode::IncrementExamMode(deltaMode); + m_examMode = mode; } void GlobalPreferences::setBrightnessLevel(int brightnessLevel) { diff --git a/apps/global_preferences.h b/apps/global_preferences.h index f9fe8e044..a7d0790ea 100644 --- a/apps/global_preferences.h +++ b/apps/global_preferences.h @@ -5,11 +5,18 @@ class GlobalPreferences { public: + enum class ExamMode : int8_t { + Unknown = -1, + Off = 0, + Standard = 1, + Dutch = 2 + }; static GlobalPreferences * sharedGlobalPreferences(); I18n::Language language() const { return m_language; } void setLanguage(I18n::Language language) { m_language = language; } - bool examMode() const; - void setExamMode(bool activateExamMode); + bool isInExamMode() const { return (int8_t)examMode() > 0; } + ExamMode examMode() const; + void setExamMode(ExamMode examMode); bool showPopUp() const { return m_showPopUp; } void setShowPopUp(bool showPopUp) { m_showPopUp = showPopUp; } int brightnessLevel() const { return m_brightnessLevel; } @@ -22,13 +29,8 @@ private: m_showPopUp(true), m_brightnessLevel(Ion::Backlight::MaxBrightness) {} I18n::Language m_language; - 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"); + static_assert((int8_t)GlobalPreferences::ExamMode::Off == 0, "GlobalPreferences::isInExamMode() is not right"); + static_assert((int8_t)GlobalPreferences::ExamMode::Unknown < 0, "GlobalPreferences::isInExamMode() is not right"); mutable ExamMode m_examMode; bool m_showPopUp; int m_brightnessLevel; diff --git a/apps/home/controller.cpp b/apps/home/controller.cpp index 221ba5ec9..00c2f287a 100644 --- a/apps/home/controller.cpp +++ b/apps/home/controller.cpp @@ -59,8 +59,7 @@ bool Controller::handleEvent(Ion::Events::Event event) { if (event == Ion::Events::OK || event == Ion::Events::EXE) { AppsContainer * container = AppsContainer::sharedAppsContainer(); ::App::Snapshot * selectedSnapshot = container->appSnapshotAtIndex(selectionDataSource()->selectedRow()*k_numberOfColumns+selectionDataSource()->selectedColumn()+1); - // TODO: check that we are in Dutch exam mode - if (GlobalPreferences::sharedGlobalPreferences()->examMode() && selectedSnapshot->descriptor()->name() == I18n::Message::CodeApp) { + if (GlobalPreferences::sharedGlobalPreferences()->examMode() == GlobalPreferences::ExamMode::Dutch && selectedSnapshot->descriptor()->name() == I18n::Message::CodeApp) { App::app()->displayWarning(I18n::Message::ForbidenAppInExamMode1, I18n::Message::ForbidenAppInExamMode2); } else { bool switched = container->switchTo(selectedSnapshot); diff --git a/apps/on_boarding/logo_controller.cpp b/apps/on_boarding/logo_controller.cpp index 91ea5173e..56aabfb2d 100644 --- a/apps/on_boarding/logo_controller.cpp +++ b/apps/on_boarding/logo_controller.cpp @@ -49,7 +49,7 @@ void LogoController::viewDidDisappear() { Ion::LED::setColor(m_previousLEDColor); /* TODO: instead of setting again the exam mode, put the previous led color * AND BLINKING.*/ - if (GlobalPreferences::sharedGlobalPreferences()->examMode()) { + if (GlobalPreferences::sharedGlobalPreferences()->isInExamMode()) { // TODO AppsContainer::sharedAppsContainer()->activateExamMode(); } } diff --git a/apps/settings/sub_menu/exam_mode_controller.cpp b/apps/settings/sub_menu/exam_mode_controller.cpp index 1590f04c4..83709a5b4 100644 --- a/apps/settings/sub_menu/exam_mode_controller.cpp +++ b/apps/settings/sub_menu/exam_mode_controller.cpp @@ -39,7 +39,8 @@ int ExamModeController::reusableCellCount(int type) { void ExamModeController::willDisplayCellForIndex(HighlightCell * cell, int index) { GenericSubController::willDisplayCellForIndex(cell, index); - if (GlobalPreferences::sharedGlobalPreferences()->examMode()) { + // TODO + if (GlobalPreferences::sharedGlobalPreferences()->isInExamMode()) { MessageTableCell * myCell = (MessageTableCell *)cell; myCell->setMessage(I18n::Message::ExamModeActive); } diff --git a/apps/title_bar_view.cpp b/apps/title_bar_view.cpp index fc5c23992..53cee9ab5 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()) { + if (GlobalPreferences::sharedGlobalPreferences()->isInExamMode()) { m_examModeIconView.setFrame(KDRect(k_examIconMargin, (bounds().height() - k_examIconHeight)/2, k_examIconWidth, k_examIconHeight)); } else { m_examModeIconView.setFrame(KDRectZero); From 5491dee5ce0743a909ec79c2a45cf6f4e51ad157 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 12 Dec 2019 13:22:10 +0100 Subject: [PATCH 11/44] [calculation][solver] Do not display exact solutions in Dutch exam mode --- apps/calculation/calculation.cpp | 5 ++++- apps/solver/equation_store.cpp | 7 ++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/apps/calculation/calculation.cpp b/apps/calculation/calculation.cpp index 25b71a71d..711408b3e 100644 --- a/apps/calculation/calculation.cpp +++ b/apps/calculation/calculation.cpp @@ -1,5 +1,6 @@ #include "calculation.h" #include "../shared/poincare_helpers.h" +#include "../global_preferences.h" #include #include #include @@ -123,7 +124,9 @@ Calculation::DisplayOutput Calculation::displayOutput(Context * context) { } if (shouldOnlyDisplayExactOutput()) { m_displayOutput = DisplayOutput::ExactOnly; - } else if (input().recursivelyMatches( + // Force all results to be ApproximateOnly in Dutch exam mode + } else if (GlobalPreferences::sharedGlobalPreferences()->examMode() == GlobalPreferences::ExamMode::Dutch || + input().recursivelyMatches( [](const Expression e, Context * c) { constexpr int approximateOnlyTypesCount = 9; /* If the input contains the following types, we only display the diff --git a/apps/solver/equation_store.cpp b/apps/solver/equation_store.cpp index ea3112b53..0691c77c0 100644 --- a/apps/solver/equation_store.cpp +++ b/apps/solver/equation_store.cpp @@ -1,6 +1,7 @@ #include "equation_store.h" #include "../constant.h" #include "../shared/poincare_helpers.h" +#include "../global_preferences.h" #include #include @@ -193,6 +194,8 @@ EquationStore::Error EquationStore::exactSolve(Poincare::Context * context) { } } // Create the results' layouts + // In Dutch exam mode, display only approximate solutions + bool forbidExactSolutions = GlobalPreferences::sharedGlobalPreferences()->examMode() == GlobalPreferences::ExamMode::Dutch; int solutionIndex = 0; int initialNumberOfSolutions = m_numberOfSolutions <= k_maxNumberOfExactSolutions ? m_numberOfSolutions : -1; // We iterate through the solutions and the potential delta @@ -211,7 +214,9 @@ EquationStore::Error EquationStore::exactSolve(Poincare::Context * context) { char approximateBuffer[::Constant::MaxSerializedExpressionSize]; m_exactSolutionExactLayouts[solutionIndex].serializeForParsing(exactBuffer, ::Constant::MaxSerializedExpressionSize); m_exactSolutionApproximateLayouts[solutionIndex].serializeForParsing(approximateBuffer, ::Constant::MaxSerializedExpressionSize); - m_exactSolutionIdentity[solutionIndex] = strcmp(exactBuffer, approximateBuffer) == 0; + /* Cheat: declare exact and approximate solutions to be identical in + * Dutch exam mode to display only the approximate solutions. */ + m_exactSolutionIdentity[solutionIndex] = forbidExactSolutions || strcmp(exactBuffer, approximateBuffer) == 0; if (!m_exactSolutionIdentity[solutionIndex]) { char buffer[::Constant::MaxSerializedExpressionSize]; m_exactSolutionEquality[solutionIndex] = exactSolutions[i].isEqualToItsApproximationLayout(exactSolutionsApproximations[i], buffer, ::Constant::MaxSerializedExpressionSize, preferences->complexFormat(), preferences->angleUnit(), preferences->displayMode(), preferences->numberOfSignificantDigits(), context); From 49d2a248da530e6824fab50ddf5e72244002e7c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 13 Dec 2019 11:05:05 +0100 Subject: [PATCH 12/44] [settings] Fix messages for Dutch exam mode --- apps/settings/base.de.i18n | 1 - apps/settings/base.en.i18n | 3 +-- apps/settings/base.es.i18n | 1 - apps/settings/base.fr.i18n | 1 - apps/settings/base.pt.i18n | 1 - 5 files changed, 1 insertion(+), 6 deletions(-) diff --git a/apps/settings/base.de.i18n b/apps/settings/base.de.i18n index 0f3e127e1..263451755 100644 --- a/apps/settings/base.de.i18n +++ b/apps/settings/base.de.i18n @@ -10,7 +10,6 @@ ExamMode = "Testmodus" ActivateExamMode = "Starten Testmodus" ExamModeActive = "Wieder starten Testmodus" ActivateDutchExamMode = "" -DutchExamModeActive = "" About = "Über" Degrees = "Grad " Gradians = "Gone " diff --git a/apps/settings/base.en.i18n b/apps/settings/base.en.i18n index 7f7309985..26bb775c4 100644 --- a/apps/settings/base.en.i18n +++ b/apps/settings/base.en.i18n @@ -7,10 +7,9 @@ EditionLinear = "Linear " Edition2D = "Natural " ComplexFormat = "Complex format" ExamMode = "Exam mode" -ActivateExamMode = "Activate exam mode" +ActivateExamMode = "Activate standard exam mode" ExamModeActive = "Reactivate exam mode" ActivateDutchExamMode = "Activate Dutch exam mode" -DutchExamModeActive = "Reactivate Dutch exam mode" About = "About" Degrees = "Degrees " Gradians = "Gradians " diff --git a/apps/settings/base.es.i18n b/apps/settings/base.es.i18n index aaf71e055..698f978ba 100644 --- a/apps/settings/base.es.i18n +++ b/apps/settings/base.es.i18n @@ -10,7 +10,6 @@ ExamMode = "Modo examen" ActivateExamMode = "Activar el modo examen" ExamModeActive = "Reactivar el modo examen" ActivateDutchExamMode = "" -DutchExamModeActive = "" About = "Acerca" Degrees = "Grados " Gradians = "Gradianes " diff --git a/apps/settings/base.fr.i18n b/apps/settings/base.fr.i18n index e8782094c..f625ffc86 100644 --- a/apps/settings/base.fr.i18n +++ b/apps/settings/base.fr.i18n @@ -10,7 +10,6 @@ ExamMode = "Mode examen" ActivateExamMode = "Activer le mode examen" ExamModeActive = "Réactiver le mode examen" ActivateDutchExamMode = "" -DutchExamModeActive = "" About = "À propos" Degrees = "Degrés " Gradians = "Grades " diff --git a/apps/settings/base.pt.i18n b/apps/settings/base.pt.i18n index 18d8b0ca4..f872bcf5c 100644 --- a/apps/settings/base.pt.i18n +++ b/apps/settings/base.pt.i18n @@ -10,7 +10,6 @@ ExamMode = "Modo de exame" ActivateExamMode = "Ativar o modo de exame" ExamModeActive = "Reativar o modo de exame" ActivateDutchExamMode = "" -DutchExamModeActive = "" About = "Acerca" Degrees = "Graus " Gradians = "Grados " From 6cd98a3a484b5cb415383d34fea42141e0217749 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 13 Dec 2019 11:31:40 +0100 Subject: [PATCH 13/44] [apps] AppsContainer::activateExamMode can make the LED blink in orange or red according to the chosen exam mode --- apps/apps_container.cpp | 8 ++++---- apps/apps_container.h | 3 ++- apps/exam_pop_up_controller.cpp | 5 +++-- apps/on_boarding/logo_controller.cpp | 4 ++-- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/apps/apps_container.cpp b/apps/apps_container.cpp index bee6ddd4e..bd60f10fd 100644 --- a/apps/apps_container.cpp +++ b/apps/apps_container.cpp @@ -214,9 +214,8 @@ void AppsContainer::run() { * and it is visible when reflashing a N0100 (there is some noise on the * screen before the logo appears). */ Ion::Display::pushRectUniform(screenRect, KDColorWhite); - // TODO if (GlobalPreferences::sharedGlobalPreferences()->isInExamMode()) { - activateExamMode(); + activateExamMode(GlobalPreferences::sharedGlobalPreferences()->examMode()); } refreshPreferences(); @@ -326,9 +325,10 @@ void AppsContainer::redrawWindow() { m_window.redraw(); } -void AppsContainer::activateExamMode() { +void AppsContainer::activateExamMode(GlobalPreferences::ExamMode examMode) { + assert(examMode == GlobalPreferences::ExamMode::Standard || examMode == GlobalPreferences::ExamMode::Dutch); reset(); - Ion::LED::setColor(KDColorRed); + Ion::LED::setColor(examMode == GlobalPreferences::ExamMode::Dutch ? KDColorOrange : KDColorRed); Ion::LED::setBlinking(1000, 0.1f); } diff --git a/apps/apps_container.h b/apps/apps_container.h index 834d7e336..4cd05c7f8 100644 --- a/apps/apps_container.h +++ b/apps/apps_container.h @@ -13,6 +13,7 @@ #include "exam_pop_up_controller_delegate.h" #include "battery_timer.h" #include "suspend_timer.h" +#include "global_preferences.h" #include "backlight_dimming_timer.h" #include "shared/global_context.h" #include "on_boarding/pop_up_controller.h" @@ -46,7 +47,7 @@ public: void setShiftAlphaStatus(Ion::Events::ShiftAlphaStatus newStatus); OnBoarding::PopUpController * promptController(); void redrawWindow(); - void activateExamMode(); + void activateExamMode(GlobalPreferences::ExamMode examMode); // Exam pop-up controller delegate void examDeactivatingPopUpIsDismissed() override; // Ion::StorageDelegate diff --git a/apps/exam_pop_up_controller.cpp b/apps/exam_pop_up_controller.cpp index a51286e81..6ed85321c 100644 --- a/apps/exam_pop_up_controller.cpp +++ b/apps/exam_pop_up_controller.cpp @@ -51,10 +51,11 @@ ExamPopUpController::ContentView::ContentView(Responder * parentResponder) : m_okButton(parentResponder, I18n::Message::Ok, Invocation([](void * context, void * sender) { ExamPopUpController * controller = (ExamPopUpController *)context; // TODO - GlobalPreferences::sharedGlobalPreferences()->setExamMode(controller->isActivatingExamMode() ? GlobalPreferences::ExamMode::Dutch : GlobalPreferences::ExamMode::Off); + GlobalPreferences::ExamMode mode = controller->isActivatingExamMode() ? GlobalPreferences::ExamMode::Dutch : GlobalPreferences::ExamMode::Off; + GlobalPreferences::sharedGlobalPreferences()->setExamMode(mode); AppsContainer * container = AppsContainer::sharedAppsContainer(); if (controller->isActivatingExamMode()) { - container->activateExamMode(); + container->activateExamMode(mode); } else { Ion::LED::setColor(KDColorBlack); Ion::LED::updateColorWithPlugAndCharge(); diff --git a/apps/on_boarding/logo_controller.cpp b/apps/on_boarding/logo_controller.cpp index 56aabfb2d..13df87e4d 100644 --- a/apps/on_boarding/logo_controller.cpp +++ b/apps/on_boarding/logo_controller.cpp @@ -49,8 +49,8 @@ void LogoController::viewDidDisappear() { Ion::LED::setColor(m_previousLEDColor); /* TODO: instead of setting again the exam mode, put the previous led color * AND BLINKING.*/ - if (GlobalPreferences::sharedGlobalPreferences()->isInExamMode()) { // TODO - AppsContainer::sharedAppsContainer()->activateExamMode(); + if (GlobalPreferences::sharedGlobalPreferences()->isInExamMode()) { + AppsContainer::sharedAppsContainer()->activateExamMode(GlobalPreferences::sharedGlobalPreferences()->examMode()); } } ViewController::viewDidDisappear(); From 6ecfe9c5dbd68a3052c775ebaa860589e6ab81d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 17 Dec 2019 11:51:24 +0100 Subject: [PATCH 14/44] [apps] Two exam modes in settings: Standard & Dutch --- apps/apps_container.cpp | 7 ++-- apps/apps_container.h | 2 +- apps/exam_pop_up_controller.cpp | 33 ++++++++++--------- apps/exam_pop_up_controller.h | 9 ++--- apps/settings/main_controller_prompt_beta.cpp | 4 +-- apps/settings/main_controller_prompt_none.cpp | 4 +-- .../main_controller_prompt_update.cpp | 4 +-- .../sub_menu/exam_mode_controller.cpp | 21 ++++++++---- apps/settings/sub_menu/exam_mode_controller.h | 4 ++- 9 files changed, 50 insertions(+), 38 deletions(-) diff --git a/apps/apps_container.cpp b/apps/apps_container.cpp index bd60f10fd..952f83db3 100644 --- a/apps/apps_container.cpp +++ b/apps/apps_container.cpp @@ -168,9 +168,8 @@ 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()) { - // TODO if (GlobalPreferences::sharedGlobalPreferences()->isInExamMode()) { - displayExamModePopUp(false); + displayExamModePopUp(GlobalPreferences::ExamMode::Off); window()->redraw(); } else { Ion::USB::enable(); @@ -276,8 +275,8 @@ void AppsContainer::reloadTitleBarView() { m_window.reloadTitleBarView(); } -void AppsContainer::displayExamModePopUp(bool activate) { - m_examPopUpController.setActivatingExamMode(activate); +void AppsContainer::displayExamModePopUp(GlobalPreferences::ExamMode mode) { + m_examPopUpController.setTargetExamMode(mode); s_activeApp->displayModalViewController(&m_examPopUpController, 0.f, 0.f, Metric::ExamPopUpTopMargin, Metric::PopUpRightMargin, Metric::ExamPopUpBottomMargin, Metric::PopUpLeftMargin); } diff --git a/apps/apps_container.h b/apps/apps_container.h index 4cd05c7f8..f4c683d5a 100644 --- a/apps/apps_container.h +++ b/apps/apps_container.h @@ -42,7 +42,7 @@ public: bool updateBatteryState(); void refreshPreferences(); void reloadTitleBarView(); - void displayExamModePopUp(bool activate); + void displayExamModePopUp(GlobalPreferences::ExamMode mode); void shutdownDueToLowBattery(); void setShiftAlphaStatus(Ion::Events::ShiftAlphaStatus newStatus); OnBoarding::PopUpController * promptController(); diff --git a/apps/exam_pop_up_controller.cpp b/apps/exam_pop_up_controller.cpp index 6ed85321c..651171bd2 100644 --- a/apps/exam_pop_up_controller.cpp +++ b/apps/exam_pop_up_controller.cpp @@ -7,14 +7,14 @@ ExamPopUpController::ExamPopUpController(ExamPopUpControllerDelegate * delegate) : ViewController(nullptr), m_contentView(this), - m_isActivatingExamMode(false), + m_targetExamMode(GlobalPreferences::ExamMode::Unknown), m_delegate(delegate) { } -void ExamPopUpController::setActivatingExamMode(bool activatingExamMode) { - m_isActivatingExamMode = activatingExamMode; - m_contentView.setMessages(activatingExamMode); +void ExamPopUpController::setTargetExamMode(GlobalPreferences::ExamMode mode) { + m_targetExamMode = mode; + m_contentView.setMessagesForExamMode(mode); } View * ExamPopUpController::view() { @@ -22,7 +22,7 @@ View * ExamPopUpController::view() { } void ExamPopUpController::viewDidDisappear() { - if (m_isActivatingExamMode == false) { + if (m_targetExamMode == GlobalPreferences::ExamMode::Off) { m_delegate->examDeactivatingPopUpIsDismissed(); } } @@ -50,15 +50,15 @@ ExamPopUpController::ContentView::ContentView(Responder * parentResponder) : }, parentResponder), KDFont::SmallFont), m_okButton(parentResponder, I18n::Message::Ok, Invocation([](void * context, void * sender) { ExamPopUpController * controller = (ExamPopUpController *)context; - // TODO - GlobalPreferences::ExamMode mode = controller->isActivatingExamMode() ? GlobalPreferences::ExamMode::Dutch : GlobalPreferences::ExamMode::Off; + GlobalPreferences::ExamMode mode = controller->targetExamMode(); + assert(mode != GlobalPreferences::ExamMode::Unknown); GlobalPreferences::sharedGlobalPreferences()->setExamMode(mode); AppsContainer * container = AppsContainer::sharedAppsContainer(); - if (controller->isActivatingExamMode()) { - container->activateExamMode(mode); - } else { + if (mode == GlobalPreferences::ExamMode::Off) { Ion::LED::setColor(KDColorBlack); Ion::LED::updateColorWithPlugAndCharge(); + } else { + container->activateExamMode(mode); } container->refreshPreferences(); Container::activeApp()->dismissModalViewController(); @@ -88,15 +88,16 @@ int ExamPopUpController::ContentView::selectedButton() { return 1; } -void ExamPopUpController::ContentView::setMessages(bool activingExamMode) { - if (activingExamMode) { - m_messageTextView1.setMessage(I18n::Message::ActiveExamModeMessage1); - m_messageTextView2.setMessage(I18n::Message::ActiveExamModeMessage2); - m_messageTextView3.setMessage(I18n::Message::ActiveExamModeMessage3); - } else { +void ExamPopUpController::ContentView::setMessagesForExamMode(GlobalPreferences::ExamMode mode) { + if (mode == GlobalPreferences::ExamMode::Off) { m_messageTextView1.setMessage(I18n::Message::ExitExamMode1); m_messageTextView2.setMessage(I18n::Message::ExitExamMode2); m_messageTextView3.setMessage(I18n::Message::Default); + } else { + // TODO different messages for Dutch + m_messageTextView1.setMessage(I18n::Message::ActiveExamModeMessage1); + m_messageTextView2.setMessage(I18n::Message::ActiveExamModeMessage2); + m_messageTextView3.setMessage(I18n::Message::ActiveExamModeMessage3); } } diff --git a/apps/exam_pop_up_controller.h b/apps/exam_pop_up_controller.h index ad888cff9..0249e9d3f 100644 --- a/apps/exam_pop_up_controller.h +++ b/apps/exam_pop_up_controller.h @@ -3,6 +3,7 @@ #include #include "exam_pop_up_controller_delegate.h" +#include "global_preferences.h" class HighContrastButton : public Button { public: @@ -13,8 +14,8 @@ public: class ExamPopUpController : public ViewController { public: ExamPopUpController(ExamPopUpControllerDelegate * delegate); - void setActivatingExamMode(bool activingExamMode); - bool isActivatingExamMode() const { return m_isActivatingExamMode; } + void setTargetExamMode(GlobalPreferences::ExamMode mode); + GlobalPreferences::ExamMode targetExamMode() const { return m_targetExamMode; } // View Controller View * view() override; void viewDidDisappear() override; @@ -28,7 +29,7 @@ private: void drawRect(KDContext * ctx, KDRect rect) const override; void setSelectedButton(int selectedButton); int selectedButton(); - void setMessages(bool activingExamMode); + void setMessagesForExamMode(GlobalPreferences::ExamMode mode); private: constexpr static KDCoordinate k_buttonMargin = 10; constexpr static KDCoordinate k_buttonHeight = 20; @@ -45,7 +46,7 @@ private: MessageTextView m_messageTextView3; }; ContentView m_contentView; - bool m_isActivatingExamMode; + GlobalPreferences::ExamMode m_targetExamMode; ExamPopUpControllerDelegate * m_delegate; }; diff --git a/apps/settings/main_controller_prompt_beta.cpp b/apps/settings/main_controller_prompt_beta.cpp index ac36893e2..0ba86a359 100644 --- a/apps/settings/main_controller_prompt_beta.cpp +++ b/apps/settings/main_controller_prompt_beta.cpp @@ -7,7 +7,7 @@ constexpr SettingsMessageTree s_modelAngleChildren[3] = {SettingsMessageTree(I18 constexpr SettingsMessageTree s_modelEditionModeChildren[2] = {SettingsMessageTree(I18n::Message::Edition2D), SettingsMessageTree(I18n::Message::EditionLinear)}; constexpr SettingsMessageTree s_modelFloatDisplayModeChildren[4] = {SettingsMessageTree(I18n::Message::Decimal), SettingsMessageTree(I18n::Message::Scientific), SettingsMessageTree(I18n::Message::Engineering), SettingsMessageTree(I18n::Message::SignificantFigures)}; constexpr SettingsMessageTree s_modelComplexFormatChildren[3] = {SettingsMessageTree(I18n::Message::Real), SettingsMessageTree(I18n::Message::Cartesian), SettingsMessageTree(I18n::Message::Polar)}; -constexpr SettingsMessageTree s_modelExamChildren[1] = {SettingsMessageTree(I18n::Message::ActivateExamMode)}; +constexpr SettingsMessageTree s_modelExamChildren[2] = {SettingsMessageTree(I18n::Message::ActivateExamMode), SettingsMessageTree(I18n::Message::ActivateDutchExamMode)}; constexpr SettingsMessageTree s_modelAboutChildren[3] = {SettingsMessageTree(I18n::Message::SoftwareVersion), SettingsMessageTree(I18n::Message::SerialNumber), SettingsMessageTree(I18n::Message::FccId)}; constexpr SettingsMessageTree s_modelMenu[] = @@ -17,7 +17,7 @@ constexpr SettingsMessageTree s_modelMenu[] = SettingsMessageTree(I18n::Message::ComplexFormat, s_modelComplexFormatChildren, 3), SettingsMessageTree(I18n::Message::Brightness), SettingsMessageTree(I18n::Message::Language), - SettingsMessageTree(I18n::Message::ExamMode, s_modelExamChildren, 1), + SettingsMessageTree(I18n::Message::ExamMode, s_modelExamChildren, 2), SettingsMessageTree(I18n::Message::BetaPopUp), SettingsMessageTree(I18n::Message::About, s_modelAboutChildren, 3)}; diff --git a/apps/settings/main_controller_prompt_none.cpp b/apps/settings/main_controller_prompt_none.cpp index a159b6e96..9595b235c 100644 --- a/apps/settings/main_controller_prompt_none.cpp +++ b/apps/settings/main_controller_prompt_none.cpp @@ -8,7 +8,7 @@ constexpr SettingsMessageTree s_modelAngleChildren[3] = {SettingsMessageTree(I18 constexpr SettingsMessageTree s_modelEditionModeChildren[2] = {SettingsMessageTree(I18n::Message::Edition2D), SettingsMessageTree(I18n::Message::EditionLinear)}; constexpr SettingsMessageTree s_modelFloatDisplayModeChildren[4] = {SettingsMessageTree(I18n::Message::Decimal), SettingsMessageTree(I18n::Message::Scientific), SettingsMessageTree(I18n::Message::Engineering), SettingsMessageTree(I18n::Message::SignificantFigures)}; constexpr SettingsMessageTree s_modelComplexFormatChildren[3] = {SettingsMessageTree(I18n::Message::Real), SettingsMessageTree(I18n::Message::Cartesian), SettingsMessageTree(I18n::Message::Polar)}; -constexpr SettingsMessageTree s_modelExamChildren[1] = {SettingsMessageTree(I18n::Message::ActivateExamMode)}; +constexpr SettingsMessageTree s_modelExamChildren[2] = {SettingsMessageTree(I18n::Message::ActivateExamMode), SettingsMessageTree(I18n::Message::ActivateDutchExamMode)}; constexpr SettingsMessageTree s_modelAboutChildren[3] = {SettingsMessageTree(I18n::Message::SoftwareVersion), SettingsMessageTree(I18n::Message::SerialNumber), SettingsMessageTree(I18n::Message::FccId)}; constexpr SettingsMessageTree s_modelMenu[] = @@ -18,7 +18,7 @@ constexpr SettingsMessageTree s_modelMenu[] = SettingsMessageTree(I18n::Message::ComplexFormat, s_modelComplexFormatChildren, 3), SettingsMessageTree(I18n::Message::Brightness), SettingsMessageTree(I18n::Message::Language), - SettingsMessageTree(I18n::Message::ExamMode, s_modelExamChildren, 1), + SettingsMessageTree(I18n::Message::ExamMode, s_modelExamChildren, 2), SettingsMessageTree(I18n::Message::About, s_modelAboutChildren, 3)}; constexpr SettingsMessageTree s_model = SettingsMessageTree(I18n::Message::SettingsApp, s_modelMenu, 8); diff --git a/apps/settings/main_controller_prompt_update.cpp b/apps/settings/main_controller_prompt_update.cpp index 5e45f8821..1bd728f3e 100644 --- a/apps/settings/main_controller_prompt_update.cpp +++ b/apps/settings/main_controller_prompt_update.cpp @@ -7,7 +7,7 @@ constexpr SettingsMessageTree s_modelAngleChildren[3] = {SettingsMessageTree(I18 constexpr SettingsMessageTree s_modelEditionModeChildren[2] = {SettingsMessageTree(I18n::Message::Edition2D), SettingsMessageTree(I18n::Message::EditionLinear)}; constexpr SettingsMessageTree s_modelFloatDisplayModeChildren[4] = {SettingsMessageTree(I18n::Message::Decimal), SettingsMessageTree(I18n::Message::Scientific), SettingsMessageTree(I18n::Message::Engineering), SettingsMessageTree(I18n::Message::SignificantFigures)}; constexpr SettingsMessageTree s_modelComplexFormatChildren[3] = {SettingsMessageTree(I18n::Message::Real), SettingsMessageTree(I18n::Message::Cartesian), SettingsMessageTree(I18n::Message::Polar)}; -constexpr SettingsMessageTree s_modelExamChildren[1] = {SettingsMessageTree(I18n::Message::ActivateExamMode)}; +constexpr SettingsMessageTree s_modelExamChildren[2] = {SettingsMessageTree(I18n::Message::ActivateExamMode), SettingsMessageTree(I18n::Message::ActivateDutchExamMode)}; constexpr SettingsMessageTree s_modelAboutChildren[3] = {SettingsMessageTree(I18n::Message::SoftwareVersion), SettingsMessageTree(I18n::Message::SerialNumber), SettingsMessageTree(I18n::Message::FccId)}; constexpr SettingsMessageTree s_modelMenu[] = @@ -17,7 +17,7 @@ constexpr SettingsMessageTree s_modelMenu[] = SettingsMessageTree(I18n::Message::ComplexFormat, s_modelComplexFormatChildren, 3), SettingsMessageTree(I18n::Message::Brightness), SettingsMessageTree(I18n::Message::Language), - SettingsMessageTree(I18n::Message::ExamMode, s_modelExamChildren, 1), + SettingsMessageTree(I18n::Message::ExamMode, s_modelExamChildren, 2), SettingsMessageTree(I18n::Message::UpdatePopUp), SettingsMessageTree(I18n::Message::About, s_modelAboutChildren, 3)}; diff --git a/apps/settings/sub_menu/exam_mode_controller.cpp b/apps/settings/sub_menu/exam_mode_controller.cpp index 83709a5b4..025464e9a 100644 --- a/apps/settings/sub_menu/exam_mode_controller.cpp +++ b/apps/settings/sub_menu/exam_mode_controller.cpp @@ -1,6 +1,7 @@ #include "exam_mode_controller.h" #include "../../global_preferences.h" #include "../../apps_container.h" +#include #include #include @@ -11,35 +12,43 @@ namespace Settings { ExamModeController::ExamModeController(Responder * parentResponder) : GenericSubController(parentResponder), - m_cell(I18n::Message::ExamModeActive, KDFont::LargeFont) + m_cell{MessageTableCell(I18n::Message::ExamModeActive, KDFont::LargeFont), MessageTableCell(I18n::Message::ActivateDutchExamMode, KDFont::LargeFont)} { } void ExamModeController::didEnterResponderChain(Responder * previousFirstResponder) { + selectCellAtLocation(0, 0); m_selectableTableView.reloadData(); } bool ExamModeController::handleEvent(Ion::Events::Event event) { if (event == Ion::Events::OK || event == Ion::Events::EXE) { - AppsContainer::sharedAppsContainer()->displayExamModePopUp(true); + GlobalPreferences::ExamMode mode = m_messageTreeModel->children(selectedRow())->label() == I18n::Message::ActivateExamMode ? GlobalPreferences::ExamMode::Standard : GlobalPreferences::ExamMode::Dutch; + AppsContainer::sharedAppsContainer()->displayExamModePopUp(mode); return true; } return GenericSubController::handleEvent(event); } +int ExamModeController::numberOfRows() const { + if (GlobalPreferences::sharedGlobalPreferences()->language() != I18n::Language::EN || GlobalPreferences::sharedGlobalPreferences()->isInExamMode()) { + return 1; + } + return GenericSubController::numberOfRows(); +} + HighlightCell * ExamModeController::reusableCell(int index, int type) { assert(type == 0); - assert(index == 0); - return &m_cell; + assert(index >= 0 && index < k_maxNumberOfCells); + return &m_cell[index]; } int ExamModeController::reusableCellCount(int type) { - return 1; + return k_maxNumberOfCells; } void ExamModeController::willDisplayCellForIndex(HighlightCell * cell, int index) { GenericSubController::willDisplayCellForIndex(cell, index); - // TODO if (GlobalPreferences::sharedGlobalPreferences()->isInExamMode()) { MessageTableCell * myCell = (MessageTableCell *)cell; myCell->setMessage(I18n::Message::ExamModeActive); diff --git a/apps/settings/sub_menu/exam_mode_controller.h b/apps/settings/sub_menu/exam_mode_controller.h index 22a0da0c7..5b0164c0c 100644 --- a/apps/settings/sub_menu/exam_mode_controller.h +++ b/apps/settings/sub_menu/exam_mode_controller.h @@ -10,11 +10,13 @@ public: ExamModeController(Responder * parentResponder); void didEnterResponderChain(Responder * previousFirstResponder) override; bool handleEvent(Ion::Events::Event event) override; + int numberOfRows() const override; HighlightCell * reusableCell(int index, int type) override; int reusableCellCount(int type) override; void willDisplayCellForIndex(HighlightCell * cell, int index) override; private: - MessageTableCell m_cell; + static constexpr int k_maxNumberOfCells = 2; + MessageTableCell m_cell[k_maxNumberOfCells]; }; } From de34c0b8db9f70f16219af53b622390881d752c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 17 Dec 2019 14:23:24 +0100 Subject: [PATCH 15/44] [apps] Change pop-up message for Dutch exam mode --- apps/exam_pop_up_controller.cpp | 8 ++++++-- apps/shared.de.i18n | 3 +++ apps/shared.en.i18n | 3 +++ apps/shared.es.i18n | 3 +++ apps/shared.fr.i18n | 3 +++ apps/shared.pt.i18n | 3 +++ 6 files changed, 21 insertions(+), 2 deletions(-) diff --git a/apps/exam_pop_up_controller.cpp b/apps/exam_pop_up_controller.cpp index 651171bd2..dfe068ef2 100644 --- a/apps/exam_pop_up_controller.cpp +++ b/apps/exam_pop_up_controller.cpp @@ -93,11 +93,15 @@ void ExamPopUpController::ContentView::setMessagesForExamMode(GlobalPreferences: m_messageTextView1.setMessage(I18n::Message::ExitExamMode1); m_messageTextView2.setMessage(I18n::Message::ExitExamMode2); m_messageTextView3.setMessage(I18n::Message::Default); - } else { - // TODO different messages for Dutch + } else if (mode == GlobalPreferences::ExamMode::Standard) { m_messageTextView1.setMessage(I18n::Message::ActiveExamModeMessage1); m_messageTextView2.setMessage(I18n::Message::ActiveExamModeMessage2); m_messageTextView3.setMessage(I18n::Message::ActiveExamModeMessage3); + } else { + assert(mode == GlobalPreferences::ExamMode::Dutch); + m_messageTextView1.setMessage(I18n::Message::ActiveDutchExamModeMessage1); + m_messageTextView2.setMessage(I18n::Message::ActiveDutchExamModeMessage2); + m_messageTextView3.setMessage(I18n::Message::ActiveDutchExamModeMessage3); } } diff --git a/apps/shared.de.i18n b/apps/shared.de.i18n index 6309dac2a..ff08c00ff 100644 --- a/apps/shared.de.i18n +++ b/apps/shared.de.i18n @@ -2,6 +2,9 @@ ActivateDeactivate = "Aktivieren/Deaktivieren" ActiveExamModeMessage1 = "Alle Ihre Daten werden " ActiveExamModeMessage2 = "gelöscht, wenn Sie den " ActiveExamModeMessage3 = "Testmodus einschalten." +ActiveDutchExamModeMessage1 = "" +ActiveDutchExamModeMessage2 = "" +ActiveDutchExamModeMessage3 = "" Axis = "Achsen" Cancel = "Abbrechen" ClearColumn = "Spalte löschen" diff --git a/apps/shared.en.i18n b/apps/shared.en.i18n index 952b615b8..d5a6d108a 100644 --- a/apps/shared.en.i18n +++ b/apps/shared.en.i18n @@ -2,6 +2,9 @@ ActivateDeactivate = "Turn on/off" ActiveExamModeMessage1 = "All your data will be " ActiveExamModeMessage2 = "deleted when you activate " ActiveExamModeMessage3 = "the exam mode." +ActiveDutchExamModeMessage1 = "All your data will be deleted when" +ActiveDutchExamModeMessage2 = "you activate the exam mode. Python" +ActiveDutchExamModeMessage3 = "application will be unaccessible." Axis = "Axes" Cancel = "Cancel" ClearColumn = "Clear column" diff --git a/apps/shared.es.i18n b/apps/shared.es.i18n index 53570691e..18ac4dc39 100644 --- a/apps/shared.es.i18n +++ b/apps/shared.es.i18n @@ -2,6 +2,9 @@ ActivateDeactivate = "Activar/Desactivar" ActiveExamModeMessage1 = "Todos sus datos se " ActiveExamModeMessage2 = "eliminaran al activar " ActiveExamModeMessage3 = "el modo examen." +ActiveDutchExamModeMessage1 = "" +ActiveDutchExamModeMessage2 = "" +ActiveDutchExamModeMessage3 = "" Axis = "Ejes" Cancel = "Cancelar" ClearColumn = "Borrar la columna" diff --git a/apps/shared.fr.i18n b/apps/shared.fr.i18n index 15e2d760c..b3f6fc997 100644 --- a/apps/shared.fr.i18n +++ b/apps/shared.fr.i18n @@ -2,6 +2,9 @@ ActivateDeactivate = "Activer/Désactiver" ActiveExamModeMessage1 = "Toutes vos données seront " ActiveExamModeMessage2 = "supprimées si vous activez " ActiveExamModeMessage3 = "le mode examen." +ActiveDutchExamModeMessage1 = "" +ActiveDutchExamModeMessage2 = "" +ActiveDutchExamModeMessage3 = "" Axis = "Axes" Cancel = "Annuler" ClearColumn = "Effacer la colonne" diff --git a/apps/shared.pt.i18n b/apps/shared.pt.i18n index 9d624d78d..911100216 100644 --- a/apps/shared.pt.i18n +++ b/apps/shared.pt.i18n @@ -2,6 +2,9 @@ ActivateDeactivate = "Activar/Desactivar" ActiveExamModeMessage1 = "Todos os seus dados serão " ActiveExamModeMessage2 = "apagados se você ligar " ActiveExamModeMessage3 = "o modo de exame." +ActiveDutchExamModeMessage1 = "" +ActiveDutchExamModeMessage2 = "" +ActiveDutchExamModeMessage3 = "" Axis = "Eixos" Cancel = "Cancelar" ClearColumn = "Excluir coluna" From a3774fb51036c4c6b9ef28b4dc14562c6711043b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 17 Dec 2019 14:24:02 +0100 Subject: [PATCH 16/44] [settings] Exam mode: reactivate the current exam mode (stick to Dutch exam mode if it is already on) --- apps/settings/sub_menu/exam_mode_controller.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/settings/sub_menu/exam_mode_controller.cpp b/apps/settings/sub_menu/exam_mode_controller.cpp index 025464e9a..f4921ff2f 100644 --- a/apps/settings/sub_menu/exam_mode_controller.cpp +++ b/apps/settings/sub_menu/exam_mode_controller.cpp @@ -23,7 +23,13 @@ void ExamModeController::didEnterResponderChain(Responder * previousFirstRespond bool ExamModeController::handleEvent(Ion::Events::Event event) { if (event == Ion::Events::OK || event == Ion::Events::EXE) { - GlobalPreferences::ExamMode mode = m_messageTreeModel->children(selectedRow())->label() == I18n::Message::ActivateExamMode ? GlobalPreferences::ExamMode::Standard : GlobalPreferences::ExamMode::Dutch; + GlobalPreferences::ExamMode mode = GlobalPreferences::ExamMode::Standard; + if (GlobalPreferences::sharedGlobalPreferences()->isInExamMode()) { + // If the exam mode is already on, this re-activate the same exam mode + mode = GlobalPreferences::sharedGlobalPreferences()->examMode(); + } else if (m_messageTreeModel->children(selectedRow())->label() == I18n::Message::ActivateDutchExamMode) { + mode = GlobalPreferences::ExamMode::Dutch; + } AppsContainer::sharedAppsContainer()->displayExamModePopUp(mode); return true; } From 8c6a2836de11958b4b9fa01935a21172ece1f73f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 17 Dec 2019 14:32:44 +0100 Subject: [PATCH 17/44] [settings] Fix row initialization in sub menus --- apps/settings/sub_menu/exam_mode_controller.cpp | 11 ++++++++--- apps/settings/sub_menu/exam_mode_controller.h | 2 +- apps/settings/sub_menu/generic_sub_controller.cpp | 10 +++++----- apps/settings/sub_menu/generic_sub_controller.h | 3 ++- apps/settings/sub_menu/preferences_controller.cpp | 3 +-- apps/settings/sub_menu/preferences_controller.h | 3 ++- 6 files changed, 19 insertions(+), 13 deletions(-) diff --git a/apps/settings/sub_menu/exam_mode_controller.cpp b/apps/settings/sub_menu/exam_mode_controller.cpp index f4921ff2f..03a30422e 100644 --- a/apps/settings/sub_menu/exam_mode_controller.cpp +++ b/apps/settings/sub_menu/exam_mode_controller.cpp @@ -16,9 +16,14 @@ ExamModeController::ExamModeController(Responder * parentResponder) : { } -void ExamModeController::didEnterResponderChain(Responder * previousFirstResponder) { - selectCellAtLocation(0, 0); - m_selectableTableView.reloadData(); +int ExamModeController::initialSelectedRow() const { + int row = selectedRow(); + if (row >= numberOfRows()) { + return numberOfRows()-1; + } else if (row < 0) { + return 0; + } + return row; } bool ExamModeController::handleEvent(Ion::Events::Event event) { diff --git a/apps/settings/sub_menu/exam_mode_controller.h b/apps/settings/sub_menu/exam_mode_controller.h index 5b0164c0c..2627c7f29 100644 --- a/apps/settings/sub_menu/exam_mode_controller.h +++ b/apps/settings/sub_menu/exam_mode_controller.h @@ -8,13 +8,13 @@ namespace Settings { class ExamModeController : public GenericSubController { public: ExamModeController(Responder * parentResponder); - void didEnterResponderChain(Responder * previousFirstResponder) override; bool handleEvent(Ion::Events::Event event) override; int numberOfRows() const override; HighlightCell * reusableCell(int index, int type) override; int reusableCellCount(int type) override; void willDisplayCellForIndex(HighlightCell * cell, int index) override; private: + int initialSelectedRow() const override; static constexpr int k_maxNumberOfCells = 2; MessageTableCell m_cell[k_maxNumberOfCells]; }; diff --git a/apps/settings/sub_menu/generic_sub_controller.cpp b/apps/settings/sub_menu/generic_sub_controller.cpp index 96c0a39a4..67af6c918 100644 --- a/apps/settings/sub_menu/generic_sub_controller.cpp +++ b/apps/settings/sub_menu/generic_sub_controller.cpp @@ -26,8 +26,12 @@ View * GenericSubController::view() { return &m_selectableTableView; } +void GenericSubController::didEnterResponderChain(Responder * previousFirstResponder) { + selectCellAtLocation(0, initialSelectedRow()); + m_selectableTableView.reloadData(); +} + void GenericSubController::didBecomeFirstResponder() { - selectCellAtLocation(0, 0); Container::activeApp()->setFirstResponder(&m_selectableTableView); } @@ -75,10 +79,6 @@ void GenericSubController::setMessageTreeModel(const MessageTree * messageTreeMo m_messageTreeModel = (MessageTree *)messageTreeModel; } -void GenericSubController::viewWillAppear() { - m_selectableTableView.reloadData(); -} - void GenericSubController::viewDidDisappear() { m_selectableTableView.deselectTable(); } diff --git a/apps/settings/sub_menu/generic_sub_controller.h b/apps/settings/sub_menu/generic_sub_controller.h index 132cc1773..445857c41 100644 --- a/apps/settings/sub_menu/generic_sub_controller.h +++ b/apps/settings/sub_menu/generic_sub_controller.h @@ -11,6 +11,7 @@ public: GenericSubController(Responder * parentResponder); const char * title() override; View * view() override; + void didEnterResponderChain(Responder * previousFirstResponder) override; void didBecomeFirstResponder() override; bool handleEvent(Ion::Events::Event event) override; int numberOfRows() const override; @@ -20,10 +21,10 @@ public: int typeAtLocation(int i, int j) override; void willDisplayCellForIndex(HighlightCell * cell, int index) override; void setMessageTreeModel(const MessageTree * messageTreeModel); - void viewWillAppear() override; void viewDidDisappear() override; protected: StackViewController * stackController() const; + virtual int initialSelectedRow() const { return 0; } constexpr static KDCoordinate k_topBottomMargin = 13; SelectableTableView m_selectableTableView; MessageTree * m_messageTreeModel; diff --git a/apps/settings/sub_menu/preferences_controller.cpp b/apps/settings/sub_menu/preferences_controller.cpp index 6d964fd7a..609b190a2 100644 --- a/apps/settings/sub_menu/preferences_controller.cpp +++ b/apps/settings/sub_menu/preferences_controller.cpp @@ -23,7 +23,6 @@ PreferencesController::PreferencesController(Responder * parentResponder) : } void PreferencesController::didBecomeFirstResponder() { - selectCellAtLocation(0, valueIndexForPreference(m_messageTreeModel->label())); Container::activeApp()->setFirstResponder(&m_selectableTableView); } @@ -145,7 +144,7 @@ void PreferencesController::setPreferenceWithValueIndex(I18n::Message message, i } } -int PreferencesController::valueIndexForPreference(I18n::Message message) { +int PreferencesController::valueIndexForPreference(I18n::Message message) const { Preferences * preferences = Preferences::sharedPreferences(); if (message == I18n::Message::AngleUnit) { return (int)preferences->angleUnit(); diff --git a/apps/settings/sub_menu/preferences_controller.h b/apps/settings/sub_menu/preferences_controller.h index c2a860cf7..ba21cfc5c 100644 --- a/apps/settings/sub_menu/preferences_controller.h +++ b/apps/settings/sub_menu/preferences_controller.h @@ -18,9 +18,10 @@ protected: constexpr static int k_totalNumberOfCell = 3; private: constexpr static const KDFont * k_layoutFont = KDFont::SmallFont; + int initialSelectedRow() const override { return valueIndexForPreference(m_messageTreeModel->label()); } Poincare::Layout layoutForPreferences(I18n::Message message); void setPreferenceWithValueIndex(I18n::Message message, int valueIndex); - int valueIndexForPreference(I18n::Message message); + int valueIndexForPreference(I18n::Message message) const; MessageTableCellWithExpression m_cells[k_totalNumberOfCell]; }; From 7fc730597ccaa7615d2d8ace78ffe947e6a3ff4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 17 Dec 2019 14:33:41 +0100 Subject: [PATCH 18/44] [apps] Fix exam mode messages --- apps/settings/base.en.i18n | 2 +- apps/shared.en.i18n | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/settings/base.en.i18n b/apps/settings/base.en.i18n index 26bb775c4..3683e54ce 100644 --- a/apps/settings/base.en.i18n +++ b/apps/settings/base.en.i18n @@ -7,7 +7,7 @@ EditionLinear = "Linear " Edition2D = "Natural " ComplexFormat = "Complex format" ExamMode = "Exam mode" -ActivateExamMode = "Activate standard exam mode" +ActivateExamMode = "Activate exam mode" ExamModeActive = "Reactivate exam mode" ActivateDutchExamMode = "Activate Dutch exam mode" About = "About" diff --git a/apps/shared.en.i18n b/apps/shared.en.i18n index d5a6d108a..49bec75e6 100644 --- a/apps/shared.en.i18n +++ b/apps/shared.en.i18n @@ -4,7 +4,7 @@ ActiveExamModeMessage2 = "deleted when you activate " ActiveExamModeMessage3 = "the exam mode." ActiveDutchExamModeMessage1 = "All your data will be deleted when" ActiveDutchExamModeMessage2 = "you activate the exam mode. Python" -ActiveDutchExamModeMessage3 = "application will be unaccessible." +ActiveDutchExamModeMessage3 = "application will be unavailable." Axis = "Axes" Cancel = "Cancel" ClearColumn = "Clear column" From f5e7c016e8d1342cfe44613ea0d0e2714ced4031 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 17 Dec 2019 16:58:45 +0100 Subject: [PATCH 19/44] [apps] GlobalPreferences: avoid multiple calls to examMode() --- apps/global_preferences.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/global_preferences.cpp b/apps/global_preferences.cpp index 52572a469..7a0763e49 100644 --- a/apps/global_preferences.cpp +++ b/apps/global_preferences.cpp @@ -14,11 +14,12 @@ GlobalPreferences::ExamMode GlobalPreferences::examMode() const { } void GlobalPreferences::setExamMode(ExamMode mode) { - if (examMode() == mode) { + ExamMode currentMode = examMode(); + if (currentMode == mode) { return; } assert(mode != ExamMode::Unknown); - int8_t deltaMode = (int8_t)mode - (int8_t)examMode(); + int8_t deltaMode = (int8_t)mode - (int8_t)currentMode; deltaMode = deltaMode < 0 ? deltaMode + 3 : deltaMode; assert(deltaMode > 0); Ion::ExamMode::IncrementExamMode(deltaMode); From 2fc8799feefbdc3413b2906c58c98be359d6616e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 17 Dec 2019 16:59:07 +0100 Subject: [PATCH 20/44] [ion] Exam mode on device: Fix FetchExamMode and IncrementExamMode --- ion/src/device/shared/drivers/exam_mode.cpp | 91 +++++++++++++-------- 1 file changed, 56 insertions(+), 35 deletions(-) diff --git a/ion/src/device/shared/drivers/exam_mode.cpp b/ion/src/device/shared/drivers/exam_mode.cpp index 806729c01..96e10a2d0 100644 --- a/ion/src/device/shared/drivers/exam_mode.cpp +++ b/ion/src/device/shared/drivers/exam_mode.cpp @@ -3,14 +3,14 @@ #include "flash.h" #include -namespace Ion { -namespace ExamMode { - extern "C" { extern char _exam_mode_buffer_start; extern char _exam_mode_buffer_end; } +namespace Ion { +namespace ExamMode { + char ones[Config::ExamModeBufferSize] __attribute__((section(".exam_mode_buffer"))) __attribute__((used)) @@ -30,26 +30,11 @@ char ones[Config::ExamModeBufferSize] * if it has only one 1, it is erased (to 1) and significantExamModeAddress * returns the start of the sector. */ -uint32_t * SignificantExamModeAddress() { - uint32_t * persitence_start = (uint32_t *)&_exam_mode_buffer_start; - uint32_t * persitence_end = (uint32_t *)&_exam_mode_buffer_end; - while (persitence_start < persitence_end && *persitence_start == 0x0) { - // Skip even number of zero bits - persitence_start++; - } - if (persitence_start == persitence_end - // we can't toggle from 0[3] to 2[3] when there is only one 1 bit in the whole sector - || (persitence_start + 1 == persitence_end && *persitence_start == 1)) { - assert(Ion::Device::Flash::SectorAtAddress((uint32_t)&_exam_mode_buffer_start) >= 0); - Ion::Device::Flash::EraseSector(Ion::Device::Flash::SectorAtAddress((uint32_t)&_exam_mode_buffer_start)); - return (uint32_t *)&_exam_mode_buffer_start; - } - return persitence_start; -} +constexpr static size_t numberOfBitsInByte = 8; -size_t firstOneBit(int i, size_t size) { +size_t firstOneBitInByte(int i) { int minShift = 0; - int maxShift = size; + int maxShift = numberOfBitsInByte; while (maxShift > minShift+1) { int shift = (minShift + maxShift)/2; int shifted = i >> shift; @@ -62,32 +47,68 @@ size_t firstOneBit(int i, size_t size) { return maxShift; } +uint8_t * SignificantExamModeAddress() { + uint32_t * persitence_start_32 = (uint32_t *)&_exam_mode_buffer_start; + uint32_t * persitence_end_32 = (uint32_t *)&_exam_mode_buffer_end; + while (persitence_start_32 < persitence_end_32 && *persitence_start_32 == 0x0) { + // Scan by groups of 32 bits to reach first non-zero bit + persitence_start_32++; + } + uint8_t * persitence_start_8 = (uint8_t *)persitence_start_32; + uint8_t * persitence_end_8 = (uint8_t *)persitence_end_32; + while (persitence_start_8 < persitence_end_8 && *persitence_start_8 == 0x0) { + // Scan by groups of 8 bits to reach first non-zero bit + persitence_start_8++; + } + if (persitence_start_8 == persitence_end_8 + // we can't toggle from 0[3] to 2[3] when there is only one 1 bit in the whole sector + || (persitence_start_8 + 1 == persitence_end_8 && *persitence_start_8 == 1)) { + assert(Ion::Device::Flash::SectorAtAddress((uint32_t)&_exam_mode_buffer_start) >= 0); + Ion::Device::Flash::EraseSector(Ion::Device::Flash::SectorAtAddress((uint32_t)&_exam_mode_buffer_start)); + return (uint8_t *)&_exam_mode_buffer_start; + } + + return persitence_start_8; +} + uint8_t FetchExamMode() { - uint32_t * readingAddress = SignificantExamModeAddress(); + uint8_t * readingAddress = SignificantExamModeAddress(); // Count the number of 0[3] before reading address - uint32_t nbOfZerosBefore = ((readingAddress - (uint32_t *)&_exam_mode_buffer_start)/4 * 2) % 3; + uint32_t nbOfZerosBefore = ((readingAddress - (uint8_t *)&_exam_mode_buffer_start) * 2) % 3; // Count the number of 0[3] at reading address - size_t numberOfLeading0 = (32 - firstOneBit(*readingAddress, 32)) % 3; + size_t numberOfLeading0 = (numberOfBitsInByte - firstOneBitInByte(*readingAddress)) % 3; return (nbOfZerosBefore + numberOfLeading0) % 3; } void IncrementExamMode(uint8_t delta) { assert(delta == 1 || delta == 2); - uint32_t * writingAddress = SignificantExamModeAddress(); + uint8_t * writingAddress = SignificantExamModeAddress(); assert(*writingAddress != 0); - size_t nbOfOnes = firstOneBit(*writingAddress, 32); - // Compute the new value with two bits switched to 0. - /* We write in a uint64_t instead of uint32_t, in case there was only one bit + size_t nbOfTargetedOnes = firstOneBitInByte(*writingAddress); + + // Compute the new value with delta bits switched to 0. + /* We write in 2 bytes instead of 1, in case there was only one bit * left to 1 in writingAddress. */ - /* When writing in flash, we can only switch a 1 to a 0. If we want to switch - * the fifth and sixth bit in a byte, we can thus write "11100111". */ - uint64_t deltaOnes = (1 << delta) - 1; - uint64_t newValue = ~(deltaOnes << (32 + nbOfOnes - delta)); + nbOfTargetedOnes += numberOfBitsInByte; + nbOfTargetedOnes -= delta; + constexpr size_t newValueSize = sizeof(uint16_t)/sizeof(uint8_t); + uint8_t newValue[newValueSize]; + if (nbOfTargetedOnes > numberOfBitsInByte) { + size_t nbOfTargetedOnesInFirstByte = nbOfTargetedOnes - numberOfBitsInByte; + assert(nbOfTargetedOnesInFirstByte <= numberOfBitsInByte); + newValue[0] = ((uint16_t)1 << nbOfTargetedOnesInFirstByte) - 1; + newValue[1] = 0xFF; + } else { + assert(nbOfTargetedOnes <= numberOfBitsInByte); + newValue[0] = 0; + newValue[1] = ((uint16_t)1 << nbOfTargetedOnes) - 1; + } + // Write the value in flash /* Avoid writing out of sector */ - assert(writingAddress < (uint32_t *)&_exam_mode_buffer_end - 1 || *writingAddress > 1); - size_t writtenFlash = *writingAddress == 1 ? sizeof(uint64_t) : sizeof(uint32_t); - Ion::Device::Flash::WriteMemory((uint8_t *)writingAddress, (uint8_t *)&newValue, writtenFlash); + size_t writtenFlash = *writingAddress == 1 ? sizeof(uint16_t) : sizeof(uint8_t); + assert(writingAddress < (uint8_t *)&_exam_mode_buffer_end - 1 || (writingAddress == (uint8_t *)&_exam_mode_buffer_end - 1 && writtenFlash == 1)); + Ion::Device::Flash::WriteMemory(writingAddress, newValue, writtenFlash); } } From 2ccdc2d0dc1032433ebd0aec614bbb4e51560118 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 17 Dec 2019 17:35:00 +0100 Subject: [PATCH 21/44] [apps] Fix messages regarding Dutch exam mode in non-English languages --- apps/home/base.de.i18n | 4 ++-- apps/home/base.es.i18n | 4 ++-- apps/home/base.fr.i18n | 4 ++-- apps/home/base.pt.i18n | 4 ++-- apps/settings/base.de.i18n | 2 +- apps/settings/base.es.i18n | 2 +- apps/settings/base.fr.i18n | 2 +- apps/settings/base.pt.i18n | 2 +- apps/shared.de.i18n | 6 +++--- apps/shared.es.i18n | 6 +++--- apps/shared.fr.i18n | 6 +++--- apps/shared.pt.i18n | 6 +++--- 12 files changed, 24 insertions(+), 24 deletions(-) diff --git a/apps/home/base.de.i18n b/apps/home/base.de.i18n index a8f33d6cb..7cb389438 100644 --- a/apps/home/base.de.i18n +++ b/apps/home/base.de.i18n @@ -1,4 +1,4 @@ Apps = "Anwendungen" AppsCapital = "ANWENDUNGEN" -ForbidenAppInExamMode1 = "" -ForbidenAppInExamMode2 = "" +ForbidenAppInExamMode1 = "This application is" +ForbidenAppInExamMode2 = "forbidden in exam mode" diff --git a/apps/home/base.es.i18n b/apps/home/base.es.i18n index 8f48d86c5..4f04ddc56 100644 --- a/apps/home/base.es.i18n +++ b/apps/home/base.es.i18n @@ -1,4 +1,4 @@ Apps = "Aplicaciones" AppsCapital = "APLICACIONES" -ForbidenAppInExamMode1 = "" -ForbidenAppInExamMode2 = "" +ForbidenAppInExamMode1 = "This application is" +ForbidenAppInExamMode2 = "forbidden in exam mode" diff --git a/apps/home/base.fr.i18n b/apps/home/base.fr.i18n index 200c6f577..158fa3bda 100644 --- a/apps/home/base.fr.i18n +++ b/apps/home/base.fr.i18n @@ -1,4 +1,4 @@ Apps = "Applications" AppsCapital = "APPLICATIONS" -ForbidenAppInExamMode1 = "" -ForbidenAppInExamMode2 = "" +ForbidenAppInExamMode1 = "This application is" +ForbidenAppInExamMode2 = "forbidden in exam mode" diff --git a/apps/home/base.pt.i18n b/apps/home/base.pt.i18n index 2720ea295..e6816935c 100644 --- a/apps/home/base.pt.i18n +++ b/apps/home/base.pt.i18n @@ -1,4 +1,4 @@ Apps = "Aplicações" AppsCapital = "APLICAÇÕES" -ForbidenAppInExamMode1 = "" -ForbidenAppInExamMode2 = "" +ForbidenAppInExamMode1 = "This application is" +ForbidenAppInExamMode2 = "forbidden in exam mode" diff --git a/apps/settings/base.de.i18n b/apps/settings/base.de.i18n index 263451755..248ffa473 100644 --- a/apps/settings/base.de.i18n +++ b/apps/settings/base.de.i18n @@ -9,7 +9,7 @@ ComplexFormat = "Komplex" ExamMode = "Testmodus" ActivateExamMode = "Starten Testmodus" ExamModeActive = "Wieder starten Testmodus" -ActivateDutchExamMode = "" +ActivateDutchExamMode = "Activate Dutch exam mode" About = "Über" Degrees = "Grad " Gradians = "Gone " diff --git a/apps/settings/base.es.i18n b/apps/settings/base.es.i18n index 698f978ba..06240e3f3 100644 --- a/apps/settings/base.es.i18n +++ b/apps/settings/base.es.i18n @@ -9,7 +9,7 @@ ComplexFormat = "Forma compleja" ExamMode = "Modo examen" ActivateExamMode = "Activar el modo examen" ExamModeActive = "Reactivar el modo examen" -ActivateDutchExamMode = "" +ActivateDutchExamMode = "Activate Dutch exam mode" About = "Acerca" Degrees = "Grados " Gradians = "Gradianes " diff --git a/apps/settings/base.fr.i18n b/apps/settings/base.fr.i18n index f625ffc86..c11f9fa9a 100644 --- a/apps/settings/base.fr.i18n +++ b/apps/settings/base.fr.i18n @@ -9,7 +9,7 @@ ComplexFormat = "Forme complexe" ExamMode = "Mode examen" ActivateExamMode = "Activer le mode examen" ExamModeActive = "Réactiver le mode examen" -ActivateDutchExamMode = "" +ActivateDutchExamMode = "Activate Dutch exam mode" About = "À propos" Degrees = "Degrés " Gradians = "Grades " diff --git a/apps/settings/base.pt.i18n b/apps/settings/base.pt.i18n index f872bcf5c..e2783fc7f 100644 --- a/apps/settings/base.pt.i18n +++ b/apps/settings/base.pt.i18n @@ -9,7 +9,7 @@ ComplexFormat = "Complexos" ExamMode = "Modo de exame" ActivateExamMode = "Ativar o modo de exame" ExamModeActive = "Reativar o modo de exame" -ActivateDutchExamMode = "" +ActivateDutchExamMode = "Activate Dutch exam mode" About = "Acerca" Degrees = "Graus " Gradians = "Grados " diff --git a/apps/shared.de.i18n b/apps/shared.de.i18n index ff08c00ff..185b2f13b 100644 --- a/apps/shared.de.i18n +++ b/apps/shared.de.i18n @@ -2,9 +2,9 @@ ActivateDeactivate = "Aktivieren/Deaktivieren" ActiveExamModeMessage1 = "Alle Ihre Daten werden " ActiveExamModeMessage2 = "gelöscht, wenn Sie den " ActiveExamModeMessage3 = "Testmodus einschalten." -ActiveDutchExamModeMessage1 = "" -ActiveDutchExamModeMessage2 = "" -ActiveDutchExamModeMessage3 = "" +ActiveDutchExamModeMessage1 = "All your data will be deleted when" +ActiveDutchExamModeMessage2 = "you activate the exam mode. Python" +ActiveDutchExamModeMessage3 = "application will be unavailable." Axis = "Achsen" Cancel = "Abbrechen" ClearColumn = "Spalte löschen" diff --git a/apps/shared.es.i18n b/apps/shared.es.i18n index 18ac4dc39..ae9a65d72 100644 --- a/apps/shared.es.i18n +++ b/apps/shared.es.i18n @@ -2,9 +2,9 @@ ActivateDeactivate = "Activar/Desactivar" ActiveExamModeMessage1 = "Todos sus datos se " ActiveExamModeMessage2 = "eliminaran al activar " ActiveExamModeMessage3 = "el modo examen." -ActiveDutchExamModeMessage1 = "" -ActiveDutchExamModeMessage2 = "" -ActiveDutchExamModeMessage3 = "" +ActiveDutchExamModeMessage1 = "All your data will be deleted when" +ActiveDutchExamModeMessage2 = "you activate the exam mode. Python" +ActiveDutchExamModeMessage3 = "application will be unavailable." Axis = "Ejes" Cancel = "Cancelar" ClearColumn = "Borrar la columna" diff --git a/apps/shared.fr.i18n b/apps/shared.fr.i18n index b3f6fc997..a03e1ecc6 100644 --- a/apps/shared.fr.i18n +++ b/apps/shared.fr.i18n @@ -2,9 +2,9 @@ ActivateDeactivate = "Activer/Désactiver" ActiveExamModeMessage1 = "Toutes vos données seront " ActiveExamModeMessage2 = "supprimées si vous activez " ActiveExamModeMessage3 = "le mode examen." -ActiveDutchExamModeMessage1 = "" -ActiveDutchExamModeMessage2 = "" -ActiveDutchExamModeMessage3 = "" +ActiveDutchExamModeMessage1 = "All your data will be deleted when" +ActiveDutchExamModeMessage2 = "you activate the exam mode. Python" +ActiveDutchExamModeMessage3 = "application will be unavailable." Axis = "Axes" Cancel = "Annuler" ClearColumn = "Effacer la colonne" diff --git a/apps/shared.pt.i18n b/apps/shared.pt.i18n index 911100216..42e1752af 100644 --- a/apps/shared.pt.i18n +++ b/apps/shared.pt.i18n @@ -2,9 +2,9 @@ ActivateDeactivate = "Activar/Desactivar" ActiveExamModeMessage1 = "Todos os seus dados serão " ActiveExamModeMessage2 = "apagados se você ligar " ActiveExamModeMessage3 = "o modo de exame." -ActiveDutchExamModeMessage1 = "" -ActiveDutchExamModeMessage2 = "" -ActiveDutchExamModeMessage3 = "" +ActiveDutchExamModeMessage1 = "All your data will be deleted when" +ActiveDutchExamModeMessage2 = "you activate the exam mode. Python" +ActiveDutchExamModeMessage3 = "application will be unavailable." Axis = "Eixos" Cancel = "Cancelar" ClearColumn = "Excluir coluna" From 9d154e4e971a650ae5a29edeb436e31a96813c85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Wed, 18 Dec 2019 10:29:34 +0100 Subject: [PATCH 22/44] [ion] Exam mode: add assertion --- ion/src/device/shared/drivers/exam_mode.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/ion/src/device/shared/drivers/exam_mode.cpp b/ion/src/device/shared/drivers/exam_mode.cpp index 96e10a2d0..3ae01315c 100644 --- a/ion/src/device/shared/drivers/exam_mode.cpp +++ b/ion/src/device/shared/drivers/exam_mode.cpp @@ -50,6 +50,7 @@ size_t firstOneBitInByte(int i) { uint8_t * SignificantExamModeAddress() { uint32_t * persitence_start_32 = (uint32_t *)&_exam_mode_buffer_start; uint32_t * persitence_end_32 = (uint32_t *)&_exam_mode_buffer_end; + assert(persitence_end_32 - persitence_start_32 % 4 == 0); while (persitence_start_32 < persitence_end_32 && *persitence_start_32 == 0x0) { // Scan by groups of 32 bits to reach first non-zero bit persitence_start_32++; From 7d8bd450478bcaa6a8326fddf1d90b99a2d4325e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Wed, 18 Dec 2019 12:05:45 +0100 Subject: [PATCH 23/44] [build] Fix target two_binaries --- build/targets.device.mak | 28 ---------------------------- build/targets.device.n0110.mak | 28 ++++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/build/targets.device.mak b/build/targets.device.mak index 67265897b..3a54b7554 100644 --- a/build/targets.device.mak +++ b/build/targets.device.mak @@ -60,31 +60,3 @@ $(BUILD_DIR)/bench.flash.$(EXE): LDSCRIPT = ion/src/$(PLATFORM)/$(MODEL)/interna bench_src = $(ion_xip_src) $(liba_src) $(kandinsky_src) $(poincare_src) $(libaxx_src) $(app_shared_src) $(ion_target_device_bench_src) $(BUILD_DIR)/bench.ram.$(EXE): $(call object_for,$(bench_src)) $(BUILD_DIR)/bench.flash.$(EXE): $(call object_for,$(bench_src)) - -.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 $< $(basename $<).external.bin - $(Q) $(OBJCOPY) -O binary -R .text.external -R .rodata.external $< $(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: - rm -rf build/binpack - mkdir -p build/binpack - make clean - make -j8 $(BUILD_DIR)/flasher.light.bin - cp $(BUILD_DIR)/flasher.light.bin build/binpack - make clean - make -j8 $(BUILD_DIR)/bench.flash.bin - make -j8 $(BUILD_DIR)/bench.ram.bin - cp $(BUILD_DIR)/bench.ram.bin $(BUILD_DIR)/bench.flash.bin build/binpack - make clean - make -j8 $(BUILD_DIR)/epsilon.onboarding.update.two_binaries - cp $(BUILD_DIR)/epsilon.onboarding.update.internal.bin $(BUILD_DIR)/epsilon.onboarding.update.external.bin build/binpack - make clean - cd build && for binary in flasher.light.bin bench.flash.bin bench.ram.bin epsilon.onboarding.internal.bin epsilon.onboarding.external.bin; do shasum -a 256 -b binpack/$${binary} > binpack/$${binary}.sha256;done - cd build && tar cvfz binpack-`git rev-parse HEAD | head -c 7`.tgz binpack - rm -rf build/binpack diff --git a/build/targets.device.n0110.mak b/build/targets.device.n0110.mak index 3abc930e4..7c22b862b 100644 --- a/build/targets.device.n0110.mak +++ b/build/targets.device.n0110.mak @@ -19,3 +19,31 @@ $(BUILD_DIR)/test.external_flash.write.$(EXE): $(BUILD_DIR)/quiz/src/test_ion_ex sleep 2; \ 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" >> $(basename $<).external.bin + $(Q) printf "\xFF\xFF\xFF\xFF" >> $(basename $<).internal.bin + +.PHONY: binpack +binpack: + rm -rf build/binpack + mkdir -p build/binpack + make clean + make -j8 $(BUILD_DIR)/flasher.light.bin + cp $(BUILD_DIR)/flasher.light.bin build/binpack + make clean + make -j8 $(BUILD_DIR)/bench.flash.bin + make -j8 $(BUILD_DIR)/bench.ram.bin + cp $(BUILD_DIR)/bench.ram.bin $(BUILD_DIR)/bench.flash.bin build/binpack + make clean + make -j8 $(BUILD_DIR)/epsilon.onboarding.update.two_binaries + cp $(BUILD_DIR)/epsilon.onboarding.update.internal.bin $(BUILD_DIR)/epsilon.onboarding.update.external.bin build/binpack + make clean + cd build && for binary in flasher.light.bin bench.flash.bin bench.ram.bin epsilon.onboarding.internal.bin epsilon.onboarding.external.bin; do shasum -a 256 -b binpack/$${binary} > binpack/$${binary}.sha256;done + cd build && tar cvfz binpack-`git rev-parse HEAD | head -c 7`.tgz binpack + rm -rf build/binpack From 01ab6b5aebee1126626cf5226d930dcd5a8675d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 19 Dec 2019 15:09:46 +0100 Subject: [PATCH 24/44] [build] Fix test.elf build --- apps/Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/Makefile b/apps/Makefile index ba2e1a396..c6b21fa79 100644 --- a/apps/Makefile +++ b/apps/Makefile @@ -92,6 +92,10 @@ $(call object_for,$(all_app_src)): $(BUILD_DIR)/python/port/genhdr/qstrdefs.gene apps_tests_src = $(app_calculation_test_src) $(app_probability_test_src) $(app_regression_test_src) $(app_sequence_test_src) $(app_shared_test_src) $(app_statistics_test_src) $(app_solver_test_src) +apps_tests_src += $(addprefix apps/,\ + global_preferences.cpp \ +) + # Configure variants apps_all_src = $(app_src) apps_all_src += $(apps_launch_default_src) $(apps_launch_on_boarding_src From 96c63bd4a53dc438fcd7332bd0d353c2c809f968 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 19 Dec 2019 15:10:32 +0100 Subject: [PATCH 25/44] [apps][ion] Yellow LED is equivalent to Dutch exam mode, do not update the LED color (with plugging/charging events) if the displayed color was Red or Yellow --- apps/apps_container.cpp | 2 +- ion/src/device/n0110/drivers/led.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/apps_container.cpp b/apps/apps_container.cpp index 952f83db3..8d96b2b02 100644 --- a/apps/apps_container.cpp +++ b/apps/apps_container.cpp @@ -327,7 +327,7 @@ void AppsContainer::redrawWindow() { void AppsContainer::activateExamMode(GlobalPreferences::ExamMode examMode) { assert(examMode == GlobalPreferences::ExamMode::Standard || examMode == GlobalPreferences::ExamMode::Dutch); reset(); - Ion::LED::setColor(examMode == GlobalPreferences::ExamMode::Dutch ? KDColorOrange : KDColorRed); + Ion::LED::setColor(examMode == GlobalPreferences::ExamMode::Dutch ? KDColorYellow : KDColorRed); Ion::LED::setBlinking(1000, 0.1f); } diff --git a/ion/src/device/n0110/drivers/led.cpp b/ion/src/device/n0110/drivers/led.cpp index d29cc8494..83cf62083 100644 --- a/ion/src/device/n0110/drivers/led.cpp +++ b/ion/src/device/n0110/drivers/led.cpp @@ -7,7 +7,7 @@ namespace LED { KDColor updateColorWithPlugAndCharge() { KDColor ledColor = getColor(); - if (ledColor != KDColorRed) { // If exam mode is on, we do not update the LED with the plugged/charging state + if (ledColor != KDColorRed && ledColor != KDColorYellow) { // If exam mode is on, we do not update the LED with the plugged/charging state if (USB::isPlugged()) { ledColor = Battery::isCharging() ? KDColorOrange : KDColorGreen; } else { From 425f0cb45900f9c9cee27dbeaad0651b1d41c4fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 19 Dec 2019 15:16:05 +0100 Subject: [PATCH 26/44] [apps] GlobalPreferences: remove useless assertion --- apps/global_preferences.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/global_preferences.cpp b/apps/global_preferences.cpp index 7a0763e49..e47965cc6 100644 --- a/apps/global_preferences.cpp +++ b/apps/global_preferences.cpp @@ -9,7 +9,6 @@ GlobalPreferences::ExamMode GlobalPreferences::examMode() const { if (m_examMode == ExamMode::Unknown) { m_examMode = (ExamMode)Ion::ExamMode::FetchExamMode(); } - assert((int)m_examMode >= 0 && (int)m_examMode <= 2); return m_examMode; } From 902cc64d32a32c4d3ffe4199f0025e2e8b3fda84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 19 Dec 2019 15:18:03 +0100 Subject: [PATCH 27/44] [apps] GlobalPreferences: add an assertion to ensure the the fetched exam mode can be casted in GlobalPreferences::ExamMode --- apps/global_preferences.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/global_preferences.cpp b/apps/global_preferences.cpp index e47965cc6..c6644f5fd 100644 --- a/apps/global_preferences.cpp +++ b/apps/global_preferences.cpp @@ -7,7 +7,9 @@ GlobalPreferences * GlobalPreferences::sharedGlobalPreferences() { GlobalPreferences::ExamMode GlobalPreferences::examMode() const { if (m_examMode == ExamMode::Unknown) { - m_examMode = (ExamMode)Ion::ExamMode::FetchExamMode(); + uint8_t mode = Ion::ExamMode::FetchExamMode(); + assert(mode >= 0 && mode < 3); // mode can be cast in ExamMode (Off, Standard or Dutch) + m_examMode = (ExamMode)mode; } return m_examMode; } From 73673384aec58238e9a226359640da055f7ad75c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 19 Dec 2019 15:26:42 +0100 Subject: [PATCH 28/44] [ion] Avoid unclear, over-optimized computation in modulo 3 --- ion/src/device/shared/drivers/exam_mode.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ion/src/device/shared/drivers/exam_mode.cpp b/ion/src/device/shared/drivers/exam_mode.cpp index 3ae01315c..99b412e78 100644 --- a/ion/src/device/shared/drivers/exam_mode.cpp +++ b/ion/src/device/shared/drivers/exam_mode.cpp @@ -75,7 +75,7 @@ uint8_t * SignificantExamModeAddress() { uint8_t FetchExamMode() { uint8_t * readingAddress = SignificantExamModeAddress(); // Count the number of 0[3] before reading address - uint32_t nbOfZerosBefore = ((readingAddress - (uint8_t *)&_exam_mode_buffer_start) * 2) % 3; + uint32_t nbOfZerosBefore = ((readingAddress - (uint8_t *)&_exam_mode_buffer_start) * numberOfBitsInByte) % 3; // Count the number of 0[3] at reading address size_t numberOfLeading0 = (numberOfBitsInByte - firstOneBitInByte(*readingAddress)) % 3; return (nbOfZerosBefore + numberOfLeading0) % 3; From 3454265d7e6f55420bd02b31ecbde7a8a8d68836 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 19 Dec 2019 15:31:34 +0100 Subject: [PATCH 29/44] [ion] ExamMode: change firstOneBitInByte name to numberOfBitsAfterLeadingZeroes and add comment --- ion/src/device/shared/drivers/exam_mode.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ion/src/device/shared/drivers/exam_mode.cpp b/ion/src/device/shared/drivers/exam_mode.cpp index 99b412e78..c61d6ca97 100644 --- a/ion/src/device/shared/drivers/exam_mode.cpp +++ b/ion/src/device/shared/drivers/exam_mode.cpp @@ -32,7 +32,8 @@ char ones[Config::ExamModeBufferSize] constexpr static size_t numberOfBitsInByte = 8; -size_t firstOneBitInByte(int i) { +// if i = 0b000011101, firstOneBitInByte(i) returns 5 +size_t numberOfBitsAfterLeadingZeroes(int i) { int minShift = 0; int maxShift = numberOfBitsInByte; while (maxShift > minShift+1) { @@ -77,7 +78,7 @@ uint8_t FetchExamMode() { // Count the number of 0[3] before reading address uint32_t nbOfZerosBefore = ((readingAddress - (uint8_t *)&_exam_mode_buffer_start) * numberOfBitsInByte) % 3; // Count the number of 0[3] at reading address - size_t numberOfLeading0 = (numberOfBitsInByte - firstOneBitInByte(*readingAddress)) % 3; + size_t numberOfLeading0 = (numberOfBitsInByte - numberOfBitsAfterLeadingZeroes(*readingAddress)) % 3; return (nbOfZerosBefore + numberOfLeading0) % 3; } @@ -85,7 +86,7 @@ void IncrementExamMode(uint8_t delta) { assert(delta == 1 || delta == 2); uint8_t * writingAddress = SignificantExamModeAddress(); assert(*writingAddress != 0); - size_t nbOfTargetedOnes = firstOneBitInByte(*writingAddress); + size_t nbOfTargetedOnes = numberOfBitsAfterLeadingZeroes(*writingAddress); // Compute the new value with delta bits switched to 0. /* We write in 2 bytes instead of 1, in case there was only one bit From 0254266803627a88bbc4568ebc2da12e3b1af534 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 19 Dec 2019 15:35:57 +0100 Subject: [PATCH 30/44] [ion] ExamMode: add comment --- ion/src/device/shared/drivers/exam_mode.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ion/src/device/shared/drivers/exam_mode.cpp b/ion/src/device/shared/drivers/exam_mode.cpp index c61d6ca97..a4aa20143 100644 --- a/ion/src/device/shared/drivers/exam_mode.cpp +++ b/ion/src/device/shared/drivers/exam_mode.cpp @@ -107,8 +107,11 @@ void IncrementExamMode(uint8_t delta) { } // Write the value in flash - /* Avoid writing out of sector */ + /* As the number of changed bits is capped by 2, if *writingAddress has more + * than one remaining 1 bit, we know we toggle bits only in the first byte of + * newValue. We can settle for writing one byte instead of two. */ size_t writtenFlash = *writingAddress == 1 ? sizeof(uint16_t) : sizeof(uint8_t); + /* Avoid writing out of sector */ assert(writingAddress < (uint8_t *)&_exam_mode_buffer_end - 1 || (writingAddress == (uint8_t *)&_exam_mode_buffer_end - 1 && writtenFlash == 1)); Ion::Device::Flash::WriteMemory(writingAddress, newValue, writtenFlash); } From e13425d2318ad98c3aea67d3345f321dcc2aab0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 19 Dec 2019 15:41:40 +0100 Subject: [PATCH 31/44] [apps] Add comment about LED color in Dutch exam mode --- apps/apps_container.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/apps_container.cpp b/apps/apps_container.cpp index 8d96b2b02..5656aecb9 100644 --- a/apps/apps_container.cpp +++ b/apps/apps_container.cpp @@ -327,6 +327,13 @@ void AppsContainer::redrawWindow() { void AppsContainer::activateExamMode(GlobalPreferences::ExamMode examMode) { assert(examMode == GlobalPreferences::ExamMode::Standard || examMode == GlobalPreferences::ExamMode::Dutch); reset(); + /* The Dutch exam mode LED is supposed to be orange but we can only make + * blink "pure" colors: with RGB leds on or off (as the PWM is used for + * blinking). The closest "pure" color is Yellow. Moreover, Orange LED is + * already used when the battery is charging. Using yellow, we can assert + * that the yellow LED only means that Dutch exam mode is on and avoid + * confusing states when the battery is charging and states when the Dutch + * exam mode is on. */ Ion::LED::setColor(examMode == GlobalPreferences::ExamMode::Dutch ? KDColorYellow : KDColorRed); Ion::LED::setBlinking(1000, 0.1f); } From 2c7a26103b0af12e8f1290c575c03b4d1efb422f Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Thu, 19 Dec 2019 17:22:26 -0500 Subject: [PATCH 32/44] [ci] Use a recent ARM GCC toolchain --- .github/workflows/ci-workflow.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-workflow.yml b/.github/workflows/ci-workflow.yml index d38794afc..7b53519b9 100644 --- a/.github/workflows/ci-workflow.yml +++ b/.github/workflows/ci-workflow.yml @@ -14,7 +14,8 @@ jobs: build-device-n0100: runs-on: ubuntu-latest steps: - - run: sudo apt-get install binutils-arm-none-eabi build-essential gcc-arm-none-eabi imagemagick libfreetype6-dev libjpeg-dev libpng-dev pkg-config + - run: sudo apt-get install build-essential imagemagick libfreetype6-dev libjpeg-dev libpng-dev pkg-config + - uses: numworks/setup-arm-toolchain@v1 - uses: actions/checkout@v1 - run: make -j2 MODEL=n0100 epsilon.dfu - run: make -j2 MODEL=n0100 epsilon.onboarding.dfu @@ -30,7 +31,8 @@ jobs: build-device-n0110: runs-on: ubuntu-latest steps: - - run: sudo apt-get install binutils-arm-none-eabi build-essential gcc-arm-none-eabi imagemagick libfreetype6-dev libjpeg-dev libpng-dev pkg-config + - run: sudo apt-get install build-essential imagemagick libfreetype6-dev libjpeg-dev libpng-dev pkg-config + - uses: numworks/setup-arm-toolchain@v1 - uses: actions/checkout@v1 - run: make -j2 epsilon.dfu - run: make -j2 epsilon.onboarding.dfu From ae8c111da5b52e84db291c6238ed41ba357dc047 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Mon, 16 Dec 2019 21:36:46 -0500 Subject: [PATCH 33/44] [ion] Prevent duplicating SFLAGS Using $(sort) in the Makefile has the side effect of removing duplicates --- ion/src/device/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ion/src/device/Makefile b/ion/src/device/Makefile index 5adb13861..d15012f4e 100644 --- a/ion/src/device/Makefile +++ b/ion/src/device/Makefile @@ -19,7 +19,7 @@ ion_src += $(addprefix ion/src/shared/, \ ION_DEVICE_SFLAGS = -Iion/src/device/$(MODEL) -Iion/src/device/shared -$(call object_for,$(ion_device_src) $(dfu_src) $(ion_target_device_flasher_light_src) $(ion_target_device_flasher_verbose_src) $(usb_src) $(ion_target_device_bench_src) $(ion_device_dfu_xip_src) $(ion_device_dfu_relocated_src) $(ion_console_uart_src)): SFLAGS += $(ION_DEVICE_SFLAGS) +$(call object_for,$(sort $(ion_device_src) $(dfu_src) $(ion_target_device_flasher_light_src) $(ion_target_device_flasher_verbose_src) $(usb_src) $(ion_target_device_bench_src) $(ion_device_dfu_xip_src) $(ion_device_dfu_relocated_src) $(ion_console_uart_src))): SFLAGS += $(ION_DEVICE_SFLAGS) ion_src += $(ion_device_src) # When using the register.h C++ file in production mode, we expect the compiler From d0660b6543aa5cafbb7a3981bb39b35717a72bed Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Mon, 16 Dec 2019 21:44:56 -0500 Subject: [PATCH 34/44] [ion/device] Force inlining compile-time bit ranges Most of the time register operations can be optimized to a single assembly instruction. That being said, aggressive -Os optimization can lead the compiler to think that factorizing calls to setBitRange is a good idea. But we really want register operations to be inlined (and therefore optimized as a single instruction), so we enforce inlining setBitRange and REGS_FIELD macros. --- ion/src/device/shared/regs/register.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ion/src/device/shared/regs/register.h b/ion/src/device/shared/regs/register.h index cac002a6b..12adc8a28 100644 --- a/ion/src/device/shared/regs/register.h +++ b/ion/src/device/shared/regs/register.h @@ -4,6 +4,8 @@ #include #include +#define always_inline __attribute__((always_inline)) + namespace Ion { namespace Device { namespace Regs { @@ -22,7 +24,7 @@ public: T get() volatile { return m_value; } - void setBitRange(uint8_t high, uint8_t low, T value) volatile { + always_inline void setBitRange(uint8_t high, uint8_t low, T value) volatile { m_value = bit_range_set_value(high, low, m_value, value); } T getBitRange(uint8_t high, uint8_t low) volatile { @@ -57,8 +59,8 @@ typedef Register Register64; } } -#define REGS_FIELD_R(name,type,high,low) type get##name() volatile { return (type)getBitRange(high,low); }; -#define REGS_FIELD_W(name,type,high,low) void set##name(type v) volatile { static_assert(sizeof(type) <= 4, "Invalid size"); setBitRange(high, low, static_cast(v)); }; +#define REGS_FIELD_R(name,type,high,low) always_inline type get##name() volatile { return (type)getBitRange(high,low); }; +#define REGS_FIELD_W(name,type,high,low) always_inline void set##name(type v) volatile { static_assert(sizeof(type) <= 4, "Invalid size"); setBitRange(high, low, static_cast(v)); }; #define REGS_FIELD(name,type,high,low) REGS_FIELD_R(name,type,high,low); REGS_FIELD_W(name,type,high,low); #define REGS_TYPE_FIELD(name,high,low) REGS_FIELD(name,name,high,low) #define REGS_BOOL_FIELD(name,bit) REGS_FIELD(name,bool,bit,bit) From 5b00192b6712f3891cced8b93589f4c3ff9d4e85 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Mon, 16 Dec 2019 21:45:42 -0500 Subject: [PATCH 35/44] [ion/device] Remove ad-hoc compiler optimizations Since we hand-specify which regs/regs.h functions shoudl be inlined, we don't need to depend on specific compiler optimization levels. --- ion/src/device/Makefile | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/ion/src/device/Makefile b/ion/src/device/Makefile index d15012f4e..161218a49 100644 --- a/ion/src/device/Makefile +++ b/ion/src/device/Makefile @@ -21,18 +21,3 @@ ION_DEVICE_SFLAGS = -Iion/src/device/$(MODEL) -Iion/src/device/shared $(call object_for,$(sort $(ion_device_src) $(dfu_src) $(ion_target_device_flasher_light_src) $(ion_target_device_flasher_verbose_src) $(usb_src) $(ion_target_device_bench_src) $(ion_device_dfu_xip_src) $(ion_device_dfu_relocated_src) $(ion_console_uart_src))): SFLAGS += $(ION_DEVICE_SFLAGS) ion_src += $(ion_device_src) - -# When using the register.h C++ file in production mode, we expect the compiler -# to completely inline all bit manipulations. For some reason, if we build using -# the -Os optimization flag, GCC doesn't inline everything and and ends up -# emitting calls to aeabi_llsl for 64-bits registers. This is very sub-optimal -# so we're enforcing -O3 for this specific file. - -ifneq ($(DEBUG),1) -ifneq ($(COMPILER),llvm) -$(BUILD_DIR)/ion/src/device/led.o: SFLAGS+=-O3 -$(BUILD_DIR)/ion/src/device/console.o: SFLAGS+=-O3 -$(BUILD_DIR)/ion/src/device/display.o: SFLAGS+=-O3 -$(BUILD_DIR)/ion/src/device/swd.o: SFLAGS+=-O3 -endif -endif From 0412a45cea77557235d2fc811ce33692970a8495 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 19 Dec 2019 15:36:57 +0100 Subject: [PATCH 36/44] [escher/responder] Inline some methods --- escher/include/escher/responder.h | 14 +++++++------- escher/src/responder.cpp | 24 ------------------------ 2 files changed, 7 insertions(+), 31 deletions(-) diff --git a/escher/include/escher/responder.h b/escher/include/escher/responder.h index cf84840bb..c8315c5bb 100644 --- a/escher/include/escher/responder.h +++ b/escher/include/escher/responder.h @@ -5,15 +5,15 @@ class Responder { public: - Responder(Responder * parentResponder); + Responder(Responder * parentResponder) : m_parentResponder(parentResponder) {} virtual bool handleEvent(Ion::Events::Event event) { return false; }; // Default implementation does nothing - virtual void didBecomeFirstResponder(); - virtual void willResignFirstResponder(); - virtual void didEnterResponderChain(Responder * previousFirstResponder); - virtual void willExitResponderChain(Responder * nextFirstResponder); - Responder * parentResponder() const; + virtual void didBecomeFirstResponder() {} + virtual void willResignFirstResponder() {} + virtual void didEnterResponderChain(Responder * previousFirstResponder) {} + virtual void willExitResponderChain(Responder * nextFirstResponder) {} + Responder * parentResponder() const { return m_parentResponder; } Responder * commonAncestorWith(Responder * responder); - void setParentResponder(Responder * responder); + void setParentResponder(Responder * responder) { m_parentResponder = responder; } private: Responder * m_parentResponder; }; diff --git a/escher/src/responder.cpp b/escher/src/responder.cpp index 34cbd96a0..ba0a120f4 100644 --- a/escher/src/responder.cpp +++ b/escher/src/responder.cpp @@ -2,30 +2,6 @@ #include #include -Responder::Responder(Responder * parentResponder) : - m_parentResponder(parentResponder) -{ -} - -Responder * Responder::parentResponder() const { - return m_parentResponder; -} - -void Responder::setParentResponder(Responder * responder) { - m_parentResponder = responder; -} - -void Responder::didBecomeFirstResponder() { -} - -void Responder::willResignFirstResponder() { -} - -void Responder::didEnterResponderChain(Responder * previousFirstResponder) { -} - -void Responder::willExitResponderChain(Responder * nextFirstResponder) { -} Responder * Responder::commonAncestorWith(Responder * responder) { if (responder == nullptr) { From 4e96a11a4c98b1ec7d4fd91e1636e7b128a6c6ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 19 Dec 2019 15:55:10 +0100 Subject: [PATCH 37/44] [escher/responder] Clean commonAncestor method --- escher/include/escher/responder.h | 1 + escher/src/responder.cpp | 47 +++++++++++++------------------ 2 files changed, 20 insertions(+), 28 deletions(-) diff --git a/escher/include/escher/responder.h b/escher/include/escher/responder.h index c8315c5bb..b0918b5fc 100644 --- a/escher/include/escher/responder.h +++ b/escher/include/escher/responder.h @@ -15,6 +15,7 @@ public: Responder * commonAncestorWith(Responder * responder); void setParentResponder(Responder * responder) { m_parentResponder = responder; } private: + bool hasAncestor(Responder * responder) const; Responder * m_parentResponder; }; diff --git a/escher/src/responder.cpp b/escher/src/responder.cpp index ba0a120f4..72f12c85e 100644 --- a/escher/src/responder.cpp +++ b/escher/src/responder.cpp @@ -7,33 +7,24 @@ Responder * Responder::commonAncestorWith(Responder * responder) { if (responder == nullptr) { return nullptr; } - if (this == responder) { - return this; + Responder * p = this; + while (p != nullptr) { + if (responder->hasAncestor(p)) { + return p; + } + p = p->parentResponder(); } - Responder * rootResponder = this; - while (rootResponder->parentResponder() != responder && rootResponder->parentResponder() != nullptr) { - rootResponder = rootResponder->parentResponder(); - } - if (rootResponder->parentResponder() == responder) { - return responder; - } - rootResponder = responder; - while (rootResponder->parentResponder() != this && rootResponder->parentResponder() != nullptr) { - rootResponder = rootResponder->parentResponder(); - } - if (rootResponder->parentResponder() == this) { - return this; - } - Responder * r = nullptr; - if (parentResponder()) { - r = parentResponder()->commonAncestorWith(responder); - } - Responder * s = nullptr; - if (responder->parentResponder()) { - s = commonAncestorWith(responder->parentResponder()); - } - if (r) { - return r; - } - return s; + return nullptr; +} + +bool Responder::hasAncestor(Responder * responder) const { + assert(responder != nullptr); + Responder * p = const_cast(this); + while (p != nullptr) { + if (p == responder) { + return true; + } + p = p->parentResponder(); + } + return false; } From 053fb935e321dc366292247acef06d6a5ee82bd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 20 Dec 2019 14:02:08 +0100 Subject: [PATCH 38/44] [apps] Change color of LED in power on self test: blue is too easily confused with white --- apps/on_boarding/power_on_self_test.cpp | 2 +- kandinsky/include/kandinsky/color.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/on_boarding/power_on_self_test.cpp b/apps/on_boarding/power_on_self_test.cpp index dde93f04c..5bdeb1807 100644 --- a/apps/on_boarding/power_on_self_test.cpp +++ b/apps/on_boarding/power_on_self_test.cpp @@ -20,7 +20,7 @@ KDColor PowerOnSelfTest::Perform() { resultColor = KDColorRed; } } else { - resultColor = KDColorBlue; + resultColor = KDColorPurple; } Ion::LED::setColor(resultColor); return previousLEDColor; diff --git a/kandinsky/include/kandinsky/color.h b/kandinsky/include/kandinsky/color.h index a416bd2d7..9879e006b 100644 --- a/kandinsky/include/kandinsky/color.h +++ b/kandinsky/include/kandinsky/color.h @@ -45,5 +45,6 @@ constexpr KDColor KDColorGreen = KDColor::RGB24(0x00FF00); constexpr KDColor KDColorBlue = KDColor::RGB24(0x0000FF); constexpr KDColor KDColorYellow = KDColor::RGB24(0xFFFF00); constexpr KDColor KDColorOrange = KDColor::RGB24(0xFF9900); +constexpr KDColor KDColorPurple = KDColor::RGB24(0xFF00DD); #endif From c2f86e080629261e4a4710c9c7b7b6aca56bc85c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 13 Dec 2019 10:58:50 +0100 Subject: [PATCH 39/44] [poincare] Add tests on lcm and gcd approximations --- poincare/test/approximation.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/poincare/test/approximation.cpp b/poincare/test/approximation.cpp index bf8ff4a3e..d6573c8d7 100644 --- a/poincare/test/approximation.cpp +++ b/poincare/test/approximation.cpp @@ -269,12 +269,18 @@ QUIZ_CASE(poincare_approximation_function) { assert_expression_approximates_to("gcd(234,394)", "2"); assert_expression_approximates_to("gcd(234,394)", "2"); + assert_expression_approximates_to("gcd(-234,394)", "2"); + assert_expression_approximates_to("gcd(234,-394)", "2"); + assert_expression_approximates_to("gcd(-234,-394)", "2"); assert_expression_approximates_to("im(2+3𝐢)", "3"); assert_expression_approximates_to("im(2+3𝐢)", "3"); assert_expression_approximates_to("lcm(234,394)", "46098"); assert_expression_approximates_to("lcm(234,394)", "46098"); + assert_expression_approximates_to("lcm(-234,394)", "46098"); + assert_expression_approximates_to("lcm(234,-394)", "46098"); + assert_expression_approximates_to("lcm(-234,-394)", "46098"); assert_expression_approximates_to("int(x,x, 1, 2)", "1.5"); assert_expression_approximates_to("int(x,x, 1, 2)", "1.5"); From 07ecc119ab9da5a8afa9b97d75f40a7761976988 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 13 Dec 2019 10:59:20 +0100 Subject: [PATCH 40/44] [poincare] Fix gcd and lcm approximations --- .../include/poincare/approximation_helper.h | 1 + poincare/src/approximation_helper.cpp | 14 +++++++++++++ poincare/src/great_common_divisor.cpp | 19 ++++++++--------- poincare/src/least_common_multiple.cpp | 21 +++++++++---------- 4 files changed, 34 insertions(+), 21 deletions(-) diff --git a/poincare/include/poincare/approximation_helper.h b/poincare/include/poincare/approximation_helper.h index b079d6a62..6634e7646 100644 --- a/poincare/include/poincare/approximation_helper.h +++ b/poincare/include/poincare/approximation_helper.h @@ -9,6 +9,7 @@ namespace Poincare { namespace ApproximationHelper { + template int IntegerApproximationIfPossible(const ExpressionNode * expression, bool * isUndefined, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit); template std::complex TruncateRealOrImaginaryPartAccordingToArgument(std::complex c); template using ComplexCompute = Complex(*)(const std::complex, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit); diff --git a/poincare/src/approximation_helper.cpp b/poincare/src/approximation_helper.cpp index 2d7eafc39..2cc0b81a5 100644 --- a/poincare/src/approximation_helper.cpp +++ b/poincare/src/approximation_helper.cpp @@ -15,6 +15,18 @@ template T absMod(T a, T b) { return result > b/2 ? b-result : result; } +static inline int absInt(int x) { return x < 0 ? -x : x; } + +template int ApproximationHelper::IntegerApproximationIfPossible(const ExpressionNode * expression, bool * isUndefined, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) { + Evaluation evaluation = expression->approximate(T(), context, complexFormat, angleUnit); + T scalar = evaluation.toScalar(); + if (std::isnan(scalar) || scalar != (int)scalar) { + *isUndefined = true; + return 0; + } + return absInt((int)scalar); +} + template std::complex ApproximationHelper::TruncateRealOrImaginaryPartAccordingToArgument(std::complex c) { T arg = std::arg(c); T precision = 10*Expression::Epsilon(); @@ -92,6 +104,8 @@ template MatrixComplex ApproximationHelper::ElementWiseOnComplexM return matrix; } +template int Poincare::ApproximationHelper::IntegerApproximationIfPossible(Poincare::ExpressionNode const*, bool*, Poincare::Context*, Poincare::Preferences::ComplexFormat, Poincare::Preferences::AngleUnit); +template int Poincare::ApproximationHelper::IntegerApproximationIfPossible(Poincare::ExpressionNode const*, bool*, Poincare::Context*, Poincare::Preferences::ComplexFormat, Poincare::Preferences::AngleUnit); template std::complex Poincare::ApproximationHelper::TruncateRealOrImaginaryPartAccordingToArgument(std::complex); template std::complex Poincare::ApproximationHelper::TruncateRealOrImaginaryPartAccordingToArgument(std::complex); template Poincare::Evaluation Poincare::ApproximationHelper::Map(const Poincare::ExpressionNode * expression, Poincare::Context * context, Poincare::Preferences::ComplexFormat, Poincare::Preferences::AngleUnit angleUnit, Poincare::ApproximationHelper::ComplexCompute compute); diff --git a/poincare/src/great_common_divisor.cpp b/poincare/src/great_common_divisor.cpp index 51afde0c1..a66d3525e 100644 --- a/poincare/src/great_common_divisor.cpp +++ b/poincare/src/great_common_divisor.cpp @@ -1,5 +1,6 @@ #include +#include #include #include #include @@ -27,22 +28,20 @@ Expression GreatCommonDivisorNode::shallowReduce(ReductionContext reductionConte template Evaluation GreatCommonDivisorNode::templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const { - Evaluation f1Input = childAtIndex(0)->approximate(T(), context, complexFormat, angleUnit); - Evaluation f2Input = childAtIndex(1)->approximate(T(), context, complexFormat, angleUnit); - T f1 = f1Input.toScalar(); - T f2 = f2Input.toScalar(); - if (std::isnan(f1) || std::isnan(f2) || f1 != (int)f1 || f2 != (int)f2) { + bool isUndefined = false; + int a = ApproximationHelper::IntegerApproximationIfPossible(childAtIndex(0), &isUndefined, context, complexFormat, angleUnit); + int b = ApproximationHelper::IntegerApproximationIfPossible(childAtIndex(1), &isUndefined, context, complexFormat, angleUnit); + if (isUndefined) { return Complex::Undefined(); } - int a = (int)f2; - int b = (int)f1; - if (f1 > f2) { + if (b > a) { + int temp = b; b = a; - a = (int)f1; + a = temp; } int r = 0; while((int)b!=0){ - r = a - ((int)(a/b))*b; + r = a - (a/b)*b; a = b; b = r; } diff --git a/poincare/src/least_common_multiple.cpp b/poincare/src/least_common_multiple.cpp index c94547809..c6a104fed 100644 --- a/poincare/src/least_common_multiple.cpp +++ b/poincare/src/least_common_multiple.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -27,26 +28,24 @@ Expression LeastCommonMultipleNode::shallowReduce(ReductionContext reductionCont template Evaluation LeastCommonMultipleNode::templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const { - Evaluation f1Input = childAtIndex(0)->approximate(T(), context, complexFormat, angleUnit); - Evaluation f2Input = childAtIndex(1)->approximate(T(), context, complexFormat, angleUnit); - T f1 = f1Input.toScalar(); - T f2 = f2Input.toScalar(); - if (std::isnan(f1) || std::isnan(f2) || f1 != (int)f1 || f2 != (int)f2) { + bool isUndefined = false; + int a = ApproximationHelper::IntegerApproximationIfPossible(childAtIndex(0), &isUndefined, context, complexFormat, angleUnit); + int b = ApproximationHelper::IntegerApproximationIfPossible(childAtIndex(1), &isUndefined, context, complexFormat, angleUnit); + if (isUndefined) { return Complex::Undefined(); } - if (f1 == 0.0f || f2 == 0.0f) { + if (a == 0 || b == 0) { return Complex::Builder(0.0); } - int a = (int)f2; - int b = (int)f1; - if (f1 > f2) { + if (b > a) { + int temp = b; b = a; - a = (int)f1; + a = temp; } int product = a*b; int r = 0; while((int)b!=0){ - r = a - ((int)(a/b))*b; + r = a - (a/b)*b; a = b; b = r; } From 934e2c8aeb5626f74cecb97ab386edd1f6496c4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 20 Dec 2019 11:30:22 +0100 Subject: [PATCH 41/44] [poincare] Change name IntegerApproximationIfPossible --> PositiveIntegerApproximationIfPossible --- poincare/include/poincare/approximation_helper.h | 2 +- poincare/src/approximation_helper.cpp | 6 +++--- poincare/src/great_common_divisor.cpp | 4 ++-- poincare/src/least_common_multiple.cpp | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/poincare/include/poincare/approximation_helper.h b/poincare/include/poincare/approximation_helper.h index 6634e7646..169143faf 100644 --- a/poincare/include/poincare/approximation_helper.h +++ b/poincare/include/poincare/approximation_helper.h @@ -9,7 +9,7 @@ namespace Poincare { namespace ApproximationHelper { - template int IntegerApproximationIfPossible(const ExpressionNode * expression, bool * isUndefined, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit); + template int PositiveIntegerApproximationIfPossible(const ExpressionNode * expression, bool * isUndefined, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit); template std::complex TruncateRealOrImaginaryPartAccordingToArgument(std::complex c); template using ComplexCompute = Complex(*)(const std::complex, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit); diff --git a/poincare/src/approximation_helper.cpp b/poincare/src/approximation_helper.cpp index 2cc0b81a5..32f1f88ad 100644 --- a/poincare/src/approximation_helper.cpp +++ b/poincare/src/approximation_helper.cpp @@ -17,7 +17,7 @@ template T absMod(T a, T b) { static inline int absInt(int x) { return x < 0 ? -x : x; } -template int ApproximationHelper::IntegerApproximationIfPossible(const ExpressionNode * expression, bool * isUndefined, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) { +template int ApproximationHelper::PositiveIntegerApproximationIfPossible(const ExpressionNode * expression, bool * isUndefined, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) { Evaluation evaluation = expression->approximate(T(), context, complexFormat, angleUnit); T scalar = evaluation.toScalar(); if (std::isnan(scalar) || scalar != (int)scalar) { @@ -104,8 +104,8 @@ template MatrixComplex ApproximationHelper::ElementWiseOnComplexM return matrix; } -template int Poincare::ApproximationHelper::IntegerApproximationIfPossible(Poincare::ExpressionNode const*, bool*, Poincare::Context*, Poincare::Preferences::ComplexFormat, Poincare::Preferences::AngleUnit); -template int Poincare::ApproximationHelper::IntegerApproximationIfPossible(Poincare::ExpressionNode const*, bool*, Poincare::Context*, Poincare::Preferences::ComplexFormat, Poincare::Preferences::AngleUnit); +template int Poincare::ApproximationHelper::PositiveIntegerApproximationIfPossible(Poincare::ExpressionNode const*, bool*, Poincare::Context*, Poincare::Preferences::ComplexFormat, Poincare::Preferences::AngleUnit); +template int Poincare::ApproximationHelper::PositiveIntegerApproximationIfPossible(Poincare::ExpressionNode const*, bool*, Poincare::Context*, Poincare::Preferences::ComplexFormat, Poincare::Preferences::AngleUnit); template std::complex Poincare::ApproximationHelper::TruncateRealOrImaginaryPartAccordingToArgument(std::complex); template std::complex Poincare::ApproximationHelper::TruncateRealOrImaginaryPartAccordingToArgument(std::complex); template Poincare::Evaluation Poincare::ApproximationHelper::Map(const Poincare::ExpressionNode * expression, Poincare::Context * context, Poincare::Preferences::ComplexFormat, Poincare::Preferences::AngleUnit angleUnit, Poincare::ApproximationHelper::ComplexCompute compute); diff --git a/poincare/src/great_common_divisor.cpp b/poincare/src/great_common_divisor.cpp index a66d3525e..d9e9faec0 100644 --- a/poincare/src/great_common_divisor.cpp +++ b/poincare/src/great_common_divisor.cpp @@ -29,8 +29,8 @@ Expression GreatCommonDivisorNode::shallowReduce(ReductionContext reductionConte template Evaluation GreatCommonDivisorNode::templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const { bool isUndefined = false; - int a = ApproximationHelper::IntegerApproximationIfPossible(childAtIndex(0), &isUndefined, context, complexFormat, angleUnit); - int b = ApproximationHelper::IntegerApproximationIfPossible(childAtIndex(1), &isUndefined, context, complexFormat, angleUnit); + int a = ApproximationHelper::PositiveIntegerApproximationIfPossible(childAtIndex(0), &isUndefined, context, complexFormat, angleUnit); + int b = ApproximationHelper::PositiveIntegerApproximationIfPossible(childAtIndex(1), &isUndefined, context, complexFormat, angleUnit); if (isUndefined) { return Complex::Undefined(); } diff --git a/poincare/src/least_common_multiple.cpp b/poincare/src/least_common_multiple.cpp index c6a104fed..cb356e338 100644 --- a/poincare/src/least_common_multiple.cpp +++ b/poincare/src/least_common_multiple.cpp @@ -29,8 +29,8 @@ Expression LeastCommonMultipleNode::shallowReduce(ReductionContext reductionCont template Evaluation LeastCommonMultipleNode::templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const { bool isUndefined = false; - int a = ApproximationHelper::IntegerApproximationIfPossible(childAtIndex(0), &isUndefined, context, complexFormat, angleUnit); - int b = ApproximationHelper::IntegerApproximationIfPossible(childAtIndex(1), &isUndefined, context, complexFormat, angleUnit); + int a = ApproximationHelper::PositiveIntegerApproximationIfPossible(childAtIndex(0), &isUndefined, context, complexFormat, angleUnit); + int b = ApproximationHelper::PositiveIntegerApproximationIfPossible(childAtIndex(1), &isUndefined, context, complexFormat, angleUnit); if (isUndefined) { return Complex::Undefined(); } From 7b7447b1107dee52d0be0d6ad0705c57a67c9126 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Wed, 18 Dec 2019 11:47:05 +0100 Subject: [PATCH 42/44] [ion] N0110 cache: clean isb/dsb calls --- ion/src/device/n0110/drivers/cache.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/ion/src/device/n0110/drivers/cache.cpp b/ion/src/device/n0110/drivers/cache.cpp index 87b1a36f2..0d16f5261 100644 --- a/ion/src/device/n0110/drivers/cache.cpp +++ b/ion/src/device/n0110/drivers/cache.cpp @@ -65,7 +65,7 @@ void cleanDCache() { void enableDCache() { invalidateDCache(); - CORTEX.CCR()->setDC(true); + CORTEX.CCR()->setDC(true); // Enable D-cache dsb(); isb(); } @@ -77,14 +77,14 @@ void disableDCache() { void invalidateICache() { dsb(); isb(); - CORTEX.ICIALLU()->set(0); + CORTEX.ICIALLU()->set(0); // Invalidate I-cache dsb(); isb(); } void enableICache() { invalidateICache(); - CORTEX.CCR()->setIC(true); + CORTEX.CCR()->setIC(true); // Enable I-cache dsb(); isb(); } @@ -92,8 +92,10 @@ void enableICache() { void disableICache() { dsb(); isb(); - CORTEX.CCR()->setIC(false); - invalidateICache(); + CORTEX.CCR()->setIC(false); // Disable I-cache + CORTEX.ICIALLU()->set(0); // Invalidate I-cache + dsb(); + isb(); } From 9fca8e8b8b8a9fe45e7fa1b9f4c51e2867d089ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Wed, 18 Dec 2019 11:47:30 +0100 Subject: [PATCH 43/44] [ion] Reset: factorize cache disabling --- ion/src/device/shared/drivers/reset.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ion/src/device/shared/drivers/reset.cpp b/ion/src/device/shared/drivers/reset.cpp index d69b2e102..21f93eed1 100644 --- a/ion/src/device/shared/drivers/reset.cpp +++ b/ion/src/device/shared/drivers/reset.cpp @@ -41,8 +41,7 @@ void __attribute__((noinline)) internalFlashJump(uint32_t jumpIsrVectorAddress) void jump(uint32_t jumpIsrVectorAddress) { // Disable cache before reset - Ion::Device::Cache::disableDCache(); - Ion::Device::Cache::disableICache(); + Ion::Device::Cache::disable(); /* Shutdown all clocks and periherals to mimic a hardware reset. */ Board::shutdownPeripherals(); From 588c05f6b4fb9d3ae7eff8ea592b6a381437f7d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Wed, 18 Dec 2019 11:48:00 +0100 Subject: [PATCH 44/44] [ion] Reset: Add memory barriers before/after calling for a core reset: --- ion/src/device/shared/drivers/reset.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ion/src/device/shared/drivers/reset.cpp b/ion/src/device/shared/drivers/reset.cpp index 21f93eed1..ef6053570 100644 --- a/ion/src/device/shared/drivers/reset.cpp +++ b/ion/src/device/shared/drivers/reset.cpp @@ -12,7 +12,13 @@ using namespace Regs; void core() { // Perform a full core reset + Ion::Device::Cache::dsb(); // Complete all memory accesses CORTEX.AIRCR()->requestReset(); + Ion::Device::Cache::dsb(); + // Wait until reset + while (true) { + asm("nop"); + } } /* We isolate the jump code that needs to be executed from the internal