From 75e74904e82a18012436a3d496223d2d53111866 Mon Sep 17 00:00:00 2001 From: JF Date: Thu, 26 Dec 2019 18:33:40 +0100 Subject: [PATCH] Use push button to go to sleep/wake up. Use a queue to transmit messages between system and display task (sleep & wake up for now). --- README.md | 3 ++ src/DisplayApp/DisplayApp.cpp | 79 ++++++++++++++++++++++++++++------- src/DisplayApp/DisplayApp.h | 17 +++++++- src/main.cpp | 48 +++++++++++++++++---- src/sdk_config.h | 4 +- 5 files changed, 125 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index b428ffdc..b1806851 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,9 @@ I've tested this project on the actual PineTime hardware. * One big font to display the time (hours : minutes) * BLE advertising, connection and bonding * BLE CTS client (retrieves the time from the connected device if it implements a CTS server) + * Push button to go to disable screen (and go to low power mode) / enable screen (and wake-up). **NOTE** : I'm not completely sure the power consumption is optimal, especially in sleep mode. Any help to measure and debug this is welcome. + + ## How to build diff --git a/src/DisplayApp/DisplayApp.cpp b/src/DisplayApp/DisplayApp.cpp index ea92a29d..964db633 100644 --- a/src/DisplayApp/DisplayApp.cpp +++ b/src/DisplayApp/DisplayApp.cpp @@ -6,6 +6,7 @@ #include #include #include "Components/Gfx/Gfx.h" +#include using namespace Pinetime::Applications; @@ -21,10 +22,7 @@ void DisplayApp::Process(void *instance) { app->InitHw(); while (1) { - app->Refresh(); - - vTaskDelay(1000); } } @@ -67,6 +65,56 @@ void DisplayApp::InitHw() { } void DisplayApp::Refresh() { + TickType_t queueTimeout; + switch(state) { + case States::Idle: + IdleState(); + queueTimeout = portMAX_DELAY; + break; + case States::Running: + RunningState(); + queueTimeout = 1000; + break; + } + + Messages msg; + if(xQueueReceive( msgQueue, &msg, queueTimeout)) { + switch(msg) { + case Messages::GoToSleep: + nrf_gpio_pin_set(23); + vTaskDelay(100); + nrf_gpio_pin_set(22); + vTaskDelay(100); + nrf_gpio_pin_set(14); + state = States::Idle; + break; + case Messages::GoToRunning: + nrf_gpio_pin_clear(23); + nrf_gpio_pin_clear(22); + nrf_gpio_pin_clear(14); + state = States::Running; + break; + } + } +} + +void DisplayApp::Minutes(uint8_t m) { + // TODO yeah, I know, race condition... + minutes = m; +} + +void DisplayApp::Hours(uint8_t h) { + // TODO yeah, I know, race condition too... + hours = h; +} + +void DisplayApp::SetTime(uint8_t minutes, uint8_t hours) { + deltaSeconds = nrf_rtc_counter_get(portNRF_RTC_REG) / 1000; + this->minutes = minutes; + this->hours = hours; +} + +void DisplayApp::RunningState() { uint32_t systick_counter = nrf_rtc_counter_get(portNRF_RTC_REG); auto raw = systick_counter / 1000; @@ -118,21 +166,24 @@ void DisplayApp::Refresh() { gfx->DrawChar(&largeFont, minutesChar[1], &x, 78, 0xffff); currentChar[3] = minutesChar[1]; } +} + +void DisplayApp::IdleState() { } -void DisplayApp::Minutes(uint8_t m) { - // TODO yeah, I know, race condition... - minutes = m; +DisplayApp::DisplayApp() { + msgQueue = xQueueCreate(queueSize, itemSize); } -void DisplayApp::Hours(uint8_t h) { - // TODO yeah, I know, race condition too... - hours = h; -} +void DisplayApp::PushMessage(DisplayApp::Messages msg) { + BaseType_t xHigherPriorityTaskWoken; + xHigherPriorityTaskWoken = pdFALSE; + xQueueSendFromISR( msgQueue, &msg, &xHigherPriorityTaskWoken ); -void DisplayApp::SetTime(uint8_t minutes, uint8_t hours) { - deltaSeconds = nrf_rtc_counter_get(portNRF_RTC_REG) / 1000; - this->minutes = minutes; - this->hours = hours; + /* Now the buffer is empty we can switch context if necessary. */ + if(xHigherPriorityTaskWoken) { + /* Actual macro used here is port specific. */ + // TODO : should I do something here? + } } diff --git a/src/DisplayApp/DisplayApp.h b/src/DisplayApp/DisplayApp.h index e89ff64f..b15c3580 100644 --- a/src/DisplayApp/DisplayApp.h +++ b/src/DisplayApp/DisplayApp.h @@ -5,6 +5,7 @@ #include #include #include +#include extern const FONT_INFO lCD_70ptFontInfo; @@ -12,6 +13,9 @@ namespace Pinetime { namespace Applications { class DisplayApp { public: + enum class States {Idle, Running}; + enum class Messages : uint8_t {GoToSleep, GoToRunning} ; + DisplayApp(); void Start(); void Minutes(uint8_t m); @@ -19,6 +23,8 @@ namespace Pinetime { void SetTime(uint8_t minutes, uint8_t hours); + void PushMessage(Messages msg); + private: TaskHandle_t taskHandle; static void Process(void* instance); @@ -29,13 +35,20 @@ namespace Pinetime { const FONT_INFO largeFont {lCD_70ptFontInfo.height, lCD_70ptFontInfo.startChar, lCD_70ptFontInfo.endChar, lCD_70ptFontInfo.spacePixels, lCD_70ptFontInfo.charInfo, lCD_70ptFontInfo.data}; void Refresh(); - - uint8_t seconds = 0; uint8_t minutes = 0; uint8_t hours = 0; char currentChar[4]; uint32_t deltaSeconds = 0; + + States state = States::Running; + void RunningState(); + void IdleState(); + QueueHandle_t msgQueue; + + static constexpr uint8_t queueSize = 10; + static constexpr uint8_t itemSize = 1; + }; } } diff --git a/src/main.cpp b/src/main.cpp index 9cc1b671..029619bf 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,5 @@ #include #include -#include #include #include #include @@ -9,6 +8,8 @@ #include #include +#include +#include #include "BLE/BleManager.h" @@ -20,9 +21,10 @@ Pinetime::Logging::NrfLogger logger; Pinetime::Logging::DummyLogger logger; #endif -Pinetime::Applications::BlinkApp blinkApp; Pinetime::Applications::DisplayApp displayApp; TaskHandle_t systemThread; +bool isSleeping = false; +TimerHandle_t debounceTimer; extern "C" { void vApplicationIdleHook() { @@ -34,17 +36,48 @@ extern "C" { } } + + +void nrfx_gpiote_evt_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) { + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + xTimerStartFromISR(debounceTimer, &xHigherPriorityTaskWoken); + // TODO should I do something if xHigherPriorityTaskWoken == pdTRUE? +} + +void DebounceTimerCallback(TimerHandle_t xTimer) { + xTimerStop(xTimer, 0); + if(isSleeping) { + displayApp.PushMessage(Pinetime::Applications::DisplayApp::Messages::GoToRunning); + isSleeping = false; + } + else { + displayApp.PushMessage(Pinetime::Applications::DisplayApp::Messages::GoToSleep); + isSleeping = true; + } +} + void SystemTask(void *) { APP_GPIOTE_INIT(2); - app_timer_init(); bool erase_bonds=false; nrf_sdh_freertos_init(ble_manager_start_advertising, &erase_bonds); -// blinkApp.Start(); displayApp.Start(); - while (1) { - vTaskSuspend(nullptr); - } + debounceTimer = xTimerCreate ("debounceTimer", 200, pdFALSE, (void *) 0, DebounceTimerCallback); + + nrf_gpio_cfg_sense_input(13, (nrf_gpio_pin_pull_t)GPIO_PIN_CNF_PULL_Pulldown, (nrf_gpio_pin_sense_t)GPIO_PIN_CNF_SENSE_High); + nrf_gpio_cfg_output(15); + nrf_gpio_pin_set(15); + + nrfx_gpiote_in_config_t pinConfig; + pinConfig.skip_gpio_setup = true; + pinConfig.hi_accuracy = false; + pinConfig.is_watcher = false; + pinConfig.sense = (nrf_gpiote_polarity_t)NRF_GPIOTE_POLARITY_HITOLO; + pinConfig.pull = (nrf_gpio_pin_pull_t)GPIO_PIN_CNF_PULL_Pulldown; + + nrfx_gpiote_in_init(13, &pinConfig, nrfx_gpiote_evt_handler); + + vTaskSuspend(nullptr); } void OnNewTime(uint8_t minutes, uint8_t hours) { @@ -55,7 +88,6 @@ int main(void) { logger.Init(); nrf_drv_clock_init(); - if (pdPASS != xTaskCreate(SystemTask, "MAIN", 256, nullptr, 0, &systemThread)) APP_ERROR_HANDLER(NRF_ERROR_NO_MEM); diff --git a/src/sdk_config.h b/src/sdk_config.h index 5ed46ed7..0fde8bac 100644 --- a/src/sdk_config.h +++ b/src/sdk_config.h @@ -4839,13 +4839,13 @@ // NRFX_TIMER_ENABLED - nrfx_timer - TIMER periperal driver //========================================================== #ifndef NRFX_TIMER_ENABLED -#define NRFX_TIMER_ENABLED 0 +#define NRFX_TIMER_ENABLED 1 #endif // NRFX_TIMER0_ENABLED - Enable TIMER0 instance #ifndef NRFX_TIMER0_ENABLED -#define NRFX_TIMER0_ENABLED 0 +#define NRFX_TIMER0_ENABLED 1 #endif // NRFX_TIMER1_ENABLED - Enable TIMER1 instance