From b744b96622e684a2aa29c358e124f288ba3cf9cc Mon Sep 17 00:00:00 2001 From: JF Date: Sat, 28 Dec 2019 14:34:50 +0100 Subject: [PATCH] Add DateTimeController to manage the time. Use messages in message queues to refresh the UI --- src/BLE/BleManager.c | 7 +- src/BLE/BleManager.h | 2 +- src/CMakeLists.txt | 4 + .../DateTime/DateTimeController.cpp | 16 ++ src/Components/DateTime/DateTimeController.h | 30 ++++ src/DisplayApp/DisplayApp.cpp | 145 +++++++++++------- src/DisplayApp/DisplayApp.h | 26 ++-- src/main.cpp | 23 ++- 8 files changed, 179 insertions(+), 74 deletions(-) create mode 100644 src/Components/DateTime/DateTimeController.cpp create mode 100644 src/Components/DateTime/DateTimeController.h diff --git a/src/BLE/BleManager.c b/src/BLE/BleManager.c index af5d51fd..b369ca23 100644 --- a/src/BLE/BleManager.c +++ b/src/BLE/BleManager.c @@ -320,8 +320,8 @@ void ble_manager_start_advertising(void *p_erase_bonds) { } } -void (*OnNewTimeCallback)(uint8_t, uint8_t); -void ble_manager_set_callback(void (*OnNewTime)(uint8_t, uint8_t)) { +void (*OnNewTimeCallback)(current_time_char_t*); +void ble_manager_set_callback(void (*OnNewTime)(current_time_char_t*)) { OnNewTimeCallback = OnNewTime; } @@ -485,8 +485,7 @@ void ble_manager_cts_print_time(ble_cts_c_evt_t *p_evt) { NRF_LOG_INFO("\tManual update %x", p_evt->params.current_time.adjust_reason.manual_time_update); - OnNewTimeCallback(p_evt->params.current_time.exact_time_256.day_date_time.date_time.minutes, - p_evt->params.current_time.exact_time_256.day_date_time.date_time.hours); + OnNewTimeCallback(&p_evt->params.current_time); } void ble_manager_init_connection_params() { diff --git a/src/BLE/BleManager.h b/src/BLE/BleManager.h index 21a91e3b..b664bacc 100644 --- a/src/BLE/BleManager.h +++ b/src/BLE/BleManager.h @@ -35,7 +35,7 @@ void ble_manager_init(); void ble_manager_start_advertising(void *p_erase_bonds); // TODO use signals from RTOS to notify new time -void ble_manager_set_callback(void (*OnNewTime)(uint8_t minutes, uint8_t hours)); +void ble_manager_set_callback(void (*OnNewTime)(current_time_char_t* currentTime)); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a30bd19a..663bb749 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -40,6 +40,8 @@ list(APPEND SOURCE_FILES BLE/BleManager.c Components/Battery/BatteryController.cpp Components/Ble/BleController.cpp + Components/Pinetime/PinetimeController.cpp + Components/DateTime/DateTimeController.cpp ) set(INCLUDE_FILES @@ -55,6 +57,8 @@ set(INCLUDE_FILES BLE/BleManager.h Components/Battery/BatteryController.h Components/Ble/BleController.h + Components/Pinetime/PinetimeController.h + Components/DateTime/DateTimeController.h ) nRF5x_addExecutable(pinetime-app "${SOURCE_FILES}") \ No newline at end of file diff --git a/src/Components/DateTime/DateTimeController.cpp b/src/Components/DateTime/DateTimeController.cpp new file mode 100644 index 00000000..1c15642e --- /dev/null +++ b/src/Components/DateTime/DateTimeController.cpp @@ -0,0 +1,16 @@ +#include "DateTimeController.h" + +using namespace Pinetime::Controllers; + + +void DateTime::UpdateTime(uint16_t year, Months month, uint8_t day, Days dayOfWeek, uint8_t hour, uint8_t minute, + uint8_t second) { + this->year = year; + this->month = month; + this->dayOfWeek = dayOfWeek; + this->day = day; + this->hour = hour; + this->minute = minute; + this->second = second; +} + diff --git a/src/Components/DateTime/DateTimeController.h b/src/Components/DateTime/DateTimeController.h new file mode 100644 index 00000000..edbb46c7 --- /dev/null +++ b/src/Components/DateTime/DateTimeController.h @@ -0,0 +1,30 @@ +#pragma once + +#include + +namespace Pinetime { + namespace Controllers { + class DateTime { + public: + enum class Days : uint8_t {Unknown, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday}; + enum class Months : uint8_t {Unknown, January, February, March, April, May, June, July, August, September, October, November, December}; + + void UpdateTime(uint16_t year, Months month, uint8_t day, Days dayOfWeek, uint8_t hour, uint8_t minute, uint8_t second); + uint16_t Year() const { return year; } + Months Month() const { return month; } + uint8_t Day() const { return day; } + Days DayOfWeek() const { return dayOfWeek; } + uint8_t Hours() const { return hour; } + uint8_t Minutes() const { return minute; } + uint8_t Seconds() const { return second; } + private: + uint16_t year = 0; + Months month = Months::Unknown; + uint8_t day = 0; + Days dayOfWeek = Days::Unknown; + uint8_t hour = 0; + uint8_t minute = 0; + uint8_t second = 0; + }; + } +} \ No newline at end of file diff --git a/src/DisplayApp/DisplayApp.cpp b/src/DisplayApp/DisplayApp.cpp index f72f057b..24cd2f36 100644 --- a/src/DisplayApp/DisplayApp.cpp +++ b/src/DisplayApp/DisplayApp.cpp @@ -7,12 +7,43 @@ #include #include "Components/Gfx/Gfx.h" #include +#include using namespace Pinetime::Applications; -DisplayApp::DisplayApp(Pinetime::Controllers::Battery &batteryController, Pinetime::Controllers::Ble &bleController) : +char const *DisplayApp::DaysString[] = { + "", + "MONDAY", + "TUESDAY", + "WEDNESDAY", + "THURSDAY", + "FRIDAY", + "SATURDAY", + "SUNDAY" +}; + +char const *DisplayApp::MonthsString[] = { + "", + "JAN", + "FEB", + "MAR", + "APR", + "MAY", + "JUN", + "JUL", + "AUG", + "SEP", + "OCT", + "NOV", + "DEC" +}; + +DisplayApp::DisplayApp(Controllers::Battery &batteryController, + Controllers::Ble &bleController, + Controllers::DateTime &dateTimeController) : batteryController{batteryController}, - bleController{bleController} { + bleController{bleController}, + dateTimeController{dateTimeController} { msgQueue = xQueueCreate(queueSize, itemSize); } @@ -22,7 +53,7 @@ void DisplayApp::Start() { } void DisplayApp::Process(void *instance) { - auto* app = static_cast(instance); + auto *app = static_cast(instance); NRF_LOG_INFO("DisplayApp task started!"); app->InitHw(); @@ -54,7 +85,7 @@ void DisplayApp::InitHw() { gfx->ClearScreen(); uint8_t x = 7; - gfx->DrawChar(&largeFont , '0', &x, 78, 0xffff); + gfx->DrawChar(&largeFont, '0', &x, 78, 0xffff); x = 61; gfx->DrawChar(&largeFont, '0', &x, 78, 0xffff); @@ -69,12 +100,12 @@ void DisplayApp::InitHw() { gfx->DrawChar(&largeFont, '0', &x, 78, 0xffff); gfx->DrawString(10, 0, 0x0000, "BLE", &smallFont, false); - gfx->DrawString(20, 180, 0xffff, "FRIDAY 27 DEC 2019", &smallFont, false); + gfx->DrawString(20, 180, 0xffff, "", &smallFont, false); } void DisplayApp::Refresh() { TickType_t queueTimeout; - switch(state) { + switch (state) { case States::Idle: IdleState(); queueTimeout = portMAX_DELAY; @@ -86,8 +117,8 @@ void DisplayApp::Refresh() { } Messages msg; - if(xQueueReceive( msgQueue, &msg, queueTimeout)) { - switch(msg) { + if (xQueueReceive(msgQueue, &msg, queueTimeout)) { + switch (msg) { case Messages::GoToSleep: nrf_gpio_pin_set(23); vTaskDelay(100); @@ -102,66 +133,53 @@ void DisplayApp::Refresh() { nrf_gpio_pin_clear(14); state = States::Running; break; + case Messages::UpdateDateTime: + deltaSeconds = nrf_rtc_counter_get(portNRF_RTC_REG) / 1000; + this->seconds = dateTimeController.Seconds(); + this->minutes = dateTimeController.Minutes(); + this->hours = dateTimeController.Hours(); + dateUpdated = true; + break; + case Messages::UpdateBleConnection: + bleConnectionUpdated = true; + break; + case Messages::UpdateBatteryLevel: + batteryLevelUpdated = true; + 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); - char batteryChar[11]; - uint16_t newBatteryValue = batteryController.PercentRemaining(); - newBatteryValue = (newBatteryValue>100) ? 100 : newBatteryValue; - newBatteryValue = (newBatteryValue<0) ? 0 : newBatteryValue; - if(newBatteryValue != battery) { - battery = newBatteryValue; - sprintf(batteryChar, "BAT: %d%%", battery); - gfx->DrawString((240-108), 0, 0xffff, batteryChar, &smallFont, false); + if (batteryLevelUpdated) { + char batteryChar[11]; + uint16_t newBatteryValue = batteryController.PercentRemaining(); + newBatteryValue = (newBatteryValue > 100) ? 100 : newBatteryValue; + newBatteryValue = (newBatteryValue < 0) ? 0 : newBatteryValue; + + batteryLevelUpdated = false; + sprintf(batteryChar, "BAT: %d%%", newBatteryValue); + gfx->DrawString((240 - 108), 0, 0xffff, batteryChar, &smallFont, false); } - bool newIsBleConnected = bleController.IsConnected(); - if(newIsBleConnected != bleConnected) { - bleConnected = newIsBleConnected; - uint16_t color = (bleConnected) ? 0xffff : 0x0000; + if (bleConnectionUpdated) { + bleConnectionUpdated = false; + uint16_t color = (bleController.IsConnected()) ? 0xffff : 0x0000; gfx->DrawString(10, 0, color, "BLE", &smallFont, false); } auto raw = systick_counter / 1000; auto currentDeltaSeconds = raw - deltaSeconds; - auto deltaMinutes = (currentDeltaSeconds / 60); auto currentMinutes = minutes + deltaMinutes; auto deltaHours = currentMinutes / 60; currentMinutes -= (deltaHours * 60); - -// -// TODO make this better! -// minutes = raw / 60; -// seconds = raw - (minutes*60); - - auto currentHours = hours + deltaHours; - - char minutesChar[3]; sprintf(minutesChar, "%02d", currentMinutes); @@ -169,30 +187,51 @@ void DisplayApp::RunningState() { sprintf(hoursChar, "%02d", currentHours); uint8_t x = 7; - if(hoursChar[0] != currentChar[0]) { + if (hoursChar[0] != currentChar[0]) { gfx->DrawChar(&largeFont, hoursChar[0], &x, 78, 0xffff); currentChar[0] = hoursChar[0]; } x = 61; - if(hoursChar[1] != currentChar[1]) { + if (hoursChar[1] != currentChar[1]) { gfx->DrawChar(&largeFont, hoursChar[1], &x, 78, 0xffff); currentChar[1] = hoursChar[1]; } x = 127; - if(minutesChar[0] != currentChar[2]) { + if (minutesChar[0] != currentChar[2]) { gfx->DrawChar(&largeFont, minutesChar[0], &x, 78, 0xffff); currentChar[2] = minutesChar[0]; } x = 181; - if(minutesChar[1] != currentChar[3]) { + if (minutesChar[1] != currentChar[3]) { gfx->DrawChar(&largeFont, minutesChar[1], &x, 78, 0xffff); currentChar[3] = minutesChar[1]; } + + if (dateUpdated) { + auto year = dateTimeController.Year(); + auto month = dateTimeController.Month(); + auto day = dateTimeController.Day(); + auto dayOfWeek = dateTimeController.DayOfWeek(); + + char dateStr[22]; + sprintf(dateStr, "%s %d %s %d", DayOfWeekToString(dayOfWeek), day, MonthToString(month), year); + gfx->DrawString(10, 180, 0xffff, dateStr, &smallFont, false); + dateUpdated = false; + } } +const char *DisplayApp::MonthToString(Pinetime::Controllers::DateTime::Months month) { + return DisplayApp::MonthsString[static_cast(month)]; +} + +const char *DisplayApp::DayOfWeekToString(Pinetime::Controllers::DateTime::Days dayOfWeek) { + return DisplayApp::DaysString[static_cast(dayOfWeek)]; +} + + void DisplayApp::IdleState() { } @@ -200,10 +239,8 @@ void DisplayApp::IdleState() { void DisplayApp::PushMessage(DisplayApp::Messages msg) { BaseType_t xHigherPriorityTaskWoken; xHigherPriorityTaskWoken = pdFALSE; - xQueueSendFromISR( msgQueue, &msg, &xHigherPriorityTaskWoken ); - - /* Now the buffer is empty we can switch context if necessary. */ - if(xHigherPriorityTaskWoken) { + xQueueSendFromISR(msgQueue, &msg, &xHigherPriorityTaskWoken); + 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 3bc9f468..24b8e45d 100644 --- a/src/DisplayApp/DisplayApp.h +++ b/src/DisplayApp/DisplayApp.h @@ -8,6 +8,7 @@ #include #include #include +#include #include "lcdfont14.h" extern const FONT_INFO lCD_70ptFontInfo; @@ -17,15 +18,11 @@ namespace Pinetime { class DisplayApp { public: enum class States {Idle, Running}; - enum class Messages : uint8_t {GoToSleep, GoToRunning} ; - DisplayApp(Pinetime::Controllers::Battery& batteryController, Pinetime::Controllers::Ble& bleController); + enum class Messages : uint8_t {GoToSleep, GoToRunning, UpdateDateTime, UpdateBleConnection, UpdateBatteryLevel} ; + DisplayApp(Controllers::Battery &batteryController, + Controllers::Ble &bleController, + Controllers::DateTime& dateTimeController); void Start(); - - void Minutes(uint8_t m); - void Hours(uint8_t h); - - void SetTime(uint8_t minutes, uint8_t hours); - void PushMessage(Messages msg); private: @@ -39,6 +36,8 @@ namespace Pinetime { const FONT_INFO smallFont {lCD_14ptFontInfo.height, lCD_14ptFontInfo.startChar, lCD_14ptFontInfo.endChar, lCD_14ptFontInfo.spacePixels, lCD_14ptFontInfo.charInfo, lCD_14ptFontInfo.data}; void Refresh(); + static const char* MonthToString(Pinetime::Controllers::DateTime::Months month); + static const char* DayOfWeekToString(Pinetime::Controllers::DateTime::Days dayOfWeek); uint8_t seconds = 0; uint8_t minutes = 0; uint8_t hours = 0; @@ -55,8 +54,15 @@ namespace Pinetime { Pinetime::Controllers::Battery &batteryController; Pinetime::Controllers::Ble &bleController; - uint16_t battery = 0; - bool bleConnected = false; + Pinetime::Controllers::DateTime& dateTimeController; + bool bleConnectionUpdated = false; + bool batteryLevelUpdated = false; + + static char const *DaysString[]; + + static char const *MonthsString[]; + + bool dateUpdated = false; }; } diff --git a/src/main.cpp b/src/main.cpp index 396935b0..6463415a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include "BLE/BleManager.h" #include "Components/Battery/BatteryController.h" #include "Components/Ble/BleController.h" @@ -28,6 +30,7 @@ bool isSleeping = false; TimerHandle_t debounceTimer; Pinetime::Controllers::Battery batteryController; Pinetime::Controllers::Ble bleController; +Pinetime::Controllers::DateTime dateTimeController; extern "C" { void vApplicationIdleHook() { @@ -51,6 +54,7 @@ void DebounceTimerCallback(TimerHandle_t xTimer) { displayApp->PushMessage(Pinetime::Applications::DisplayApp::Messages::GoToRunning); isSleeping = false; batteryController.Update(); + displayApp->PushMessage(Pinetime::Applications::DisplayApp::Messages::UpdateBatteryLevel); } else { displayApp->PushMessage(Pinetime::Applications::DisplayApp::Messages::GoToSleep); @@ -66,6 +70,7 @@ void SystemTask(void *) { batteryController.Init(); batteryController.Update(); + displayApp->PushMessage(Pinetime::Applications::DisplayApp::Messages::UpdateBatteryLevel); debounceTimer = xTimerCreate ("debounceTimer", 200, pdFALSE, (void *) 0, DebounceTimerCallback); @@ -81,18 +86,26 @@ void SystemTask(void *) { 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) { +void OnNewTime(current_time_char_t* currentTime) { bleController.Connect(); - displayApp->SetTime(minutes, hours); + displayApp->PushMessage(Pinetime::Applications::DisplayApp::Messages::UpdateBleConnection); + + auto dayOfWeek = currentTime->exact_time_256.day_date_time.day_of_week; + auto year = currentTime->exact_time_256.day_date_time.date_time.year; + auto month = currentTime->exact_time_256.day_date_time.date_time.month; + auto day = currentTime->exact_time_256.day_date_time.date_time.day; + auto hour = currentTime->exact_time_256.day_date_time.date_time.hours; + auto minute = currentTime->exact_time_256.day_date_time.date_time.minutes; + auto second = currentTime->exact_time_256.day_date_time.date_time.seconds; + dateTimeController.UpdateTime(year, static_cast(month), day, static_cast(dayOfWeek), hour, minute, second); + displayApp->PushMessage(Pinetime::Applications::DisplayApp::Messages::UpdateDateTime); } int main(void) { - displayApp.reset(new Pinetime::Applications::DisplayApp(batteryController, bleController)); + displayApp.reset(new Pinetime::Applications::DisplayApp(batteryController, bleController, dateTimeController)); logger.Init(); nrf_drv_clock_init();