From 8e2ed09875f2aa944164242bc646729c48332a2d Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Boric Date: Mon, 29 Jan 2018 17:58:56 +0100 Subject: [PATCH 01/43] Touch up register definitions --- ion/src/device/led.cpp | 12 ++--- ion/src/device/regs/pwr.h | 8 +++ ion/src/device/regs/rcc.h | 44 +++++++++++++++++ ion/src/device/regs/regs.h | 1 + ion/src/device/regs/rtc.h | 99 ++++++++++++++++++++++++++++++++++++++ ion/src/device/regs/tim.h | 89 ++++++++++++++++++++++++++++++---- 6 files changed, 238 insertions(+), 15 deletions(-) create mode 100644 ion/src/device/regs/rtc.h diff --git a/ion/src/device/led.cpp b/ion/src/device/led.cpp index f4c7037ee..a281d3bf5 100644 --- a/ion/src/device/led.cpp +++ b/ion/src/device/led.cpp @@ -58,9 +58,9 @@ void initTimer() { TIM3.CCR4()->set(0); // Set Channels 2-4 as outputs, PWM mode 1 - TIM3.CCMR()->setOC2M(TIM::CCMR::OCM::PWM1); - TIM3.CCMR()->setOC3M(TIM::CCMR::OCM::PWM1); - TIM3.CCMR()->setOC4M(TIM::CCMR::OCM::PWM1); + TIM3.CCMR()->setOC2M(TIM::CCMR::OCM::PWM1); + TIM3.CCMR()->setOC3M(TIM::CCMR::OCM::PWM1); + TIM3.CCMR()->setOC4M(TIM::CCMR::OCM::PWM1); // Output preload enable for channels 2-4 TIM3.CCMR()->setOC2PE(true); @@ -81,9 +81,9 @@ void initTimer() { } void shutdownTimer() { - TIM3.CCMR()->setOC2M(TIM::CCMR::OCM::ForceInactive); - TIM3.CCMR()->setOC3M(TIM::CCMR::OCM::ForceInactive); - TIM3.CCMR()->setOC4M(TIM::CCMR::OCM::ForceInactive); + TIM3.CCMR()->setOC2M(TIM::CCMR::OCM::ForceInactive); + TIM3.CCMR()->setOC3M(TIM::CCMR::OCM::ForceInactive); + TIM3.CCMR()->setOC4M(TIM::CCMR::OCM::ForceInactive); } void enforceState(bool red, bool green, bool blue) { diff --git a/ion/src/device/regs/pwr.h b/ion/src/device/regs/pwr.h index 089d72e18..60fe325ff 100644 --- a/ion/src/device/regs/pwr.h +++ b/ion/src/device/regs/pwr.h @@ -9,11 +9,19 @@ public: public: REGS_BOOL_FIELD(LPDS, 0); REGS_BOOL_FIELD(PPDS, 1); + REGS_BOOL_FIELD(DBP, 8); REGS_BOOL_FIELD(FPDS, 9); }; + class CSR : Register32 { + public: + REGS_BOOL_FIELD(BRE, 9); + REGS_BOOL_FIELD_R(BRR, 3); + }; + constexpr PWR() {}; REGS_REGISTER_AT(CR, 0x00); + REGS_REGISTER_AT(CSR, 0x04); private: constexpr uint32_t Base() const { return 0x40007000; diff --git a/ion/src/device/regs/rcc.h b/ion/src/device/regs/rcc.h index 64ec87472..1249489b2 100644 --- a/ion/src/device/regs/rcc.h +++ b/ion/src/device/regs/rcc.h @@ -7,8 +7,16 @@ class RCC { public: class CR : public Register32 { public: + REGS_BOOL_FIELD_R(PLLI2SRDY, 27); + REGS_BOOL_FIELD(PLLI2SON, 26); REGS_BOOL_FIELD(PLLRDY, 25); REGS_BOOL_FIELD(PLLON, 24); + REGS_BOOL_FIELD(CSSON, 19); + REGS_BOOL_FIELD(HSEBYP, 18); + REGS_BOOL_FIELD_R(HSERDY, 17); + REGS_BOOL_FIELD(HSEON, 16); + REGS_BOOL_FIELD_R(HSIRDY, 1); + REGS_BOOL_FIELD(HSION, 0); }; class PLLCFGR : public Register32 { @@ -41,7 +49,9 @@ public: DivideBy8 = 6, DivideBy16 = 7 }; + void setPPRE2(AHBRatio r) volatile { setBitRange(15, 13, (uint32_t)r); } void setPPRE1(AHBRatio r) volatile { setBitRange(12, 10, (uint32_t)r); } + REGS_FIELD(RTCPRE, uint8_t, 4, 0); }; class AHB1ENR : public Register32 { @@ -74,7 +84,16 @@ public: class APB1ENR : public Register32 { public: using Register32::Register32; + REGS_BOOL_FIELD(TIM2EN, 0); REGS_BOOL_FIELD(TIM3EN, 1); + REGS_BOOL_FIELD(TIM4EN, 2); + REGS_BOOL_FIELD(TIM5EN, 3); + REGS_BOOL_FIELD(TIM6EN, 4); + REGS_BOOL_FIELD(TIM7EN, 5); + REGS_BOOL_FIELD(TIM12EN, 6); + REGS_BOOL_FIELD(TIM13EN, 7); + REGS_BOOL_FIELD(TIM14EN, 8); + REGS_BOOL_FIELD(RTCAPB, 10); REGS_BOOL_FIELD(SPI3EN, 15); REGS_BOOL_FIELD(USART3EN, 18); REGS_BOOL_FIELD(PWREN, 28); @@ -84,10 +103,33 @@ public: public: using Register32::Register32; REGS_BOOL_FIELD(TIM1EN, 0); + REGS_BOOL_FIELD(TIM8EN, 1); REGS_BOOL_FIELD(USART1EN, 4); REGS_BOOL_FIELD(ADC1EN, 8); REGS_BOOL_FIELD(SDIOEN, 11); REGS_BOOL_FIELD(SYSCFGEN, 14); + REGS_BOOL_FIELD(TIM9EN, 16); + REGS_BOOL_FIELD(TIM10EN, 17); + REGS_BOOL_FIELD(TIM11EN, 18); + }; + + class BDCR : public Register32 { + public: + REGS_BOOL_FIELD(BDRST, 16); + REGS_BOOL_FIELD(RTCEN, 15); + enum class RTCSel { + RTC_NoClock = 0, + RTC_LSEClock = 1, + RTC_LSIClock = 2, + RTC_HSEClock = 3 + }; + void setRTCSel(RTCSel s) volatile { setBitRange(9, 8, (uint32_t)s); } + }; + + class CSR : public Register32 { + public: + REGS_BOOL_FIELD(LSION, 0); + REGS_BOOL_FIELD_R(LSIRDY, 1); }; class DCKCFGR2 : Register32 { @@ -105,6 +147,8 @@ public: REGS_REGISTER_AT(AHB3ENR, 0x38); REGS_REGISTER_AT(APB1ENR, 0x40); REGS_REGISTER_AT(APB2ENR, 0x44); + REGS_REGISTER_AT(BDCR, 0x70); + REGS_REGISTER_AT(CSR, 0x74); REGS_REGISTER_AT(DCKCFGR2, 0x94); private: constexpr uint32_t Base() const { diff --git a/ion/src/device/regs/regs.h b/ion/src/device/regs/regs.h index 175862830..b75de5e88 100644 --- a/ion/src/device/regs/regs.h +++ b/ion/src/device/regs/regs.h @@ -13,6 +13,7 @@ #include "pwr.h" #include "rcc.h" #include "rng.h" +#include "rtc.h" #include "sdio.h" #include "spi.h" #include "syscfg.h" diff --git a/ion/src/device/regs/rtc.h b/ion/src/device/regs/rtc.h new file mode 100644 index 000000000..3a2007dd1 --- /dev/null +++ b/ion/src/device/regs/rtc.h @@ -0,0 +1,99 @@ +#ifndef REGS_RTC_H +#define REGS_RTC_H + +#include "register.h" + +class RTC { +public: + class TR : public Register32 { + public: + using Register32::Register32; + REGS_BOOL_FIELD(PM, 22); + REGS_FIELD(HT, uint8_t, 21, 20); + REGS_FIELD(HU, uint8_t, 19, 16); + REGS_FIELD(MNT, uint8_t, 14, 12); + REGS_FIELD(MNU, uint8_t, 11, 8); + REGS_FIELD(ST, uint8_t, 6, 4); + REGS_FIELD(SU, uint8_t, 3, 0); + }; + + class DR : public Register32 { + public: + using Register32::Register32; + REGS_FIELD(YT, uint8_t, 23, 20); + REGS_FIELD(YU, uint8_t, 19, 16); + REGS_FIELD(WDU, uint8_t, 15, 13); + REGS_FIELD(MT, uint8_t, 12, 12); + REGS_FIELD(MU, uint8_t, 11, 8); + REGS_FIELD(DT, uint8_t, 5, 4); + REGS_FIELD(DU, uint8_t, 3, 0); + }; + + class CR : Register32 { + public: + REGS_BOOL_FIELD(COE, 23); + REGS_FIELD(OSEL, uint8_t, 22, 21); + REGS_BOOL_FIELD(POL, 20); + REGS_BOOL_FIELD(COSEL, 19); + REGS_BOOL_FIELD(BKP, 18); + REGS_BOOL_FIELD_W(SUB1H, 17); + REGS_BOOL_FIELD_W(ADD1H, 16); + REGS_BOOL_FIELD(TSIE, 15); + REGS_BOOL_FIELD(WUTIE, 14); + REGS_BOOL_FIELD(ALRBIE, 13); + REGS_BOOL_FIELD(ALRAIE, 12); + REGS_BOOL_FIELD(TSE, 11); + REGS_BOOL_FIELD(WUTE, 10); + REGS_BOOL_FIELD(ALRBE, 9); + REGS_BOOL_FIELD(ALRAE, 8); + REGS_BOOL_FIELD(DCE, 7); + REGS_BOOL_FIELD(FMT, 6); + REGS_BOOL_FIELD(BYPSHAD, 5); + REGS_BOOL_FIELD(REFCKON, 4); + REGS_BOOL_FIELD(TSEDGE, 3); + REGS_FIELD(WUCKSEL, uint8_t, 2, 0); + }; + + class ISR : Register32 { + public: + REGS_BOOL_FIELD_R(RECALPF, 16); + REGS_BOOL_FIELD(INIT, 7); + REGS_BOOL_FIELD_R(INITF, 6); + REGS_BOOL_FIELD(RSF, 5); + REGS_BOOL_FIELD_R(INITS, 4); + }; + + class PRER : public Register32 { + public: + using Register32::Register32; + REGS_FIELD(PREDIV_A, uint8_t, 22, 16); + REGS_FIELD(PREDIV_S, uint16_t, 14, 0); + }; + + class WPR : Register32 { + public: + REGS_FIELD_W(KEY, uint8_t, 7, 0); + }; + + class CALR : Register32 { + public: + REGS_FIELD(CALM, uint8_t, 8, 0); + }; + + constexpr RTC() {} + REGS_REGISTER_AT(TR, 0x00); + REGS_REGISTER_AT(DR, 0x04); + REGS_REGISTER_AT(CR, 0x08); + REGS_REGISTER_AT(ISR, 0x0C); + REGS_REGISTER_AT(PRER, 0x10); + REGS_REGISTER_AT(WPR, 0x24); + REGS_REGISTER_AT(CALR, 0x3C); +private: + constexpr uint32_t Base() const { + return 0x40002800; + }; +}; + +constexpr RTC RTC; + +#endif diff --git a/ion/src/device/regs/tim.h b/ion/src/device/regs/tim.h index c614c82f1..fc285941d 100644 --- a/ion/src/device/regs/tim.h +++ b/ion/src/device/regs/tim.h @@ -3,14 +3,40 @@ #include "register.h" +template class TIM { public: class CR1 : Register16 { public: REGS_BOOL_FIELD(CEN, 0); + REGS_BOOL_FIELD(URS, 1); + REGS_BOOL_FIELD(UDIS, 1); REGS_BOOL_FIELD(ARPE, 7); }; + class SR : Register16 { + public: + REGS_BOOL_FIELD(CC4OF, 12); + REGS_BOOL_FIELD(CC3OF, 11); + REGS_BOOL_FIELD(CC2OF, 10); + REGS_BOOL_FIELD(CC1OF, 9); + REGS_BOOL_FIELD(CC4IF, 4); + REGS_BOOL_FIELD(CC3IF, 3); + REGS_BOOL_FIELD(CC2IF, 2); + REGS_BOOL_FIELD(CC1IF, 1); + REGS_BOOL_FIELD(UIF, 0); + }; + + class EGR : Register16 { + public: + REGS_BOOL_FIELD(UG, 0); + }; + + class DIER : Register16 { + public: + REGS_BOOL_FIELD(UIE, 0); + }; + class CCMR : Register64 { /* We're declaring CCMR as a 64 bits register. CCMR doesn't exsist per se, * it is in fact the consolidation of CCMR1 and CCMR2. Both are 16 bits @@ -24,6 +50,12 @@ public: INPUT_TI1 = 2, INPUT_TRC = 3 }; + enum class CC4S : uint8_t { + OUTPUT = 0, + INPUT_TI4 = 1, + INPUT_TI3 = 2, + INPUT_TRC = 3 + }; enum class OCM : uint8_t { Frozen = 0, ActiveOnMatch = 1, @@ -44,6 +76,8 @@ public: REGS_TYPE_FIELD(OC2M, 14, 12); REGS_BOOL_FIELD(OC3PE, 35); REGS_TYPE_FIELD(OC3M, 38, 36); + REGS_TYPE_FIELD(CC4S, 41, 40); + REGS_FIELD(IC4PSC, uint8_t, 43, 42); REGS_BOOL_FIELD(OC4PE, 43); REGS_TYPE_FIELD(OC4M, 46, 44); }; @@ -61,17 +95,33 @@ public: REGS_BOOL_FIELD(MOE, 15); }; + class CNT : public RegisterWidth {}; class PSC : public Register16 {}; - class ARR : public Register16 {}; - class CCR1 : public Register16 {}; - class CCR2 : public Register16 {}; - class CCR3 : public Register16 {}; - class CCR4 : public Register16 {}; + class ARR : public RegisterWidth {}; + class CCR1 : public RegisterWidth {}; + class CCR2 : public RegisterWidth {}; + class CCR3 : public RegisterWidth {}; + class CCR4 : public RegisterWidth {}; + + class OR : Register16 { + public: + enum class TI4_RMP { + GPIO = 0, + LSI = 1, + LSE = 2, + WAKEUP = 3 + }; + void setTI4RMP(TI4_RMP r) volatile { setBitRange(7, 6, (uint32_t)r); } + }; constexpr TIM(int i) : m_index(i) {} REGS_REGISTER_AT(CR1, 0x0); + REGS_REGISTER_AT(DIER, 0xC); + REGS_REGISTER_AT(SR, 0x10); + REGS_REGISTER_AT(EGR, 0x14); REGS_REGISTER_AT(CCMR, 0x18); REGS_REGISTER_AT(CCER, 0x20); + REGS_REGISTER_AT(CNT, 0x24); REGS_REGISTER_AT(PSC, 0x28); REGS_REGISTER_AT(ARR, 0x2C); REGS_REGISTER_AT(CCR1, 0x34); @@ -79,14 +129,35 @@ public: REGS_REGISTER_AT(CCR3, 0x3C); REGS_REGISTER_AT(CCR4, 0x40); REGS_REGISTER_AT(BDTR, 0x44); + REGS_REGISTER_AT(OR, 0x50); private: constexpr uint32_t Base() const { - return (m_index == 1 ? 0x40010000 : 0x40000000 + 0x400*(m_index-2)); - }; + return (m_index == 1 ? 0x40010000 : + (m_index <= 7 ? 0x40000000 + 0x400*(m_index-2) : + (m_index == 8 ? 0x40010400 : + (m_index <= 11 ? 0x40014000 + 0x400*(m_index-9) : + 0x40001800 + 0x400*(m_index-12) + ) + ) + ) + ); + } int m_index; }; -constexpr TIM TIM1(1); -constexpr TIM TIM3(3); +constexpr TIM TIM1(1); +constexpr TIM TIM2(2); +constexpr TIM TIM3(3); +constexpr TIM TIM4(4); +constexpr TIM TIM5(5); +constexpr TIM TIM6(6); +constexpr TIM TIM7(7); +constexpr TIM TIM8(8); +constexpr TIM TIM9(9); +constexpr TIM TIM10(10); +constexpr TIM TIM11(11); +constexpr TIM TIM12(12); +constexpr TIM TIM13(13); +constexpr TIM TIM14(14); #endif From b774ddf7e7a54c36479d481cfa68db98fa73172d Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Boric Date: Wed, 31 Jan 2018 18:36:18 +0100 Subject: [PATCH 02/43] [ion] Use TIM6 to keep track of time during Ion::msleep --- ion/src/device/device.cpp | 49 ++++++++++++++++++++++++++++++++------- ion/src/device/device.h | 4 ++++ ion/src/device/power.cpp | 2 +- 3 files changed, 46 insertions(+), 9 deletions(-) diff --git a/ion/src/device/device.cpp b/ion/src/device/device.cpp index 23daf95f9..05e17fa21 100644 --- a/ion/src/device/device.cpp +++ b/ion/src/device/device.cpp @@ -19,15 +19,20 @@ extern "C" { // Public Ion methods -/* TODO: The delay methods 'msleep' and 'usleep' are currently dependent on the - * optimizations chosen by the compiler. To prevent that and to gain in - * precision, we could use the controller cycle counter (Systick). */ - void Ion::msleep(long ms) { - for (volatile long i=0; i<8852*ms; i++) { - __asm volatile("nop"); - } + // We need a frequency high enough to not overflow the prescaler, + // which is 16 bits wide. + constexpr int TIM6_FREQ = 4*1000; + + Ion::Device::waitTIM6(Ion::Device::SYSBUS_FREQ / TIM6_FREQ, ms * TIM6_FREQ / 1000); } + +/* TODO: The delay method 'usleep' is currently dependent on the optimizations + * chosen by the compiler. To prevent that and to gain in precision, we could + * use the controller cycle counter (Systick). We can't use a regular timer + * (like TIM6) for this since setting it up takes a significant amount of time + * in these timescales. + */ void Ion::usleep(long us) { for (volatile long i=0; i<9*us; i++) { __asm volatile("nop"); @@ -211,8 +216,10 @@ void initClocks() { RCC.AHB1ENR()->set(ahb1enr); // APB1 bus - // We're using TIM3 + // We're using TIM3 for the LEDs RCC.APB1ENR()->setTIM3EN(true); + // We're using TIM6 for sleeping + RCC.APB1ENR()->setTIM6EN(true); RCC.APB1ENR()->setPWREN(true); // APB2 bus @@ -240,5 +247,31 @@ void shutdownClocks() { RCC.AHB3ENR()->setFSMCEN(false); } +void waitTIM6(unsigned short prescaler, long cycles) { + while (cycles > 0) { + // TIM6 counts up to 2^16-1, make sure we won't overflow the counter. + uint16_t iterCycles = (cycles > 0xFFFF ? 0xFFFF : cycles); + + // Initialize TIM6 + TIM6.PSC()->set(prescaler); + TIM6.CNT()->set(0); + TIM6.ARR()->set(iterCycles); + TIM6.EGR()->setUG(true); + TIM6.SR()->setUIF(false); + TIM6.CR1()->setCEN(true); + + // Wait until the timer elapses + do { + // TODO: Use interrupts instead of busy-waiting + __asm volatile("nop"); + } while (TIM6.SR()->getUIF() == false); + + // Stop TIM6 + TIM6.CR1()->setCEN(false); + + cycles -= iterCycles; + } +} + } } diff --git a/ion/src/device/device.h b/ion/src/device/device.h index b72759bae..77547952d 100644 --- a/ion/src/device/device.h +++ b/ion/src/device/device.h @@ -4,6 +4,8 @@ namespace Ion { namespace Device { +constexpr int SYSBUS_FREQ = 96*1000*1000; + void init(); void shutdown(); @@ -13,6 +15,8 @@ void shutdownPeripherals(); void initClocks(); void shutdownClocks(); +void waitTIM6(unsigned short prescaler, long cycles); + /* Pin | Role | Mode | Function * -----+-------------------+-----------------------+---------- * PA0 | Battery sensing | | diff --git a/ion/src/device/power.cpp b/ion/src/device/power.cpp index 948b9eb89..de15a1af2 100644 --- a/ion/src/device/power.cpp +++ b/ion/src/device/power.cpp @@ -47,7 +47,7 @@ void Ion::Power::suspend(bool checkIfPowerKeyReleased) { * to clear it, and then a second WFE to wait for a _new_ event. */ asm("sev"); asm("wfe"); - msleep(1); + asm("nop"); asm("wfe"); Device::initClocks(); From 2d088473a540330813464040acf5cfa6fb3af8fb Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Boric Date: Wed, 31 Jan 2018 20:29:46 +0100 Subject: [PATCH 03/43] Reimplement LED charging Fixes #196 --- apps/Makefile | 1 - apps/apps_container.cpp | 5 +- apps/apps_container.h | 2 - apps/exam_pop_up_controller.cpp | 3 + apps/led_timer.cpp | 14 ---- apps/led_timer.h | 15 ---- apps/usb_timer.cpp | 5 +- ion/include/ion/led.h | 9 +++ ion/src/device/device.cpp | 5 +- ion/src/device/led.cpp | 130 ++++++++++++++++++++++++++++---- ion/src/device/led.h | 14 +++- ion/src/device/power.cpp | 12 +-- ion/src/device/regs/rcc.h | 19 +++++ ion/src/shared/dummy/led.cpp | 13 ++++ ion/src/simulator/led.cpp | 11 +++ 15 files changed, 197 insertions(+), 61 deletions(-) delete mode 100644 apps/led_timer.cpp delete mode 100644 apps/led_timer.h diff --git a/apps/Makefile b/apps/Makefile index fe201355d..d4618acfe 100644 --- a/apps/Makefile +++ b/apps/Makefile @@ -21,7 +21,6 @@ app_objs += $(addprefix apps/,\ exam_pop_up_controller.o\ global_preferences.o\ i18n.o\ - led_timer.o\ lock_view.o\ main.o\ math_toolbox.o\ diff --git a/apps/apps_container.cpp b/apps/apps_container.cpp index 0e662ee05..8df83a41b 100644 --- a/apps/apps_container.cpp +++ b/apps/apps_container.cpp @@ -16,7 +16,6 @@ AppsContainer::AppsContainer() : m_variableBoxController(&m_globalContext), m_examPopUpController(), m_updateController(), - m_ledTimer(LedTimer()), m_batteryTimer(BatteryTimer(this)), m_USBTimer(USBTimer(this)), m_suspendTimer(SuspendTimer(this)), @@ -185,11 +184,11 @@ Window * AppsContainer::window() { } int AppsContainer::numberOfContainerTimers() { - return 4+(GlobalPreferences::sharedGlobalPreferences()->examMode() == GlobalPreferences::ExamMode::Activate); + return 4; } Timer * AppsContainer::containerTimerAtIndex(int i) { - Timer * timers[5] = {&m_batteryTimer, &m_USBTimer, &m_suspendTimer, &m_backlightDimmingTimer, &m_ledTimer}; + Timer * timers[4] = {&m_batteryTimer, &m_USBTimer, &m_suspendTimer, &m_backlightDimmingTimer}; return timers[i]; } diff --git a/apps/apps_container.h b/apps/apps_container.h index 89126897f..00ee8b179 100644 --- a/apps/apps_container.h +++ b/apps/apps_container.h @@ -10,7 +10,6 @@ #include "math_toolbox.h" #include "variable_box_controller.h" #include "exam_pop_up_controller.h" -#include "led_timer.h" #include "battery_timer.h" #include "usb_timer.h" #include "suspend_timer.h" @@ -65,7 +64,6 @@ private: VariableBoxController m_variableBoxController; ExamPopUpController m_examPopUpController; OnBoarding::UpdateController m_updateController; - LedTimer m_ledTimer; BatteryTimer m_batteryTimer; USBTimer m_USBTimer; SuspendTimer m_suspendTimer; diff --git a/apps/exam_pop_up_controller.cpp b/apps/exam_pop_up_controller.cpp index d938b0aee..d58596ed5 100644 --- a/apps/exam_pop_up_controller.cpp +++ b/apps/exam_pop_up_controller.cpp @@ -55,7 +55,10 @@ ExamPopUpController::ContentView::ContentView(Responder * parentResponder) : AppsContainer * container = (AppsContainer *)controller->app()->container(); if (controller->isActivatingExamMode()) { container->reset(); + Ion::LED::setBlinking(0.5, true, false, false); + Ion::LED::setLockState(true); } else { + Ion::LED::setLockState(false); Ion::LED::setColor(KDColorBlack); } container->refreshPreferences(); diff --git a/apps/led_timer.cpp b/apps/led_timer.cpp deleted file mode 100644 index d462ca6c7..000000000 --- a/apps/led_timer.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "led_timer.h" - -LedTimer::LedTimer() : - Timer(1), - m_on(false) -{ -} - -bool LedTimer::fire() { - m_on = !m_on; - KDColor ledColor = m_on ? KDColorRed : KDColorBlack; - Ion::LED::setColor(ledColor); - return false; -} diff --git a/apps/led_timer.h b/apps/led_timer.h deleted file mode 100644 index 17f221e48..000000000 --- a/apps/led_timer.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef APPS_LED_TIMER_H -#define APPS_LED_TIMER_H - -#include - -class LedTimer : public Timer { -public: - LedTimer(); -private: - bool fire() override; - bool m_on; -}; - -#endif - diff --git a/apps/usb_timer.cpp b/apps/usb_timer.cpp index d14fa8965..18a72e32e 100644 --- a/apps/usb_timer.cpp +++ b/apps/usb_timer.cpp @@ -17,8 +17,7 @@ bool USBTimer::fire() { needRedrawing = true; } #if LED_WHILE_CHARGING - KDColor LEDColor = Ion::Battery::isCharging() ? KDColorYellow : KDColorGreen; - Ion::LED::setColor(LEDColor); + Ion::LED::setCharging(Ion::USB::isPlugged(), Ion::Battery::isCharging()); #endif if (!m_previousPluggedState) { Ion::Backlight::setBrightness(Ion::Backlight::MaxBrightness); @@ -27,7 +26,7 @@ bool USBTimer::fire() { } else { if (m_previousPluggedState) { #if LED_WHILE_CHARGING - Ion::LED::setColor(KDColorBlack); + Ion::LED::setCharging(Ion::USB::isPlugged(), Ion::Battery::isCharging()); #endif m_previousPluggedState = false; } diff --git a/ion/include/ion/led.h b/ion/include/ion/led.h index 8ca251504..b2d40cad7 100644 --- a/ion/include/ion/led.h +++ b/ion/include/ion/led.h @@ -7,6 +7,15 @@ namespace Ion { namespace LED { void setColor(KDColor c); +void setBlinking(float blinkLength, bool red, bool green, bool blue); +void setCharging(bool isPluggedIn, bool isCharging); + +/* + * This is just a flag to see if we should mess with the LEDs on our own. + * Especially useful for keeping the LED blinking while in exam mode. + */ +bool getLockState(); +void setLockState(bool state); } } diff --git a/ion/src/device/device.cpp b/ion/src/device/device.cpp index 05e17fa21..2c3def4ff 100644 --- a/ion/src/device/device.cpp +++ b/ion/src/device/device.cpp @@ -238,8 +238,9 @@ void shutdownClocks() { // APB2 bus RCC.APB2ENR()->set(0x00008000); // Reset value - // AHB1 - RCC.APB1ENR()->set(0x00000400); + // APB1 + RCC.APB1ENR()->set(0x00000402); + RCC.APB1LPENR()->setTIM3LPEN(true); // Keep the LED going // AHB1 bus RCC.AHB1ENR()->set(0); // Reset value diff --git a/ion/src/device/led.cpp b/ion/src/device/led.cpp index a281d3bf5..3557ffe79 100644 --- a/ion/src/device/led.cpp +++ b/ion/src/device/led.cpp @@ -1,16 +1,63 @@ #include #include +#include "device.h" #include "led.h" #include "regs/regs.h" // Public Ion::LED methods void Ion::LED::setColor(KDColor c) { + if (getLockState()) { + return; + } + + initTimer(Ion::LED::Device::Mode::PWM); + + Ion::LED::Device::setColorStatus(Ion::LED::Device::Color::RED, true); + Ion::LED::Device::setColorStatus(Ion::LED::Device::Color::GREEN, true); + Ion::LED::Device::setColorStatus(Ion::LED::Device::Color::BLUE, true); + TIM3.CCR2()->set(Device::dutyCycleForUInt8(c.red())); TIM3.CCR3()->set(Device::dutyCycleForUInt8(c.blue())); TIM3.CCR4()->set(Device::dutyCycleForUInt8(c.green())); } +void Ion::LED::setBlinking(float blinkPeriod, bool red, bool green, bool blue) { + if (getLockState()) { + return; + } + + initTimer(Ion::LED::Device::Mode::BLINK, blinkPeriod); + + Ion::LED::Device::setColorStatus(Ion::LED::Device::Color::RED, red); + Ion::LED::Device::setColorStatus(Ion::LED::Device::Color::GREEN, green); + Ion::LED::Device::setColorStatus(Ion::LED::Device::Color::BLUE, blue); +} + +void Ion::LED::setCharging(bool isPluggedIn, bool isCharging) { + if (!isPluggedIn) { + Ion::LED::setColor(KDColorBlack); + } + else { + if (isCharging) { + Ion::LED::setColor(KDColorRed); + } + else { + Ion::LED::setColor(KDColorGreen); + } + } +} + +static bool lockState = false; + +bool Ion::LED::getLockState() { + return lockState; +} + +void Ion::LED::setLockState(bool state) { + lockState = state; +} + // Private Ion::Device::LED methods namespace Ion { @@ -19,12 +66,9 @@ namespace Device { void init() { initGPIO(); - initTimer(); } void shutdown() { - shutdownTimer(); - shutdownGPIO(); } void initGPIO() { @@ -44,18 +88,31 @@ void shutdownGPIO() { } } -void initTimer() { - /* Let's set the prescaler to 1. Increasing the prescaler would slow down the - * modulation, which can be useful when debugging. */ - TIM3.PSC()->set(1); +void initTimer(Mode mode, float blinkPeriod) { + constexpr int TIM3_FREQ = 4*1000; /* Pulse width modulation mode allows you to generate a signal with a * frequency determined by the value of the TIMx_ARR register and a duty cycle * determined by the value of the TIMx_CCRx register. */ - TIM3.ARR()->set(PWMPeriod); - TIM3.CCR2()->set(0); - TIM3.CCR3()->set(0); - TIM3.CCR4()->set(0); + switch (mode) { + case Ion::LED::Device::Mode::PWM: + /* Let's set the prescaler to 1. Increasing the prescaler would slow down the + * modulation, which can be useful when debugging. */ + TIM3.PSC()->set(1); + TIM3.ARR()->set(PWMPeriod); + TIM3.CCR2()->set(0); + TIM3.CCR3()->set(0); + TIM3.CCR4()->set(0); + break; + case Ion::LED::Device::Mode::BLINK: + /* We still want to do PWM, but at a rate slow enough to blink. */ + TIM3.PSC()->set(Ion::Device::SYSBUS_FREQ / TIM3_FREQ); + TIM3.ARR()->set(blinkPeriod * TIM3_FREQ); + TIM3.CCR2()->set(blinkPeriod * TIM3_FREQ / 2); + TIM3.CCR3()->set(blinkPeriod * TIM3_FREQ / 2); + TIM3.CCR4()->set(blinkPeriod * TIM3_FREQ / 2); + break; + } // Set Channels 2-4 as outputs, PWM mode 1 TIM3.CCMR()->setOC2M(TIM::CCMR::OCM::PWM1); @@ -80,10 +137,55 @@ void initTimer() { TIM3.CR1()->setCEN(true); } +void initTimerColor() { + /* Let's set the prescaler to 1. Increasing the prescaler would slow down the + * modulation, which can be useful when debugging. */ + TIM3.PSC()->set(1); + + /* Pulse width modulation mode allows you to generate a signal with a + * frequency determined by the value of the TIMx_ARR register and a duty cycle + * determined by the value of the TIMx_CCRx register. */ + TIM3.ARR()->set(PWMPeriod); + TIM3.CCR2()->set(0); + TIM3.CCR3()->set(0); + TIM3.CCR4()->set(0); + + // Output preload enable for channels 2-4 + TIM3.CCMR()->setOC2PE(true); + TIM3.CCMR()->setOC3PE(true); + TIM3.CCMR()->setOC4PE(true); + + // Auto-reload preload enable + TIM3.CR1()->setARPE(true); + + // Enable Capture/Compare for channel 2 to 4 + TIM3.CCER()->setCC2E(true); + TIM3.CCER()->setCC3E(true); + TIM3.CCER()->setCC4E(true); + + TIM3.BDTR()->setMOE(true); + + TIM3.CR1()->setCEN(true); +} + void shutdownTimer() { - TIM3.CCMR()->setOC2M(TIM::CCMR::OCM::ForceInactive); - TIM3.CCMR()->setOC3M(TIM::CCMR::OCM::ForceInactive); - TIM3.CCMR()->setOC4M(TIM::CCMR::OCM::ForceInactive); + setColorStatus(Ion::LED::Device::Color::RED, false); + setColorStatus(Ion::LED::Device::Color::GREEN, false); + setColorStatus(Ion::LED::Device::Color::BLUE, false); +} + +void setColorStatus(Color color, bool enable) { + switch (color) { + case Ion::LED::Device::Color::RED: + TIM3.CCMR()->setOC2M(enable ? TIM::CCMR::OCM::PWM1 : TIM::CCMR::OCM::ForceInactive); + break; + case Ion::LED::Device::Color::GREEN: + TIM3.CCMR()->setOC4M(enable ? TIM::CCMR::OCM::PWM1 : TIM::CCMR::OCM::ForceInactive); + break; + case Ion::LED::Device::Color::BLUE: + TIM3.CCMR()->setOC3M(enable ? TIM::CCMR::OCM::PWM1 : TIM::CCMR::OCM::ForceInactive); + break; + } } void enforceState(bool red, bool green, bool blue) { diff --git a/ion/src/device/led.h b/ion/src/device/led.h index b4b368c5e..19a918366 100644 --- a/ion/src/device/led.h +++ b/ion/src/device/led.h @@ -14,14 +14,26 @@ namespace Device { * PC7 | LED red | Alternate Function 2 | TIM3_CH2 */ +enum Mode { + PWM, + BLINK +} ; + +enum Color { + RED, + GREEN, + BLUE +} ; + void init(); void shutdown(); +void setColorStatus(Color color, bool enable); /* This call bypasses the timer, and immediately enforces a given LED state. */ void enforceState(bool red, bool green, bool blue); void initGPIO(); void shutdownGPIO(); -void initTimer(); +void initTimer(Mode mode, float blinkPeriod = 0); void shutdownTimer(); constexpr static GPIOPin RGBPins[] = { diff --git a/ion/src/device/power.cpp b/ion/src/device/power.cpp index de15a1af2..e57e966c2 100644 --- a/ion/src/device/power.cpp +++ b/ion/src/device/power.cpp @@ -21,22 +21,22 @@ void Ion::Power::suspend(bool checkIfPowerKeyReleased) { PWR.CR()->setLPDS(true); // Turn the regulator off. Takes longer to wake up. PWR.CR()->setFPDS(true); // Put the flash to sleep. Takes longer to wake up. - CM4.SCR()->setSLEEPDEEP(true); + CM4.SCR()->setSLEEPDEEP(!Ion::LED::getLockState()); - WakeUp::Device::onUSBPlugging(); -#if LED_WHILE_CHARGING - WakeUp::Device::onChargingEvent(); -#endif while (1) { #if LED_WHILE_CHARGING /* Update LEDS * if the standby mode was stopped due to a "stop charging" event, we wait * a while to be sure that the plug state of the USB is up-to-date. */ msleep(200); - LED::Device::enforceState(Battery::isCharging(), USB::isPlugged(), false); + Ion::LED::setCharging(Ion::USB::isPlugged(), Ion::Battery::isCharging()); #endif WakeUp::Device::onPowerKeyDown(); + WakeUp::Device::onUSBPlugging(); +#if LED_WHILE_CHARGING + WakeUp::Device::onChargingEvent(); +#endif Device::shutdownClocks(); diff --git a/ion/src/device/regs/rcc.h b/ion/src/device/regs/rcc.h index 1249489b2..4254d8901 100644 --- a/ion/src/device/regs/rcc.h +++ b/ion/src/device/regs/rcc.h @@ -113,6 +113,24 @@ public: REGS_BOOL_FIELD(TIM11EN, 18); }; + class APB1LPENR : public Register32 { + public: + using Register32::Register32; + REGS_BOOL_FIELD(TIM2LPEN, 0); + REGS_BOOL_FIELD(TIM3LPEN, 1); + REGS_BOOL_FIELD(TIM4LPEN, 2); + REGS_BOOL_FIELD(TIM5LPEN, 3); + REGS_BOOL_FIELD(TIM6LPEN, 4); + REGS_BOOL_FIELD(TIM7LPEN, 5); + REGS_BOOL_FIELD(TIM12LPEN, 6); + REGS_BOOL_FIELD(TIM13LPEN, 7); + REGS_BOOL_FIELD(TIM14LPEN, 8); + REGS_BOOL_FIELD(RTCAPBEN, 10); + REGS_BOOL_FIELD(SPI3LPEN, 15); + REGS_BOOL_FIELD(USART3LPEN, 18); + REGS_BOOL_FIELD(PWRLPEN, 28); + }; + class BDCR : public Register32 { public: REGS_BOOL_FIELD(BDRST, 16); @@ -147,6 +165,7 @@ public: REGS_REGISTER_AT(AHB3ENR, 0x38); REGS_REGISTER_AT(APB1ENR, 0x40); REGS_REGISTER_AT(APB2ENR, 0x44); + REGS_REGISTER_AT(APB1LPENR, 0x60); REGS_REGISTER_AT(BDCR, 0x70); REGS_REGISTER_AT(CSR, 0x74); REGS_REGISTER_AT(DCKCFGR2, 0x94); diff --git a/ion/src/shared/dummy/led.cpp b/ion/src/shared/dummy/led.cpp index 12452f37b..985b049a2 100644 --- a/ion/src/shared/dummy/led.cpp +++ b/ion/src/shared/dummy/led.cpp @@ -2,3 +2,16 @@ void Ion::LED::setColor(KDColor c) { } + +void Ion::LED::setBlinking(float blinkPeriod, bool red, bool green, bool blue) { +} + +void Ion::LED::setCharging(bool isPlugged, bool isCharging) { +} + +bool Ion::LED::getLockState() { + return false; +} + +void Ion::LED::setLockState(bool state) { +} diff --git a/ion/src/simulator/led.cpp b/ion/src/simulator/led.cpp index a48d4ca13..985b049a2 100644 --- a/ion/src/simulator/led.cpp +++ b/ion/src/simulator/led.cpp @@ -3,4 +3,15 @@ void Ion::LED::setColor(KDColor c) { } +void Ion::LED::setBlinking(float blinkPeriod, bool red, bool green, bool blue) { +} +void Ion::LED::setCharging(bool isPlugged, bool isCharging) { +} + +bool Ion::LED::getLockState() { + return false; +} + +void Ion::LED::setLockState(bool state) { +} From 123dc1b2671fde6765601c957c086091f2b52563 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Boric Date: Sun, 4 Feb 2018 19:59:11 +0100 Subject: [PATCH 04/43] Enable LED charging Fixes #34 --- apps/usb_timer.cpp | 4 ++-- build/config.mak | 2 ++ ion/src/device/power.cpp | 4 ++-- ion/src/device/wakeup.cpp | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/apps/usb_timer.cpp b/apps/usb_timer.cpp index 18a72e32e..78e2da98a 100644 --- a/apps/usb_timer.cpp +++ b/apps/usb_timer.cpp @@ -16,7 +16,7 @@ bool USBTimer::fire() { m_container->displayExamModePopUp(false); needRedrawing = true; } -#if LED_WHILE_CHARGING +#if EPSILON_LED_WHILE_CHARGING Ion::LED::setCharging(Ion::USB::isPlugged(), Ion::Battery::isCharging()); #endif if (!m_previousPluggedState) { @@ -25,7 +25,7 @@ bool USBTimer::fire() { m_previousPluggedState = true; } else { if (m_previousPluggedState) { -#if LED_WHILE_CHARGING +#if EPSILON_LED_WHILE_CHARGING Ion::LED::setCharging(Ion::USB::isPlugged(), Ion::Battery::isCharging()); #endif m_previousPluggedState = false; diff --git a/build/config.mak b/build/config.mak index bbb0fd9cc..306214236 100644 --- a/build/config.mak +++ b/build/config.mak @@ -6,6 +6,7 @@ DEBUG ?= 0 EPSILON_VERSION ?= 1.3.0 EPSILON_ONBOARDING_APP ?= 1 EPSILON_SOFTWARE_UPDATE_PROMPT ?= 1 +EPSILON_LED_WHILE_CHARGING ?= 1 EPSILON_APPS ?= calculation graph sequence settings statistics probability regression code EPSILON_I18N ?= en fr es de pt @@ -22,3 +23,4 @@ include build/toolchain.$(TOOLCHAIN).mak SFLAGS += -DDEBUG=$(DEBUG) SFLAGS += -DEPSILON_ONBOARDING_APP=$(EPSILON_ONBOARDING_APP) SFLAGS += -DEPSILON_SOFTWARE_UPDATE_PROMPT=$(EPSILON_SOFTWARE_UPDATE_PROMPT) +SFLAGS += -DEPSILON_LED_WHILE_CHARGING=$(EPSILON_LED_WHILE_CHARGING) diff --git a/ion/src/device/power.cpp b/ion/src/device/power.cpp index e57e966c2..0d0cacf93 100644 --- a/ion/src/device/power.cpp +++ b/ion/src/device/power.cpp @@ -24,7 +24,7 @@ void Ion::Power::suspend(bool checkIfPowerKeyReleased) { CM4.SCR()->setSLEEPDEEP(!Ion::LED::getLockState()); while (1) { -#if LED_WHILE_CHARGING +#if EPSILON_LED_WHILE_CHARGING /* Update LEDS * if the standby mode was stopped due to a "stop charging" event, we wait * a while to be sure that the plug state of the USB is up-to-date. */ @@ -34,7 +34,7 @@ void Ion::Power::suspend(bool checkIfPowerKeyReleased) { WakeUp::Device::onPowerKeyDown(); WakeUp::Device::onUSBPlugging(); -#if LED_WHILE_CHARGING +#if EPSILON_LED_WHILE_CHARGING WakeUp::Device::onChargingEvent(); #endif diff --git a/ion/src/device/wakeup.cpp b/ion/src/device/wakeup.cpp index d54ea0f83..3582d6ad3 100644 --- a/ion/src/device/wakeup.cpp +++ b/ion/src/device/wakeup.cpp @@ -31,7 +31,7 @@ void onUSBPlugging() { SYSCFG.EXTICR3()->setEXTI(USB::Device::VbusPin.pin(), USB::Device::VbusPin.group()); EXTI.EMR()->set(USB::Device::VbusPin.pin(), true); -#if LED_WHILE_CHARGING +#if EPSILON_LED_WHILE_CHARGING EXTI.FTSR()->set(USB::Device::VbusPin.pin(), true); #endif EXTI.RTSR()->set(USB::Device::VbusPin.pin(), true); From 2d30b24d4fa86e2ea1e46ccc3f9656e713a8b540 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 19 Jul 2018 10:55:07 +0200 Subject: [PATCH 05/43] [poincare] Fix memory leak in mapReduce --- poincare/src/approximation_engine.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/poincare/src/approximation_engine.cpp b/poincare/src/approximation_engine.cpp index c637c49ad..b423326c2 100644 --- a/poincare/src/approximation_engine.cpp +++ b/poincare/src/approximation_engine.cpp @@ -78,6 +78,7 @@ template Evaluation * ApproximationEngine::mapReduce(const Expres result = intermediateResult; assert(result != nullptr); if (result->isUndefined()) { + delete result; return new Complex(Complex::Undefined()); } } From 20543ec1aa775c9a14b1e6a918aea99a4a41082c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 27 Jul 2018 16:34:32 +0200 Subject: [PATCH 06/43] [poincare] Clean dead code --- poincare/include/poincare/evaluation.h | 28 ------------------ poincare/src/evaluation.cpp | 40 -------------------------- 2 files changed, 68 deletions(-) diff --git a/poincare/include/poincare/evaluation.h b/poincare/include/poincare/evaluation.h index e127f99a1..ef831a250 100644 --- a/poincare/include/poincare/evaluation.h +++ b/poincare/include/poincare/evaluation.h @@ -9,16 +9,6 @@ extern "C" { namespace Poincare { -/* acos, asin, arctan, acosh, asinh, arctanh and log have branch cuts on the - * complex plan. - * - acos, asin, atanh: ]-inf, -1[U]1, +inf[ - * - atan, asinh: ]-inf*i, -i[U]i, +inf*i[ - * - acosh: ]-inf, 1] - * - log: ]-inf, 0] - * They are then multivalued on these cuts. We followed the convention chosen - * by the lib c++ of llvm but it might differ from a calculator to another - * (ie acos(2) = -1.3169578969248*I or 1.3169578969248*I). */ - template class Evaluation { public: @@ -37,9 +27,6 @@ public: virtual Evaluation * createTranspose() const = 0; }; -template -using ComplexFunction = std::complex (*)(const std::complex&); - template class Complex : public std::complex, public Evaluation { public: @@ -66,21 +53,6 @@ public: std::complex createDeterminant() const override { return *this; } Complex * createInverse() const override; Complex * createTranspose() const override { return new Complex(*this); } - /* Complex functions */ - static std::complex pow(const std::complex &c, const std::complex &d); - static std::complex sqrt(const std::complex &c) { - return approximate(c, std::sqrt); - } - static std::complex cos(const std::complex &c) { - return approximate(c, std::cos); - } - static std::complex sin(const std::complex &c) { - return approximate(c, std::sin); - } - static std::complex tan(const std::complex &c) { - return approximate(c, std::tan); - } - static std::complex approximate(const std::complex& c, ComplexFunction approximation); }; template diff --git a/poincare/src/evaluation.cpp b/poincare/src/evaluation.cpp index da74af9e7..daf6ac91d 100644 --- a/poincare/src/evaluation.cpp +++ b/poincare/src/evaluation.cpp @@ -114,46 +114,6 @@ Complex * Complex::createInverse() const { return new Complex(Division::compute(std::complex(1.0), *this)); } -template -std::complex Complex::pow(const std::complex &c, const std::complex &d) { - std::complex result = std::pow(c, d); - /* Cheat: pow openbsd immplementationd is a numerical approximation. - * We though want to avoid evaluating e^(i*pi) to -1+1E-17i. We thus round - * real and imaginary parts to 0 if they are negligible compared to their - * norm. */ - T norm = std::norm(result); - if (norm != 0 && std::fabs(result.real()/norm) <= Expression::epsilon()) { - result.real(0); - } - if (norm != 0 && std::fabs(result.imag()/norm) <= Expression::epsilon()) { - result.imag(0); - } - if (c.imag() == 0 && d.imag() == 0 && (c.real() >= 0 || d.real() == std::round(d.real()))) { - result.imag(0); - } - return result; -} - -template -std::complex Complex::approximate(const std::complex& c, ComplexFunction function) { - std::complex result = function(c); - /* Cheat: openbsd trigonometric functions (cos, sin, tan, sqrt) are numerical - * implementation and thus are approximative. The error epsilon is ~1E-7 - * on float and ~1E-15 on double. In order to avoid weird results as - * cos(90) = 6E-17, we neglect the result when its ratio with the argument - * (pi in the exemple) is smaller than epsilon. - * We can't do that for all evaluation as the user can operate on values as - * small as 1E-308 (in double) and most results still be correct. */ - T inputNorm = std::abs(c); - if (inputNorm != 0 && std::fabs(result.real()/inputNorm) <= Expression::epsilon()) { - result.real(0); - } - if (inputNorm != 0 && std::fabs(result.imag()/inputNorm) <= Expression::epsilon()) { - result.imag(0); - } - return result; -} - template MatrixComplex::MatrixComplex(std::complex * operands, int numberOfRows, int numberOfColumns) : m_numberOfRows(numberOfRows), From 8107d63a6b3621c090a05c60ecfb20529a1887bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 31 Jul 2018 10:29:08 +0200 Subject: [PATCH 07/43] [poincare] Evaluation: implement destructor of MatrixComplex --- poincare/include/poincare/evaluation.h | 2 +- poincare/src/evaluation.cpp | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/poincare/include/poincare/evaluation.h b/poincare/include/poincare/evaluation.h index ef831a250..2da37f262 100644 --- a/poincare/include/poincare/evaluation.h +++ b/poincare/include/poincare/evaluation.h @@ -63,7 +63,7 @@ public: std::complex undef = std::complex(NAN, NAN); return MatrixComplex(&undef, 1, 1); } - virtual ~MatrixComplex() {} + ~MatrixComplex(); typename Poincare::Evaluation::Type type() const override { return Poincare::Evaluation::Type::MatrixComplex; } const std::complex complexOperand(int i) const { return m_operands[i]; } int numberOfComplexOperands() const { return m_numberOfRows*m_numberOfColumns; } diff --git a/poincare/src/evaluation.cpp b/poincare/src/evaluation.cpp index daf6ac91d..004b5a039 100644 --- a/poincare/src/evaluation.cpp +++ b/poincare/src/evaluation.cpp @@ -131,6 +131,13 @@ MatrixComplex::MatrixComplex(std::complex * operands, int numberOfRows, in } } +template +MatrixComplex::~MatrixComplex() { + if (m_operands != nullptr) { + delete [] m_operands; + } +} + template Expression * MatrixComplex::complexToExpression(Expression::ComplexFormat complexFormat) const { Expression ** operands = new Expression * [numberOfComplexOperands()]; From bb9b86516a9d2ceff286753405314c03b1a069c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 31 Jul 2018 11:13:05 +0200 Subject: [PATCH 08/43] [poincare] MatrixComplex: rule of 5 --- poincare/include/poincare/evaluation.h | 5 +++ poincare/src/evaluation.cpp | 42 ++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/poincare/include/poincare/evaluation.h b/poincare/include/poincare/evaluation.h index 2da37f262..988e7204e 100644 --- a/poincare/include/poincare/evaluation.h +++ b/poincare/include/poincare/evaluation.h @@ -64,6 +64,11 @@ public: return MatrixComplex(&undef, 1, 1); } ~MatrixComplex(); + MatrixComplex(MatrixComplex&& other); // C++11 move constructor + MatrixComplex& operator=(MatrixComplex&& other); // C++11 move assignment operator + MatrixComplex(const MatrixComplex& other); // C++11 copy constructor + MatrixComplex& operator=(const MatrixComplex& other) = delete; // C++11 copy assignment operator + typename Poincare::Evaluation::Type type() const override { return Poincare::Evaluation::Type::MatrixComplex; } const std::complex complexOperand(int i) const { return m_operands[i]; } int numberOfComplexOperands() const { return m_numberOfRows*m_numberOfColumns; } diff --git a/poincare/src/evaluation.cpp b/poincare/src/evaluation.cpp index 004b5a039..089beb925 100644 --- a/poincare/src/evaluation.cpp +++ b/poincare/src/evaluation.cpp @@ -138,6 +138,48 @@ MatrixComplex::~MatrixComplex() { } } +template +MatrixComplex::MatrixComplex(MatrixComplex&& other) { + // Pilfer other's data + m_operands = other.m_operands; + m_numberOfRows = other.m_numberOfRows; + m_numberOfColumns = other.m_numberOfColumns; + + // Reset other + other.m_operands = nullptr; + other.m_numberOfRows = 0; + other.m_numberOfColumns = 0; +} + +template +MatrixComplex::MatrixComplex(const MatrixComplex& other) { + // Copy other's data + m_numberOfRows = other.m_numberOfRows; + m_numberOfColumns = other.m_numberOfColumns; + std::complex * operands = new std::complex [m_numberOfRows*m_numberOfColumns]; + for (int i=0; i +MatrixComplex& MatrixComplex::operator=(MatrixComplex && other) { + if (this != &other) { + if (m_operands) { delete [] m_operands; } + // Pilfer other's ivars + m_operands = other.m_operands; + m_numberOfRows = other.m_numberOfRows; + m_numberOfColumns = other.m_numberOfColumns; + + // Reset other + other.m_operands = nullptr; + other.m_numberOfRows = 0; + other.m_numberOfColumns = 0; + } + return *this; +} + template Expression * MatrixComplex::complexToExpression(Expression::ComplexFormat complexFormat) const { Expression ** operands = new Expression * [numberOfComplexOperands()]; From 4eb450e94b9530d202ac0739e6afadf7a91ecfa7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 3 Aug 2018 14:14:32 +0200 Subject: [PATCH 09/43] [escher] When handling event on text, display the maximal number of significant digits --- escher/src/expression_layout_field.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/escher/src/expression_layout_field.cpp b/escher/src/expression_layout_field.cpp index 3d095bec3..b0c965155 100644 --- a/escher/src/expression_layout_field.cpp +++ b/escher/src/expression_layout_field.cpp @@ -213,7 +213,7 @@ bool ExpressionLayoutField::handleEventWithText(const char * text, bool indentat m_contentView.cursor()->insertText(text); return true; } - Poincare::ExpressionLayout * resultLayout = resultExpression->createLayout(Poincare::Preferences::sharedPreferences()->displayMode(), Poincare::Preferences::sharedPreferences()->numberOfSignificantDigits()); + Poincare::ExpressionLayout * resultLayout = resultExpression->createLayout(Poincare::Preferences::sharedPreferences()->displayMode(), Poincare::PrintFloat::k_numberOfStoredSignificantDigits); delete resultExpression; if (currentNumberOfLayouts + resultLayout->numberOfDescendants(true) >= k_maxNumberOfLayouts) { delete resultLayout; From 9fbdc605728811390a6ca8e1a409762d5b11e282 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 3 Aug 2018 14:15:12 +0200 Subject: [PATCH 10/43] [poincare] Add test to Decimal::convert_expression_to_text --- poincare/test/convert_expression_to_text.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/poincare/test/convert_expression_to_text.cpp b/poincare/test/convert_expression_to_text.cpp index fbdc0a079..6e0036f8e 100644 --- a/poincare/test/convert_expression_to_text.cpp +++ b/poincare/test/convert_expression_to_text.cpp @@ -189,6 +189,14 @@ QUIZ_CASE(poincare_decimal_to_text) { assert_expression_prints_to(&e15, "0.000001", DecimalMode); Decimal e16(0.000000999999999901200121020102010201201201021099995); assert_expression_prints_to(&e16, "9.999999999012E-7", DecimalMode, 14); + Decimal e17(9999999999999.6); + assert_expression_prints_to(&e17, "9999999999999.6", DecimalMode, 14); + Decimal e18(99999999999999.6); + assert_expression_prints_to(&e18, "1E14", DecimalMode, 14); + Decimal e19(999999999999999.6); + assert_expression_prints_to(&e19, "1E15", DecimalMode, 14); + Decimal e20(9999999999999999.6); + assert_expression_prints_to(&e20, "1E16", DecimalMode, 14); } QUIZ_CASE(poincare_approximation_to_text) { From 4dff3a26090789bf6d2b4f59448777c44d170c69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 16 Aug 2018 18:07:16 +0200 Subject: [PATCH 11/43] [poincare] Fix power simplification: a^(b+c+d) --> a^b*a^(c+d) instead of a^b*a^c --- poincare/src/power.cpp | 8 ++++---- poincare/test/power.cpp | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/poincare/src/power.cpp b/poincare/src/power.cpp index ff7c1502e..5124ede3b 100644 --- a/poincare/src/power.cpp +++ b/poincare/src/power.cpp @@ -413,7 +413,7 @@ Expression * Power::shallowReduce(Context& context, AngleUnit angleUnit) { } } } - // a^(b+c) -> Rational(a^b)*a^c with a and b rational and a != 0 + // a^(b+c+...) -> Rational(a^b)*a^c with a and b rational and a != 0 if (!letPowerAtRoot && operand(0)->type() == Type::Rational && !static_cast(operand(0))->isZero() && operand(1)->type() == Type::Addition) { Addition * a = static_cast(editableOperand(1)); // Check is b is rational @@ -423,11 +423,11 @@ Expression * Power::shallowReduce(Context& context, AngleUnit angleUnit) { if (RationalExponentShouldNotBeReduced(rationalBase, rationalIndex)) { return this; } - Power * p1 = static_cast(clone()); - replaceOperand(a, a->editableOperand(1), true); + Power * p1 = new Power(editableOperand(0), a->editableOperand(0), true); // a^b Power * p2 = static_cast(clone()); + static_cast(p2->editableOperand(1))->removeOperand(p2->editableOperand(1)->editableOperand(0), true); // p2 = a^(c+...) Multiplication * m = new Multiplication(p1, p2, false); - simplifyRationalRationalPower(p1, static_cast(p1->editableOperand(0)), static_cast(p1->editableOperand(1)->editableOperand(0)), context, angleUnit); + simplifyRationalRationalPower(p1, static_cast(p1->editableOperand(0)), static_cast(p1->editableOperand(1)), context, angleUnit); replaceWith(m, true); return m->shallowReduce(context, angleUnit); } diff --git a/poincare/test/power.cpp b/poincare/test/power.cpp index 96c0b4c4a..21b8b29ac 100644 --- a/poincare/test/power.cpp +++ b/poincare/test/power.cpp @@ -89,4 +89,5 @@ QUIZ_CASE(poincare_power_simplify) { assert_parsed_expression_simplify_to("(1+R(2)+R(3))^5", "296+224*R(2)+184*R(3)+120*R(6)"); assert_parsed_expression_simplify_to("(P+R(2)+R(3)+x)^(-3)", "1/(11*R(2)+9*R(3)+15*x+6*R(6)*x+3*R(2)*x^2+3*R(3)*x^2+x^3+15*P+6*R(6)*P+6*R(2)*x*P+6*R(3)*x*P+3*x^2*P+3*R(2)*P^2+3*R(3)*P^2+3*x*P^2+P^3)"); assert_parsed_expression_simplify_to("1.006666666666667^60", "(1006666666666667/1000000000000000)^60"); + assert_parsed_expression_simplify_to("2^(6+P+x)", "64*2^(x+P)"); } From 5f1da3b8243b7ddb9185d65ca0c96a9b52e7b66b Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Thu, 9 Aug 2018 15:03:12 +0200 Subject: [PATCH 12/43] [ion/device/bench] Count display memory errors --- ion/src/device/bench/command/display.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/ion/src/device/bench/command/display.cpp b/ion/src/device/bench/command/display.cpp index 98e536d54..224c83d47 100644 --- a/ion/src/device/bench/command/display.cpp +++ b/ion/src/device/bench/command/display.cpp @@ -1,6 +1,7 @@ #include "command.h" #include #include +#include namespace Ion { namespace Device { @@ -46,6 +47,8 @@ void Display(const char * input) { } } + int numberOfInvalidPixels = 0; + for (int i=0; i TIM1(1); -constexpr TIM TIM2(2); constexpr TIM TIM3(3); -constexpr TIM TIM4(4); -constexpr TIM TIM5(5); -constexpr TIM TIM6(6); -constexpr TIM TIM7(7); -constexpr TIM TIM8(8); -constexpr TIM TIM9(9); -constexpr TIM TIM10(10); -constexpr TIM TIM11(11); -constexpr TIM TIM12(12); -constexpr TIM TIM13(13); -constexpr TIM TIM14(14); #endif From c8b26a2bd5a58ce5b90c997b96e80f8cdf96e0c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 23 Aug 2018 15:57:38 +0200 Subject: [PATCH 14/43] [build] Revert compile FLAG --- build/config.mak | 2 -- 1 file changed, 2 deletions(-) diff --git a/build/config.mak b/build/config.mak index 4d4b73a68..2b6e610a3 100644 --- a/build/config.mak +++ b/build/config.mak @@ -7,7 +7,6 @@ EPSILON_VERSION ?= 1.6.0 EPSILON_ONBOARDING_APP ?= 1 EPSILON_SOFTWARE_UPDATE_PROMPT ?= 1 EPSILON_APPS ?= calculation graph code statistics probability solver sequence regression settings -EPSILON_LED_WHILE_CHARGING = 1 EPSILON_I18N ?= en fr es de pt EPSILON_GETOPT ?= 0 @@ -25,4 +24,3 @@ SFLAGS += -DDEBUG=$(DEBUG) SFLAGS += -DEPSILON_ONBOARDING_APP=$(EPSILON_ONBOARDING_APP) SFLAGS += -DEPSILON_SOFTWARE_UPDATE_PROMPT=$(EPSILON_SOFTWARE_UPDATE_PROMPT) SFLAGS += -DEPSILON_GETOPT=$(EPSILON_GETOPT) -SFLAGS += -DEPSILON_LED_WHILE_CHARGING=$(EPSILON_LED_WHILE_CHARGING) From 6add685ce08a2d3d14cad07cb73bac4295edb507 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 23 Aug 2018 16:01:13 +0200 Subject: [PATCH 15/43] [ion] Revert implementation of msleep using internal clock --- ion/src/device/device.cpp | 47 ++++++--------------------------------- ion/src/device/device.h | 39 -------------------------------- 2 files changed, 7 insertions(+), 79 deletions(-) diff --git a/ion/src/device/device.cpp b/ion/src/device/device.cpp index 348aafafc..485fc6ca3 100644 --- a/ion/src/device/device.cpp +++ b/ion/src/device/device.cpp @@ -20,20 +20,15 @@ extern "C" { // Public Ion methods +/* TODO: The delay methods 'msleep' and 'usleep' are currently dependent on the + * optimizations chosen by the compiler. To prevent that and to gain in + * precision, we could use the controller cycle counter (Systick). */ + void Ion::msleep(long ms) { - // We need a frequency high enough to not overflow the prescaler, - // which is 16 bits wide. - constexpr int TIM6_FREQ = 4*1000; - - Ion::Device::waitTIM6(Ion::Device::SYSBUS_FREQ / TIM6_FREQ, ms * TIM6_FREQ / 1000); + for (volatile long i=0; i<8852*ms; i++) { + __asm volatile("nop"); + } } - -/* TODO: The delay method 'usleep' is currently dependent on the optimizations - * chosen by the compiler. To prevent that and to gain in precision, we could - * use the controller cycle counter (Systick). We can't use a regular timer - * (like TIM6) for this since setting it up takes a significant amount of time - * in these timescales. - */ void Ion::usleep(long us) { for (volatile long i=0; i<9*us; i++) { __asm volatile("nop"); @@ -272,8 +267,6 @@ void initClocks() { // APB1 bus // We're using TIM3 for the LEDs RCC.APB1ENR()->setTIM3EN(true); - // We're using TIM6 for sleeping - RCC.APB1ENR()->setTIM6EN(true); RCC.APB1ENR()->setPWREN(true); // APB2 bus @@ -300,31 +293,5 @@ void shutdownClocks() { RCC.AHB3ENR()->setFSMCEN(false); } -void waitTIM6(unsigned short prescaler, long cycles) { - while (cycles > 0) { - // TIM6 counts up to 2^16-1, make sure we won't overflow the counter. - uint16_t iterCycles = (cycles > 0xFFFF ? 0xFFFF : cycles); - - // Initialize TIM6 - TIM6.PSC()->set(prescaler); - TIM6.CNT()->set(0); - TIM6.ARR()->set(iterCycles); - TIM6.EGR()->setUG(true); - TIM6.SR()->setUIF(false); - TIM6.CR1()->setCEN(true); - - // Wait until the timer elapses - do { - // TODO: Use interrupts instead of busy-waiting - __asm volatile("nop"); - } while (TIM6.SR()->getUIF() == false); - - // Stop TIM6 - TIM6.CR1()->setCEN(false); - - cycles -= iterCycles; - } -} - } } diff --git a/ion/src/device/device.h b/ion/src/device/device.h index 4757ff3ba..16af422b6 100644 --- a/ion/src/device/device.h +++ b/ion/src/device/device.h @@ -25,45 +25,6 @@ void shutdownClocks(); constexpr static int SerialNumberLength = 16; void copySerialNumber(char * buffer); -void waitTIM6(unsigned short prescaler, long cycles); - -/* Pin | Role | Mode | Function - * -----+-------------------+-----------------------+---------- - * PA0 | Battery sensing | | - * PA2 | LCD D4 | Alternate Function 12 | FMSC_D4 - * PA3 | LCD D5 | Alternate Function 12 | FSMC_D5 - * PA4 | LCD D6 | Alternate Function 12 | FSMC_D6 - * PA5 | LCD D7 | Alternate Function 12 | FSMC_D7 - * PA6 | LED red | Alternate Function XX | TIM3_CH1 - * PA7 | LED green | Alternate Function XX | TIM3_CH2 - * PA9 | USB VBUS prob | Input, pulled down | - * PB0 | LED blue | Alternate Function XX | TIM3_CH3 - * PB1 | Keyboard row A | Output, open-drain | - * PB2 | Keyboard row B | Output, open-drain | - * PB3 | Keyboard row C | Output, open-drain | - * PB4 | Keyboard row D | Output, open-drain | - * PB5 | Keyboard row E | Output, open-drain | - * PB6 | Keyboard row F | Output, open-drain | - * PB7 | Keyboard row G | Output, open-drain | - * PB8 | Keyboard row H | Output, open-drain | - * PB9 | Keyboard row I | Output, open-drain | - * PB10 | Keyboard row J | Output, open-drain | - * PB14 | LCD D0 | Alternate Function 12 | FSMC_D0 - * PC0 | Keyboard column 1 | Input, pulled-up | - * PC1 | Keyboard column 2 | Input, pulled-up | - * PC3 | LCD data/command | Alternate Function 12 | FSMC_A0 - * PC4 | LCD chip select | Alternate Function 12 | FSMC_NE4 - * PC5 | LCD read signal | Alternate Function 12 | FSMC_NOE - * PC6 | LCD D1 | Alternate Function 12 | FSMC_D7 - * PC9 | LCD backlight | Alternate Function 12 | TIM3_CH4 - * PC11 | LCD D2 | Alternate Function 12 | FSMC_D2 - * PC12 | LCD D3 | Alternate Function 12 | FSMC_D3 - * PC13 | Keyboard column 3 | Input, pulled-up | - * PC14 | Keyboard column 4 | Input, pulled-up | - * PC15 | Keyboard column 5 | Input, pulled-up | - * PD2 | LCD write signal | Alternate Function 12 | FSMC_NWE - */ - } } From 5eb18c601c4dcd820a6c17f6ace641e0e9f4d31e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 23 Aug 2018 16:05:08 +0200 Subject: [PATCH 16/43] [ion] Add registers in RCC --- ion/src/device/regs/rcc.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ion/src/device/regs/rcc.h b/ion/src/device/regs/rcc.h index d00ad9608..0536441d4 100644 --- a/ion/src/device/regs/rcc.h +++ b/ion/src/device/regs/rcc.h @@ -107,6 +107,13 @@ public: REGS_BOOL_FIELD(SYSCFGEN, 14); }; + class AHB1LPENR : public Register32 { + public: + using Register32::Register32; + REGS_BOOL_FIELD(GPIOBLPEN, 1); + REGS_BOOL_FIELD(GPIOCLPEN, 2); + }; + class APB1LPENR : public Register32 { public: using Register32::Register32; @@ -128,6 +135,7 @@ public: REGS_REGISTER_AT(AHB3ENR, 0x38); REGS_REGISTER_AT(APB1ENR, 0x40); REGS_REGISTER_AT(APB2ENR, 0x44); + REGS_REGISTER_AT(AHB1LPENR, 0x50); REGS_REGISTER_AT(APB1LPENR, 0x60); REGS_REGISTER_AT(DCKCFGR2, 0x94); private: From 4613dd9d8fac8d4f719c9a45088d84ed6c310836 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 23 Aug 2018 16:05:52 +0200 Subject: [PATCH 17/43] [ion] Change LED API --- apps/exam_pop_up_controller.cpp | 5 +- ion/include/ion/led.h | 11 +-- ion/src/device/device.cpp | 35 ++++++-- ion/src/device/device.h | 4 +- ion/src/device/led.cpp | 142 +++++++++++--------------------- ion/src/device/led.h | 14 ++-- ion/src/device/power.cpp | 9 +- ion/src/shared/dummy/led.cpp | 16 +--- ion/src/simulator/Makefile | 2 +- ion/src/simulator/led.cpp | 17 ---- 10 files changed, 97 insertions(+), 158 deletions(-) delete mode 100644 ion/src/simulator/led.cpp diff --git a/apps/exam_pop_up_controller.cpp b/apps/exam_pop_up_controller.cpp index 47ab4629b..7e8736a74 100644 --- a/apps/exam_pop_up_controller.cpp +++ b/apps/exam_pop_up_controller.cpp @@ -58,10 +58,9 @@ ExamPopUpController::ContentView::ContentView(Responder * parentResponder) : AppsContainer * container = (AppsContainer *)controller->app()->container(); if (controller->isActivatingExamMode()) { container->reset(); - Ion::LED::setBlinking(0.5, true, false, false); - Ion::LED::setLockState(true); + Ion::LED::setColor(KDColorRed); + Ion::LED::setBlinking(1.0f, 0.1f); } else { - Ion::LED::setLockState(false); Ion::LED::setColor(KDColorBlack); } container->refreshPreferences(); diff --git a/ion/include/ion/led.h b/ion/include/ion/led.h index b2d40cad7..dfb69c420 100644 --- a/ion/include/ion/led.h +++ b/ion/include/ion/led.h @@ -6,16 +6,9 @@ namespace Ion { namespace LED { +KDColor getColor(); void setColor(KDColor c); -void setBlinking(float blinkLength, bool red, bool green, bool blue); -void setCharging(bool isPluggedIn, bool isCharging); - -/* - * This is just a flag to see if we should mess with the LEDs on our own. - * Especially useful for keeping the LED blinking while in exam mode. - */ -bool getLockState(); -void setLockState(bool state); +void setBlinking(float period, float dutyCycle); } } diff --git a/ion/src/device/device.cpp b/ion/src/device/device.cpp index 485fc6ca3..d23dd35d9 100644 --- a/ion/src/device/device.cpp +++ b/ion/src/device/device.cpp @@ -169,7 +169,7 @@ void initPeripherals() { SWD::Device::init(); } -void shutdownPeripherals() { +void shutdownPeripherals(bool keepLEDAwake) { SWD::Device::shutdown(); Console::Device::shutdown(); #if USE_SD_CARD @@ -177,7 +177,9 @@ void shutdownPeripherals() { #endif USB::Device::shutdown(); Battery::Device::shutdown(); - LED::Device::shutdown(); + if (!keepLEDAwake) { + LED::Device::shutdown(); + } Keyboard::Device::shutdown(); Backlight::Device::shutdown(); Display::Device::shutdown(); @@ -279,16 +281,33 @@ void initClocks() { RCC.APB2ENR()->set(apb2enr); } -void shutdownClocks() { +void shutdownClocks(bool keepLEDAwake) { // APB2 bus RCC.APB2ENR()->set(0x00008000); // Reset value - // APB1 - RCC.APB1ENR()->set(0x00000402); - RCC.APB1LPENR()->setTIM3LPEN(true); // Keep the LED going + if (keepLEDAwake) { + /* TODO: enter sleep mode even if the LED is used and enable LED in low + * power mode. */ + // Keep the LED going: peripheral clock enable in low power mode register + /*RCC.APB1LPENR()->setTIM3LPEN(true); + RCC.AHB1LPENR()->setGPIOBLPEN(true); + RCC.AHB1LPENR()->setGPIOCLPEN(true);*/ - // AHB1 bus - RCC.AHB1ENR()->set(0); // Reset value + // APB1 + class RCC::APB1ENR apb1enr(0x00000400); + apb1enr.setTIM3EN(true); + RCC.APB1ENR()->set(apb1enr); + // AHB1 bus + class RCC::AHB1ENR ahb1enr(0); // Reset value + ahb1enr.setGPIOBEN(true); + ahb1enr.setGPIOCEN(true); + RCC.AHB1ENR()->set(ahb1enr); + } else { + // APB1 + RCC.APB1ENR()->set(0x00000400); + // AHB1 bus + RCC.AHB1ENR()->set(0); // Reset value + } RCC.AHB3ENR()->setFSMCEN(false); } diff --git a/ion/src/device/device.h b/ion/src/device/device.h index 16af422b6..a95bf85e7 100644 --- a/ion/src/device/device.h +++ b/ion/src/device/device.h @@ -14,9 +14,9 @@ void coreReset(); void jumpReset(); void initPeripherals(); -void shutdownPeripherals(); +void shutdownPeripherals(bool keepLEDAwake = false); void initClocks(); -void shutdownClocks(); +void shutdownClocks(bool keepLEDAwake = false); /* The serial number is 96 bits long. That's equal to 16 digits in base 64. We * expose a convenient "copySerialNumber" routine which can be called without diff --git a/ion/src/device/led.cpp b/ion/src/device/led.cpp index 3557ffe79..26cce0243 100644 --- a/ion/src/device/led.cpp +++ b/ion/src/device/led.cpp @@ -6,35 +6,32 @@ // Public Ion::LED methods -void Ion::LED::setColor(KDColor c) { - if (getLockState()) { - return; - } +static KDColor sLedColor = KDColorBlack; - initTimer(Ion::LED::Device::Mode::PWM); +KDColor Ion::LED::getColor() { + return sLedColor; +} + +void Ion::LED::setColor(KDColor c) { + sLedColor = c; Ion::LED::Device::setColorStatus(Ion::LED::Device::Color::RED, true); Ion::LED::Device::setColorStatus(Ion::LED::Device::Color::GREEN, true); Ion::LED::Device::setColorStatus(Ion::LED::Device::Color::BLUE, true); - TIM3.CCR2()->set(Device::dutyCycleForUInt8(c.red())); - TIM3.CCR3()->set(Device::dutyCycleForUInt8(c.blue())); - TIM3.CCR4()->set(Device::dutyCycleForUInt8(c.green())); + constexpr float maxColorValue = (float)((1 << 8) -1); + Device::setPeriodAndDutyCycles(Device::Mode::PWM, c.red()/maxColorValue, c.green()/maxColorValue, c.blue()/maxColorValue); } -void Ion::LED::setBlinking(float blinkPeriod, bool red, bool green, bool blue) { - if (getLockState()) { - return; - } +void Ion::LED::setBlinking(float period, float dutyCycle) { + Ion::LED::Device::setColorStatus(Ion::LED::Device::Color::RED, sLedColor.red() > 0); + Ion::LED::Device::setColorStatus(Ion::LED::Device::Color::GREEN, sLedColor.green() > 0); + Ion::LED::Device::setColorStatus(Ion::LED::Device::Color::BLUE, sLedColor.blue() > 0); - initTimer(Ion::LED::Device::Mode::BLINK, blinkPeriod); - - Ion::LED::Device::setColorStatus(Ion::LED::Device::Color::RED, red); - Ion::LED::Device::setColorStatus(Ion::LED::Device::Color::GREEN, green); - Ion::LED::Device::setColorStatus(Ion::LED::Device::Color::BLUE, blue); + Device::setPeriodAndDutyCycles(Device::Mode::BLINK, dutyCycle, dutyCycle, dutyCycle, period); } -void Ion::LED::setCharging(bool isPluggedIn, bool isCharging) { +/*void Ion::LED::setCharging(bool isPluggedIn, bool isCharging) { if (!isPluggedIn) { Ion::LED::setColor(KDColorBlack); } @@ -46,17 +43,7 @@ void Ion::LED::setCharging(bool isPluggedIn, bool isCharging) { Ion::LED::setColor(KDColorGreen); } } -} - -static bool lockState = false; - -bool Ion::LED::getLockState() { - return lockState; -} - -void Ion::LED::setLockState(bool state) { - lockState = state; -} +}*/ // Private Ion::Device::LED methods @@ -66,9 +53,12 @@ namespace Device { void init() { initGPIO(); + initTimer(); } void shutdown() { + shutdownTimer(); + shutdownGPIO(); } void initGPIO() { @@ -88,68 +78,7 @@ void shutdownGPIO() { } } -void initTimer(Mode mode, float blinkPeriod) { - constexpr int TIM3_FREQ = 4*1000; - - /* Pulse width modulation mode allows you to generate a signal with a - * frequency determined by the value of the TIMx_ARR register and a duty cycle - * determined by the value of the TIMx_CCRx register. */ - switch (mode) { - case Ion::LED::Device::Mode::PWM: - /* Let's set the prescaler to 1. Increasing the prescaler would slow down the - * modulation, which can be useful when debugging. */ - TIM3.PSC()->set(1); - TIM3.ARR()->set(PWMPeriod); - TIM3.CCR2()->set(0); - TIM3.CCR3()->set(0); - TIM3.CCR4()->set(0); - break; - case Ion::LED::Device::Mode::BLINK: - /* We still want to do PWM, but at a rate slow enough to blink. */ - TIM3.PSC()->set(Ion::Device::SYSBUS_FREQ / TIM3_FREQ); - TIM3.ARR()->set(blinkPeriod * TIM3_FREQ); - TIM3.CCR2()->set(blinkPeriod * TIM3_FREQ / 2); - TIM3.CCR3()->set(blinkPeriod * TIM3_FREQ / 2); - TIM3.CCR4()->set(blinkPeriod * TIM3_FREQ / 2); - break; - } - - // Set Channels 2-4 as outputs, PWM mode 1 - TIM3.CCMR()->setOC2M(TIM::CCMR::OCM::PWM1); - TIM3.CCMR()->setOC3M(TIM::CCMR::OCM::PWM1); - TIM3.CCMR()->setOC4M(TIM::CCMR::OCM::PWM1); - - // Output preload enable for channels 2-4 - TIM3.CCMR()->setOC2PE(true); - TIM3.CCMR()->setOC3PE(true); - TIM3.CCMR()->setOC4PE(true); - - // Auto-reload preload enable - TIM3.CR1()->setARPE(true); - - // Enable Capture/Compare for channel 2 to 4 - TIM3.CCER()->setCC2E(true); - TIM3.CCER()->setCC3E(true); - TIM3.CCER()->setCC4E(true); - - TIM3.BDTR()->setMOE(true); - - TIM3.CR1()->setCEN(true); -} - -void initTimerColor() { - /* Let's set the prescaler to 1. Increasing the prescaler would slow down the - * modulation, which can be useful when debugging. */ - TIM3.PSC()->set(1); - - /* Pulse width modulation mode allows you to generate a signal with a - * frequency determined by the value of the TIMx_ARR register and a duty cycle - * determined by the value of the TIMx_CCRx register. */ - TIM3.ARR()->set(PWMPeriod); - TIM3.CCR2()->set(0); - TIM3.CCR3()->set(0); - TIM3.CCR4()->set(0); - +void initTimer() { // Output preload enable for channels 2-4 TIM3.CCMR()->setOC2PE(true); TIM3.CCMR()->setOC3PE(true); @@ -174,6 +103,33 @@ void shutdownTimer() { setColorStatus(Ion::LED::Device::Color::BLUE, false); } +/* Pulse width modulation mode allows you to generate a signal with a + * frequency determined by the value of the TIMx_ARR register and a duty cycle + * determined by the value of the TIMx_CCRx register. */ + +void setPeriodAndDutyCycles(Mode mode, float dutyCycleRed, float dutyCycleGreen, float dutyCycleBlue, float period) { + constexpr int TIM3_FREQ = 4*1000; + switch (mode) { + case Mode::PWM: + /* Let's set the prescaler to 1. Increasing the prescaler would slow down the + * modulation, which can be useful when debugging. */ + TIM3.PSC()->set(1); + TIM3.ARR()->set(PWMPeriod); + period = PWMPeriod; + break; + case Mode::BLINK: + /* We still want to do PWM, but at a rate slow enough to blink. */ + TIM3.PSC()->set(Ion::Device::SYSBUS_FREQ / TIM3_FREQ); + TIM3.ARR()->set(period * TIM3_FREQ); + period *= TIM3_FREQ; // as we pre-scaled, we update the period + break; + } + + TIM3.CCR2()->set(dutyCycleRed*period); + TIM3.CCR3()->set(dutyCycleBlue*period); + TIM3.CCR4()->set(dutyCycleGreen*period); +} + void setColorStatus(Color color, bool enable) { switch (color) { case Ion::LED::Device::Color::RED: @@ -188,7 +144,7 @@ void setColorStatus(Color color, bool enable) { } } -void enforceState(bool red, bool green, bool blue) { +/*void enforceState(bool red, bool green, bool blue) { bool states[3] = {red, green, blue}; for (int i=0; i<3; i++) { GPIOPin p = RGBPins[i]; @@ -200,7 +156,7 @@ void enforceState(bool red, bool green, bool blue) { p.group().PUPDR()->setPull(p.pin(), GPIO::PUPDR::Pull::None); } } -} +}*/ } } diff --git a/ion/src/device/led.h b/ion/src/device/led.h index 19a918366..426ce9607 100644 --- a/ion/src/device/led.h +++ b/ion/src/device/led.h @@ -17,23 +17,24 @@ namespace Device { enum Mode { PWM, BLINK -} ; +}; enum Color { RED, GREEN, BLUE -} ; +}; void init(); void shutdown(); +void setPeriodAndDutyCycles(Mode mode, float dutyCycleRed, float dutyCycleGreen, float dutyCycleBlue, float period = 0.0f); void setColorStatus(Color color, bool enable); /* This call bypasses the timer, and immediately enforces a given LED state. */ -void enforceState(bool red, bool green, bool blue); +//void enforceState(bool red, bool green, bool blue); void initGPIO(); void shutdownGPIO(); -void initTimer(Mode mode, float blinkPeriod = 0); +void initTimer(); void shutdownTimer(); constexpr static GPIOPin RGBPins[] = { @@ -43,11 +44,6 @@ constexpr static GPIOPin RGBPins[] = { constexpr uint16_t PWMPeriod = 40000; -inline uint16_t dutyCycleForUInt8(uint8_t value) { - /* This function is a linear function from colors [0->255] to duty cycles [0->PWMPeriod].*/ - return ((uint32_t)value)*(PWMPeriod/255); -} - } } } diff --git a/ion/src/device/power.cpp b/ion/src/device/power.cpp index 0d0cacf93..021d75cc6 100644 --- a/ion/src/device/power.cpp +++ b/ion/src/device/power.cpp @@ -9,6 +9,7 @@ #include "regs/regs.h" void Ion::Power::suspend(bool checkIfPowerKeyReleased) { + bool isLEDActive = Ion::LED::getColor() != KDColorBlack; if (checkIfPowerKeyReleased) { /* Wait until power is released to avoid restarting just after suspending */ bool isPowerDown = true; @@ -17,11 +18,11 @@ void Ion::Power::suspend(bool checkIfPowerKeyReleased) { isPowerDown = scan.keyDown(Keyboard::Key::B2); } } - Device::shutdownPeripherals(); + Device::shutdownPeripherals(isLEDActive); PWR.CR()->setLPDS(true); // Turn the regulator off. Takes longer to wake up. PWR.CR()->setFPDS(true); // Put the flash to sleep. Takes longer to wake up. - CM4.SCR()->setSLEEPDEEP(!Ion::LED::getLockState()); + CM4.SCR()->setSLEEPDEEP(!isLEDActive); while (1) { #if EPSILON_LED_WHILE_CHARGING @@ -29,7 +30,7 @@ void Ion::Power::suspend(bool checkIfPowerKeyReleased) { * if the standby mode was stopped due to a "stop charging" event, we wait * a while to be sure that the plug state of the USB is up-to-date. */ msleep(200); - Ion::LED::setCharging(Ion::USB::isPlugged(), Ion::Battery::isCharging()); + //Ion::LED::setCharging(Ion::USB::isPlugged(), Ion::Battery::isCharging()); #endif WakeUp::Device::onPowerKeyDown(); @@ -38,7 +39,7 @@ void Ion::Power::suspend(bool checkIfPowerKeyReleased) { WakeUp::Device::onChargingEvent(); #endif - Device::shutdownClocks(); + Device::shutdownClocks(isLEDActive); /* To enter sleep, we need to issue a WFE instruction, which waits for the * event flag to be set and then clears it. However, the event flag might diff --git a/ion/src/shared/dummy/led.cpp b/ion/src/shared/dummy/led.cpp index 985b049a2..725c7c29d 100644 --- a/ion/src/shared/dummy/led.cpp +++ b/ion/src/shared/dummy/led.cpp @@ -1,17 +1,9 @@ #include -void Ion::LED::setColor(KDColor c) { +KDColor getColor() { + return KDColorBlack; } -void Ion::LED::setBlinking(float blinkPeriod, bool red, bool green, bool blue) { -} +void setColor(KDColor c) {} -void Ion::LED::setCharging(bool isPlugged, bool isCharging) { -} - -bool Ion::LED::getLockState() { - return false; -} - -void Ion::LED::setLockState(bool state) { -} +void setBlinking(float period, float dutyCycle) {} \ No newline at end of file diff --git a/ion/src/simulator/Makefile b/ion/src/simulator/Makefile index 9f73f59b1..9185e96b4 100644 --- a/ion/src/simulator/Makefile +++ b/ion/src/simulator/Makefile @@ -1,6 +1,5 @@ objs += $(addprefix ion/src/simulator/, \ init.o\ - led.o\ ) objs += $(addprefix ion/src/simulator/boot/, main.o) @@ -17,6 +16,7 @@ objs += $(addprefix ion/src/shared/, \ dummy/backlight.o \ dummy/battery.o \ dummy/fcc_id.o \ + dummy/led.o \ dummy/serial_number.o \ dummy/usb.o \ ) diff --git a/ion/src/simulator/led.cpp b/ion/src/simulator/led.cpp deleted file mode 100644 index 985b049a2..000000000 --- a/ion/src/simulator/led.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include - -void Ion::LED::setColor(KDColor c) { -} - -void Ion::LED::setBlinking(float blinkPeriod, bool red, bool green, bool blue) { -} - -void Ion::LED::setCharging(bool isPlugged, bool isCharging) { -} - -bool Ion::LED::getLockState() { - return false; -} - -void Ion::LED::setLockState(bool state) { -} From e303570e16b2e6edfaff5fa2fc702c05b53c8671 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 23 Aug 2018 18:02:32 +0200 Subject: [PATCH 18/43] [ion] Fix a register size wrongly defined --- ion/src/device/regs/tim.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ion/src/device/regs/tim.h b/ion/src/device/regs/tim.h index 1d8abb3a0..d76f8e293 100644 --- a/ion/src/device/regs/tim.h +++ b/ion/src/device/regs/tim.h @@ -63,7 +63,7 @@ public: }; class PSC : public Register16 {}; - class ARR : public RegisterWidth {}; + class ARR : public Register16 {}; class CCR1 : public RegisterWidth {}; class CCR2 : public RegisterWidth {}; class CCR3 : public RegisterWidth {}; From 992575084ead50699ed0690ab6d82527e5f9f8da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 23 Aug 2018 18:10:02 +0200 Subject: [PATCH 19/43] [ion] Add comment on LED --- ion/src/device/led.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ion/src/device/led.cpp b/ion/src/device/led.cpp index 26cce0243..566eb67df 100644 --- a/ion/src/device/led.cpp +++ b/ion/src/device/led.cpp @@ -15,15 +15,20 @@ KDColor Ion::LED::getColor() { void Ion::LED::setColor(KDColor c) { sLedColor = c; + /* Active RGB colors */ Ion::LED::Device::setColorStatus(Ion::LED::Device::Color::RED, true); Ion::LED::Device::setColorStatus(Ion::LED::Device::Color::GREEN, true); Ion::LED::Device::setColorStatus(Ion::LED::Device::Color::BLUE, true); + /* Set the PWM duty cycles to display the right color */ constexpr float maxColorValue = (float)((1 << 8) -1); Device::setPeriodAndDutyCycles(Device::Mode::PWM, c.red()/maxColorValue, c.green()/maxColorValue, c.blue()/maxColorValue); } void Ion::LED::setBlinking(float period, float dutyCycle) { + /* We want to use the PWM at a slow rate to display a seeable blink. + * Consequently, we do not use PWM to display the right color anymore. + * Instead we 'project the color on 3 bits' : RED LED is active or not etc. */ Ion::LED::Device::setColorStatus(Ion::LED::Device::Color::RED, sLedColor.red() > 0); Ion::LED::Device::setColorStatus(Ion::LED::Device::Color::GREEN, sLedColor.green() > 0); Ion::LED::Device::setColorStatus(Ion::LED::Device::Color::BLUE, sLedColor.blue() > 0); From 812de5d1a0acc35c3d63a4610997270713145b9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 23 Aug 2018 17:37:10 +0200 Subject: [PATCH 20/43] [apps] Fix pop up clash when plugging the device Build with ON_BOARDING_APP=1 and power off the calculator. When plugging the calculator, the device did not enter the DFU mode nor quits exam mode. --- apps/on_boarding/update_controller.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/on_boarding/update_controller.cpp b/apps/on_boarding/update_controller.cpp index f9243f418..d674e4b3a 100644 --- a/apps/on_boarding/update_controller.cpp +++ b/apps/on_boarding/update_controller.cpp @@ -65,7 +65,7 @@ UpdateController::UpdateController() : } bool UpdateController::handleEvent(Ion::Events::Event event) { - if (event != Ion::Events::Back && event != Ion::Events::OnOff) { + if (event != Ion::Events::Back && event != Ion::Events::OnOff && event != Ion::Events::USBPlug && event != Ion::Events::USBEnumeration) { app()->dismissModalViewController(); AppsContainer * appsContainer = (AppsContainer *)app()->container(); if (appsContainer->activeApp()->snapshot() == appsContainer->onBoardingAppSnapshot()) { From 47ce55b74d74b087048781017080bd66116cd720 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 24 Aug 2018 10:05:05 +0200 Subject: [PATCH 21/43] [ion] Fix namespace in dummy LED implementation --- ion/src/shared/dummy/led.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ion/src/shared/dummy/led.cpp b/ion/src/shared/dummy/led.cpp index 725c7c29d..d317c207d 100644 --- a/ion/src/shared/dummy/led.cpp +++ b/ion/src/shared/dummy/led.cpp @@ -1,9 +1,15 @@ #include +namespace Ion { +namespace LED { + KDColor getColor() { return KDColorBlack; } void setColor(KDColor c) {} -void setBlinking(float period, float dutyCycle) {} \ No newline at end of file +void setBlinking(float period, float dutyCycle) {} + +} +} From 7a0e39f88e0dd8d1e5c3ae6455021c9257f75b39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Da=20Costa=20Faro?= Date: Fri, 24 Aug 2018 09:01:28 +0200 Subject: [PATCH 22/43] Inverted SwitchView handle position --- escher/src/switch_view.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/escher/src/switch_view.cpp b/escher/src/switch_view.cpp index 23ebd23a6..a88dfb7a0 100644 --- a/escher/src/switch_view.cpp +++ b/escher/src/switch_view.cpp @@ -59,7 +59,7 @@ void SwitchView::drawRect(KDContext * ctx, KDRect rect) const { KDColor mainColor = m_state ? Palette::YellowDark : Palette::GreyDark; KDRect frame(width - k_switchWidth, heightCenter -switchHalfHeight, k_switchWidth, k_switchHeight); ctx->blendRectWithMask(frame, mainColor, (const uint8_t *)switchMask, s_switchWorkingBuffer); - KDCoordinate onOffX = width - (m_state ? k_switchWidth : k_onOffSize); + KDCoordinate onOffX = width - (m_state ? k_onOffSize : k_switchWidth); KDRect onOffFrame(onOffX, heightCenter -switchHalfHeight, k_onOffSize, k_onOffSize); ctx->blendRectWithMask(onOffFrame, KDColorWhite, (const uint8_t *)onOffMask, s_switchWorkingBuffer); } From 90f6205330f84cb2eccbe0d977d04968aaa17c47 Mon Sep 17 00:00:00 2001 From: 0b101 <29680628+0b101@users.noreply.github.com> Date: Thu, 5 Jul 2018 10:11:04 -0500 Subject: [PATCH 23/43] Changed active button color to YellowDark --- escher/src/button.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/escher/src/button.cpp b/escher/src/button.cpp index 97dd9814e..636ee8aac 100644 --- a/escher/src/button.cpp +++ b/escher/src/button.cpp @@ -38,7 +38,7 @@ bool Button::handleEvent(Ion::Events::Event event) { void Button::setHighlighted(bool highlight) { HighlightCell::setHighlighted(highlight); - KDColor backgroundColor = highlight? Palette::Select : KDColorWhite; + KDColor backgroundColor = highlight? Palette::YellowDark : KDColorWhite; m_messageTextView.setBackgroundColor(backgroundColor); markRectAsDirty(bounds()); } From 70a2db9336a83530b32dfc7abdf0a52af73c0f40 Mon Sep 17 00:00:00 2001 From: Louis Rannou Date: Mon, 20 Aug 2018 16:02:24 +0200 Subject: [PATCH 24/43] Fix warnings about comparing different signedness Some variables were declared as int while they are size_t. As we try to compare them to unsigned values, a warning was raised (comparison of integer expressions of different signedness). --- apps/code/python_text_area.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/code/python_text_area.cpp b/apps/code/python_text_area.cpp index cb14bdf78..0151ce29c 100644 --- a/apps/code/python_text_area.cpp +++ b/apps/code/python_text_area.cpp @@ -36,7 +36,7 @@ static inline KDColor TokenColor(mp_token_kind_t tokenKind) { return KDColorBlack; } -static inline int TokenLength(mp_lexer_t * lex) { +static inline size_t TokenLength(mp_lexer_t * lex) { if (lex->tok_kind == MP_TOKEN_STRING) { return lex->vstr.len + 2; } @@ -122,7 +122,7 @@ void PythonTextArea::ContentView::drawLine(KDContext * ctx, int line, const char * basis. This can work, however the MicroPython lexer won't accept a line * starting with a whitespace. So we're discarding leading whitespaces * beforehand. */ - int whitespaceOffset = 0; + size_t whitespaceOffset = 0; while (text[whitespaceOffset] == ' ' && whitespaceOffset < length) { whitespaceOffset++; } @@ -130,8 +130,8 @@ void PythonTextArea::ContentView::drawLine(KDContext * ctx, int line, const char mp_lexer_t * lex = mp_lexer_new_from_str_len(0, text + whitespaceOffset, length - whitespaceOffset, 0); LOG_DRAW("Pop token %d\n", lex->tok_kind); - int tokenFrom = 0; - int tokenLength = 0; + size_t tokenFrom = 0; + size_t tokenLength = 0; KDColor tokenColor = KDColorBlack; while (lex->tok_kind != MP_TOKEN_NEWLINE && lex->tok_kind != MP_TOKEN_END) { From ebf309654c997b434fee304ef4796e4f02b7158c Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Fri, 24 Aug 2018 16:54:29 +0200 Subject: [PATCH 25/43] Revert "Changed active button color to YellowDark" This reverts commit 90f6205330f84cb2eccbe0d977d04968aaa17c47. --- escher/src/button.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/escher/src/button.cpp b/escher/src/button.cpp index 636ee8aac..97dd9814e 100644 --- a/escher/src/button.cpp +++ b/escher/src/button.cpp @@ -38,7 +38,7 @@ bool Button::handleEvent(Ion::Events::Event event) { void Button::setHighlighted(bool highlight) { HighlightCell::setHighlighted(highlight); - KDColor backgroundColor = highlight? Palette::YellowDark : KDColorWhite; + KDColor backgroundColor = highlight? Palette::Select : KDColorWhite; m_messageTextView.setBackgroundColor(backgroundColor); markRectAsDirty(bounds()); } From c52ed0bf6d0e1f570da2ffcc244495d70318132b Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Fri, 24 Aug 2018 17:16:58 +0200 Subject: [PATCH 26/43] [escher] Allow customizing the background color of a button --- escher/include/escher/button.h | 2 ++ escher/src/button.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/escher/include/escher/button.h b/escher/include/escher/button.h index 9722c0a5f..fc3633a98 100644 --- a/escher/include/escher/button.h +++ b/escher/include/escher/button.h @@ -6,6 +6,7 @@ #include #include #include +#include class Button : public HighlightCell, public Responder { public: @@ -13,6 +14,7 @@ public: void setMessage(I18n::Message message); bool handleEvent(Ion::Events::Event event) override; void setHighlighted(bool highlight) override; + virtual KDColor highlightedBackgroundColor() const { return Palette::Select; } Responder * responder() override { return this; } diff --git a/escher/src/button.cpp b/escher/src/button.cpp index 97dd9814e..1f2bbf33f 100644 --- a/escher/src/button.cpp +++ b/escher/src/button.cpp @@ -38,7 +38,7 @@ bool Button::handleEvent(Ion::Events::Event event) { void Button::setHighlighted(bool highlight) { HighlightCell::setHighlighted(highlight); - KDColor backgroundColor = highlight? Palette::Select : KDColorWhite; + KDColor backgroundColor = highlight? highlightedBackgroundColor() : KDColorWhite; m_messageTextView.setBackgroundColor(backgroundColor); markRectAsDirty(bounds()); } From f0c06a0405cb0eb554d19380cec8a95b35803c84 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Fri, 24 Aug 2018 17:17:13 +0200 Subject: [PATCH 27/43] [apps] Exam mode controller uses dark yellow buttons --- apps/exam_pop_up_controller.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/exam_pop_up_controller.h b/apps/exam_pop_up_controller.h index 5cf9e2b44..fd04f50dc 100644 --- a/apps/exam_pop_up_controller.h +++ b/apps/exam_pop_up_controller.h @@ -4,6 +4,12 @@ #include #include "exam_pop_up_controller_delegate.h" +class HighContrastButton : public Button { +public: + using Button::Button; + virtual KDColor highlightedBackgroundColor() const override { return Palette::YellowDark; } +}; + class ExamPopUpController : public ViewController { public: ExamPopUpController(ExamPopUpControllerDelegate * delegate); @@ -31,8 +37,8 @@ private: int numberOfSubviews() const override; View * subviewAtIndex(int index) override; void layoutSubviews() override; - Button m_cancelButton; - Button m_okButton; + HighContrastButton m_cancelButton; + HighContrastButton m_okButton; MessageTextView m_warningTextView; MessageTextView m_messageTextView1; MessageTextView m_messageTextView2; From a4abd5e34c4161ee5e64dde1722060471647f89f Mon Sep 17 00:00:00 2001 From: Damien Nicolet Date: Fri, 22 Dec 2017 22:19:55 +0100 Subject: [PATCH 28/43] Add option USE_LIBGCC to link agains libgcc instead of liba softfloat implementation. --- Makefile | 4 ++ build/targets.device.mak | 2 +- build/toolchain.arm-gcc.mak | 4 +- liba/Makefile.libgcc | 139 ++++++++++++++++++++++++++++++++++++ 4 files changed, 146 insertions(+), 3 deletions(-) create mode 100644 liba/Makefile.libgcc diff --git a/Makefile b/Makefile index a55c41842..0fa75ba67 100644 --- a/Makefile +++ b/Makefile @@ -24,7 +24,11 @@ ifeq ($(USE_LIBA),0) include liba/Makefile.bridge else SFLAGS += -ffreestanding -nostdinc -nostdlib +ifneq ($(USE_LIBGCC),0) +include liba/Makefile.libgcc +else include liba/Makefile +endif include libaxx/Makefile endif include ion/Makefile diff --git a/build/targets.device.mak b/build/targets.device.mak index 7e610b06d..5a277dd20 100644 --- a/build/targets.device.mak +++ b/build/targets.device.mak @@ -23,7 +23,7 @@ products += $(patsubst %.$(EXE),%.map,$(filter %.$(EXE),$(products))) %.map: %.elf @echo "LDMAP $@" - $(Q) $(LD) $^ $(LDFLAGS) -M -Map $@ -o /dev/null + $(Q) $(LD) $^ $(LDFLAGS) -Wl,-M -Wl,-Map=$@ -o /dev/null .PHONY: %_memory_map %_memory_map: %.map diff --git a/build/toolchain.arm-gcc.mak b/build/toolchain.arm-gcc.mak index 845994b2d..b01b6d00b 100644 --- a/build/toolchain.arm-gcc.mak +++ b/build/toolchain.arm-gcc.mak @@ -1,6 +1,6 @@ CC = arm-none-eabi-gcc CXX = arm-none-eabi-g++ -LD = arm-none-eabi-ld.bfd +LD = arm-none-eabi-gcc GDB = arm-none-eabi-gdb OBJCOPY = arm-none-eabi-objcopy SIZE = arm-none-eabi-size @@ -9,6 +9,6 @@ ifeq ($(DEBUG),1) SFLAGS += -ggdb3 else SFLAGS += -fdata-sections -ffunction-sections -LDFLAGS += --gc-sections +LDFLAGS += -Wl,--gc-sections endif SFLAGS += -mthumb -march=armv7e-m -mfloat-abi=hard -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 diff --git a/liba/Makefile.libgcc b/liba/Makefile.libgcc new file mode 100644 index 000000000..0dd83e824 --- /dev/null +++ b/liba/Makefile.libgcc @@ -0,0 +1,139 @@ +SFLAGS += -Iliba/include + +liba/src/external/sqlite/mem5.o: CFLAGS += -w + +objs += $(addprefix liba/src/, \ + armv7m/setjmp.o \ + armv7m/longjmp.o \ + assert.o \ + bzero.o \ + ctype.o \ + errno.o \ + fpclassify.o \ + fpclassifyf.o \ + ieee754.o \ + malloc.o \ + memcmp.o \ + memcpy.o \ + memmove.o \ + memset.o \ + nearbyint.o \ + nearbyintf.o \ + strcmp.o \ + strchr.o \ + strlcpy.o \ + strlen.o \ + external/sqlite/mem5.o \ +) + +objs += $(addprefix liba/src/external/openbsd/, \ + b_exp__D.o \ + b_log__D.o \ + b_tgamma.o \ + e_acosf.o \ + e_acoshf.o \ + e_asinf.o \ + e_atanhf.o \ + e_atan2.o \ + e_atan2f.o \ + e_coshf.o \ + e_expf.o \ + e_fmod.o \ + e_fmodf.o \ + e_lgammaf_r.o \ + e_log10f.o \ + e_log2.o \ + e_logf.o \ + e_powf.o \ + e_rem_pio2f.o \ + e_scalb.o \ + e_sinhf.o \ + e_sqrtf.o \ + k_cosf.o \ + k_rem_pio2f.o \ + k_sinf.o \ + k_tanf.o \ + s_asinhf.o\ + s_atanf.o \ + s_ceilf.o \ + s_copysignf.o \ + s_cosf.o \ + s_erf.o \ + s_expm1f.o\ + s_fabsf.o \ + s_floorf.o \ + s_frexpf.o \ + s_frexp.o \ + s_log1pf.o \ + s_logb.o \ + s_modf.o \ + s_modff.o \ + s_rint.o \ + s_roundf.o \ + s_scalbnf.o \ + s_signgam.o \ + s_sinf.o \ + s_tanf.o \ + s_tanhf.o \ + s_trunc.o \ + s_truncf.o \ + w_lgammaf.o \ +) + +objs += $(addprefix liba/src/external/openbsd/, \ + e_acos.o \ + e_acosh.o \ + e_asin.o \ + e_atanh.o \ + e_cosh.o \ + e_exp.o \ + e_lgamma_r.o \ + e_log.o \ + e_log10.o \ + e_pow.o \ + e_rem_pio2.o \ + e_sinh.o \ + e_sqrt.o \ + k_cos.o \ + k_rem_pio2.o \ + k_sin.o \ + k_tan.o \ + s_asinh.o \ + s_atan.o \ + s_ceil.o \ + s_copysign.o \ + s_cos.o \ + s_expm1.o \ + s_fabs.o \ + s_floor.o \ + s_log1p.o \ + s_round.o \ + s_scalbn.o \ + s_sin.o \ + s_tan.o \ + s_tanh.o \ + w_lgamma.o \ +) + +liba/src/external/openbsd/%.o: SFLAGS := -Iliba/src/external/openbsd/include $(SFLAGS) +liba/src/external/openbsd/%.o: CFLAGS += -w + +tests += $(addprefix liba/test/, \ + aeabi.c \ + double.c \ + ieee754.c \ + long.c \ + math.c \ + setjmp.c \ + stddef.c \ + stdint.c \ + strlcpy.c \ +) + +# The use of aeabi-rt could be made conditional to an AEABI target. +# In practice we're always using liba on such a target. +objs += $(addprefix liba/src/aeabi-rt/, \ + atexit.o \ +) + +LDFLAGS+=-lgcc From 40f499b594bbef3f5982a39216cf5a3955b2a0e1 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Tue, 21 Aug 2018 15:34:50 +0200 Subject: [PATCH 29/43] Switch to libgcc entierly when using gcc as a toolchain --- Makefile | 4 - build/toolchain.arm-gcc.mak | 1 + ion/src/device/boot/Makefile | 2 +- ion/src/device/usb/Makefile | 2 +- liba/Makefile | 54 -------------- liba/Makefile.libgcc | 139 ----------------------------------- 6 files changed, 3 insertions(+), 199 deletions(-) delete mode 100644 liba/Makefile.libgcc diff --git a/Makefile b/Makefile index 0fa75ba67..a55c41842 100644 --- a/Makefile +++ b/Makefile @@ -24,11 +24,7 @@ ifeq ($(USE_LIBA),0) include liba/Makefile.bridge else SFLAGS += -ffreestanding -nostdinc -nostdlib -ifneq ($(USE_LIBGCC),0) -include liba/Makefile.libgcc -else include liba/Makefile -endif include libaxx/Makefile endif include ion/Makefile diff --git a/build/toolchain.arm-gcc.mak b/build/toolchain.arm-gcc.mak index b01b6d00b..5549509f1 100644 --- a/build/toolchain.arm-gcc.mak +++ b/build/toolchain.arm-gcc.mak @@ -12,3 +12,4 @@ SFLAGS += -fdata-sections -ffunction-sections LDFLAGS += -Wl,--gc-sections endif SFLAGS += -mthumb -march=armv7e-m -mfloat-abi=hard -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 +LDFLAGS += $(SFLAGS) -lgcc -Wl,-T,$(LDSCRIPT) diff --git a/ion/src/device/boot/Makefile b/ion/src/device/boot/Makefile index a47336847..ded572acd 100644 --- a/ion/src/device/boot/Makefile +++ b/ion/src/device/boot/Makefile @@ -1,2 +1,2 @@ objs += $(addprefix ion/src/device/boot/, isr.o rt0.o) -LDFLAGS += -T ion/src/device/boot/flash.ld +LDSCRIPT = ion/src/device/boot/flash.ld diff --git a/ion/src/device/usb/Makefile b/ion/src/device/usb/Makefile index 468372384..8873590c8 100644 --- a/ion/src/device/usb/Makefile +++ b/ion/src/device/usb/Makefile @@ -51,7 +51,7 @@ dfu_objs += ion/src/device/usb.o dfu_objs += ion/src/device/base64.o dfu_objs += ion/src/device/flash.o -ion/src/device/usb/dfu.elf: LDFLAGS = --gc-sections -T ion/src/device/usb/dfu.ld +ion/src/device/usb/dfu.elf: LDSCRIPT = ion/src/device/usb/dfu.ld ion/src/device/usb/dfu.elf: $(usb_objs) $(dfu_objs) ion/src/device/usb/dfu.o: ion/src/device/usb/dfu.bin diff --git a/liba/Makefile b/liba/Makefile index 9dc39e4de..da54983c1 100644 --- a/liba/Makefile +++ b/liba/Makefile @@ -138,58 +138,4 @@ tests += $(addprefix liba/test/, \ # In practice we're always using liba on such a target. objs += $(addprefix liba/src/aeabi-rt/, \ atexit.o \ - double.o \ - llsl.o \ - llsr.o \ - long.o \ - memclr.o \ - memcpy.o \ -) - -liba/src/external/softfloat/src/%.o: CFLAGS += -Iliba/src/external/softfloat/include -Iliba/src/external/softfloat/src/8086 -Iliba/src/external/softfloat/port -liba/src/external/softfloat/src/s_roundPackToF64.o: CFLAGS += -w -liba/src/external/softfloat/src/s_roundPackToF32.o: CFLAGS += -w -# s_roundPackToF64 and s_roundPackToF32 are throwing warnings - -objs += $(addprefix liba/src/external/softfloat/src/, \ - 8086/s_commonNaNToF32UI.o \ - 8086/s_commonNaNToF64UI.o \ - 8086/s_f32UIToCommonNaN.o \ - 8086/s_f64UIToCommonNaN.o \ - 8086/s_propagateNaNF64UI.o \ - 8086/softfloat_raiseFlags.o \ - f32_to_f64.o \ - f32_to_i64_r_minMag.o\ - f64_add.o \ - f64_div.o \ - f64_eq.o \ - f64_le.o \ - f64_lt.o \ - f64_mul.o \ - f64_sub.o \ - f64_to_i32_r_minMag.o \ - f64_to_i64_r_minMag.o \ - f64_to_f32.o \ - i32_to_f64.o \ - i64_to_f32.o \ - i64_to_f64.o \ - s_addMagsF64.o \ - s_approxRecip32_1.o \ - s_approxRecip_1Ks.o \ - s_countLeadingZeros32.o \ - s_countLeadingZeros64.o \ - s_countLeadingZeros8.o \ - s_mul64To128M.o \ - s_normRoundPackToF64.o \ - s_normSubnormalF32Sig.o \ - s_normSubnormalF64Sig.o \ - s_roundPackToF32.o \ - s_roundPackToF64.o \ - s_shiftRightJam32.o \ - s_shiftRightJam64.o \ - s_shortShiftRightJam64.o \ - s_subMagsF64.o \ - softfloat_state.o \ - ui32_to_f64.o \ - ui64_to_f64.o \ ) diff --git a/liba/Makefile.libgcc b/liba/Makefile.libgcc deleted file mode 100644 index 0dd83e824..000000000 --- a/liba/Makefile.libgcc +++ /dev/null @@ -1,139 +0,0 @@ -SFLAGS += -Iliba/include - -liba/src/external/sqlite/mem5.o: CFLAGS += -w - -objs += $(addprefix liba/src/, \ - armv7m/setjmp.o \ - armv7m/longjmp.o \ - assert.o \ - bzero.o \ - ctype.o \ - errno.o \ - fpclassify.o \ - fpclassifyf.o \ - ieee754.o \ - malloc.o \ - memcmp.o \ - memcpy.o \ - memmove.o \ - memset.o \ - nearbyint.o \ - nearbyintf.o \ - strcmp.o \ - strchr.o \ - strlcpy.o \ - strlen.o \ - external/sqlite/mem5.o \ -) - -objs += $(addprefix liba/src/external/openbsd/, \ - b_exp__D.o \ - b_log__D.o \ - b_tgamma.o \ - e_acosf.o \ - e_acoshf.o \ - e_asinf.o \ - e_atanhf.o \ - e_atan2.o \ - e_atan2f.o \ - e_coshf.o \ - e_expf.o \ - e_fmod.o \ - e_fmodf.o \ - e_lgammaf_r.o \ - e_log10f.o \ - e_log2.o \ - e_logf.o \ - e_powf.o \ - e_rem_pio2f.o \ - e_scalb.o \ - e_sinhf.o \ - e_sqrtf.o \ - k_cosf.o \ - k_rem_pio2f.o \ - k_sinf.o \ - k_tanf.o \ - s_asinhf.o\ - s_atanf.o \ - s_ceilf.o \ - s_copysignf.o \ - s_cosf.o \ - s_erf.o \ - s_expm1f.o\ - s_fabsf.o \ - s_floorf.o \ - s_frexpf.o \ - s_frexp.o \ - s_log1pf.o \ - s_logb.o \ - s_modf.o \ - s_modff.o \ - s_rint.o \ - s_roundf.o \ - s_scalbnf.o \ - s_signgam.o \ - s_sinf.o \ - s_tanf.o \ - s_tanhf.o \ - s_trunc.o \ - s_truncf.o \ - w_lgammaf.o \ -) - -objs += $(addprefix liba/src/external/openbsd/, \ - e_acos.o \ - e_acosh.o \ - e_asin.o \ - e_atanh.o \ - e_cosh.o \ - e_exp.o \ - e_lgamma_r.o \ - e_log.o \ - e_log10.o \ - e_pow.o \ - e_rem_pio2.o \ - e_sinh.o \ - e_sqrt.o \ - k_cos.o \ - k_rem_pio2.o \ - k_sin.o \ - k_tan.o \ - s_asinh.o \ - s_atan.o \ - s_ceil.o \ - s_copysign.o \ - s_cos.o \ - s_expm1.o \ - s_fabs.o \ - s_floor.o \ - s_log1p.o \ - s_round.o \ - s_scalbn.o \ - s_sin.o \ - s_tan.o \ - s_tanh.o \ - w_lgamma.o \ -) - -liba/src/external/openbsd/%.o: SFLAGS := -Iliba/src/external/openbsd/include $(SFLAGS) -liba/src/external/openbsd/%.o: CFLAGS += -w - -tests += $(addprefix liba/test/, \ - aeabi.c \ - double.c \ - ieee754.c \ - long.c \ - math.c \ - setjmp.c \ - stddef.c \ - stdint.c \ - strlcpy.c \ -) - -# The use of aeabi-rt could be made conditional to an AEABI target. -# In practice we're always using liba on such a target. -objs += $(addprefix liba/src/aeabi-rt/, \ - atexit.o \ -) - -LDFLAGS+=-lgcc From 7d26412afb7c8877be76e98be54484ff2a828388 Mon Sep 17 00:00:00 2001 From: David <0b101@users.noreply.github.com> Date: Fri, 15 Jun 2018 15:39:50 -0500 Subject: [PATCH 30/43] Fixed README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fa3c97775..07b25d011 100644 --- a/README.md +++ b/README.md @@ -23,4 +23,4 @@ We welcome contributions. For smaller changes just open a pull request straight ## License -NumWorks Epsilon is released under a [CC BY-NC-SA License](https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode). NumWorks is a registered trade mark. +NumWorks Epsilon is released under a [CC BY-NC-SA License](https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode). NumWorks is a registered trademark. From 3177b26f306d08eb7e308f4c085369fa35c7a304 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 27 Aug 2018 09:52:17 +0200 Subject: [PATCH 31/43] [ion] Clean LED API --- apps/exam_pop_up_controller.cpp | 2 +- ion/include/ion/led.h | 2 +- ion/src/device/device.cpp | 24 +++------ ion/src/device/device.h | 2 - ion/src/device/led.cpp | 95 +++++++++++---------------------- ion/src/device/led.h | 17 +++--- ion/src/shared/dummy/led.cpp | 2 +- 7 files changed, 46 insertions(+), 98 deletions(-) diff --git a/apps/exam_pop_up_controller.cpp b/apps/exam_pop_up_controller.cpp index 7e8736a74..c0c935bf9 100644 --- a/apps/exam_pop_up_controller.cpp +++ b/apps/exam_pop_up_controller.cpp @@ -59,7 +59,7 @@ ExamPopUpController::ContentView::ContentView(Responder * parentResponder) : if (controller->isActivatingExamMode()) { container->reset(); Ion::LED::setColor(KDColorRed); - Ion::LED::setBlinking(1.0f, 0.1f); + Ion::LED::setBlinking(1000, 0.1f); } else { Ion::LED::setColor(KDColorBlack); } diff --git a/ion/include/ion/led.h b/ion/include/ion/led.h index dfb69c420..2d4475eab 100644 --- a/ion/include/ion/led.h +++ b/ion/include/ion/led.h @@ -8,7 +8,7 @@ namespace LED { KDColor getColor(); void setColor(KDColor c); -void setBlinking(float period, float dutyCycle); +void setBlinking(uint16_t periodInMilliseconds, float dutyCycle); } } diff --git a/ion/src/device/device.cpp b/ion/src/device/device.cpp index d23dd35d9..53de95726 100644 --- a/ion/src/device/device.cpp +++ b/ion/src/device/device.cpp @@ -285,29 +285,17 @@ void shutdownClocks(bool keepLEDAwake) { // APB2 bus RCC.APB2ENR()->set(0x00008000); // Reset value + // APB1 + class RCC::APB1ENR apb1enr(0x00000400); // Reset value + // AHB1 bus + class RCC::AHB1ENR ahb1enr(0); // Reset value if (keepLEDAwake) { - /* TODO: enter sleep mode even if the LED is used and enable LED in low - * power mode. */ - // Keep the LED going: peripheral clock enable in low power mode register - /*RCC.APB1LPENR()->setTIM3LPEN(true); - RCC.AHB1LPENR()->setGPIOBLPEN(true); - RCC.AHB1LPENR()->setGPIOCLPEN(true);*/ - - // APB1 - class RCC::APB1ENR apb1enr(0x00000400); apb1enr.setTIM3EN(true); - RCC.APB1ENR()->set(apb1enr); - // AHB1 bus - class RCC::AHB1ENR ahb1enr(0); // Reset value ahb1enr.setGPIOBEN(true); ahb1enr.setGPIOCEN(true); - RCC.AHB1ENR()->set(ahb1enr); - } else { - // APB1 - RCC.APB1ENR()->set(0x00000400); - // AHB1 bus - RCC.AHB1ENR()->set(0); // Reset value } + RCC.APB1ENR()->set(apb1enr); + RCC.AHB1ENR()->set(ahb1enr); RCC.AHB3ENR()->setFSMCEN(false); } diff --git a/ion/src/device/device.h b/ion/src/device/device.h index a95bf85e7..c3332fd77 100644 --- a/ion/src/device/device.h +++ b/ion/src/device/device.h @@ -4,8 +4,6 @@ namespace Ion { namespace Device { -constexpr int SYSBUS_FREQ = 96*1000*1000; - void init(); void shutdown(); diff --git a/ion/src/device/led.cpp b/ion/src/device/led.cpp index 566eb67df..028e8e846 100644 --- a/ion/src/device/led.cpp +++ b/ion/src/device/led.cpp @@ -15,41 +15,28 @@ KDColor Ion::LED::getColor() { void Ion::LED::setColor(KDColor c) { sLedColor = c; - /* Active RGB colors */ - Ion::LED::Device::setColorStatus(Ion::LED::Device::Color::RED, true); - Ion::LED::Device::setColorStatus(Ion::LED::Device::Color::GREEN, true); - Ion::LED::Device::setColorStatus(Ion::LED::Device::Color::BLUE, true); + /* Active all RGB colors */ + TIM3.CCMR()->setOC2M(TIM::CCMR::OCM::PWM1); + TIM3.CCMR()->setOC4M(TIM::CCMR::OCM::PWM1); + TIM3.CCMR()->setOC3M(TIM::CCMR::OCM::PWM1); /* Set the PWM duty cycles to display the right color */ constexpr float maxColorValue = (float)((1 << 8) -1); Device::setPeriodAndDutyCycles(Device::Mode::PWM, c.red()/maxColorValue, c.green()/maxColorValue, c.blue()/maxColorValue); } -void Ion::LED::setBlinking(float period, float dutyCycle) { +void Ion::LED::setBlinking(uint16_t period, float dutyCycle) { /* We want to use the PWM at a slow rate to display a seeable blink. - * Consequently, we do not use PWM to display the right color anymore. - * Instead we 'project the color on 3 bits' : RED LED is active or not etc. */ - Ion::LED::Device::setColorStatus(Ion::LED::Device::Color::RED, sLedColor.red() > 0); - Ion::LED::Device::setColorStatus(Ion::LED::Device::Color::GREEN, sLedColor.green() > 0); - Ion::LED::Device::setColorStatus(Ion::LED::Device::Color::BLUE, sLedColor.blue() > 0); + * Consequently, we do not use PWM to display the right color anymore but to + * blink. We cannot use the PWM to display the exact color so we 'project the + * color on 3 bits' : all colors have 2 states - active or not. */ + TIM3.CCMR()->setOC2M(sLedColor.red() > 0 ? TIM::CCMR::OCM::PWM1 : TIM::CCMR::OCM::ForceInactive); + TIM3.CCMR()->setOC4M(sLedColor.green() > 0 ? TIM::CCMR::OCM::PWM1 : TIM::CCMR::OCM::ForceInactive); + TIM3.CCMR()->setOC3M(sLedColor.blue() > 0 ? TIM::CCMR::OCM::PWM1 : TIM::CCMR::OCM::ForceInactive); - Device::setPeriodAndDutyCycles(Device::Mode::BLINK, dutyCycle, dutyCycle, dutyCycle, period); + Device::setPeriodAndDutyCycles(Device::Mode::Blink, dutyCycle, dutyCycle, dutyCycle, period); } -/*void Ion::LED::setCharging(bool isPluggedIn, bool isCharging) { - if (!isPluggedIn) { - Ion::LED::setColor(KDColorBlack); - } - else { - if (isCharging) { - Ion::LED::setColor(KDColorRed); - } - else { - Ion::LED::setColor(KDColorGreen); - } - } -}*/ - // Private Ion::Device::LED methods namespace Ion { @@ -103,30 +90,36 @@ void initTimer() { } void shutdownTimer() { - setColorStatus(Ion::LED::Device::Color::RED, false); - setColorStatus(Ion::LED::Device::Color::GREEN, false); - setColorStatus(Ion::LED::Device::Color::BLUE, false); + TIM3.CCMR()->setOC2M(TIM::CCMR::OCM::ForceInactive); + TIM3.CCMR()->setOC4M(TIM::CCMR::OCM::ForceInactive); + TIM3.CCMR()->setOC3M(TIM::CCMR::OCM::ForceInactive); } /* Pulse width modulation mode allows you to generate a signal with a * frequency determined by the value of the TIMx_ARR register and a duty cycle * determined by the value of the TIMx_CCRx register. */ -void setPeriodAndDutyCycles(Mode mode, float dutyCycleRed, float dutyCycleGreen, float dutyCycleBlue, float period) { - constexpr int TIM3_FREQ = 4*1000; +void setPeriodAndDutyCycles(Mode mode, float dutyCycleRed, float dutyCycleGreen, float dutyCycleBlue, uint16_t period) { switch (mode) { case Mode::PWM: - /* Let's set the prescaler to 1. Increasing the prescaler would slow down the - * modulation, which can be useful when debugging. */ + /* Let's set the prescaler to 1. Increasing the prescaler would slow down + * the modulation, which can be useful when debugging or when we want an + * actual blinking. */ TIM3.PSC()->set(1); TIM3.ARR()->set(PWMPeriod); period = PWMPeriod; break; - case Mode::BLINK: - /* We still want to do PWM, but at a rate slow enough to blink. */ - TIM3.PSC()->set(Ion::Device::SYSBUS_FREQ / TIM3_FREQ); - TIM3.ARR()->set(period * TIM3_FREQ); - period *= TIM3_FREQ; // as we pre-scaled, we update the period + case Mode::Blink: + int systemClockFreq = 96; + /* We still want to do PWM, but at a rate slow enough to blink. Ideally, + * we want to pre-scale the period to be able to set it in milliseconds; + * however, as the prescaler is cap by 2^16-1, we divide it by a factor + * and correct the period consequently. */ + int factor = 2; + // TODO: explain the 2 ? + TIM3.PSC()->set(systemClockFreq*1000/factor); + period *= factor; + TIM3.ARR()->set(period); break; } @@ -135,34 +128,6 @@ void setPeriodAndDutyCycles(Mode mode, float dutyCycleRed, float dutyCycleGreen, TIM3.CCR4()->set(dutyCycleGreen*period); } -void setColorStatus(Color color, bool enable) { - switch (color) { - case Ion::LED::Device::Color::RED: - TIM3.CCMR()->setOC2M(enable ? TIM::CCMR::OCM::PWM1 : TIM::CCMR::OCM::ForceInactive); - break; - case Ion::LED::Device::Color::GREEN: - TIM3.CCMR()->setOC4M(enable ? TIM::CCMR::OCM::PWM1 : TIM::CCMR::OCM::ForceInactive); - break; - case Ion::LED::Device::Color::BLUE: - TIM3.CCMR()->setOC3M(enable ? TIM::CCMR::OCM::PWM1 : TIM::CCMR::OCM::ForceInactive); - break; - } -} - -/*void enforceState(bool red, bool green, bool blue) { - bool states[3] = {red, green, blue}; - for (int i=0; i<3; i++) { - GPIOPin p = RGBPins[i]; - if (states[i]) { - p.group().MODER()->setMode(p.pin(), GPIO::MODER::Mode::Output); - p.group().ODR()->set(p.pin(), true); - } else { - p.group().MODER()->setMode(p.pin(), GPIO::MODER::Mode::Analog); - p.group().PUPDR()->setPull(p.pin(), GPIO::PUPDR::Pull::None); - } - } -}*/ - } } } diff --git a/ion/src/device/led.h b/ion/src/device/led.h index 426ce9607..fe46994d9 100644 --- a/ion/src/device/led.h +++ b/ion/src/device/led.h @@ -14,23 +14,20 @@ namespace Device { * PC7 | LED red | Alternate Function 2 | TIM3_CH2 */ -enum Mode { +enum class Mode { PWM, - BLINK + Blink }; -enum Color { - RED, - GREEN, - BLUE +enum class Color { + Red, + Green, + Blue }; void init(); void shutdown(); -void setPeriodAndDutyCycles(Mode mode, float dutyCycleRed, float dutyCycleGreen, float dutyCycleBlue, float period = 0.0f); -void setColorStatus(Color color, bool enable); -/* This call bypasses the timer, and immediately enforces a given LED state. */ -//void enforceState(bool red, bool green, bool blue); +void setPeriodAndDutyCycles(Mode mode, float dutyCycleRed, float dutyCycleGreen, float dutyCycleBlue, uint16_t period = 0); void initGPIO(); void shutdownGPIO(); diff --git a/ion/src/shared/dummy/led.cpp b/ion/src/shared/dummy/led.cpp index d317c207d..097aff116 100644 --- a/ion/src/shared/dummy/led.cpp +++ b/ion/src/shared/dummy/led.cpp @@ -9,7 +9,7 @@ KDColor getColor() { void setColor(KDColor c) {} -void setBlinking(float period, float dutyCycle) {} +void setBlinking(uint16_t period, float dutyCycle) {} } } From 2f946e79877e9c0696bd9833d963494397dbdf5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 30 Aug 2018 17:39:10 +0200 Subject: [PATCH 32/43] [apps/regression] Add private method globalContext on GraphController --- apps/regression/graph_controller.cpp | 12 +++++++----- apps/regression/graph_controller.h | 1 + 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/apps/regression/graph_controller.cpp b/apps/regression/graph_controller.cpp index 650f67e99..4a427c4fc 100644 --- a/apps/regression/graph_controller.cpp +++ b/apps/regression/graph_controller.cpp @@ -68,6 +68,10 @@ void GraphController::selectRegressionCurve() { m_roundCursorView.setColor(Palette::DataColor[*m_selectedSeriesIndex]); } +Poincare::Context * GraphController::globalContext() { + return const_cast(static_cast(app()->container()))->globalContext(); +} + CurveView * GraphController::curveView() { return &m_view; } @@ -157,8 +161,7 @@ void GraphController::reloadBannerView() { m_bannerView.setMessageAtIndex(model->formulaMessage(), 3); // Get the coefficients - Poincare::Context * globContext = const_cast(static_cast(app()->container()))->globalContext(); - double * coefficients = m_store->coefficientsForSeries(selectedSeriesIndex(), globContext); + double * coefficients = m_store->coefficientsForSeries(selectedSeriesIndex(), globalContext()); bool coefficientsAreDefined = true; for (int i = 0; i < model->numberOfCoefficients(); i++) { if (std::isnan(coefficients[i])) { @@ -259,8 +262,7 @@ bool GraphController::moveCursorHorizontally(int direction) { } double x = direction > 0 ? m_cursor->x() + m_store->xGridUnit()/k_numberOfCursorStepsInGradUnit : m_cursor->x() - m_store->xGridUnit()/k_numberOfCursorStepsInGradUnit; - Poincare::Context * globContext = const_cast(static_cast(app()->container()))->globalContext(); - double y = m_store->yValueForXValue(*m_selectedSeriesIndex, x, globContext); + double y = m_store->yValueForXValue(*m_selectedSeriesIndex, x, globalContext()); m_cursor->moveTo(x, y); m_store->panToMakePointVisible(x, y, cursorTopMarginRatio(), k_cursorRightMarginRatio, cursorBottomMarginRatio(), k_cursorLeftMarginRatio); return true; @@ -270,7 +272,7 @@ bool GraphController::moveCursorVertically(int direction) { int closestRegressionSeries = -1; int closestDotSeries = -1; int dotSelected = -1; - Poincare::Context * globContext = const_cast(static_cast(app()->container()))->globalContext(); + Poincare::Context * globContext = globalContext(); if (*m_selectedDotIndex == -1) { // The current cursor is on a regression diff --git a/apps/regression/graph_controller.h b/apps/regression/graph_controller.h index bf3abb67d..1a2a9cda1 100644 --- a/apps/regression/graph_controller.h +++ b/apps/regression/graph_controller.h @@ -28,6 +28,7 @@ private: constexpr static int k_maxLegendLength = 16; constexpr static int k_maxNumberOfCharacters = 50; constexpr static float k_viewHeight = 174.0f; + Poincare::Context * globalContext(); Shared::CurveView * curveView() override; Shared::InteractiveCurveViewRange * interactiveCurveViewRange() override; bool handleEnter() override; From adf895daeee3b797394e7a939b98ace4cedc8948 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 30 Aug 2018 17:39:44 +0200 Subject: [PATCH 33/43] [apps] Fix DoublePairStore::storeChecksum computation We used to compute the crc32 of the whole data array, putting empty data pairs to (0,0), but this hides (0,0) data points additions or removals. --- apps/shared/double_pair_store.cpp | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/apps/shared/double_pair_store.cpp b/apps/shared/double_pair_store.cpp index dc44171a3..1a4a1064e 100644 --- a/apps/shared/double_pair_store.cpp +++ b/apps/shared/double_pair_store.cpp @@ -131,19 +131,29 @@ bool DoublePairStore::seriesNumberOfAbscissaeGreaterOrEqualTo(int series, int i) } uint32_t DoublePairStore::storeChecksum() const { - /* Ideally, we would only compute the checksum of the first m_numberOfPairs - * pairs. However, the two values of a pair are not stored consecutively. We - * thus compute the checksum on all pairs and ensure to set the pair at 0 - * when removing them. */ - size_t dataLengthInBytes = k_numberOfSeries*k_maxNumberOfPairs*k_numberOfColumnsPerSeries*sizeof(double); - assert((dataLengthInBytes & 0x3) == 0); // Assert that dataLengthInBytes is a multiple of 4 - return Ion::crc32((uint32_t *)m_data, dataLengthInBytes/sizeof(uint32_t)); + uint32_t checkSumPerSeries[k_numberOfSeries]; + for (int i = 0; i < k_numberOfSeries; i++) { + checkSumPerSeries[i] = storeChecksumForSeries(i); + } + return Ion::crc32(checkSumPerSeries, k_numberOfSeries); } uint32_t DoublePairStore::storeChecksumForSeries(int series) const { - size_t dataLengthInBytes = k_maxNumberOfPairs*k_numberOfColumnsPerSeries*sizeof(double); - assert((dataLengthInBytes & 0x3) == 0); // Assert that dataLengthInBytes is a multiple of 4 - return Ion::crc32((uint32_t *)m_data[series], dataLengthInBytes/sizeof(uint32_t)); + /* Ideally, we would compute the checksum of the first m_numberOfPairs pairs. + * However, the two values of a pair are not stored consecutively. We thus + * compute the checksum of the x values of the pairs, then we compute the + * checksum of the y values of the pairs, and finally we compute the checksum + * of the checksums. + * We cannot simply put "empty" values to 0 and compute the checksum of the + * whole data, because adding or removing (0, 0) "real" data pairs would not + * change the checksum. */ + size_t dataLengthInBytesPerDataColumn = m_numberOfPairs[series]*sizeof(double); + assert((dataLengthInBytesPerDataColumn & 0x3) == 0); // Assert that dataLengthInBytes is a multiple of 4 + uint32_t checkSumPerColumn[k_numberOfColumnsPerSeries]; + for (int i = 0; i < k_numberOfColumnsPerSeries; i++) { + checkSumPerColumn[i] = Ion::crc32((uint32_t *)m_data[series][i], dataLengthInBytesPerDataColumn/sizeof(uint32_t)); + } + return Ion::crc32(checkSumPerColumn, k_numberOfColumnsPerSeries); } double DoublePairStore::defaultValue(int series, int i, int j) const { From 9ddfdf9b81028bf0a60e1849ff9988883671b455 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 4 Sep 2018 11:57:58 +0200 Subject: [PATCH 34/43] [poincare] The third parameter of strlcpy is a size_t: fix error when converting a signed int to size_t --- poincare/src/decimal.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/poincare/src/decimal.cpp b/poincare/src/decimal.cpp index 0f08a44b7..a66cd4cd9 100644 --- a/poincare/src/decimal.cpp +++ b/poincare/src/decimal.cpp @@ -11,6 +11,8 @@ extern "C" { namespace Poincare { +static inline int max(int x, int y) { return (x>y ? x : y); } + int Decimal::exponent(const char * integralPart, int integralPartLength, const char * fractionalPart, int fractionalPartLength, const char * exponent, int exponentLength, bool exponentNegative) { int base = 10; int exp = 0; @@ -171,7 +173,7 @@ int Decimal::convertToText(char * buffer, int bufferSize, PrintFloat::Mode mode, } /* Case 1: Decimal mode */ int deltaCharMantissa = exponent < 0 ? -exponent+1 : 0; - strlcpy(buffer+currentChar+deltaCharMantissa, tempBuffer, bufferSize-deltaCharMantissa-currentChar); + strlcpy(buffer+currentChar+deltaCharMantissa, tempBuffer, max(0, bufferSize-deltaCharMantissa-currentChar)); if (exponent < 0) { for (int i = 0; i <= -exponent; i++) { if (currentChar >= bufferSize-1) { return bufferSize-1; } From b2b0f4fab02da8db15e5a20535ff0cd4116bdb04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 4 Sep 2018 11:58:43 +0200 Subject: [PATCH 35/43] [apps] Clean buffer size declaration --- apps/calculation/app.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/calculation/app.cpp b/apps/calculation/app.cpp index 3814110b6..3724c35da 100644 --- a/apps/calculation/app.cpp +++ b/apps/calculation/app.cpp @@ -75,9 +75,8 @@ bool App::expressionLayoutFieldDidReceiveEvent(::ExpressionLayoutField * express return true; } - int bufferLength = Calculation::k_printedExpressionSize; - char bufferForParsing[bufferLength]; - expressionLayoutField->writeTextInBuffer(bufferForParsing, bufferLength); + char bufferForParsing[Calculation::k_printedExpressionSize]; + expressionLayoutField->writeTextInBuffer(bufferForParsing, Calculation::k_printedExpressionSize); if (!textInputIsCorrect(bufferForParsing)) { displayWarning(I18n::Message::SyntaxError); From 0b71e9262584930dd94b7dd1ee714ec406c0e0fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 4 Sep 2018 11:59:09 +0200 Subject: [PATCH 36/43] [apps] Add missing min/max redefinition --- apps/code/python_text_area.cpp | 2 ++ apps/shared/store_controller.cpp | 3 +++ 2 files changed, 5 insertions(+) diff --git a/apps/code/python_text_area.cpp b/apps/code/python_text_area.cpp index 0151ce29c..8f7f3b6d7 100644 --- a/apps/code/python_text_area.cpp +++ b/apps/code/python_text_area.cpp @@ -17,6 +17,8 @@ constexpr KDColor OperatorColor = KDColor::RGB24(0xd73a49); constexpr KDColor StringColor = KDColor::RGB24(0x032f62); constexpr KDColor BackgroundColor = KDColorWhite; +static inline int min(int x, int y) { return (xy ? x : y); } + namespace Shared { StoreController::ContentView::ContentView(DoublePairStore * store, Responder * parentResponder, TableViewDataSource * dataSource, SelectableTableViewDataSource * selectionDataSource, TextFieldDelegate * textFieldDelegate) : From a233df76193822bee27d7906709848bc8a938746 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 5 Sep 2018 13:29:00 +0200 Subject: [PATCH 37/43] [poincare] Fix DataNotSuitable message (was too long) --- apps/regression/banner_view.cpp | 21 ++++++++++++--------- apps/regression/banner_view.h | 4 ++++ apps/regression/base.de.i18n | 2 +- apps/regression/base.es.i18n | 2 +- apps/regression/base.fr.i18n | 2 +- apps/regression/base.pt.i18n | 2 +- apps/regression/graph_controller.cpp | 27 +++++++++++++++++++-------- 7 files changed, 39 insertions(+), 21 deletions(-) diff --git a/apps/regression/banner_view.cpp b/apps/regression/banner_view.cpp index 24852c39e..259cff4ea 100644 --- a/apps/regression/banner_view.cpp +++ b/apps/regression/banner_view.cpp @@ -2,16 +2,19 @@ namespace Regression { +constexpr KDColor BannerView::k_textColor; +constexpr KDColor BannerView::k_backgroundColor; + BannerView::BannerView() : - m_dotNameView(KDText::FontSize::Small, 0.0f, 0.5f, KDColorBlack, Palette::GreyMiddle), - m_xView(KDText::FontSize::Small, 0.5f, 0.5f, KDColorBlack, Palette::GreyMiddle), - m_yView(KDText::FontSize::Small, 0.5f, 0.5f, KDColorBlack, Palette::GreyMiddle), - m_regressionTypeView(KDText::FontSize::Small, (I18n::Message)0, 0.0f, 0.5f, KDColorBlack, Palette::GreyMiddle), - m_subText1(KDText::FontSize::Small, 0.5f, 0.5f, KDColorBlack, Palette::GreyMiddle), - m_subText2(KDText::FontSize::Small, 0.5f, 0.5f, KDColorBlack, Palette::GreyMiddle), - m_subText3(KDText::FontSize::Small, 0.5f, 0.5f, KDColorBlack, Palette::GreyMiddle), - m_subText4(KDText::FontSize::Small, 0.5f, 0.5f, KDColorBlack, Palette::GreyMiddle), - m_subText5(KDText::FontSize::Small, 0.5f, 0.5f, KDColorBlack, Palette::GreyMiddle) + m_dotNameView(k_fontSize, 0.0f, 0.5f, k_textColor, k_backgroundColor), + m_xView(k_fontSize, 0.5f, 0.5f, k_textColor, k_backgroundColor), + m_yView(k_fontSize, 0.5f, 0.5f, k_textColor, k_backgroundColor), + m_regressionTypeView(k_fontSize, (I18n::Message)0, 0.0f, 0.5f, k_textColor,k_backgroundColor), + m_subText1(k_fontSize, 0.5f, 0.5f, k_textColor, k_backgroundColor), + m_subText2(k_fontSize, 0.5f, 0.5f, k_textColor, k_backgroundColor), + m_subText3(k_fontSize, 0.5f, 0.5f, k_textColor, k_backgroundColor), + m_subText4(k_fontSize, 0.5f, 0.5f, k_textColor, k_backgroundColor), + m_subText5(k_fontSize, 0.5f, 0.5f, k_textColor, k_backgroundColor) { } diff --git a/apps/regression/banner_view.h b/apps/regression/banner_view.h index 2483b8af1..49427a699 100644 --- a/apps/regression/banner_view.h +++ b/apps/regression/banner_view.h @@ -10,7 +10,11 @@ class BannerView : public Shared::BannerView { public: BannerView(); int numberOfTextviews() const { return k_numberOfTextViews; } + KDText::FontSize fontSize() const { return k_fontSize; } private: + static constexpr KDText::FontSize k_fontSize = KDText::FontSize::Small; + static constexpr KDColor k_textColor = KDColorBlack; + static constexpr KDColor k_backgroundColor = Palette::GreyMiddle; static constexpr int k_numberOfTextViews = 9; int numberOfSubviews() const override; TextView * textViewAtIndex(int i) const override; diff --git a/apps/regression/base.de.i18n b/apps/regression/base.de.i18n index f262ffe0f..7c49c2e7d 100644 --- a/apps/regression/base.de.i18n +++ b/apps/regression/base.de.i18n @@ -18,4 +18,4 @@ Exponential = "Exponentielle" Power = "Potenz" Trigonometrical = "Trigonometrische" Logistic = "Logistische" -DataNotSuitableForRegression = " Daten sind nicht für dieses Regressionsmodell geeignete" +DataNotSuitableForRegression = "Daten sind nicht geeignet" diff --git a/apps/regression/base.es.i18n b/apps/regression/base.es.i18n index 615b1b296..99448e054 100644 --- a/apps/regression/base.es.i18n +++ b/apps/regression/base.es.i18n @@ -18,4 +18,4 @@ Exponential = "Exponencial" Power = "Potencial" Trigonometrical = "Trigonometrica" Logistic = "Logistica" -DataNotSuitableForRegression = " Datos no adecuados para este modelo de regresión" +DataNotSuitableForRegression = "Datos no adecuados" diff --git a/apps/regression/base.fr.i18n b/apps/regression/base.fr.i18n index acf5196a8..dae5817a5 100644 --- a/apps/regression/base.fr.i18n +++ b/apps/regression/base.fr.i18n @@ -18,4 +18,4 @@ Exponential = "Exponentielle" Power = "Puissance" Trigonometrical = "Trigonométrique" Logistic = "Logistique" -DataNotSuitableForRegression = " Les données ne conviennent pas à ce modèle de régression" +DataNotSuitableForRegression = "Les données ne conviennent pas" diff --git a/apps/regression/base.pt.i18n b/apps/regression/base.pt.i18n index 993aa766e..33edbb367 100644 --- a/apps/regression/base.pt.i18n +++ b/apps/regression/base.pt.i18n @@ -18,4 +18,4 @@ Exponential = "Exponencial" Power = "Potencia" Trigonometrical = "Trigonometrica" Logistic = "Logistica" -DataNotSuitableForRegression = " Dados não adequados para este modelo de regressão" +DataNotSuitableForRegression = "Dados não adequados" diff --git a/apps/regression/graph_controller.cpp b/apps/regression/graph_controller.cpp index 4a427c4fc..3fc70cbf3 100644 --- a/apps/regression/graph_controller.cpp +++ b/apps/regression/graph_controller.cpp @@ -9,6 +9,7 @@ using namespace Shared; static inline float min(float x, float y) { return (xy ? x : y); } +static inline int maxInt(int x, int y) { return (x>y ? x : y); } namespace Regression { @@ -158,7 +159,8 @@ void GraphController::reloadBannerView() { // Set formula Model * model = m_store->modelForSeries(selectedSeriesIndex()); - m_bannerView.setMessageAtIndex(model->formulaMessage(), 3); + I18n::Message formula = model->formulaMessage(); + m_bannerView.setMessageAtIndex(formula, 3); // Get the coefficients double * coefficients = m_store->coefficientsForSeries(selectedSeriesIndex(), globalContext()); @@ -170,13 +172,22 @@ void GraphController::reloadBannerView() { } } if (!coefficientsAreDefined) { + // Force the "Data not suitable" message to be on the next line + int numberOfCharToCompleteLine = maxInt(Ion::Display::Width/(KDText::charSize(m_bannerView.fontSize()).width())- strlen(I18n::translate(formula)), 0); + numberOfChar = 0; + for (int i = 0; i < numberOfCharToCompleteLine-1; i++) { + buffer[numberOfChar++] = ' '; + } + buffer[numberOfChar] = 0; + m_bannerView.setLegendAtIndex(buffer, 4); + const char * dataNotSuitableMessage = I18n::translate(I18n::Message::DataNotSuitableForRegression); - m_bannerView.setLegendAtIndex(const_cast(dataNotSuitableMessage), 4); - for (int i = 5; i < m_bannerView.numberOfTextviews(); i++) { - char empty[] = {0}; - m_bannerView.setLegendAtIndex(empty, i); - } - return; + m_bannerView.setLegendAtIndex(const_cast(dataNotSuitableMessage), 5); + for (int i = 6; i < m_bannerView.numberOfTextviews(); i++) { + char empty[] = {0}; + m_bannerView.setLegendAtIndex(empty, i); + } + return; } char coefficientName = 'a'; for (int i = 0; i < model->numberOfCoefficients(); i++) { @@ -261,7 +272,7 @@ bool GraphController::moveCursorHorizontally(int direction) { return false; } double x = direction > 0 ? m_cursor->x() + m_store->xGridUnit()/k_numberOfCursorStepsInGradUnit : - m_cursor->x() - m_store->xGridUnit()/k_numberOfCursorStepsInGradUnit; + m_cursor->x() - m_store->xGridUnit()/k_numberOfCursorStepsInGradUnit; double y = m_store->yValueForXValue(*m_selectedSeriesIndex, x, globalContext()); m_cursor->moveTo(x, y); m_store->panToMakePointVisible(x, y, cursorTopMarginRatio(), k_cursorRightMarginRatio, cursorBottomMarginRatio(), k_cursorLeftMarginRatio); From b784e7933ab1d8ef20c7af1c9c5466c06533382e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Wed, 5 Sep 2018 14:55:20 +0200 Subject: [PATCH 38/43] Makefile: Version 1.7.0 --- build/config.mak | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/config.mak b/build/config.mak index 2b6e610a3..08597b617 100644 --- a/build/config.mak +++ b/build/config.mak @@ -3,7 +3,7 @@ PLATFORM ?= device DEBUG ?= 0 -EPSILON_VERSION ?= 1.6.0 +EPSILON_VERSION ?= 1.7.0 EPSILON_ONBOARDING_APP ?= 1 EPSILON_SOFTWARE_UPDATE_PROMPT ?= 1 EPSILON_APPS ?= calculation graph code statistics probability solver sequence regression settings From 7b88770c150289bc45838ff912c9cb1b5b43d3c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 7 Sep 2018 15:05:06 +0200 Subject: [PATCH 39/43] [apps] VariableBoxController: fix the row size to avoid overflowing the maximal number of displayable rows --- apps/variable_box_controller.cpp | 2 +- apps/variable_box_controller.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/variable_box_controller.cpp b/apps/variable_box_controller.cpp index 015351cf9..3ab6142a4 100644 --- a/apps/variable_box_controller.cpp +++ b/apps/variable_box_controller.cpp @@ -170,7 +170,7 @@ KDCoordinate VariableBoxController::ContentViewController::rowHeight(int index) } ExpressionLayout * expressionLayout = expressionLayoutForIndex(index); if (expressionLayout) { - return expressionLayout->size().height()+k_leafMargin; + return max(expressionLayout->size().height()+k_leafMargin, Metric::ToolboxRowHeight); } return Metric::ToolboxRowHeight; } diff --git a/apps/variable_box_controller.h b/apps/variable_box_controller.h index 2ada661ea..110d5d0f5 100644 --- a/apps/variable_box_controller.h +++ b/apps/variable_box_controller.h @@ -42,13 +42,13 @@ private: #endif Matrix }; - constexpr static int k_maxNumberOfDisplayedRows = 6; //240/40 + constexpr static int k_maxNumberOfDisplayedRows = 6; //240/Matrix::ToolboxRowHeight #if LIST_VARIABLES constexpr static int k_numberOfMenuRows = 3; #else constexpr static int k_numberOfMenuRows = 2; #endif - constexpr static KDCoordinate k_leafMargin = 10; + constexpr static KDCoordinate k_leafMargin = 20; Page pageAtIndex(int index); void putLabelAtIndexInBuffer(int index, char * buffer); I18n::Message nodeLabelAtIndex(int index); From 02899b863bee91bb616b6779636b65d261cc1e1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 10 Sep 2018 13:28:38 +0200 Subject: [PATCH 40/43] [poincare] Median computation (and quartile...) tackles imprecision --- apps/statistics/store.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/statistics/store.cpp b/apps/statistics/store.cpp index d605b1b25..086d6af08 100644 --- a/apps/statistics/store.cpp +++ b/apps/statistics/store.cpp @@ -249,7 +249,7 @@ double Store::sortedElementAtCumulatedFrequency(int series, double k, bool creat memcpy(bufferValues, m_data[series][0], numberOfPairsOfSeries(series)*sizeof(double)); int sortedElementIndex = 0; double cumulatedFrequency = 0.0; - while (cumulatedFrequency < k) { + while (cumulatedFrequency < k-DBL_EPSILON) { sortedElementIndex = minIndex(bufferValues, numberOfPairsOfSeries(series)); bufferValues[sortedElementIndex] = DBL_MAX; cumulatedFrequency += m_data[series][1][sortedElementIndex] / totalNumberOfElements; From 8d95f408bec5b2d3b5536460e2c2508f7b2303e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 10 Sep 2018 13:29:34 +0200 Subject: [PATCH 41/43] [poincare] Tests on statistics --- apps/statistics/Makefile | 5 + apps/statistics/test/store.cpp | 207 +++++++++++++++++++++++++++++++++ 2 files changed, 212 insertions(+) create mode 100644 apps/statistics/test/store.cpp diff --git a/apps/statistics/Makefile b/apps/statistics/Makefile index 0caf06634..8fcdc7d19 100644 --- a/apps/statistics/Makefile +++ b/apps/statistics/Makefile @@ -31,4 +31,9 @@ i18n_files += $(addprefix apps/statistics/,\ base.pt.i18n\ ) +tests += $(addprefix apps/statistics/test/,\ + store.cpp\ +) +test_objs += $(addprefix apps/statistics/, store.o) + app_images += apps/statistics/stat_icon.png diff --git a/apps/statistics/test/store.cpp b/apps/statistics/test/store.cpp new file mode 100644 index 000000000..486bc15ae --- /dev/null +++ b/apps/statistics/test/store.cpp @@ -0,0 +1,207 @@ +#include +#include +#include +#include "../store.h" + +namespace Statistics { + +void assert_value_approximately_equal_to(double d1, double d2) { + assert(d1 == d2 || fabs(d1-d2) < 0.001); +} + +void assert_data_statictics_equal_to(double n[], double v[], int numberOfData, double sumOfOccurrences, double maxValue, double minValue, double range, double mean, double variance, double standardDeviation, double sampleStandardDeviation, double firstQuartile, double thirdQuartile, double quartileRange, double median, double sum, double squaredValueSum) { + Store store; + int seriesIndex = 0; + + // Set the data in the store + for (int i = 0; i < numberOfData; i++) { + store.set(n[i], seriesIndex, 0, i); + store.set(v[i], seriesIndex, 1, i); + } + + // Compare the statistics + assert_value_approximately_equal_to(standardDeviation * standardDeviation, variance); + assert_value_approximately_equal_to(store.sumOfOccurrences(seriesIndex), sumOfOccurrences); + assert_value_approximately_equal_to(store.maxValue(seriesIndex), maxValue); + assert_value_approximately_equal_to(store.minValue(seriesIndex), minValue); + assert_value_approximately_equal_to(store.range(seriesIndex), range); + assert_value_approximately_equal_to(store.mean(seriesIndex), mean); + assert_value_approximately_equal_to(store.variance(seriesIndex), variance); + assert_value_approximately_equal_to(store.standardDeviation(seriesIndex), standardDeviation); + assert_value_approximately_equal_to(store.sampleStandardDeviation(seriesIndex), sampleStandardDeviation); + assert_value_approximately_equal_to(store.firstQuartile(seriesIndex), firstQuartile); + assert_value_approximately_equal_to(store.thirdQuartile(seriesIndex), thirdQuartile); + assert_value_approximately_equal_to(store.quartileRange(seriesIndex), quartileRange); + assert_value_approximately_equal_to(store.median(seriesIndex), median); + assert_value_approximately_equal_to(store.sum(seriesIndex), sum); + assert_value_approximately_equal_to(store.squaredValueSum(seriesIndex), squaredValueSum); +} + +QUIZ_CASE(data_statistics) { + /* 1 2 3 4 + * 1 1 1 1 */ + double n1[4] = {1.0, 2.0, 3.0, 4.0}; + double v1[4] = {1.0, 1.0, 1.0, 1.0}; + assert_data_statictics_equal_to( + n1, + v1, + 4, + /* sumOfOccurrences */ 4.0, + /* maxValue */ 4.0, + /* minValue */ 1.0, + /* range */ 3.0, + /* mean */ 2.5, + /* variance */ 1.25, + /* standardDeviation */ 1.118, + /* sampleStandardDeviation */ 1.291, + /* firstQuartile */ 1.0, + /* thirdQuartile */ 3.0, + /* quartileRange */ 2.0, + /* median */ 2.5, + /* sum */ 10.0, + /* squaredValueSum */ 30.0); + + + /* 1 2 3 4 5 6 7 8 9 10 11 + * 1 1 1 1 1 1 1 1 1 1 1 */ + + double n2[11] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0}; + double v2[11] = {1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0}; + assert_data_statictics_equal_to( + n2, + v2, + 11, + /* sumOfOccurrences */ 11.0, + /* maxValue */ 11.0, + /* minValue */ 1.0, + /* range */ 10.0, + /* mean */ 6.0, + /* variance */ 10.0, + /* standardDeviation */ 3.1623, + /* sampleStandardDeviation */ 3.3166, + /* firstQuartile */ 3.0, + /* thirdQuartile */ 9.0, + /* quartileRange */ 6.0, + /* median */ 6.0, + /* sum */ 66.0, + /* squaredValueSum */ 506.0); + + /* 1 2 3 4 5 6 7 8 9 10 11 12 + * 1 1 1 1 1 1 1 1 1 1 1 1 */ + + double n3[12] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0}; + double v3[12] = {1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0}; + assert_data_statictics_equal_to( + n3, + v3, + 12, + /* sumOfOccurrences */ 12.0, + /* maxValue */ 12.0, + /* minValue */ 1.0, + /* range */ 11.0, + /* mean */ 6.5, + /* variance */ 11.917, + /* standardDeviation */ 3.4521, + /* sampleStandardDeviation */ 3.6056, + /* firstQuartile */ 3.0, + /* thirdQuartile */ 9.0, + /* quartileRange */ 6.0, + /* median */ 6.5, + /* sum */ 78.0, + /* squaredValueSum */ 650.0); + + /* 1 2 3 5 10 + * 0.2 0.05 0.3 0.0001 0.4499 */ + double n4[5] = {1.0, 2.0, 3.0, 5.0, 10.0}; + double v4[5] = {0.2, 0.05, 0.3, 0.0001, 0.4499}; + assert_data_statictics_equal_to( + n4, + v4, + 5, + /* sumOfOccurrences */ 1.0, + /* maxValue */ 10.0, + /* minValue */ 1.0, + /* range */ 9.0, + /* mean */ 5.6995, + /* variance */ 15.6082, + /* standardDeviation */ 3.9507, + /* sampleStandardDeviation */ INFINITY, + /* firstQuartile */ 2.0, + /* thirdQuartile */ 10.0, + /* quartileRange */ 8.0, + /* median */ 3.0, + /* sum */ 5.6995, + /* squaredValueSum */ 48.0925); + + /* 1 -2 3 5 10 + * 0.4 0.00005 0.9 0.4 0.5 */ + double n5[5] = {1.0, -2.0, 3.0, 5.0, 10.0}; + double v5[5] = {0.4, 0.00005, 0.9, 0.4, 0.5}; + assert_data_statictics_equal_to( + n5, + v5, + 5, + /* sumOfOccurrences */ 2.2, + /* maxValue */ 10.0, + /* minValue */ -2.0, + /* range */ 12.0, + /* mean */ 4.5908, + /* variance */ 10.06, + /* standardDeviation */ 3.1719, + /* sampleStandardDeviation */ 4.2947, + /* firstQuartile */ 3.0, + /* thirdQuartile */ 5.0, + /* quartileRange */ 2.0, + /* median */ 3.0, + /* sum */ 10.1, + /* squaredValueSum */ 68.500); + + /* -7 -10 12 5 -2 + * 4 5 3 1 9 */ + double n6[6] = {-7.0, -10.0, 1.0, 2.0, 5.0, -2.0}; + double v6[6] = {4.0, 5.0, 3.0, 0.5, 1.0, 9.0}; + assert_data_statictics_equal_to( + n6, + v6, + 6, + /* sumOfOccurrences */ 22.5, + /* maxValue */ 5.0, + /* minValue */ -10.0, + /* range */ 15.0, + /* mean */ -3.8667, + /* variance */ 18.9155, + /* standardDeviation */ 4.3492, + /* sampleStandardDeviation */ 4.4492, + /* firstQuartile */ -7.0, + /* thirdQuartile */ -2.0, + /* quartileRange */ 5.0, + /* median */ -2.0, + /* sum */ -87.0, + /* squaredValueSum */ 762.0); + + /* 1 1 1 10 3 -1 3 + * 1 1 1 0 0 0 1 */ + double n7[7] = {1.0, 1.0, 1.0, 10.0, 3.0, -1.0, 3.0}; + double v7[7] = {1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0}; + assert_data_statictics_equal_to( + n7, + v7, + 7, + /* sumOfOccurrences */ 4.0, + /* maxValue */ 3.0, + /* minValue */ 1.0, + /* range */ 2.0, + /* mean */ 1.5, + /* variance */ 0.75, + /* standardDeviation */ 0.866, + /* sampleStandardDeviation */ 1.0, + /* firstQuartile */ 1.0, + /* thirdQuartile */ 1.0, + /* quartileRange */ 0.0, + /* median */ 1.0, + /* sum */ 6.0, + /* squaredValueSum */ 12.0); + +} + +} From 0038cb537a0e916ce8d3ca88e707f4a05e1b191f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 11 Sep 2018 09:56:06 +0200 Subject: [PATCH 42/43] [statistics] For median and quartiles, compare absolute frequencies Instead of relative frequencies --- apps/statistics/store.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/statistics/store.cpp b/apps/statistics/store.cpp index 086d6af08..7224eca88 100644 --- a/apps/statistics/store.cpp +++ b/apps/statistics/store.cpp @@ -245,16 +245,18 @@ double Store::sortedElementAtCumulatedFrequency(int series, double k, bool creat // TODO: use an other algorithm (ex quickselect) to avoid quadratic complexity assert(k >= 0.0 && k <= 1.0); double totalNumberOfElements = sumOfOccurrences(series); + double numberOfElementsAtFrequencyK = totalNumberOfElements * k; + double bufferValues[numberOfPairsOfSeries(series)]; memcpy(bufferValues, m_data[series][0], numberOfPairsOfSeries(series)*sizeof(double)); int sortedElementIndex = 0; - double cumulatedFrequency = 0.0; - while (cumulatedFrequency < k-DBL_EPSILON) { + double cumulatedNumberOfElements = 0.0; + while (cumulatedNumberOfElements < numberOfElementsAtFrequencyK-DBL_EPSILON) { sortedElementIndex = minIndex(bufferValues, numberOfPairsOfSeries(series)); bufferValues[sortedElementIndex] = DBL_MAX; - cumulatedFrequency += m_data[series][1][sortedElementIndex] / totalNumberOfElements; + cumulatedNumberOfElements += m_data[series][1][sortedElementIndex]; } - if (createMiddleElement && std::fabs(cumulatedFrequency - k) < DBL_EPSILON) { + if (createMiddleElement && std::fabs(cumulatedNumberOfElements - numberOfElementsAtFrequencyK) < DBL_EPSILON) { int nextElementIndex = minIndex(bufferValues, numberOfPairsOfSeries(series)); if (bufferValues[nextElementIndex] != DBL_MAX) { return (m_data[series][0][sortedElementIndex] + m_data[series][0][nextElementIndex]) / 2.0; From 5821388b9813b668fd36b22f300d229c443baeec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 11 Sep 2018 10:38:06 +0200 Subject: [PATCH 43/43] [statistics/test] Clearer assertion --- apps/statistics/test/store.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/statistics/test/store.cpp b/apps/statistics/test/store.cpp index 486bc15ae..ecca0596e 100644 --- a/apps/statistics/test/store.cpp +++ b/apps/statistics/test/store.cpp @@ -1,12 +1,15 @@ #include #include #include +#include #include "../store.h" namespace Statistics { void assert_value_approximately_equal_to(double d1, double d2) { - assert(d1 == d2 || fabs(d1-d2) < 0.001); + assert((std::isnan(d1) && std::isnan(d2)) + || (std::isinf(d1) && std::isinf(d2) && d1*d2 > 0 /*same sign*/) + || fabs(d1-d2) < 0.001); } void assert_data_statictics_equal_to(double n[], double v[], int numberOfData, double sumOfOccurrences, double maxValue, double minValue, double range, double mean, double variance, double standardDeviation, double sampleStandardDeviation, double firstQuartile, double thirdQuartile, double quartileRange, double median, double sum, double squaredValueSum) {