#include "DisplayApp.h" #include #include #include #include #include #include #include "Components/Gfx/Gfx.h" #include #include #include #include #include #include using namespace Pinetime::Applications; 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}, dateTimeController{dateTimeController} { msgQueue = xQueueCreate(queueSize, itemSize); } void DisplayApp::Start() { if (pdPASS != xTaskCreate(DisplayApp::Process, "DisplayApp", 256, this, 0, &taskHandle)) APP_ERROR_HANDLER(NRF_ERROR_NO_MEM); } void DisplayApp::Process(void *instance) { auto *app = static_cast(instance); NRF_LOG_INFO("DisplayApp task started!"); app->InitHw(); while (1) { app->Refresh(); } } void DisplayApp::InitHw() { nrf_gpio_cfg_output(14); nrf_gpio_cfg_output(22); nrf_gpio_cfg_output(23); nrf_gpio_pin_clear(14); nrf_gpio_pin_clear(22); nrf_gpio_pin_clear(23); Drivers::SpiMaster::Parameters params; params.bitOrder = Drivers::SpiMaster::BitOrder::Msb_Lsb; params.mode = Drivers::SpiMaster::Modes::Mode3; params.Frequency = Drivers::SpiMaster::Frequencies::Freq8Mhz; params.pinCSN = 25; params.pinMISO = 4; params.pinMOSI = 3; params.pinSCK = 2; spi.Init(Drivers::SpiMaster::SpiModule::SPI0, params); lcd.reset(new Drivers::St7789(spi, 18)); gfx.reset(new Components::Gfx(*lcd.get())); gfx->ClearScreen(); uint8_t x = 7; gfx->DrawChar(&largeFont, '0', &x, 78, 0xffff); x = 61; gfx->DrawChar(&largeFont, '0', &x, 78, 0xffff); x = 94; gfx->DrawChar(&largeFont, ':', &x, 78, 0xffff); x = 127; gfx->DrawChar(&largeFont, '0', &x, 78, 0xffff); x = 181; gfx->DrawChar(&largeFont, '0', &x, 78, 0xffff); gfx->DrawString(10, 0, 0x0000, "BLE", &smallFont, false); gfx->DrawString(20, 180, 0xffff, "", &smallFont, false); currentChar[0] = 0; currentChar[1] = 0; currentChar[2] = 0; currentChar[3] = 0; touchPanel.Init(); } 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); lcd->DisplayOff(); state = States::Idle; break; case Messages::GoToRunning: lcd->DisplayOn(); nrf_gpio_pin_clear(23); nrf_gpio_pin_clear(22); nrf_gpio_pin_clear(14); state = States::Running; break; case Messages::UpdateDateTime: break; case Messages::UpdateBleConnection: bleConnectionUpdated = true; break; case Messages::UpdateBatteryLevel: batteryLevelUpdated = true; break; case Messages::TouchEvent: if(state != States::Running) break; OnTouchEvent(); break; } } } void DisplayApp::RunningState() { uint32_t systick_counter = nrf_rtc_counter_get(portNRF_RTC_REG); 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); } 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; std::chrono::time_point currentDateTime; currentDateTime += date::years( dateTimeController.Year()-1970); currentDateTime += date::days( dateTimeController.Day() - 1); currentDateTime += date::months( (int)dateTimeController.Month() - 1); currentDateTime += std::chrono::hours(dateTimeController.Hours()); currentDateTime += std::chrono::minutes (dateTimeController.Minutes()); currentDateTime += std::chrono::seconds(dateTimeController.Seconds() + currentDeltaSeconds); currentDateTime -= std::chrono::hours(3); // TODO WHYYYY? auto dp = date::floor(currentDateTime); auto time = date::make_time(currentDateTime-dp); auto ymd = date::year_month_day(dp); auto year = (int)ymd.year(); auto month = (unsigned)ymd.month(); auto day = (unsigned)ymd.day(); auto weekday = date::weekday(ymd); auto hh = time.hours().count(); auto mm = time.minutes().count(); auto ss = time.seconds().count(); char minutesChar[3]; sprintf(minutesChar, "%02d", mm); char hoursChar[3]; sprintf(hoursChar, "%02d", hh); uint8_t x = 7; if (hoursChar[0] != currentChar[0]) { gfx->DrawChar(&largeFont, hoursChar[0], &x, 78, 0xffff); currentChar[0] = hoursChar[0]; } x = 61; if (hoursChar[1] != currentChar[1]) { gfx->DrawChar(&largeFont, hoursChar[1], &x, 78, 0xffff); currentChar[1] = hoursChar[1]; } x = 127; if (minutesChar[0] != currentChar[2]) { gfx->DrawChar(&largeFont, minutesChar[0], &x, 78, 0xffff); currentChar[2] = minutesChar[0]; } x = 181; if (minutesChar[1] != currentChar[3]) { gfx->DrawChar(&largeFont, minutesChar[1], &x, 78, 0xffff); currentChar[3] = minutesChar[1]; } if (ymd != currentYmd) { gfx->FillRectangle(0,180, 240, 15, 0x0000); char dateStr[22]; sprintf(dateStr, "%s %d %s %d", DayOfWeekToString(Pinetime::Controllers::DateTime::Days(weekday.iso_encoding())), day, MonthToString((Pinetime::Controllers::DateTime::Months )month), year); gfx->DrawString(10, 180, 0xffff, dateStr, &smallFont, false); currentYmd = ymd; } } 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() { } void DisplayApp::PushMessage(DisplayApp::Messages msg) { BaseType_t xHigherPriorityTaskWoken; xHigherPriorityTaskWoken = pdFALSE; xQueueSendFromISR(msgQueue, &msg, &xHigherPriorityTaskWoken); if (xHigherPriorityTaskWoken) { /* Actual macro used here is port specific. */ // TODO : should I do something here? } } static uint16_t pointColor = 0x07e0; void DisplayApp::OnTouchEvent() { auto info = touchPanel.GetTouchInfo(); if(info.isTouch) { lcd->FillRectangle(info.x-10, info.y-10, 20,20, pointColor); pointColor+=10; } }