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).
This commit is contained in:
JF 2019-12-26 18:33:40 +01:00
parent 9a379e180f
commit 75e74904e8
5 changed files with 125 additions and 26 deletions

View file

@ -28,6 +28,9 @@ I've tested this project on the actual PineTime hardware.
* One big font to display the time (hours : minutes) * One big font to display the time (hours : minutes)
* BLE advertising, connection and bonding * BLE advertising, connection and bonding
* BLE CTS client (retrieves the time from the connected device if it implements a CTS server) * 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 ## How to build

View file

@ -6,6 +6,7 @@
#include <nrf_font.h> #include <nrf_font.h>
#include <hal/nrf_rtc.h> #include <hal/nrf_rtc.h>
#include "Components/Gfx/Gfx.h" #include "Components/Gfx/Gfx.h"
#include <queue.h>
using namespace Pinetime::Applications; using namespace Pinetime::Applications;
@ -21,10 +22,7 @@ void DisplayApp::Process(void *instance) {
app->InitHw(); app->InitHw();
while (1) { while (1) {
app->Refresh(); app->Refresh();
vTaskDelay(1000);
} }
} }
@ -67,6 +65,56 @@ void DisplayApp::InitHw() {
} }
void DisplayApp::Refresh() { 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); uint32_t systick_counter = nrf_rtc_counter_get(portNRF_RTC_REG);
auto raw = systick_counter / 1000; auto raw = systick_counter / 1000;
@ -118,21 +166,24 @@ void DisplayApp::Refresh() {
gfx->DrawChar(&largeFont, minutesChar[1], &x, 78, 0xffff); gfx->DrawChar(&largeFont, minutesChar[1], &x, 78, 0xffff);
currentChar[3] = minutesChar[1]; currentChar[3] = minutesChar[1];
} }
}
void DisplayApp::IdleState() {
} }
void DisplayApp::Minutes(uint8_t m) { DisplayApp::DisplayApp() {
// TODO yeah, I know, race condition... msgQueue = xQueueCreate(queueSize, itemSize);
minutes = m;
} }
void DisplayApp::Hours(uint8_t h) { void DisplayApp::PushMessage(DisplayApp::Messages msg) {
// TODO yeah, I know, race condition too... BaseType_t xHigherPriorityTaskWoken;
hours = h; xHigherPriorityTaskWoken = pdFALSE;
} xQueueSendFromISR( msgQueue, &msg, &xHigherPriorityTaskWoken );
void DisplayApp::SetTime(uint8_t minutes, uint8_t hours) { /* Now the buffer is empty we can switch context if necessary. */
deltaSeconds = nrf_rtc_counter_get(portNRF_RTC_REG) / 1000; if(xHigherPriorityTaskWoken) {
this->minutes = minutes; /* Actual macro used here is port specific. */
this->hours = hours; // TODO : should I do something here?
}
} }

View file

@ -5,6 +5,7 @@
#include <drivers/SpiMaster.h> #include <drivers/SpiMaster.h>
#include <Components/Gfx/Gfx.h> #include <Components/Gfx/Gfx.h>
#include <bits/unique_ptr.h> #include <bits/unique_ptr.h>
#include <queue.h>
extern const FONT_INFO lCD_70ptFontInfo; extern const FONT_INFO lCD_70ptFontInfo;
@ -12,6 +13,9 @@ namespace Pinetime {
namespace Applications { namespace Applications {
class DisplayApp { class DisplayApp {
public: public:
enum class States {Idle, Running};
enum class Messages : uint8_t {GoToSleep, GoToRunning} ;
DisplayApp();
void Start(); void Start();
void Minutes(uint8_t m); void Minutes(uint8_t m);
@ -19,6 +23,8 @@ namespace Pinetime {
void SetTime(uint8_t minutes, uint8_t hours); void SetTime(uint8_t minutes, uint8_t hours);
void PushMessage(Messages msg);
private: private:
TaskHandle_t taskHandle; TaskHandle_t taskHandle;
static void Process(void* instance); 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}; const FONT_INFO largeFont {lCD_70ptFontInfo.height, lCD_70ptFontInfo.startChar, lCD_70ptFontInfo.endChar, lCD_70ptFontInfo.spacePixels, lCD_70ptFontInfo.charInfo, lCD_70ptFontInfo.data};
void Refresh(); void Refresh();
uint8_t seconds = 0; uint8_t seconds = 0;
uint8_t minutes = 0; uint8_t minutes = 0;
uint8_t hours = 0; uint8_t hours = 0;
char currentChar[4]; char currentChar[4];
uint32_t deltaSeconds = 0; 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;
}; };
} }
} }

View file

@ -1,6 +1,5 @@
#include <FreeRTOS.h> #include <FreeRTOS.h>
#include <task.h> #include <task.h>
#include <BlinkApp/BlinkApp.h>
#include <libraries/bsp/bsp.h> #include <libraries/bsp/bsp.h>
#include <legacy/nrf_drv_clock.h> #include <legacy/nrf_drv_clock.h>
#include <libraries/timer/app_timer.h> #include <libraries/timer/app_timer.h>
@ -9,6 +8,8 @@
#include <softdevice/common/nrf_sdh.h> #include <softdevice/common/nrf_sdh.h>
#include <softdevice/common/nrf_sdh_freertos.h> #include <softdevice/common/nrf_sdh_freertos.h>
#include <hal/nrf_rtc.h>
#include <timers.h>
#include "BLE/BleManager.h" #include "BLE/BleManager.h"
@ -20,9 +21,10 @@ Pinetime::Logging::NrfLogger logger;
Pinetime::Logging::DummyLogger logger; Pinetime::Logging::DummyLogger logger;
#endif #endif
Pinetime::Applications::BlinkApp blinkApp;
Pinetime::Applications::DisplayApp displayApp; Pinetime::Applications::DisplayApp displayApp;
TaskHandle_t systemThread; TaskHandle_t systemThread;
bool isSleeping = false;
TimerHandle_t debounceTimer;
extern "C" { extern "C" {
void vApplicationIdleHook() { 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 *) { void SystemTask(void *) {
APP_GPIOTE_INIT(2); APP_GPIOTE_INIT(2);
app_timer_init();
bool erase_bonds=false; bool erase_bonds=false;
nrf_sdh_freertos_init(ble_manager_start_advertising, &erase_bonds); nrf_sdh_freertos_init(ble_manager_start_advertising, &erase_bonds);
// blinkApp.Start();
displayApp.Start(); displayApp.Start();
while (1) { 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); vTaskSuspend(nullptr);
}
} }
void OnNewTime(uint8_t minutes, uint8_t hours) { void OnNewTime(uint8_t minutes, uint8_t hours) {
@ -55,7 +88,6 @@ int main(void) {
logger.Init(); logger.Init();
nrf_drv_clock_init(); nrf_drv_clock_init();
if (pdPASS != xTaskCreate(SystemTask, "MAIN", 256, nullptr, 0, &systemThread)) if (pdPASS != xTaskCreate(SystemTask, "MAIN", 256, nullptr, 0, &systemThread))
APP_ERROR_HANDLER(NRF_ERROR_NO_MEM); APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);

View file

@ -4839,13 +4839,13 @@
// <e> NRFX_TIMER_ENABLED - nrfx_timer - TIMER periperal driver // <e> NRFX_TIMER_ENABLED - nrfx_timer - TIMER periperal driver
//========================================================== //==========================================================
#ifndef NRFX_TIMER_ENABLED #ifndef NRFX_TIMER_ENABLED
#define NRFX_TIMER_ENABLED 0 #define NRFX_TIMER_ENABLED 1
#endif #endif
// <q> NRFX_TIMER0_ENABLED - Enable TIMER0 instance // <q> NRFX_TIMER0_ENABLED - Enable TIMER0 instance
#ifndef NRFX_TIMER0_ENABLED #ifndef NRFX_TIMER0_ENABLED
#define NRFX_TIMER0_ENABLED 0 #define NRFX_TIMER0_ENABLED 1
#endif #endif
// <q> NRFX_TIMER1_ENABLED - Enable TIMER1 instance // <q> NRFX_TIMER1_ENABLED - Enable TIMER1 instance