diff options
Diffstat (limited to 'src')
127 files changed, 2336 insertions, 805 deletions
diff --git a/src/BootErrors.h b/src/BootErrors.h new file mode 100644 index 00000000..d00418cc --- /dev/null +++ b/src/BootErrors.h @@ -0,0 +1,10 @@ +#pragma once + +namespace Pinetime { + namespace System { + enum class BootErrors { + None, + TouchController, + }; + } +} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ae3cc3b1..07eabe11 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -92,6 +92,9 @@ set(SDK_SOURCE_FILES set(TINYCRYPT_SRC libs/mynewt-nimble/ext/tinycrypt/src/aes_encrypt.c libs/mynewt-nimble/ext/tinycrypt/src/utils.c + libs/mynewt-nimble/ext/tinycrypt/src/cmac_mode.c + libs/mynewt-nimble/ext/tinycrypt/src/ecc.c + libs/mynewt-nimble/ext/tinycrypt/src/ecc_dh.c ) set(NIMBLE_SRC @@ -104,6 +107,10 @@ set(NIMBLE_SRC libs/mynewt-nimble/nimble/host/src/ble_l2cap.c libs/mynewt-nimble/nimble/host/src/ble_hs_mbuf.c libs/mynewt-nimble/nimble/host/src/ble_sm.c + libs/mynewt-nimble/nimble/host/src/ble_sm_cmd.c + libs/mynewt-nimble/nimble/host/src/ble_sm_lgcy.c + libs/mynewt-nimble/nimble/host/src/ble_sm_alg.c + libs/mynewt-nimble/nimble/host/src/ble_sm_sc.c libs/mynewt-nimble/nimble/host/src/ble_gap.c libs/mynewt-nimble/nimble/host/src/ble_gatts.c libs/mynewt-nimble/nimble/host/src/ble_gattc.c @@ -127,10 +134,6 @@ set(NIMBLE_SRC libs/mynewt-nimble/nimble/host/src/ble_hs_atomic.c libs/mynewt-nimble/nimble/host/src/ble_hs_adv.c libs/mynewt-nimble/nimble/host/src/ble_hs_flow.c - libs/mynewt-nimble/nimble/host/src/ble_sm.c - libs/mynewt-nimble/nimble/host/src/ble_sm_cmd.c - libs/mynewt-nimble/nimble/host/src/ble_sm_lgcy.c - libs/mynewt-nimble/nimble/host/src/ble_sm_alg.c libs/mynewt-nimble/nimble/host/src/ble_hs_mqueue.c libs/mynewt-nimble/nimble/host/src/ble_hs_stop.c libs/mynewt-nimble/nimble/host/src/ble_hs_startup.c @@ -418,6 +421,9 @@ list(APPEND SOURCE_FILES displayapp/screens/BatteryInfo.cpp displayapp/screens/Steps.cpp displayapp/screens/Timer.cpp + displayapp/screens/Error.cpp + displayapp/screens/Alarm.cpp + displayapp/Colors.cpp ## Settings displayapp/screens/settings/QuickSettings.cpp @@ -427,6 +433,9 @@ list(APPEND SOURCE_FILES displayapp/screens/settings/SettingWakeUp.cpp displayapp/screens/settings/SettingDisplay.cpp displayapp/screens/settings/SettingSteps.cpp + displayapp/screens/settings/SettingPineTimeStyle.cpp + displayapp/screens/settings/SettingSetDate.cpp + displayapp/screens/settings/SettingSetTime.cpp ## Watch faces displayapp/icons/bg_clock.c @@ -472,6 +481,7 @@ list(APPEND SOURCE_FILES components/motor/MotorController.cpp components/settings/Settings.cpp components/timer/TimerController.cpp + components/alarm/AlarmController.cpp components/fs/FS.cpp drivers/Cst816s.cpp FreeRTOS/port.c @@ -538,6 +548,7 @@ list(APPEND RECOVERY_SOURCE_FILES components/firmwarevalidator/FirmwareValidator.cpp components/settings/Settings.cpp components/timer/TimerController.cpp + components/alarm/AlarmController.cpp drivers/Cst816s.cpp FreeRTOS/port.c FreeRTOS/port_cmsis_systick.c @@ -610,6 +621,8 @@ set(INCLUDE_FILES displayapp/screens/Metronome.h displayapp/screens/Motion.h displayapp/screens/Timer.h + displayapp/screens/Alarm.h + displayapp/Colors.h drivers/St7789.h drivers/SpiNorFlash.h drivers/SpiMaster.h @@ -618,6 +631,7 @@ set(INCLUDE_FILES drivers/DebugPins.h drivers/InternalFlash.h drivers/Hrs3300.h + drivers/PinMap.h drivers/Bma421.h drivers/Bma421_C/bma4.c drivers/Bma421_C/bma423.c @@ -640,6 +654,7 @@ set(INCLUDE_FILES components/ble/HeartRateService.h components/settings/Settings.h components/timer/TimerController.h + components/alarm/AlarmController.h drivers/Cst816s.h FreeRTOS/portmacro.h FreeRTOS/portmacro_cmsis.h diff --git a/src/components/alarm/AlarmController.cpp b/src/components/alarm/AlarmController.cpp new file mode 100644 index 00000000..67ca05a9 --- /dev/null +++ b/src/components/alarm/AlarmController.cpp @@ -0,0 +1,114 @@ +/* Copyright (C) 2021 mruss77, Florian + + This file is part of InfiniTime. + + InfiniTime is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + InfiniTime is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ +#include "AlarmController.h" +#include "systemtask/SystemTask.h" +#include "app_timer.h" +#include "task.h" +#include <chrono> + +using namespace Pinetime::Controllers; +using namespace std::chrono_literals; + +AlarmController::AlarmController(Controllers::DateTime& dateTimeController) : dateTimeController {dateTimeController} { +} + +APP_TIMER_DEF(alarmAppTimer); + +namespace { + void SetOffAlarm(void* p_context) { + auto* controller = static_cast<Pinetime::Controllers::AlarmController*>(p_context); + if (controller != nullptr) { + controller->SetOffAlarmNow(); + } + } +} + +void AlarmController::Init(System::SystemTask* systemTask) { + app_timer_create(&alarmAppTimer, APP_TIMER_MODE_SINGLE_SHOT, SetOffAlarm); + this->systemTask = systemTask; +} + +void AlarmController::SetAlarmTime(uint8_t alarmHr, uint8_t alarmMin) { + hours = alarmHr; + minutes = alarmMin; +} + +void AlarmController::ScheduleAlarm() { + // Determine the next time the alarm needs to go off and set the app_timer + app_timer_stop(alarmAppTimer); + + auto now = dateTimeController.CurrentDateTime(); + alarmTime = now; + time_t ttAlarmTime = std::chrono::system_clock::to_time_t(alarmTime); + tm* tmAlarmTime = std::localtime(&ttAlarmTime); + + // If the time being set has already passed today,the alarm should be set for tomorrow + if (hours < dateTimeController.Hours() || (hours == dateTimeController.Hours() && minutes <= dateTimeController.Minutes())) { + tmAlarmTime->tm_mday += 1; + // tm_wday doesn't update automatically + tmAlarmTime->tm_wday = (tmAlarmTime->tm_wday + 1) % 7; + } + + tmAlarmTime->tm_hour = hours; + tmAlarmTime->tm_min = minutes; + tmAlarmTime->tm_sec = 0; + + // if alarm is in weekday-only mode, make sure it shifts to the next weekday + if (recurrence == RecurType::Weekdays) { + if (tmAlarmTime->tm_wday == 0) { // Sunday, shift 1 day + tmAlarmTime->tm_mday += 1; + } else if (tmAlarmTime->tm_wday == 6) { // Saturday, shift 2 days + tmAlarmTime->tm_mday += 2; + } + } + tmAlarmTime->tm_isdst = -1; // use system timezone setting to determine DST + + // now can convert back to a time_point + alarmTime = std::chrono::system_clock::from_time_t(std::mktime(tmAlarmTime)); + auto mSecToAlarm = std::chrono::duration_cast<std::chrono::milliseconds>(alarmTime - now).count(); + app_timer_start(alarmAppTimer, APP_TIMER_TICKS(mSecToAlarm), this); + + state = AlarmState::Set; +} + +uint32_t AlarmController::SecondsToAlarm() { + return std::chrono::duration_cast<std::chrono::seconds>(alarmTime - dateTimeController.CurrentDateTime()).count(); +} + +void AlarmController::DisableAlarm() { + app_timer_stop(alarmAppTimer); + state = AlarmState::Not_Set; +} + +void AlarmController::SetOffAlarmNow() { + state = AlarmState::Alerting; + systemTask->PushMessage(System::Messages::SetOffAlarm); +} + +void AlarmController::StopAlerting() { + systemTask->PushMessage(System::Messages::StopRinging); + + // Alarm state is off unless this is a recurring alarm + if (recurrence == RecurType::None) { + state = AlarmState::Not_Set; + } else { + state = AlarmState::Set; + // set next instance + ScheduleAlarm(); + } +} diff --git a/src/components/alarm/AlarmController.h b/src/components/alarm/AlarmController.h new file mode 100644 index 00000000..bf85d431 --- /dev/null +++ b/src/components/alarm/AlarmController.h @@ -0,0 +1,68 @@ +/* Copyright (C) 2021 mruss77, Florian + + This file is part of InfiniTime. + + InfiniTime is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + InfiniTime is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ +#pragma once + +#include <cstdint> +#include "app_timer.h" +#include "components/datetime/DateTimeController.h" + +namespace Pinetime { + namespace System { + class SystemTask; + } + namespace Controllers { + class AlarmController { + public: + AlarmController(Controllers::DateTime& dateTimeController); + + void Init(System::SystemTask* systemTask); + void SetAlarmTime(uint8_t alarmHr, uint8_t alarmMin); + void ScheduleAlarm(); + void DisableAlarm(); + void SetOffAlarmNow(); + uint32_t SecondsToAlarm(); + void StopAlerting(); + enum class AlarmState { Not_Set, Set, Alerting }; + enum class RecurType { None, Daily, Weekdays }; + uint8_t Hours() const { + return hours; + } + uint8_t Minutes() const { + return minutes; + } + AlarmState State() const { + return state; + } + RecurType Recurrence() const { + return recurrence; + } + void SetRecurrence(RecurType recurType) { + recurrence = recurType; + } + + private: + Controllers::DateTime& dateTimeController; + System::SystemTask* systemTask = nullptr; + uint8_t hours = 7; + uint8_t minutes = 0; + std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> alarmTime; + AlarmState state = AlarmState::Not_Set; + RecurType recurrence = RecurType::None; + }; + } +} diff --git a/src/components/battery/BatteryController.cpp b/src/components/battery/BatteryController.cpp index f8a64ecd..e807f033 100644 --- a/src/components/battery/BatteryController.cpp +++ b/src/components/battery/BatteryController.cpp @@ -1,4 +1,5 @@ #include "BatteryController.h" +#include "drivers/PinMap.h" #include <hal/nrf_gpio.h> #include <nrfx_saadc.h> #include <algorithm> @@ -9,15 +10,22 @@ Battery* Battery::instance = nullptr; Battery::Battery() { instance = this; + nrf_gpio_cfg_input(PinMap::Charging, static_cast<nrf_gpio_pin_pull_t> GPIO_PIN_CNF_PULL_Disabled); } -void Battery::Init() { - nrf_gpio_cfg_input(chargingPin, static_cast<nrf_gpio_pin_pull_t> GPIO_PIN_CNF_PULL_Pullup); +void Battery::ReadPowerState() { + isCharging = !nrf_gpio_pin_read(PinMap::Charging); + isPowerPresent = !nrf_gpio_pin_read(PinMap::PowerPresent); + + if (isPowerPresent && !isCharging) { + isFull = true; + } else if (!isPowerPresent) { + isFull = false; + } } -void Battery::Update() { - isCharging = !nrf_gpio_pin_read(chargingPin); - isPowerPresent = !nrf_gpio_pin_read(powerPresentPin); +void Battery::MeasureVoltage() { + ReadPowerState(); if (isReading) { return; @@ -65,15 +73,26 @@ void Battery::SaadcEventHandler(nrfx_saadc_evt_t const* p_event) { // p_event->data.done.p_buffer[0] = (adc_voltage / reference_voltage) * 1024 voltage = p_event->data.done.p_buffer[0] * (8 * 600) / 1024; - if (voltage > battery_max) { - percentRemaining = 100; + uint8_t newPercent; + if (isFull) { + newPercent = 100; } else if (voltage < battery_min) { - percentRemaining = 0; + newPercent = 0; } else { - percentRemaining = (voltage - battery_min) * 100 / (battery_max - battery_min); + newPercent = std::min((voltage - battery_min) * 100 / (battery_max - battery_min), isCharging ? 99 : 100); + } + + if ((isPowerPresent && newPercent > percentRemaining) || (!isPowerPresent && newPercent < percentRemaining) || firstMeasurement) { + firstMeasurement = false; + percentRemaining = newPercent; + systemTask->PushMessage(System::Messages::BatteryPercentageUpdated); } nrfx_saadc_uninit(); isReading = false; } } + +void Battery::Register(Pinetime::System::SystemTask* systemTask) { + this->systemTask = systemTask; +} diff --git a/src/components/battery/BatteryController.h b/src/components/battery/BatteryController.h index 6f09b737..5a7394c4 100644 --- a/src/components/battery/BatteryController.h +++ b/src/components/battery/BatteryController.h @@ -1,8 +1,7 @@ #pragma once #include <cstdint> #include <drivers/include/nrfx_saadc.h> -#include <array> -#include <numeric> +#include <systemtask/SystemTask.h> namespace Pinetime { namespace Controllers { @@ -11,8 +10,9 @@ namespace Pinetime { public: Battery(); - void Init(); - void Update(); + void ReadPowerState(); + void MeasureVoltage(); + void Register(System::SystemTask* systemTask); uint8_t PercentRemaining() const { return percentRemaining; @@ -23,7 +23,9 @@ namespace Pinetime { } bool IsCharging() const { - return isCharging; + // isCharging will go up and down when fully charged + // isFull makes sure this returns false while fully charged. + return isCharging && !isFull; } bool IsPowerPresent() const { @@ -34,14 +36,14 @@ namespace Pinetime { static Battery* instance; nrf_saadc_value_t saadc_value; - static constexpr uint32_t chargingPin = 12; - static constexpr uint32_t powerPresentPin = 19; static constexpr nrf_saadc_input_t batteryVoltageAdcInput = NRF_SAADC_INPUT_AIN7; uint16_t voltage = 0; uint8_t percentRemaining = 0; + bool isFull = false; bool isCharging = false; bool isPowerPresent = false; + bool firstMeasurement = true; void SaadcInit(); @@ -49,6 +51,8 @@ namespace Pinetime { static void AdcCallbackStatic(nrfx_saadc_evt_t const* event); bool isReading = false; + + Pinetime::System::SystemTask* systemTask = nullptr; }; } } diff --git a/src/components/ble/AlertNotificationClient.cpp b/src/components/ble/AlertNotificationClient.cpp index c3d1d69a..5e5c25cf 100644 --- a/src/components/ble/AlertNotificationClient.cpp +++ b/src/components/ble/AlertNotificationClient.cpp @@ -55,7 +55,7 @@ bool AlertNotificationClient::OnDiscoveryEvent(uint16_t connectionHandle, const return true; } - if (service != nullptr && ble_uuid_cmp(((ble_uuid_t*) &ansServiceUuid), &service->uuid.u) == 0) { + if (service != nullptr && ble_uuid_cmp(&ansServiceUuid.u, &service->uuid.u) == 0) { NRF_LOG_INFO("ANS discovered : 0x%x - 0x%x", service->start_handle, service->end_handle); ansStartHandle = service->start_handle; ansEndHandle = service->end_handle; @@ -80,21 +80,21 @@ int AlertNotificationClient::OnCharacteristicsDiscoveryEvent(uint16_t connection } else onServiceDiscovered(connectionHandle); } else { - if (characteristic != nullptr && ble_uuid_cmp(((ble_uuid_t*) &supportedNewAlertCategoryUuid), &characteristic->uuid.u) == 0) { + if (characteristic != nullptr && ble_uuid_cmp(&supportedNewAlertCategoryUuid.u, &characteristic->uuid.u) == 0) { NRF_LOG_INFO("ANS Characteristic discovered : supportedNewAlertCategoryUuid"); supportedNewAlertCategoryHandle = characteristic->val_handle; - } else if (characteristic != nullptr && ble_uuid_cmp(((ble_uuid_t*) &supportedUnreadAlertCategoryUuid), &characteristic->uuid.u) == 0) { + } else if (characteristic != nullptr && ble_uuid_cmp(&supportedUnreadAlertCategoryUuid.u, &characteristic->uuid.u) == 0) { NRF_LOG_INFO("ANS Characteristic discovered : supportedUnreadAlertCategoryUuid"); supportedUnreadAlertCategoryHandle = characteristic->val_handle; - } else if (characteristic != nullptr && ble_uuid_cmp(((ble_uuid_t*) &newAlertUuid), &characteristic->uuid.u) == 0) { + } else if (characteristic != nullptr && ble_uuid_cmp(&newAlertUuid.u, &characteristic->uuid.u) == 0) { NRF_LOG_INFO("ANS Characteristic discovered : newAlertUuid"); newAlertHandle = characteristic->val_handle; newAlertDefHandle = characteristic->def_handle; isCharacteristicDiscovered = true; - } else if (characteristic != nullptr && ble_uuid_cmp(((ble_uuid_t*) &unreadAlertStatusUuid), &characteristic->uuid.u) == 0) { + } else if (characteristic != nullptr && ble_uuid_cmp(&unreadAlertStatusUuid.u, &characteristic->uuid.u) == 0) { NRF_LOG_INFO("ANS Characteristic discovered : unreadAlertStatusUuid"); unreadAlertStatusHandle = characteristic->val_handle; - } else if (characteristic != nullptr && ble_uuid_cmp(((ble_uuid_t*) &controlPointUuid), &characteristic->uuid.u) == 0) { + } else if (characteristic != nullptr && ble_uuid_cmp(&controlPointUuid.u, &characteristic->uuid.u) == 0) { NRF_LOG_INFO("ANS Characteristic discovered : controlPointUuid"); controlPointHandle = characteristic->val_handle; } else @@ -119,7 +119,7 @@ int AlertNotificationClient::OnDescriptorDiscoveryEventCallback(uint16_t connect uint16_t characteristicValueHandle, const ble_gatt_dsc* descriptor) { if (error->status == 0) { - if (characteristicValueHandle == newAlertHandle && ble_uuid_cmp(((ble_uuid_t*) &newAlertUuid), &descriptor->uuid.u)) { + if (characteristicValueHandle == newAlertHandle && ble_uuid_cmp(&newAlertUuid.u, &descriptor->uuid.u)) { if (newAlertDescriptorHandle == 0) { NRF_LOG_INFO("ANS Descriptor discovered : %d", descriptor->handle); newAlertDescriptorHandle = descriptor->handle; diff --git a/src/components/ble/AlertNotificationService.cpp b/src/components/ble/AlertNotificationService.cpp index d5fc7f65..56fc595f 100644 --- a/src/components/ble/AlertNotificationService.cpp +++ b/src/components/ble/AlertNotificationService.cpp @@ -26,11 +26,8 @@ void AlertNotificationService::Init() { } AlertNotificationService::AlertNotificationService(System::SystemTask& systemTask, NotificationManager& notificationManager) - : characteristicDefinition {{.uuid = (ble_uuid_t*) &ansCharUuid, - .access_cb = AlertNotificationCallback, - .arg = this, - .flags = BLE_GATT_CHR_F_WRITE}, - {.uuid = (ble_uuid_t*) ¬ificationEventUuid, + : characteristicDefinition {{.uuid = &ansCharUuid.u, .access_cb = AlertNotificationCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE}, + {.uuid = ¬ificationEventUuid.u, .access_cb = AlertNotificationCallback, .arg = this, .flags = BLE_GATT_CHR_F_NOTIFY, @@ -39,7 +36,7 @@ AlertNotificationService::AlertNotificationService(System::SystemTask& systemTas serviceDefinition { {/* Device Information Service */ .type = BLE_GATT_SVC_TYPE_PRIMARY, - .uuid = (ble_uuid_t*) &ansUuid, + .uuid = &ansUuid.u, .characteristics = characteristicDefinition}, {0}, }, @@ -123,4 +120,4 @@ void AlertNotificationService::MuteIncomingCall() { } ble_gattc_notify_custom(connectionHandle, eventHandle, om); -}
\ No newline at end of file +} diff --git a/src/components/ble/BatteryInformationService.cpp b/src/components/ble/BatteryInformationService.cpp index 7f176904..29178667 100644 --- a/src/components/ble/BatteryInformationService.cpp +++ b/src/components/ble/BatteryInformationService.cpp @@ -14,7 +14,7 @@ int BatteryInformationServiceCallback(uint16_t conn_handle, uint16_t attr_handle BatteryInformationService::BatteryInformationService(Controllers::Battery& batteryController) : batteryController {batteryController}, - characteristicDefinition {{.uuid = (ble_uuid_t*) &batteryLevelUuid, + characteristicDefinition {{.uuid = &batteryLevelUuid.u, .access_cb = BatteryInformationServiceCallback, .arg = this, .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY, @@ -23,7 +23,7 @@ BatteryInformationService::BatteryInformationService(Controllers::Battery& batte serviceDefinition { {/* Device Information Service */ .type = BLE_GATT_SVC_TYPE_PRIMARY, - .uuid = (ble_uuid_t*) &batteryInformationServiceUuid, + .uuid = &batteryInformationServiceUuid.u, .characteristics = characteristicDefinition}, {0}, } { @@ -43,7 +43,7 @@ int BatteryInformationService::OnBatteryServiceRequested(uint16_t connectionHand ble_gatt_access_ctxt* context) { if (attributeHandle == batteryLevelHandle) { NRF_LOG_INFO("BATTERY : handle = %d", batteryLevelHandle); - static uint8_t batteryValue = batteryController.PercentRemaining(); + uint8_t batteryValue = batteryController.PercentRemaining(); int res = os_mbuf_append(context->om, &batteryValue, 1); return (res == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; } diff --git a/src/components/ble/CurrentTimeClient.cpp b/src/components/ble/CurrentTimeClient.cpp index c6e68312..90d1f0c7 100644 --- a/src/components/ble/CurrentTimeClient.cpp +++ b/src/components/ble/CurrentTimeClient.cpp @@ -47,7 +47,7 @@ bool CurrentTimeClient::OnDiscoveryEvent(uint16_t connectionHandle, const ble_ga return true; } - if (service != nullptr && ble_uuid_cmp(((ble_uuid_t*) &ctsServiceUuid), &service->uuid.u) == 0) { + if (service != nullptr && ble_uuid_cmp(&ctsServiceUuid.u, &service->uuid.u) == 0) { NRF_LOG_INFO("CTS discovered : 0x%x - 0x%x", service->start_handle, service->end_handle); isDiscovered = true; ctsStartHandle = service->start_handle; @@ -72,7 +72,7 @@ int CurrentTimeClient::OnCharacteristicDiscoveryEvent(uint16_t conn_handle, return 0; } - if (characteristic != nullptr && ble_uuid_cmp(((ble_uuid_t*) ¤tTimeCharacteristicUuid), &characteristic->uuid.u) == 0) { + if (characteristic != nullptr && ble_uuid_cmp(¤tTimeCharacteristicUuid.u, &characteristic->uuid.u) == 0) { NRF_LOG_INFO("CTS Characteristic discovered : 0x%x", characteristic->val_handle); isCharacteristicDiscovered = true; currentTimeHandle = characteristic->val_handle; diff --git a/src/components/ble/CurrentTimeService.cpp b/src/components/ble/CurrentTimeService.cpp index b49be39c..eefb7ec1 100644 --- a/src/components/ble/CurrentTimeService.cpp +++ b/src/components/ble/CurrentTimeService.cpp @@ -53,7 +53,7 @@ int CurrentTimeService::OnTimeAccessed(uint16_t conn_handle, uint16_t attr_handl } CurrentTimeService::CurrentTimeService(DateTime& dateTimeController) - : characteristicDefinition {{.uuid = (ble_uuid_t*) &ctChrUuid, + : characteristicDefinition {{.uuid = &ctChrUuid.u, .access_cb = CTSCallback, .arg = this, @@ -62,7 +62,7 @@ CurrentTimeService::CurrentTimeService(DateTime& dateTimeController) serviceDefinition { {/* Device Information Service */ .type = BLE_GATT_SVC_TYPE_PRIMARY, - .uuid = (ble_uuid_t*) &ctsUuid, + .uuid = &ctsUuid.u, .characteristics = characteristicDefinition}, {0}, }, diff --git a/src/components/ble/DeviceInformationService.cpp b/src/components/ble/DeviceInformationService.cpp index cf482079..778d6e35 100644 --- a/src/components/ble/DeviceInformationService.cpp +++ b/src/components/ble/DeviceInformationService.cpp @@ -56,37 +56,37 @@ int DeviceInformationService::OnDeviceInfoRequested(uint16_t conn_handle, uint16 DeviceInformationService::DeviceInformationService() : characteristicDefinition {{ - .uuid = (ble_uuid_t*) &manufacturerNameUuid, + .uuid = &manufacturerNameUuid.u, .access_cb = DeviceInformationCallback, .arg = this, .flags = BLE_GATT_CHR_F_READ, }, { - .uuid = (ble_uuid_t*) &modelNumberUuid, + .uuid = &modelNumberUuid.u, .access_cb = DeviceInformationCallback, .arg = this, .flags = BLE_GATT_CHR_F_READ, }, { - .uuid = (ble_uuid_t*) &serialNumberUuid, + .uuid = &serialNumberUuid.u, .access_cb = DeviceInformationCallback, .arg = this, .flags = BLE_GATT_CHR_F_READ, }, { - .uuid = (ble_uuid_t*) &fwRevisionUuid, + .uuid = &fwRevisionUuid.u, .access_cb = DeviceInformationCallback, .arg = this, .flags = BLE_GATT_CHR_F_READ, }, { - .uuid = (ble_uuid_t*) &hwRevisionUuid, + .uuid = &hwRevisionUuid.u, .access_cb = DeviceInformationCallback, .arg = this, .flags = BLE_GATT_CHR_F_READ, }, { - .uuid = (ble_uuid_t*) &swRevisionUuid, + .uuid = &swRevisionUuid.u, .access_cb = DeviceInformationCallback, .arg = this, .flags = BLE_GATT_CHR_F_READ, @@ -95,7 +95,7 @@ DeviceInformationService::DeviceInformationService() serviceDefinition { {/* Device Information Service */ .type = BLE_GATT_SVC_TYPE_PRIMARY, - .uuid = (ble_uuid_t*) &deviceInfoUuid, + .uuid = &deviceInfoUuid.u, .characteristics = characteristicDefinition}, {0}, } { diff --git a/src/components/ble/DfuService.cpp b/src/components/ble/DfuService.cpp index 4179994d..3d6416fa 100644 --- a/src/components/ble/DfuService.cpp +++ b/src/components/ble/DfuService.cpp @@ -33,21 +33,21 @@ DfuService::DfuService(Pinetime::System::SystemTask& systemTask, bleController {bleController}, dfuImage {spiNorFlash}, characteristicDefinition {{ - .uuid = (ble_uuid_t*) &packetCharacteristicUuid, + .uuid = &packetCharacteristicUuid.u, .access_cb = DfuServiceCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE_NO_RSP, .val_handle = nullptr, }, { - .uuid = (ble_uuid_t*) &controlPointCharacteristicUuid, + .uuid = &controlPointCharacteristicUuid.u, .access_cb = DfuServiceCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_NOTIFY, .val_handle = nullptr, }, { - .uuid = (ble_uuid_t*) &revisionCharacteristicUuid, + .uuid = &revisionCharacteristicUuid.u, .access_cb = DfuServiceCallback, .arg = this, .flags = BLE_GATT_CHR_F_READ, @@ -60,7 +60,7 @@ DfuService::DfuService(Pinetime::System::SystemTask& systemTask, serviceDefinition { {/* Device Information Service */ .type = BLE_GATT_SVC_TYPE_PRIMARY, - .uuid = (ble_uuid_t*) &serviceUuid, + .uuid = &serviceUuid.u, .characteristics = characteristicDefinition}, {0}, } { @@ -81,9 +81,9 @@ int DfuService::OnServiceData(uint16_t connectionHandle, uint16_t attributeHandl xTimerStart(timeoutTimer, 0); } - ble_gatts_find_chr((ble_uuid_t*) &serviceUuid, (ble_uuid_t*) &packetCharacteristicUuid, nullptr, &packetCharacteristicHandle); - ble_gatts_find_chr((ble_uuid_t*) &serviceUuid, (ble_uuid_t*) &controlPointCharacteristicUuid, nullptr, &controlPointCharacteristicHandle); - ble_gatts_find_chr((ble_uuid_t*) &serviceUuid, (ble_uuid_t*) &revisionCharacteristicUuid, nullptr, &revisionCharacteristicHandle); + ble_gatts_find_chr(&serviceUuid.u, &packetCharacteristicUuid.u, nullptr, &packetCharacteristicHandle); + ble_gatts_find_chr(&serviceUuid.u, &controlPointCharacteristicUuid.u, nullptr, &controlPointCharacteristicHandle); + ble_gatts_find_chr(&serviceUuid.u, &revisionCharacteristicUuid.u, nullptr, &revisionCharacteristicHandle); if (attributeHandle == packetCharacteristicHandle) { if (context->op == BLE_GATT_ACCESS_OP_WRITE_CHR) @@ -164,10 +164,10 @@ int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf* om) { if ((nbPacketReceived % nbPacketsToNotify) == 0 && bytesReceived != applicationSize) { uint8_t data[5] {static_cast<uint8_t>(Opcodes::PacketReceiptNotification), - (uint8_t) (bytesReceived & 0x000000FFu), - (uint8_t) (bytesReceived >> 8u), - (uint8_t) (bytesReceived >> 16u), - (uint8_t) (bytesReceived >> 24u)}; + (uint8_t)(bytesReceived & 0x000000FFu), + (uint8_t)(bytesReceived >> 8u), + (uint8_t)(bytesReceived >> 16u), + (uint8_t)(bytesReceived >> 24u)}; NRF_LOG_INFO("[DFU] -> Send packet notification: %d bytes received", bytesReceived); notificationManager.Send(connectionHandle, controlPointCharacteristicHandle, data, 5); } @@ -422,9 +422,9 @@ uint16_t DfuService::DfuImage::ComputeCrc(uint8_t const* p_data, uint32_t size, uint16_t crc = (p_crc == NULL) ? 0xFFFF : *p_crc; for (uint32_t i = 0; i < size; i++) { - crc = (uint8_t) (crc >> 8) | (crc << 8); + crc = (uint8_t)(crc >> 8) | (crc << 8); crc ^= p_data[i]; - crc ^= (uint8_t) (crc & 0xFF) >> 4; + crc ^= (uint8_t)(crc & 0xFF) >> 4; crc ^= (crc << 8) << 4; crc ^= ((crc & 0xFF) << 4) << 1; } diff --git a/src/components/ble/HeartRateService.cpp b/src/components/ble/HeartRateService.cpp index c556566b..5b00f492 100644 --- a/src/components/ble/HeartRateService.cpp +++ b/src/components/ble/HeartRateService.cpp @@ -18,7 +18,7 @@ namespace { HeartRateService::HeartRateService(Pinetime::System::SystemTask& system, Controllers::HeartRateController& heartRateController) : system {system}, heartRateController {heartRateController}, - characteristicDefinition {{.uuid = (ble_uuid_t*) &heartRateMeasurementUuid, + characteristicDefinition {{.uuid = &heartRateMeasurementUuid.u, .access_cb = HeartRateServiceServiceCallback, .arg = this, .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY, @@ -27,7 +27,7 @@ HeartRateService::HeartRateService(Pinetime::System::SystemTask& system, Control serviceDefinition { {/* Device Information Service */ .type = BLE_GATT_SVC_TYPE_PRIMARY, - .uuid = (ble_uuid_t*) &heartRateServiceUuid, + .uuid = &heartRateServiceUuid.u, .characteristics = characteristicDefinition}, {0}, } { diff --git a/src/components/ble/ImmediateAlertService.cpp b/src/components/ble/ImmediateAlertService.cpp index 820d3b6e..17ed1a96 100644 --- a/src/components/ble/ImmediateAlertService.cpp +++ b/src/components/ble/ImmediateAlertService.cpp @@ -32,7 +32,7 @@ ImmediateAlertService::ImmediateAlertService(Pinetime::System::SystemTask& syste Pinetime::Controllers::NotificationManager& notificationManager) : systemTask {systemTask}, notificationManager {notificationManager}, - characteristicDefinition {{.uuid = (ble_uuid_t*) &alertLevelUuid, + characteristicDefinition {{.uuid = &alertLevelUuid.u, .access_cb = AlertLevelCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE_NO_RSP, @@ -41,7 +41,7 @@ ImmediateAlertService::ImmediateAlertService(Pinetime::System::SystemTask& syste serviceDefinition { {/* Device Information Service */ .type = BLE_GATT_SVC_TYPE_PRIMARY, - .uuid = (ble_uuid_t*) &immediateAlertServiceUuid, + .uuid = &immediateAlertServiceUuid.u, .characteristics = characteristicDefinition}, {0}, } { @@ -72,4 +72,4 @@ int ImmediateAlertService::OnAlertLevelChanged(uint16_t connectionHandle, uint16 } return 0; -}
\ No newline at end of file +} diff --git a/src/components/ble/NavigationService.cpp b/src/components/ble/NavigationService.cpp index e1c20bf1..b49148d2 100644 --- a/src/components/ble/NavigationService.cpp +++ b/src/components/ble/NavigationService.cpp @@ -20,54 +20,45 @@ #include "systemtask/SystemTask.h" -int NAVCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) { - auto navService = static_cast<Pinetime::Controllers::NavigationService*>(arg); - return navService->OnCommand(conn_handle, attr_handle, ctxt); -} - -Pinetime::Controllers::NavigationService::NavigationService(Pinetime::System::SystemTask& system) : m_system(system) { - navUuid.value[14] = navId[0]; - navUuid.value[15] = navId[1]; +namespace { + // 0001yyxx-78fc-48fe-8e23-433b3a1942d0 + constexpr ble_uuid128_t CharUuid(uint8_t x, uint8_t y) { + return ble_uuid128_t {.u = {.type = BLE_UUID_TYPE_128}, + .value = {0xd0, 0x42, 0x19, 0x3a, 0x3b, 0x43, 0x23, 0x8e, 0xfe, 0x48, 0xfc, 0x78, x, y, 0x01, 0x00}}; + } - navFlagCharUuid.value[12] = navFlagCharId[0]; - navFlagCharUuid.value[13] = navFlagCharId[1]; - navFlagCharUuid.value[14] = navId[0]; - navFlagCharUuid.value[15] = navId[1]; + // 00010000-78fc-48fe-8e23-433b3a1942d0 + constexpr ble_uuid128_t BaseUuid() { + return CharUuid(0x00, 0x00); + } - navNarrativeCharUuid.value[12] = navNarrativeCharId[0]; - navNarrativeCharUuid.value[13] = navNarrativeCharId[1]; - navNarrativeCharUuid.value[14] = navId[0]; - navNarrativeCharUuid.value[15] = navId[1]; + constexpr ble_uuid128_t navUuid {BaseUuid()}; - navManDistCharUuid.value[12] = navManDistCharId[0]; - navManDistCharUuid.value[13] = navManDistCharId[1]; - navManDistCharUuid.value[14] = navId[0]; - navManDistCharUuid.value[15] = navId[1]; + constexpr ble_uuid128_t navFlagCharUuid {CharUuid(0x01, 0x00)}; + constexpr ble_uuid128_t navNarrativeCharUuid {CharUuid(0x02, 0x00)}; + constexpr ble_uuid128_t navManDistCharUuid {CharUuid(0x03, 0x00)}; + constexpr ble_uuid128_t navProgressCharUuid {CharUuid(0x04, 0x00)}; - navProgressCharUuid.value[12] = navProgressCharId[0]; - navProgressCharUuid.value[13] = navProgressCharId[1]; - navProgressCharUuid.value[14] = navId[0]; - navProgressCharUuid.value[15] = navId[1]; + int NAVCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) { + auto navService = static_cast<Pinetime::Controllers::NavigationService*>(arg); + return navService->OnCommand(conn_handle, attr_handle, ctxt); + } +} // namespace +Pinetime::Controllers::NavigationService::NavigationService(Pinetime::System::SystemTask& system) : m_system(system) { characteristicDefinition[0] = { - .uuid = (ble_uuid_t*) (&navFlagCharUuid), .access_cb = NAVCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ}; + .uuid = &navFlagCharUuid.u, .access_cb = NAVCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ}; - characteristicDefinition[1] = {.uuid = (ble_uuid_t*) (&navNarrativeCharUuid), - .access_cb = NAVCallback, - .arg = this, - .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ}; - characteristicDefinition[2] = {.uuid = (ble_uuid_t*) (&navManDistCharUuid), - .access_cb = NAVCallback, - .arg = this, - .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ}; - characteristicDefinition[3] = {.uuid = (ble_uuid_t*) (&navProgressCharUuid), - .access_cb = NAVCallback, - .arg = this, - .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ}; + characteristicDefinition[1] = { + .uuid = &navNarrativeCharUuid.u, .access_cb = NAVCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ}; + characteristicDefinition[2] = { + .uuid = &navManDistCharUuid.u, .access_cb = NAVCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ}; + characteristicDefinition[3] = { + .uuid = &navProgressCharUuid.u, .access_cb = NAVCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ}; characteristicDefinition[4] = {0}; - serviceDefinition[0] = {.type = BLE_GATT_SVC_TYPE_PRIMARY, .uuid = (ble_uuid_t*) &navUuid, .characteristics = characteristicDefinition}; + serviceDefinition[0] = {.type = BLE_GATT_SVC_TYPE_PRIMARY, .uuid = &navUuid.u, .characteristics = characteristicDefinition}; serviceDefinition[1] = {0}; m_progress = 0; @@ -90,13 +81,13 @@ int Pinetime::Controllers::NavigationService::OnCommand(uint16_t conn_handle, ui data[notifSize] = '\0'; os_mbuf_copydata(ctxt->om, 0, notifSize, data); char* s = (char*) &data[0]; - if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &navFlagCharUuid) == 0) { + if (ble_uuid_cmp(ctxt->chr->uuid, &navFlagCharUuid.u) == 0) { m_flag = s; - } else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &navNarrativeCharUuid) == 0) { + } else if (ble_uuid_cmp(ctxt->chr->uuid, &navNarrativeCharUuid.u) == 0) { m_narrative = s; - } else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &navManDistCharUuid) == 0) { + } else if (ble_uuid_cmp(ctxt->chr->uuid, &navManDistCharUuid.u) == 0) { m_manDist = s; - } else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &navProgressCharUuid) == 0) { + } else if (ble_uuid_cmp(ctxt->chr->uuid, &navProgressCharUuid.u) == 0) { m_progress = data[0]; } } diff --git a/src/components/ble/NavigationService.h b/src/components/ble/NavigationService.h index 5aab263c..c0c77f35 100644 --- a/src/components/ble/NavigationService.h +++ b/src/components/ble/NavigationService.h @@ -26,10 +26,6 @@ #undef max #undef min -// c7e60000-78fc-48fe-8e23-433b3a1942d0 -#define NAVIGATION_SERVICE_UUID_BASE \ - { 0xd0, 0x42, 0x19, 0x3a, 0x3b, 0x43, 0x23, 0x8e, 0xfe, 0x48, 0xfc, 0x78, 0x00, 0x00, 0x00, 0x00 } - namespace Pinetime { namespace System { class SystemTask; @@ -53,19 +49,6 @@ namespace Pinetime { int getProgress(); private: - static constexpr uint8_t navId[2] = {0x01, 0x00}; - static constexpr uint8_t navFlagCharId[2] = {0x01, 0x00}; - static constexpr uint8_t navNarrativeCharId[2] = {0x02, 0x00}; - static constexpr uint8_t navManDistCharId[2] = {0x03, 0x00}; - static constexpr uint8_t navProgressCharId[2] = {0x04, 0x00}; - - ble_uuid128_t navUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = NAVIGATION_SERVICE_UUID_BASE}; - - ble_uuid128_t navFlagCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = NAVIGATION_SERVICE_UUID_BASE}; - ble_uuid128_t navNarrativeCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = NAVIGATION_SERVICE_UUID_BASE}; - ble_uuid128_t navManDistCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = NAVIGATION_SERVICE_UUID_BASE}; - ble_uuid128_t navProgressCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = NAVIGATION_SERVICE_UUID_BASE}; - struct ble_gatt_chr_def characteristicDefinition[5]; struct ble_gatt_svc_def serviceDefinition[2]; diff --git a/src/components/ble/NimbleController.cpp b/src/components/ble/NimbleController.cpp index 5eb227bf..879421e7 100644 --- a/src/components/ble/NimbleController.cpp +++ b/src/components/ble/NimbleController.cpp @@ -42,6 +42,19 @@ NimbleController::NimbleController(Pinetime::System::SystemTask& systemTask, serviceDiscovery({¤tTimeClient, &alertNotificationClient}) { } +void nimble_on_reset(int reason) { + NRF_LOG_INFO("Resetting state; reason=%d\n", reason); +} + +void nimble_on_sync(void) { + int rc; + + rc = ble_hs_util_ensure_addr(0); + ASSERT(rc == 0); + + nptr->StartAdvertising(); +} + int GAPEventCallback(struct ble_gap_event* event, void* arg) { auto nimbleController = static_cast<NimbleController*>(arg); return nimbleController->OnGAPEvent(event); @@ -51,6 +64,10 @@ void NimbleController::Init() { while (!ble_hs_synced()) { } + nptr = this; + ble_hs_cfg.reset_cb = nimble_on_reset; + ble_hs_cfg.sync_cb = nimble_on_sync; + ble_svc_gap_init(); ble_svc_gatt_init(); @@ -64,28 +81,31 @@ void NimbleController::Init() { batteryInformationService.Init(); immediateAlertService.Init(); heartRateService.Init(); - int res; - res = ble_hs_util_ensure_addr(0); - ASSERT(res == 0); - res = ble_hs_id_infer_auto(0, &addrType); - ASSERT(res == 0); - res = ble_svc_gap_device_name_set(deviceName); - ASSERT(res == 0); + + int rc; + rc = ble_hs_util_ensure_addr(0); + ASSERT(rc == 0); + rc = ble_hs_id_infer_auto(0, &addrType); + ASSERT(rc == 0); + rc = ble_svc_gap_device_name_set(deviceName); + ASSERT(rc == 0); + rc = ble_svc_gap_device_appearance_set(0xC2); + ASSERT(rc == 0); Pinetime::Controllers::Ble::BleAddress address; - res = ble_hs_id_copy_addr(addrType, address.data(), nullptr); - ASSERT(res == 0); + rc = ble_hs_id_copy_addr(addrType, address.data(), nullptr); + ASSERT(rc == 0); bleController.AddressType((addrType == 0) ? Ble::AddressTypes::Public : Ble::AddressTypes::Random); bleController.Address(std::move(address)); - res = ble_gatts_start(); - ASSERT(res == 0); + rc = ble_gatts_start(); + ASSERT(rc == 0); + + if (!ble_gap_adv_active() && !bleController.IsConnected()) + StartAdvertising(); } void NimbleController::StartAdvertising() { - if (bleController.IsConnected() || ble_gap_conn_active() || ble_gap_adv_active()) - return; - - ble_svc_gap_device_name_set(deviceName); + int rc; /* set adv parameters */ struct ble_gap_adv_params adv_params; @@ -102,11 +122,17 @@ void NimbleController::StartAdvertising() { adv_params.conn_mode = BLE_GAP_CONN_MODE_UND; adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN; + /* fast advertise for 30 sec */ + if (fastAdvCount < 15) { + adv_params.itvl_min = 32; + adv_params.itvl_max = 47; + fastAdvCount++; + } else { + adv_params.itvl_min = 1636; + adv_params.itvl_max = 1651; + } fields.flags = BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP; - // fields.uuids128 = BLE_UUID128(BLE_UUID128_DECLARE( - // 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, - // 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff)); fields.uuids128 = &dfuServiceUuid; fields.num_uuids128 = 1; fields.uuids128_is_complete = 1; @@ -116,28 +142,25 @@ void NimbleController::StartAdvertising() { rsp_fields.name_len = strlen(deviceName); rsp_fields.name_is_complete = 1; - ble_gap_adv_set_fields(&fields); - // ASSERT(res == 0); // TODO this one sometimes fails with error 22 (notsync) + rc = ble_gap_adv_set_fields(&fields); + ASSERT(rc == 0); - ble_gap_adv_rsp_set_fields(&rsp_fields); - // ASSERT(res == 0); + rc = ble_gap_adv_rsp_set_fields(&rsp_fields); + ASSERT(rc == 0); - ble_gap_adv_start(addrType, NULL, 180000, &adv_params, GAPEventCallback, this); - // ASSERT(res == 0);// TODO I've disabled these ASSERT as they sometime asserts and reset the mcu. - // For now, the advertising is restarted as soon as it ends. There may be a race condition - // that prevent the advertising from restarting reliably. - // I remove the assert to prevent this uncesseray crash, but in the long term, the management of - // the advertising should be improve (better error handling, and advertise for 3 minutes after - // the application has been woken up, for example. + rc = ble_gap_adv_start(addrType, NULL, 2000, &adv_params, GAPEventCallback, this); + ASSERT(rc == 0); } int NimbleController::OnGAPEvent(ble_gap_event* event) { switch (event->type) { case BLE_GAP_EVENT_ADV_COMPLETE: NRF_LOG_INFO("Advertising event : BLE_GAP_EVENT_ADV_COMPLETE"); - NRF_LOG_INFO("advertise complete; reason=%dn status=%d", event->adv_complete.reason, event->connect.status); + NRF_LOG_INFO("reason=%d; status=%d", event->adv_complete.reason, event->connect.status); + StartAdvertising(); break; - case BLE_GAP_EVENT_CONNECT: { + + case BLE_GAP_EVENT_CONNECT: NRF_LOG_INFO("Advertising event : BLE_GAP_EVENT_CONNECT"); /* A new connection was established or a connection attempt failed. */ @@ -145,35 +168,44 @@ int NimbleController::OnGAPEvent(ble_gap_event* event) { if (event->connect.status != 0) { /* Connection failed; resume advertising. */ - StartAdvertising(); + currentTimeClient.Reset(); + alertNotificationClient.Reset(); + connectionHandle = BLE_HS_CONN_HANDLE_NONE; bleController.Disconnect(); + fastAdvCount = 0; + StartAdvertising(); } else { + connectionHandle = event->connect.conn_handle; bleController.Connect(); systemTask.PushMessage(Pinetime::System::Messages::BleConnected); - connectionHandle = event->connect.conn_handle; - // Service discovery is deffered via systemtask + // Service discovery is deferred via systemtask } - } break; + break; + case BLE_GAP_EVENT_DISCONNECT: NRF_LOG_INFO("Advertising event : BLE_GAP_EVENT_DISCONNECT"); - NRF_LOG_INFO("disconnect; reason=%d", event->disconnect.reason); + NRF_LOG_INFO("disconnect reason=%d", event->disconnect.reason); /* Connection terminated; resume advertising. */ currentTimeClient.Reset(); alertNotificationClient.Reset(); connectionHandle = BLE_HS_CONN_HANDLE_NONE; bleController.Disconnect(); + fastAdvCount = 0; StartAdvertising(); break; + case BLE_GAP_EVENT_CONN_UPDATE: NRF_LOG_INFO("Advertising event : BLE_GAP_EVENT_CONN_UPDATE"); /* The central has updated the connection parameters. */ - NRF_LOG_INFO("connection updated; status=%d ", event->conn_update.status); + NRF_LOG_INFO("update status=%d ", event->conn_update.status); break; + case BLE_GAP_EVENT_ENC_CHANGE: /* Encryption has been enabled or disabled for this connection. */ NRF_LOG_INFO("encryption change event; status=%d ", event->enc_change.status); - return 0; + break; + case BLE_GAP_EVENT_SUBSCRIBE: NRF_LOG_INFO("subscribe event; conn_handle=%d attr_handle=%d " "reason=%d prevn=%d curn=%d previ=%d curi=???\n", @@ -183,10 +215,12 @@ int NimbleController::OnGAPEvent(ble_gap_event* event) { event->subscribe.prev_notify, event->subscribe.cur_notify, event->subscribe.prev_indicate); - return 0; + break; + case BLE_GAP_EVENT_MTU: - NRF_LOG_INFO("mtu update event; conn_handle=%d cid=%d mtu=%d\n", event->mtu.conn_handle, event->mtu.channel_id, event->mtu.value); - return 0; + NRF_LOG_INFO("mtu update event; conn_handle=%d cid=%d mtu=%d\n", + event->mtu.conn_handle, event->mtu.channel_id, event->mtu.value); + break; case BLE_GAP_EVENT_REPEAT_PAIRING: { /* We already have a bond with the peer, but it is attempting to @@ -217,8 +251,7 @@ int NimbleController::OnGAPEvent(ble_gap_event* event) { notifSize); alertNotificationClient.OnNotification(event); - return 0; - } + } break; /* Attribute data is contained in event->notify_rx.attr_data. */ default: @@ -229,7 +262,9 @@ int NimbleController::OnGAPEvent(ble_gap_event* event) { } void NimbleController::StartDiscovery() { - serviceDiscovery.StartDiscovery(connectionHandle); + if (connectionHandle != BLE_HS_CONN_HANDLE_NONE) { + serviceDiscovery.StartDiscovery(connectionHandle); + } } uint16_t NimbleController::connHandle() { @@ -237,7 +272,7 @@ uint16_t NimbleController::connHandle() { } void NimbleController::NotifyBatteryLevel(uint8_t level) { - if(connectionHandle != BLE_HS_CONN_HANDLE_NONE) { + if (connectionHandle != BLE_HS_CONN_HANDLE_NONE) { batteryInformationService.NotifyBatteryLevel(connectionHandle, level); } } diff --git a/src/components/ble/NimbleController.h b/src/components/ble/NimbleController.h index 0cfe983c..473bb1af 100644 --- a/src/components/ble/NimbleController.h +++ b/src/components/ble/NimbleController.h @@ -72,6 +72,10 @@ namespace Pinetime { uint16_t connHandle(); void NotifyBatteryLevel(uint8_t level); + void RestartFastAdv() { + fastAdvCount = 0; + } + private: static constexpr const char* deviceName = "InfiniTime"; Pinetime::System::SystemTask& systemTask; @@ -94,6 +98,7 @@ namespace Pinetime { uint8_t addrType; // 1 = Random, 0 = PUBLIC uint16_t connectionHandle = BLE_HS_CONN_HANDLE_NONE; + uint8_t fastAdvCount = 0; ble_uuid128_t dfuServiceUuid { .u {.type = BLE_UUID_TYPE_128}, @@ -101,5 +106,7 @@ namespace Pinetime { ServiceDiscovery serviceDiscovery; }; + + static NimbleController* nptr; } } diff --git a/src/components/ble/NotificationManager.cpp b/src/components/ble/NotificationManager.cpp index b1b0e6b2..7ffed300 100644 --- a/src/components/ble/NotificationManager.cpp +++ b/src/components/ble/NotificationManager.cpp @@ -79,14 +79,6 @@ bool NotificationManager::AreNewNotificationsAvailable() { return newNotification; } -bool NotificationManager::IsVibrationEnabled() { - return vibrationEnabled; -} - -void NotificationManager::ToggleVibrations() { - vibrationEnabled = !vibrationEnabled; -} - bool NotificationManager::ClearNewNotificationFlag() { return newNotification.exchange(false); } diff --git a/src/components/ble/NotificationManager.h b/src/components/ble/NotificationManager.h index d4072cc2..40f174ea 100644 --- a/src/components/ble/NotificationManager.h +++ b/src/components/ble/NotificationManager.h @@ -44,8 +44,6 @@ namespace Pinetime { Notification GetPrevious(Notification::Id id); bool ClearNewNotificationFlag(); bool AreNewNotificationsAvailable(); - bool IsVibrationEnabled(); - void ToggleVibrations(); static constexpr size_t MaximumMessageSize() { return MessageSize; @@ -60,7 +58,6 @@ namespace Pinetime { uint8_t writeIndex = 0; bool empty = true; std::atomic<bool> newNotification {false}; - bool vibrationEnabled = true; }; } -}
\ No newline at end of file +} diff --git a/src/components/brightness/BrightnessController.cpp b/src/components/brightness/BrightnessController.cpp index 8ad987d1..6c524679 100644 --- a/src/components/brightness/BrightnessController.cpp +++ b/src/components/brightness/BrightnessController.cpp @@ -1,13 +1,13 @@ #include "BrightnessController.h" #include <hal/nrf_gpio.h> #include "displayapp/screens/Symbols.h" - +#include "drivers/PinMap.h" using namespace Pinetime::Controllers; void BrightnessController::Init() { - nrf_gpio_cfg_output(pinLcdBacklight1); - nrf_gpio_cfg_output(pinLcdBacklight2); - nrf_gpio_cfg_output(pinLcdBacklight3); + nrf_gpio_cfg_output(PinMap::LcdBacklightLow); + nrf_gpio_cfg_output(PinMap::LcdBacklightMedium); + nrf_gpio_cfg_output(PinMap::LcdBacklightHigh); Set(level); } @@ -16,24 +16,24 @@ void BrightnessController::Set(BrightnessController::Levels level) { switch (level) { default: case Levels::High: - nrf_gpio_pin_clear(pinLcdBacklight1); - nrf_gpio_pin_clear(pinLcdBacklight2); - nrf_gpio_pin_clear(pinLcdBacklight3); + nrf_gpio_pin_clear(PinMap::LcdBacklightLow); + nrf_gpio_pin_clear(PinMap::LcdBacklightMedium); + nrf_gpio_pin_clear(PinMap::LcdBacklightHigh); break; case Levels::Medium: - nrf_gpio_pin_clear(pinLcdBacklight1); - nrf_gpio_pin_clear(pinLcdBacklight2); - nrf_gpio_pin_set(pinLcdBacklight3); + nrf_gpio_pin_clear(PinMap::LcdBacklightLow); + nrf_gpio_pin_clear(PinMap::LcdBacklightMedium); + nrf_gpio_pin_set(PinMap::LcdBacklightHigh); break; case Levels::Low: - nrf_gpio_pin_clear(pinLcdBacklight1); - nrf_gpio_pin_set(pinLcdBacklight2); - nrf_gpio_pin_set(pinLcdBacklight3); + nrf_gpio_pin_clear(PinMap::LcdBacklightLow); + nrf_gpio_pin_set(PinMap::LcdBacklightMedium); + nrf_gpio_pin_set(PinMap::LcdBacklightHigh); break; case Levels::Off: - nrf_gpio_pin_set(pinLcdBacklight1); - nrf_gpio_pin_set(pinLcdBacklight2); - nrf_gpio_pin_set(pinLcdBacklight3); + nrf_gpio_pin_set(PinMap::LcdBacklightLow); + nrf_gpio_pin_set(PinMap::LcdBacklightMedium); + nrf_gpio_pin_set(PinMap::LcdBacklightHigh); break; } } diff --git a/src/components/brightness/BrightnessController.h b/src/components/brightness/BrightnessController.h index c47158a9..0d7ac2ff 100644 --- a/src/components/brightness/BrightnessController.h +++ b/src/components/brightness/BrightnessController.h @@ -22,9 +22,6 @@ namespace Pinetime { const char* ToString(); private: - static constexpr uint8_t pinLcdBacklight1 = 14; - static constexpr uint8_t pinLcdBacklight2 = 22; - static constexpr uint8_t pinLcdBacklight3 = 23; Levels level = Levels::High; Levels backupLevel = Levels::High; }; diff --git a/src/components/datetime/DateTimeController.cpp b/src/components/datetime/DateTimeController.cpp index d6aa83c8..e9c5d870 100644 --- a/src/components/datetime/DateTimeController.cpp +++ b/src/components/datetime/DateTimeController.cpp @@ -5,6 +5,17 @@ using namespace Pinetime::Controllers; +namespace { + char const* DaysStringShort[] = {"--", "MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"}; + char const* MonthsString[] = {"--", "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"}; + char const* MonthsStringLow[] = {"--", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; +} + +void DateTime::SetCurrentTime(std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> t) { + this->currentDateTime = t; + UpdateTime(previousSystickCounter); // Update internal state without updating the time +} + void DateTime::SetTime( uint16_t year, uint8_t month, uint8_t day, uint8_t dayOfWeek, uint8_t hour, uint8_t minute, uint8_t second, uint32_t systickCounter) { std::tm tm = { @@ -67,7 +78,7 @@ void DateTime::UpdateTime(uint32_t systickCounter) { // Notify new day to SystemTask if (hour == 0 and not isMidnightAlreadyNotified) { isMidnightAlreadyNotified = true; - if(systemTask != nullptr) + if (systemTask != nullptr) systemTask->PushMessage(System::Messages::OnNewDay); } else if (hour != 0) { isMidnightAlreadyNotified = false; @@ -75,48 +86,18 @@ void DateTime::UpdateTime(uint32_t systickCounter) { } const char* DateTime::MonthShortToString() { - return DateTime::MonthsString[static_cast<uint8_t>(month)]; -} - -const char* DateTime::MonthShortToStringLow() { - return DateTime::MonthsStringLow[static_cast<uint8_t>(month)]; -} - -const char* DateTime::MonthsToStringLow() { - return DateTime::MonthsLow[static_cast<uint8_t>(month)]; -} - -const char* DateTime::DayOfWeekToString() { - return DateTime::DaysString[static_cast<uint8_t>(dayOfWeek)]; + return MonthsString[static_cast<uint8_t>(month)]; } const char* DateTime::DayOfWeekShortToString() { - return DateTime::DaysStringShort[static_cast<uint8_t>(dayOfWeek)]; -} - -const char* DateTime::DayOfWeekToStringLow() { - return DateTime::DaysStringLow[static_cast<uint8_t>(dayOfWeek)]; + return DaysStringShort[static_cast<uint8_t>(dayOfWeek)]; } -const char* DateTime::DayOfWeekShortToStringLow() { - return DateTime::DaysStringShortLow[static_cast<uint8_t>(dayOfWeek)]; +const char* DateTime::MonthShortToStringLow(Months month) { + return MonthsStringLow[static_cast<uint8_t>(month)]; } void DateTime::Register(Pinetime::System::SystemTask* systemTask) { this->systemTask = systemTask; } -char const* DateTime::DaysStringLow[] = {"--", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"}; - -char const* DateTime::DaysStringShortLow[] = {"--", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"}; - -char const* DateTime::DaysStringShort[] = {"--", "MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"}; - -char const* DateTime::DaysString[] = {"--", "MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY", "SUNDAY"}; - -char const* DateTime::MonthsString[] = {"--", "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"}; - -char const* DateTime::MonthsStringLow[] = {"--", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; - -char const* DateTime::MonthsLow[] = { - "--", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"};
\ No newline at end of file diff --git a/src/components/datetime/DateTimeController.h b/src/components/datetime/DateTimeController.h index 265d6e9d..77ed68e8 100644 --- a/src/components/datetime/DateTimeController.h +++ b/src/components/datetime/DateTimeController.h @@ -59,12 +59,8 @@ namespace Pinetime { } const char* MonthShortToString(); - const char* MonthShortToStringLow(); - const char* MonthsToStringLow(); - const char* DayOfWeekToString(); const char* DayOfWeekShortToString(); - const char* DayOfWeekToStringLow(); - const char* DayOfWeekShortToStringLow(); + static const char* MonthShortToStringLow(Months month); std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> CurrentDateTime() const { return currentDateTime; @@ -74,6 +70,7 @@ namespace Pinetime { } void Register(System::SystemTask* systemTask); + void SetCurrentTime(std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> t); private: uint16_t year = 0; @@ -90,14 +87,6 @@ namespace Pinetime { bool isMidnightAlreadyNotified = false; System::SystemTask* systemTask = nullptr; - - static char const* DaysString[]; - static char const* DaysStringShort[]; - static char const* DaysStringLow[]; - static char const* DaysStringShortLow[]; - static char const* MonthsString[]; - static char const* MonthsStringLow[]; - static char const* MonthsLow[]; }; } -}
\ No newline at end of file +} diff --git a/src/components/fs/FS.h b/src/components/fs/FS.h index 1f2eb7e0..75ba16c8 100644 --- a/src/components/fs/FS.h +++ b/src/components/fs/FS.h @@ -53,7 +53,7 @@ namespace Pinetime { * */ static constexpr size_t startAddress = 0x0B4000; - static constexpr size_t size = 0x3C0000; + static constexpr size_t size = 0x34C000; static constexpr size_t blockSize = 4096; bool resourcesValid = false; diff --git a/src/components/motor/MotorController.cpp b/src/components/motor/MotorController.cpp index b25e6bc8..f596c718 100644 --- a/src/components/motor/MotorController.cpp +++ b/src/components/motor/MotorController.cpp @@ -2,18 +2,16 @@ #include <hal/nrf_gpio.h> #include "systemtask/SystemTask.h" #include "app_timer.h" +#include "drivers/PinMap.h" APP_TIMER_DEF(shortVibTimer); APP_TIMER_DEF(longVibTimer); using namespace Pinetime::Controllers; -MotorController::MotorController(Controllers::Settings& settingsController) : settingsController {settingsController} { -} - void MotorController::Init() { - nrf_gpio_cfg_output(pinMotor); - nrf_gpio_pin_set(pinMotor); + nrf_gpio_cfg_output(PinMap::Motor); + nrf_gpio_pin_set(PinMap::Motor); app_timer_init(); app_timer_create(&shortVibTimer, APP_TIMER_MODE_SINGLE_SHOT, StopMotor); @@ -26,27 +24,20 @@ void MotorController::Ring(void* p_context) { } void MotorController::RunForDuration(uint8_t motorDuration) { - if (settingsController.GetVibrationStatus() == Controllers::Settings::Vibration::OFF) { - return; - } - - nrf_gpio_pin_clear(pinMotor); + nrf_gpio_pin_clear(PinMap::Motor); app_timer_start(shortVibTimer, APP_TIMER_TICKS(motorDuration), nullptr); } void MotorController::StartRinging() { - if (settingsController.GetVibrationStatus() == Controllers::Settings::Vibration::OFF) { - return; - } Ring(this); app_timer_start(longVibTimer, APP_TIMER_TICKS(1000), this); } void MotorController::StopRinging() { app_timer_stop(longVibTimer); - nrf_gpio_pin_set(pinMotor); + nrf_gpio_pin_set(PinMap::Motor); } void MotorController::StopMotor(void* p_context) { - nrf_gpio_pin_set(pinMotor); + nrf_gpio_pin_set(PinMap::Motor); } diff --git a/src/components/motor/MotorController.h b/src/components/motor/MotorController.h index d2c9fe5f..c9326d57 100644 --- a/src/components/motor/MotorController.h +++ b/src/components/motor/MotorController.h @@ -1,16 +1,14 @@ #pragma once #include <cstdint> -#include "app_timer.h" -#include "components/settings/Settings.h" namespace Pinetime { namespace Controllers { - static constexpr uint8_t pinMotor = 16; class MotorController { public: - MotorController(Controllers::Settings& settingsController); + MotorController() = default; + void Init(); void RunForDuration(uint8_t motorDuration); void StartRinging(); @@ -18,7 +16,6 @@ namespace Pinetime { private: static void Ring(void* p_context); - Controllers::Settings& settingsController; static void StopMotor(void* p_context); }; } diff --git a/src/components/settings/Settings.h b/src/components/settings/Settings.h index 93d6d217..871ff3b6 100644 --- a/src/components/settings/Settings.h +++ b/src/components/settings/Settings.h @@ -11,12 +11,20 @@ namespace Pinetime { class Settings { public: enum class ClockType : uint8_t { H24, H12 }; - enum class Vibration : uint8_t { ON, OFF }; + enum class Notification : uint8_t { ON, OFF }; enum class WakeUpMode : uint8_t { SingleTap = 0, DoubleTap = 1, RaiseWrist = 2, }; + enum class Colors : uint8_t { + White, Silver, Gray, Black, Red, Maroon, Yellow, Olive, Lime, Green, Cyan, Teal, Blue, Navy, Magenta, Purple, Orange + }; + struct PineTimeStyle { + Colors ColorTime = Colors::Teal; + Colors ColorBar = Colors::Teal; + Colors ColorBG = Colors::Black; + }; Settings(Pinetime::Controllers::FS& fs); @@ -33,10 +41,38 @@ namespace Pinetime { return settings.clockFace; }; + void SetPTSColorTime(Colors colorTime) { + if (colorTime != settings.PTS.ColorTime) + settingsChanged = true; + settings.PTS.ColorTime = colorTime; + }; + Colors GetPTSColorTime() const { + return settings.PTS.ColorTime; + }; + + void SetPTSColorBar(Colors colorBar) { + if (colorBar != settings.PTS.ColorBar) + settingsChanged = true; + settings.PTS.ColorBar = colorBar; + }; + Colors GetPTSColorBar() const { + return settings.PTS.ColorBar; + }; + + void SetPTSColorBG(Colors colorBG) { + if (colorBG != settings.PTS.ColorBG) + settingsChanged = true; + settings.PTS.ColorBG = colorBG; + }; + Colors GetPTSColorBG() const { + return settings.PTS.ColorBG; + }; + void SetAppMenu(uint8_t menu) { appMenu = menu; }; - uint8_t GetAppMenu() { + + uint8_t GetAppMenu() const { return appMenu; }; @@ -57,14 +93,14 @@ namespace Pinetime { return settings.clockType; }; - void SetVibrationStatus(Vibration status) { - if (status != settings.vibrationStatus) { + void SetNotificationStatus(Notification status) { + if (status != settings.notificationStatus) { settingsChanged = true; } - settings.vibrationStatus = status; + settings.notificationStatus = status; }; - Vibration GetVibrationStatus() const { - return settings.vibrationStatus; + Notification GetNotificationStatus() const { + return settings.notificationStatus; }; void SetScreenTimeOut(uint32_t timeout) { @@ -78,7 +114,7 @@ namespace Pinetime { }; void setWakeUpMode(WakeUpMode wakeUp, bool enabled) { - if (!isWakeUpModeOn(wakeUp)) { + if (enabled != isWakeUpModeOn(wakeUp)) { settingsChanged = true; } settings.wakeUpMode.set(static_cast<size_t>(wakeUp), enabled); @@ -127,18 +163,19 @@ namespace Pinetime { private: Pinetime::Controllers::FS& fs; - static constexpr uint32_t settingsVersion = 0x0001; + static constexpr uint32_t settingsVersion = 0x0002; struct SettingsData { - uint32_t version = settingsVersion; uint32_t stepsGoal = 10000; uint32_t screenTimeOut = 15000; ClockType clockType = ClockType::H24; - Vibration vibrationStatus = Vibration::ON; + Notification notificationStatus = Notification::ON; uint8_t clockFace = 0; + PineTimeStyle PTS; + std::bitset<3> wakeUpMode {0}; Controllers::BrightnessController::Levels brightLevel = Controllers::BrightnessController::Levels::Medium; diff --git a/src/displayapp/Apps.h b/src/displayapp/Apps.h index 684e3a46..d340efee 100644 --- a/src/displayapp/Apps.h +++ b/src/displayapp/Apps.h @@ -12,6 +12,7 @@ namespace Pinetime { NotificationsPreview, Notifications, Timer, + Alarm, FlashLight, BatteryInfo, Music, @@ -30,7 +31,11 @@ namespace Pinetime { SettingTimeFormat, SettingDisplay, SettingWakeUp, - SettingSteps + SettingSteps, + SettingPineTimeStyle, + SettingSetDate, + SettingSetTime, + Error, }; } } diff --git a/src/displayapp/Colors.cpp b/src/displayapp/Colors.cpp new file mode 100644 index 00000000..f45f0722 --- /dev/null +++ b/src/displayapp/Colors.cpp @@ -0,0 +1,27 @@ +#include "Colors.h" + +using namespace Pinetime::Applications; +using namespace Pinetime::Controllers; + +lv_color_t Pinetime::Applications::Convert(Pinetime::Controllers::Settings::Colors color) { + switch (color) { + case Pinetime::Controllers::Settings::Colors::White: return LV_COLOR_WHITE; + case Pinetime::Controllers::Settings::Colors::Silver: return LV_COLOR_SILVER; + case Pinetime::Controllers::Settings::Colors::Gray: return LV_COLOR_GRAY; + case Pinetime::Controllers::Settings::Colors::Black: return LV_COLOR_BLACK; + case Pinetime::Controllers::Settings::Colors::Red: return LV_COLOR_RED; + case Pinetime::Controllers::Settings::Colors::Maroon: return LV_COLOR_MAROON; + case Pinetime::Controllers::Settings::Colors::Yellow: return LV_COLOR_YELLOW; + case Pinetime::Controllers::Settings::Colors::Olive: return LV_COLOR_OLIVE; + case Pinetime::Controllers::Settings::Colors::Lime: return LV_COLOR_LIME; + case Pinetime::Controllers::Settings::Colors::Green: return LV_COLOR_GREEN; + case Pinetime::Controllers::Settings::Colors::Cyan: return LV_COLOR_CYAN; + case Pinetime::Controllers::Settings::Colors::Teal: return LV_COLOR_TEAL; + case Pinetime::Controllers::Settings::Colors::Blue: return LV_COLOR_BLUE; + case Pinetime::Controllers::Settings::Colors::Navy: return LV_COLOR_NAVY; + case Pinetime::Controllers::Settings::Colors::Magenta: return LV_COLOR_MAGENTA; + case Pinetime::Controllers::Settings::Colors::Purple: return LV_COLOR_PURPLE; + case Pinetime::Controllers::Settings::Colors::Orange: return LV_COLOR_ORANGE; + default: return LV_COLOR_WHITE; + } +} diff --git a/src/displayapp/Colors.h b/src/displayapp/Colors.h new file mode 100644 index 00000000..9db7dd20 --- /dev/null +++ b/src/displayapp/Colors.h @@ -0,0 +1,10 @@ +#pragma once + +#include <lvgl/src/lv_misc/lv_color.h> +#include <components/settings/Settings.h> + +namespace Pinetime { + namespace Applications { + lv_color_t Convert(Controllers::Settings::Colors color); + } +}
\ No newline at end of file diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 8cb8ed15..6e5cb576 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -3,6 +3,7 @@ #include <displayapp/screens/HeartRate.h> #include <displayapp/screens/Motion.h> #include <displayapp/screens/Timer.h> +#include <displayapp/screens/Alarm.h> #include "components/battery/BatteryController.h" #include "components/ble/BleController.h" #include "components/datetime/DateTimeController.h" @@ -28,6 +29,7 @@ #include "displayapp/screens/FlashLight.h" #include "displayapp/screens/BatteryInfo.h" #include "displayapp/screens/Steps.h" +#include "displayapp/screens/Error.h" #include "drivers/Cst816s.h" #include "drivers/St7789.h" @@ -42,6 +44,9 @@ #include "displayapp/screens/settings/SettingWakeUp.h" #include "displayapp/screens/settings/SettingDisplay.h" #include "displayapp/screens/settings/SettingSteps.h" +#include "displayapp/screens/settings/SettingPineTimeStyle.h" +#include "displayapp/screens/settings/SettingSetDate.h" +#include "displayapp/screens/settings/SettingSetTime.h" #include "libs/lv_conf.h" @@ -89,6 +94,7 @@ DisplayApp::DisplayApp(Drivers::St7789& lcd, Pinetime::Controllers::MotorController& motorController, Pinetime::Controllers::MotionController& motionController, Pinetime::Controllers::TimerController& timerController, + Pinetime::Controllers::AlarmController& alarmController, Pinetime::Controllers::TouchHandler& touchHandler) : lcd {lcd}, lvgl {lvgl}, @@ -103,14 +109,20 @@ DisplayApp::DisplayApp(Drivers::St7789& lcd, motorController {motorController}, motionController {motionController}, timerController {timerController}, + alarmController {alarmController}, touchHandler {touchHandler} { } -void DisplayApp::Start() { +void DisplayApp::Start(System::BootErrors error) { msgQueue = xQueueCreate(queueSize, itemSize); - // Start clock when smartwatch boots - LoadApp(Apps::Clock, DisplayApp::FullRefreshDirections::None); + bootError = error; + + if (error == System::BootErrors::TouchController) { + LoadApp(Apps::Error, DisplayApp::FullRefreshDirections::None); + } else { + LoadApp(Apps::Clock, DisplayApp::FullRefreshDirections::None); + } if (pdPASS != xTaskCreate(DisplayApp::Process, "displayapp", 800, this, 0, &taskHandle)) { APP_ERROR_HANDLER(NRF_ERROR_NO_MEM); @@ -135,24 +147,17 @@ void DisplayApp::InitHw() { brightnessController.Set(settingsController.GetBrightness()); } -uint32_t acc = 0; -uint32_t count = 0; -bool toggle = true; void DisplayApp::Refresh() { TickType_t queueTimeout; - TickType_t delta; switch (state) { case States::Idle: - IdleState(); queueTimeout = portMAX_DELAY; break; case States::Running: - RunningState(); - delta = xTaskGetTickCount() - lastWakeTime; - if (delta > LV_DISP_DEF_REFR_PERIOD) { - delta = LV_DISP_DEF_REFR_PERIOD; + if (!currentScreen->IsRunning()) { + LoadApp(returnToApp, returnDirection); } - queueTimeout = LV_DISP_DEF_REFR_PERIOD - delta; + queueTimeout = lv_task_handler(); break; default: queueTimeout = portMAX_DELAY; @@ -160,9 +165,7 @@ void DisplayApp::Refresh() { } Messages msg; - bool messageReceived = xQueueReceive(msgQueue, &msg, queueTimeout); - lastWakeTime = xTaskGetTickCount(); - if (messageReceived) { + if (xQueueReceive(msgQueue, &msg, queueTimeout)) { switch (msg) { case Messages::DimScreen: // Backup brightness is the brightness to return to after dimming or sleeping @@ -193,9 +196,6 @@ void DisplayApp::Refresh() { // clockScreen.SetBleConnectionState(bleController.IsConnected() ? Screens::Clock::BleConnectionStates::Connected : // Screens::Clock::BleConnectionStates::NotConnected); break; - case Messages::UpdateBatteryLevel: - batteryController.Update(); - break; case Messages::NewNotification: LoadApp(Apps::NotificationsPreview, DisplayApp::FullRefreshDirections::Down); break; @@ -207,6 +207,13 @@ void DisplayApp::Refresh() { LoadApp(Apps::Timer, DisplayApp::FullRefreshDirections::Down); } break; + case Messages::AlarmTriggered: + if (currentApp == Apps::Alarm) { + auto* alarm = static_cast<Screens::Alarm*>(currentScreen.get()); + alarm->SetAlerting(); + } else { + LoadApp(Apps::Alarm, DisplayApp::FullRefreshDirections::None); + } case Messages::TouchEvent: { if (state != States::Running) { break; @@ -274,13 +281,6 @@ void DisplayApp::Refresh() { } } -void DisplayApp::RunningState() { - if (!currentScreen->Refresh()) { - LoadApp(returnToApp, returnDirection); - } - lv_task_handler(); -} - void DisplayApp::StartApp(Apps app, DisplayApp::FullRefreshDirections direction) { nextApp = app; nextDirection = direction; @@ -317,6 +317,11 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction) motionController); break; + case Apps::Error: + currentScreen = std::make_unique<Screens::Error>(this, bootError); + ReturnApp(Apps::Clock, FullRefreshDirections::Down, TouchEvents::None); + break; + case Apps::FirmwareValidation: currentScreen = std::make_unique<Screens::FirmwareValidation>(this, validator); ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); @@ -339,6 +344,9 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction) case Apps::Timer: currentScreen = std::make_unique<Screens::Timer>(this, timerController); break; + case Apps::Alarm: + currentScreen = std::make_unique<Screens::Alarm>(this, alarmController); + break; // Settings case Apps::QuickSettings: @@ -370,13 +378,25 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction) currentScreen = std::make_unique<Screens::SettingSteps>(this, settingsController); ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; + case Apps::SettingSetDate: + currentScreen = std::make_unique<Screens::SettingSetDate>(this, dateTimeController); + ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); + break; + case Apps::SettingSetTime: + currentScreen = std::make_unique<Screens::SettingSetTime>(this, dateTimeController); + ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); + break; + case Apps::SettingPineTimeStyle: + currentScreen = std::make_unique<Screens::SettingPineTimeStyle>(this, settingsController); + ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); + break; case Apps::BatteryInfo: currentScreen = std::make_unique<Screens::BatteryInfo>(this, batteryController); ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::SysInfo: currentScreen = std::make_unique<Screens::SystemInfo>( - this, dateTimeController, batteryController, brightnessController, bleController, watchdog, motionController); + this, dateTimeController, batteryController, brightnessController, bleController, watchdog, motionController, touchPanel); ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::FlashLight: @@ -418,9 +438,6 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction) currentApp = app; } -void DisplayApp::IdleState() { -} - void DisplayApp::PushMessage(Messages msg) { if (in_isr()) { BaseType_t xHigherPriorityTaskWoken; diff --git a/src/displayapp/DisplayApp.h b/src/displayapp/DisplayApp.h index 96951d1c..a87cab0b 100644 --- a/src/displayapp/DisplayApp.h +++ b/src/displayapp/DisplayApp.h @@ -14,8 +14,11 @@ #include "components/settings/Settings.h" #include "displayapp/screens/Screen.h" #include "components/timer/TimerController.h" +#include "components/alarm/AlarmController.h" #include "touchhandler/TouchHandler.h" + #include "Messages.h" +#include "BootErrors.h" namespace Pinetime { @@ -57,8 +60,9 @@ namespace Pinetime { Pinetime::Controllers::MotorController& motorController, Pinetime::Controllers::MotionController& motionController, Pinetime::Controllers::TimerController& timerController, + Pinetime::Controllers::AlarmController& alarmController, Pinetime::Controllers::TouchHandler& touchHandler); - void Start(); + void Start(System::BootErrors error); void PushMessage(Display::Messages msg); void StartApp(Apps app, DisplayApp::FullRefreshDirections direction); @@ -82,6 +86,7 @@ namespace Pinetime { Pinetime::Controllers::MotorController& motorController; Pinetime::Controllers::MotionController& motionController; Pinetime::Controllers::TimerController& timerController; + Pinetime::Controllers::AlarmController& alarmController; Pinetime::Controllers::TouchHandler& touchHandler; Pinetime::Controllers::FirmwareValidator validator; @@ -103,8 +108,6 @@ namespace Pinetime { TouchEvents returnTouchEvent = TouchEvents::None; TouchEvents GetGesture(); - void RunningState(); - void IdleState(); static void Process(void* instance); void InitHw(); void Refresh(); @@ -114,7 +117,7 @@ namespace Pinetime { Apps nextApp = Apps::None; DisplayApp::FullRefreshDirections nextDirection; - TickType_t lastWakeTime; + System::BootErrors bootError; }; } } diff --git a/src/displayapp/DisplayAppRecovery.cpp b/src/displayapp/DisplayAppRecovery.cpp index 17612ef0..a42d81a2 100644 --- a/src/displayapp/DisplayAppRecovery.cpp +++ b/src/displayapp/DisplayAppRecovery.cpp @@ -5,6 +5,7 @@ #include <components/rle/RleDecoder.h> #include <touchhandler/TouchHandler.h> #include "displayapp/icons/infinitime/infinitime-nb.c" +#include "components/ble/BleController.h" using namespace Pinetime::Applications; @@ -21,6 +22,7 @@ DisplayApp::DisplayApp(Drivers::St7789& lcd, Pinetime::Controllers::MotorController& motorController, Pinetime::Controllers::MotionController& motionController, Pinetime::Controllers::TimerController& timerController, + Pinetime::Controllers::AlarmController& alarmController, Pinetime::Controllers::TouchHandler& touchHandler) : lcd {lcd}, bleController {bleController} { diff --git a/src/displayapp/DisplayAppRecovery.h b/src/displayapp/DisplayAppRecovery.h index 8b2bc7f5..425e0aca 100644 --- a/src/displayapp/DisplayAppRecovery.h +++ b/src/displayapp/DisplayAppRecovery.h @@ -6,32 +6,39 @@ #include <bits/unique_ptr.h> #include <queue.h> #include "components/gfx/Gfx.h" -#include "components/battery/BatteryController.h" -#include "components/brightness/BrightnessController.h" -#include "components/ble/BleController.h" -#include "components/datetime/DateTimeController.h" -#include "components/ble/NotificationManager.h" -#include "components/firmwarevalidator/FirmwareValidator.h" #include "drivers/Cst816s.h" #include <date/date.h> #include <drivers/Watchdog.h> -#include <components/heartrate/HeartRateController.h> -#include <components/motion/MotionController.h> #include <components/motor/MotorController.h> -#include <components/settings/Settings.h> #include "TouchEvents.h" #include "Apps.h" #include "Messages.h" #include "DummyLittleVgl.h" -#include "components/timer/TimerController.h" namespace Pinetime { - namespace System { - class SystemTask; - }; + namespace Drivers { + class St7789; + class Cst816S; + class WatchdogView; + } namespace Controllers { + class Settings; + class Battery; + class Ble; + class DateTime; + class NotificationManager; + class HeartRateController; + class MotionController; class TouchHandler; + class MotorController; + class TimerController; + class AlarmController; } + + namespace System { + class SystemTask; + }; + namespace Applications { class DisplayApp { public: @@ -48,6 +55,7 @@ namespace Pinetime { Pinetime::Controllers::MotorController& motorController, Pinetime::Controllers::MotionController& motionController, Pinetime::Controllers::TimerController& timerController, + Pinetime::Controllers::AlarmController& alarmController, Pinetime::Controllers::TouchHandler& touchHandler); void Start(); void PushMessage(Pinetime::Applications::Display::Messages msg); diff --git a/src/displayapp/Messages.h b/src/displayapp/Messages.h index 322505e6..d48b646f 100644 --- a/src/displayapp/Messages.h +++ b/src/displayapp/Messages.h @@ -7,7 +7,6 @@ namespace Pinetime { GoToRunning, UpdateDateTime, UpdateBleConnection, - UpdateBatteryLevel, TouchEvent, ButtonPushed, NewNotification, @@ -15,7 +14,8 @@ namespace Pinetime { BleFirmwareUpdateStarted, UpdateTimeOut, DimScreen, - RestoreBrightness + RestoreBrightness, + AlarmTriggered }; } } diff --git a/src/displayapp/screens/Alarm.cpp b/src/displayapp/screens/Alarm.cpp new file mode 100644 index 00000000..6b45a36e --- /dev/null +++ b/src/displayapp/screens/Alarm.cpp @@ -0,0 +1,265 @@ +/* Copyright (C) 2021 mruss77, Florian + + This file is part of InfiniTime. + + InfiniTime is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + InfiniTime is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ +#include "Alarm.h" +#include "Screen.h" +#include "Symbols.h" + +using namespace Pinetime::Applications::Screens; +using Pinetime::Controllers::AlarmController; + +static void btnEventHandler(lv_obj_t* obj, lv_event_t event) { + Alarm* screen = static_cast<Alarm*>(obj->user_data); + screen->OnButtonEvent(obj, event); +} + +Alarm::Alarm(DisplayApp* app, Controllers::AlarmController& alarmController) + : Screen(app), running {true}, alarmController {alarmController} { + + time = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_font(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76); + lv_obj_set_style_local_text_color(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY); + + alarmHours = alarmController.Hours(); + alarmMinutes = alarmController.Minutes(); + lv_label_set_text_fmt(time, "%02lu:%02lu", alarmHours, alarmMinutes); + + lv_obj_align(time, lv_scr_act(), LV_ALIGN_CENTER, 0, -25); + + btnHoursUp = lv_btn_create(lv_scr_act(), nullptr); + btnHoursUp->user_data = this; + lv_obj_set_event_cb(btnHoursUp, btnEventHandler); + lv_obj_set_size(btnHoursUp, 60, 40); + lv_obj_align(btnHoursUp, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 20, -85); + txtHrUp = lv_label_create(btnHoursUp, nullptr); + lv_label_set_text_static(txtHrUp, "+"); + + btnHoursDown = lv_btn_create(lv_scr_act(), nullptr); + btnHoursDown->user_data = this; + lv_obj_set_event_cb(btnHoursDown, btnEventHandler); + lv_obj_set_size(btnHoursDown, 60, 40); + lv_obj_align(btnHoursDown, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 20, 35); + txtHrDown = lv_label_create(btnHoursDown, nullptr); + lv_label_set_text_static(txtHrDown, "-"); + + btnMinutesUp = lv_btn_create(lv_scr_act(), nullptr); + btnMinutesUp->user_data = this; + lv_obj_set_event_cb(btnMinutesUp, btnEventHandler); + lv_obj_set_size(btnMinutesUp, 60, 40); + lv_obj_align(btnMinutesUp, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, -20, -85); + txtMinUp = lv_label_create(btnMinutesUp, nullptr); + lv_label_set_text_static(txtMinUp, "+"); + + btnMinutesDown = lv_btn_create(lv_scr_act(), nullptr); + btnMinutesDown->user_data = this; + lv_obj_set_event_cb(btnMinutesDown, btnEventHandler); + lv_obj_set_size(btnMinutesDown, 60, 40); + lv_obj_align(btnMinutesDown, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, -20, 35); + txtMinDown = lv_label_create(btnMinutesDown, nullptr); + lv_label_set_text_static(txtMinDown, "-"); + + btnEnable = lv_btn_create(lv_scr_act(), nullptr); + btnEnable->user_data = this; + lv_obj_set_event_cb(btnEnable, btnEventHandler); + lv_obj_set_size(btnEnable, 115, 50); + lv_obj_align(btnEnable, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 0, 0); + txtEnable = lv_label_create(btnEnable, nullptr); + SetEnableButtonState(); + + btnRecur = lv_btn_create(lv_scr_act(), nullptr); + btnRecur->user_data = this; + lv_obj_set_event_cb(btnRecur, btnEventHandler); + lv_obj_set_size(btnRecur, 115, 50); + lv_obj_align(btnRecur, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0); + txtRecur = lv_label_create(btnRecur, nullptr); + SetRecurButtonState(); + + btnInfo = lv_btn_create(lv_scr_act(), nullptr); + btnInfo->user_data = this; + lv_obj_set_event_cb(btnInfo, btnEventHandler); + lv_obj_set_size(btnInfo, 50, 40); + lv_obj_align(btnInfo, lv_scr_act(), LV_ALIGN_CENTER, 0, -85); + txtInfo = lv_label_create(btnInfo, nullptr); + lv_label_set_text_static(txtInfo, "i"); +} + +Alarm::~Alarm() { + lv_obj_clean(lv_scr_act()); +} + +void Alarm::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { + using Pinetime::Controllers::AlarmController; + if (event == LV_EVENT_CLICKED) { + if (obj == btnEnable) { + if (alarmController.State() == AlarmController::AlarmState::Alerting) { + alarmController.StopAlerting(); + } else if (alarmController.State() == AlarmController::AlarmState::Set) { + alarmController.DisableAlarm(); + } else { + alarmController.ScheduleAlarm(); + } + SetEnableButtonState(); + return; + } + if (obj == btnInfo) { + ShowInfo(); + return; + } + if (obj == btnMessage) { + HideInfo(); + return; + } + // If any other button was pressed, disable the alarm + // this is to make it clear that the alarm won't be set until it is turned back on + if (alarmController.State() == AlarmController::AlarmState::Set) { + alarmController.DisableAlarm(); + SetEnableButtonState(); + } + if (obj == btnMinutesUp) { + if (alarmMinutes >= 59) { + alarmMinutes = 0; + } else { + alarmMinutes++; + } + UpdateAlarmTime(); + return; + } + if (obj == btnMinutesDown) { + if (alarmMinutes == 0) { + alarmMinutes = 59; + } else { + alarmMinutes--; + } + UpdateAlarmTime(); + return; + } + if (obj == btnHoursUp) { + if (alarmHours >= 23) { + alarmHours = 0; + } else { + alarmHours++; + } + UpdateAlarmTime(); + return; + } + if (obj == btnHoursDown) { + if (alarmHours == 0) { + alarmHours = 23; + } else { + alarmHours--; + } + UpdateAlarmTime(); + return; + } + if (obj == btnRecur) { + ToggleRecurrence(); + } + } +} + +bool Alarm::OnButtonPushed() { + if (txtMessage != nullptr && btnMessage != nullptr) { + HideInfo(); + return true; + } + return false; +} + +void Alarm::UpdateAlarmTime() { + lv_label_set_text_fmt(time, "%02d:%02d", alarmHours, alarmMinutes); + alarmController.SetAlarmTime(alarmHours, alarmMinutes); +} + +void Alarm::SetAlerting() { + SetEnableButtonState(); +} + +void Alarm::SetEnableButtonState() { + switch (alarmController.State()) { + case AlarmController::AlarmState::Set: + lv_label_set_text(txtEnable, "ON"); + lv_obj_set_style_local_bg_color(btnEnable, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GREEN); + break; + case AlarmController::AlarmState::Not_Set: + lv_label_set_text(txtEnable, "OFF"); + lv_obj_set_style_local_bg_color(btnEnable, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY); + break; + case AlarmController::AlarmState::Alerting: + lv_label_set_text(txtEnable, Symbols::stop); + lv_obj_set_style_local_bg_color(btnEnable, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED); + } +} + +void Alarm::ShowInfo() { + btnMessage = lv_btn_create(lv_scr_act(), nullptr); + btnMessage->user_data = this; + lv_obj_set_event_cb(btnMessage, btnEventHandler); + lv_obj_set_height(btnMessage, 200); + lv_obj_set_width(btnMessage, 150); + lv_obj_align(btnMessage, lv_scr_act(), LV_ALIGN_CENTER, 0, 0); + txtMessage = lv_label_create(btnMessage, nullptr); + lv_obj_set_style_local_bg_color(btnMessage, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_NAVY); + + if (alarmController.State() == AlarmController::AlarmState::Set) { + auto timeToAlarm = alarmController.SecondsToAlarm(); + + auto daysToAlarm = timeToAlarm / 86400; + auto hrsToAlarm = (timeToAlarm % 86400) / 3600; + auto minToAlarm = (timeToAlarm % 3600) / 60; + auto secToAlarm = timeToAlarm % 60; + + lv_label_set_text_fmt( + txtMessage, "Time to\nalarm:\n%2d Days\n%2d Hours\n%2d Minutes\n%2d Seconds", daysToAlarm, hrsToAlarm, minToAlarm, secToAlarm); + } else { + lv_label_set_text(txtMessage, "Alarm\nis not\nset."); + } +} + +void Alarm::HideInfo() { + lv_obj_del(btnMessage); + txtMessage = nullptr; + btnMessage = nullptr; +} + +void Alarm::SetRecurButtonState() { + using Pinetime::Controllers::AlarmController; + switch (alarmController.Recurrence()) { + case AlarmController::RecurType::None: + lv_label_set_text(txtRecur, "ONCE"); + break; + case AlarmController::RecurType::Daily: + lv_label_set_text(txtRecur, "DAILY"); + break; + case AlarmController::RecurType::Weekdays: + lv_label_set_text(txtRecur, "MON-FRI"); + } +} + +void Alarm::ToggleRecurrence() { + using Pinetime::Controllers::AlarmController; + switch (alarmController.Recurrence()) { + case AlarmController::RecurType::None: + alarmController.SetRecurrence(AlarmController::RecurType::Daily); + break; + case AlarmController::RecurType::Daily: + alarmController.SetRecurrence(AlarmController::RecurType::Weekdays); + break; + case AlarmController::RecurType::Weekdays: + alarmController.SetRecurrence(AlarmController::RecurType::None); + } + SetRecurButtonState(); +} diff --git a/src/displayapp/screens/Alarm.h b/src/displayapp/screens/Alarm.h new file mode 100644 index 00000000..32a14d2f --- /dev/null +++ b/src/displayapp/screens/Alarm.h @@ -0,0 +1,56 @@ +/* Copyright (C) 2021 mruss77, Florian + + This file is part of InfiniTime. + + InfiniTime is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + InfiniTime is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ +#pragma once + +#include "Screen.h" +#include "systemtask/SystemTask.h" +#include "../LittleVgl.h" +#include "components/alarm/AlarmController.h" + +namespace Pinetime { + namespace Applications { + namespace Screens { + class Alarm : public Screen { + public: + Alarm(DisplayApp* app, Controllers::AlarmController& alarmController); + ~Alarm() override; + void SetAlerting(); + void OnButtonEvent(lv_obj_t* obj, lv_event_t event); + bool OnButtonPushed() override; + + private: + bool running; + uint8_t alarmHours; + uint8_t alarmMinutes; + Controllers::AlarmController& alarmController; + + lv_obj_t *time, *btnEnable, *txtEnable, *btnMinutesUp, *btnMinutesDown, *btnHoursUp, *btnHoursDown, *txtMinUp, *txtMinDown, + *txtHrUp, *txtHrDown, *btnRecur, *txtRecur, *btnMessage, *txtMessage, *btnInfo, *txtInfo; + + enum class EnableButtonState { On, Off, Alerting }; + void SetEnableButtonState(); + void SetRecurButtonState(); + void SetAlarm(); + void ShowInfo(); + void HideInfo(); + void ToggleRecurrence(); + void UpdateAlarmTime(); + }; + }; + }; +} diff --git a/src/displayapp/screens/ApplicationList.cpp b/src/displayapp/screens/ApplicationList.cpp index d6c3970b..5c582f60 100644 --- a/src/displayapp/screens/ApplicationList.cpp +++ b/src/displayapp/screens/ApplicationList.cpp @@ -34,12 +34,6 @@ ApplicationList::~ApplicationList() { lv_obj_clean(lv_scr_act()); } -bool ApplicationList::Refresh() { - if (running) - running = screens.Refresh(); - return running; -} - bool ApplicationList::OnTouchEvent(Pinetime::Applications::TouchEvents event) { return screens.OnTouchEvent(event); } @@ -64,7 +58,7 @@ std::unique_ptr<Screen> ApplicationList::CreateScreen2() { {"2", Apps::Twos}, {Symbols::chartLine, Apps::Motion}, {Symbols::drum, Apps::Metronome}, - {"", Apps::None}, + {Symbols::clock, Apps::Alarm}, }}; return std::make_unique<Screens::Tile>(1, 2, app, settingsController, batteryController, dateTimeController, applications); diff --git a/src/displayapp/screens/ApplicationList.h b/src/displayapp/screens/ApplicationList.h index 88534ec4..103c38ae 100644 --- a/src/displayapp/screens/ApplicationList.h +++ b/src/displayapp/screens/ApplicationList.h @@ -18,7 +18,6 @@ namespace Pinetime { Pinetime::Controllers::Battery& batteryController, Controllers::DateTime& dateTimeController); ~ApplicationList() override; - bool Refresh() override; bool OnTouchEvent(TouchEvents event) override; private: @@ -33,4 +32,4 @@ namespace Pinetime { }; } } -}
\ No newline at end of file +} diff --git a/src/displayapp/screens/BatteryInfo.cpp b/src/displayapp/screens/BatteryInfo.cpp index 0ab47ebf..44ea7f51 100644 --- a/src/displayapp/screens/BatteryInfo.cpp +++ b/src/displayapp/screens/BatteryInfo.cpp @@ -4,11 +4,6 @@ using namespace Pinetime::Applications::Screens; -static void lv_update_task(struct _lv_task_t* task) { - auto user_data = static_cast<BatteryInfo*>(task->user_data); - user_data->UpdateScreen(); -} - BatteryInfo::BatteryInfo(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Battery& batteryController) : Screen(app), batteryController {batteryController} { @@ -49,23 +44,21 @@ BatteryInfo::BatteryInfo(Pinetime::Applications::DisplayApp* app, Pinetime::Cont lv_obj_set_pos(backgroundLabel, 0, 0); lv_label_set_text_static(backgroundLabel, ""); - taskUpdate = lv_task_create(lv_update_task, 5000, LV_TASK_PRIO_LOW, this); - UpdateScreen(); + taskRefresh = lv_task_create(RefreshTaskCallback, 5000, LV_TASK_PRIO_MID, this); + Refresh(); } BatteryInfo::~BatteryInfo() { - lv_task_del(taskUpdate); + lv_task_del(taskRefresh); lv_obj_clean(lv_scr_act()); } -void BatteryInfo::UpdateScreen() { - - batteryController.Update(); +void BatteryInfo::Refresh() { batteryPercent = batteryController.PercentRemaining(); batteryVoltage = batteryController.Voltage(); - if (batteryController.IsCharging() and batteryPercent < 100) { + if (batteryController.IsCharging()) { lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_RED); lv_label_set_text_static(status, "Charging"); } else if (batteryPercent == 100) { @@ -85,7 +78,3 @@ void BatteryInfo::UpdateScreen() { lv_label_set_text_fmt(voltage, "%1i.%02i volts", batteryVoltage / 1000, batteryVoltage % 1000 / 10); lv_bar_set_value(charging_bar, batteryPercent, LV_ANIM_ON); } - -bool BatteryInfo::Refresh() { - return running; -} diff --git a/src/displayapp/screens/BatteryInfo.h b/src/displayapp/screens/BatteryInfo.h index 69793244..63454a26 100644 --- a/src/displayapp/screens/BatteryInfo.h +++ b/src/displayapp/screens/BatteryInfo.h @@ -19,9 +19,7 @@ namespace Pinetime { BatteryInfo(DisplayApp* app, Pinetime::Controllers::Battery& batteryController); ~BatteryInfo() override; - bool Refresh() override; - - void UpdateScreen(); + void Refresh() override; private: Pinetime::Controllers::Battery& batteryController; @@ -31,7 +29,7 @@ namespace Pinetime { lv_obj_t* charging_bar; lv_obj_t* status; - lv_task_t* taskUpdate; + lv_task_t* taskRefresh; uint8_t batteryPercent = 0; uint16_t batteryVoltage = 0; diff --git a/src/displayapp/screens/Brightness.cpp b/src/displayapp/screens/Brightness.cpp index 47c10561..1278cd62 100644 --- a/src/displayapp/screens/Brightness.cpp +++ b/src/displayapp/screens/Brightness.cpp @@ -30,10 +30,6 @@ Brightness::~Brightness() { lv_obj_clean(lv_scr_act()); } -bool Brightness::Refresh() { - return running; -} - const char* Brightness::LevelToString(Pinetime::Controllers::BrightnessController::Levels level) { switch (level) { case Pinetime::Controllers::BrightnessController::Levels::Off: diff --git a/src/displayapp/screens/Brightness.h b/src/displayapp/screens/Brightness.h index 9ee33753..14e48592 100644 --- a/src/displayapp/screens/Brightness.h +++ b/src/displayapp/screens/Brightness.h @@ -12,7 +12,6 @@ namespace Pinetime { public: Brightness(DisplayApp* app, Controllers::BrightnessController& brightness); ~Brightness() override; - bool Refresh() override; bool OnTouchEvent(TouchEvents event) override; @@ -31,4 +30,4 @@ namespace Pinetime { }; } } -}
\ No newline at end of file +} diff --git a/src/displayapp/screens/Clock.cpp b/src/displayapp/screens/Clock.cpp index 86afee0c..5a5cd18b 100644 --- a/src/displayapp/screens/Clock.cpp +++ b/src/displayapp/screens/Clock.cpp @@ -50,11 +50,6 @@ Clock::~Clock() { lv_obj_clean(lv_scr_act()); } -bool Clock::Refresh() { - screen->Refresh(); - return running; -} - bool Clock::OnTouchEvent(Pinetime::Applications::TouchEvents event) { return screen->OnTouchEvent(event); } @@ -83,4 +78,4 @@ std::unique_ptr<Screen> Clock::PineTimeStyleScreen() { notificatioManager, settingsController, motionController); -}
\ No newline at end of file +} diff --git a/src/displayapp/screens/Clock.h b/src/displayapp/screens/Clock.h index 7968cced..648f72da 100644 --- a/src/displayapp/screens/Clock.h +++ b/src/displayapp/screens/Clock.h @@ -31,8 +31,6 @@ namespace Pinetime { Controllers::MotionController& motionController); ~Clock() override; - bool Refresh() override; - bool OnTouchEvent(TouchEvents event) override; private: diff --git a/src/displayapp/screens/Error.cpp b/src/displayapp/screens/Error.cpp new file mode 100644 index 00000000..75946aba --- /dev/null +++ b/src/displayapp/screens/Error.cpp @@ -0,0 +1,50 @@ +#include "Error.h" + +using namespace Pinetime::Applications::Screens; + +namespace { + void ButtonEventCallback(lv_obj_t* obj, lv_event_t /*event*/) { + auto* errorScreen = static_cast<Error*>(obj->user_data); + errorScreen->ButtonEventHandler(); + } +} + +Error::Error(Pinetime::Applications::DisplayApp* app, System::BootErrors error) + : Screen(app) { + + lv_obj_t* warningLabel = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(warningLabel, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_ORANGE); + lv_label_set_text_static(warningLabel, "Warning"); + lv_obj_align(warningLabel, nullptr, LV_ALIGN_IN_TOP_MID, 0, 0); + + lv_obj_t* causeLabel = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_long_mode(causeLabel, LV_LABEL_LONG_BREAK); + lv_obj_set_width(causeLabel, LV_HOR_RES); + lv_obj_align(causeLabel, warningLabel, LV_ALIGN_OUT_BOTTOM_MID, 0, 0); + + if (error == System::BootErrors::TouchController) { + lv_label_set_text_static(causeLabel, "Touch controller error detected."); + } + + lv_obj_t* tipLabel = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_long_mode(tipLabel, LV_LABEL_LONG_BREAK); + lv_obj_set_width(tipLabel, LV_HOR_RES); + lv_label_set_text_static(tipLabel, "If you encounter problems and your device is under warranty, contact the devices seller."); + lv_obj_align(tipLabel, causeLabel, LV_ALIGN_OUT_BOTTOM_MID, 0, 0); + + btnOk = lv_btn_create(lv_scr_act(), nullptr); + btnOk->user_data = this; + lv_obj_set_event_cb(btnOk, ButtonEventCallback); + lv_obj_set_size(btnOk, LV_HOR_RES, 50); + lv_obj_align(btnOk, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 0, 0); + lv_obj_set_style_local_value_str(btnOk, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "Proceed"); + lv_obj_set_style_local_bg_color(btnOk, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_ORANGE); +} + +void Error::ButtonEventHandler() { + running = false; +} + +Error::~Error() { + lv_obj_clean(lv_scr_act()); +} diff --git a/src/displayapp/screens/Error.h b/src/displayapp/screens/Error.h new file mode 100644 index 00000000..20dde7ee --- /dev/null +++ b/src/displayapp/screens/Error.h @@ -0,0 +1,21 @@ +#pragma once + +#include "Screen.h" +#include "BootErrors.h" +#include <lvgl/lvgl.h> + +namespace Pinetime { + namespace Applications { + namespace Screens { + class Error : public Screen { + public: + Error(DisplayApp* app, System::BootErrors error); + ~Error() override; + + void ButtonEventHandler(); + private: + lv_obj_t* btnOk; + }; + } + } +} diff --git a/src/displayapp/screens/FirmwareUpdate.cpp b/src/displayapp/screens/FirmwareUpdate.cpp index edb2e49d..79bda0ba 100644 --- a/src/displayapp/screens/FirmwareUpdate.cpp +++ b/src/displayapp/screens/FirmwareUpdate.cpp @@ -30,14 +30,16 @@ FirmwareUpdate::FirmwareUpdate(Pinetime::Applications::DisplayApp* app, Pinetime lv_label_set_text(percentLabel, "Waiting..."); lv_obj_set_auto_realign(percentLabel, true); lv_obj_align(percentLabel, bar1, LV_ALIGN_OUT_TOP_MID, 0, 60); + taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this); startTime = xTaskGetTickCount(); } FirmwareUpdate::~FirmwareUpdate() { + lv_task_del(taskRefresh); lv_obj_clean(lv_scr_act()); } -bool FirmwareUpdate::Refresh() { +void FirmwareUpdate::Refresh() { switch (bleController.State()) { default: case Pinetime::Controllers::Ble::FirmwareUpdateStates::Idle: @@ -73,7 +75,6 @@ bool FirmwareUpdate::Refresh() { } break; } - return running; } void FirmwareUpdate::DisplayProgression() const { diff --git a/src/displayapp/screens/FirmwareUpdate.h b/src/displayapp/screens/FirmwareUpdate.h index 90c99f4c..8fc86d8c 100644 --- a/src/displayapp/screens/FirmwareUpdate.h +++ b/src/displayapp/screens/FirmwareUpdate.h @@ -16,7 +16,7 @@ namespace Pinetime { FirmwareUpdate(DisplayApp* app, Pinetime::Controllers::Ble& bleController); ~FirmwareUpdate() override; - bool Refresh() override; + void Refresh() override; private: enum class States { Idle, Running, Validated, Error }; @@ -36,6 +36,7 @@ namespace Pinetime { void UpdateError(); + lv_task_t* taskRefresh; TickType_t startTime; }; } diff --git a/src/displayapp/screens/FirmwareValidation.cpp b/src/displayapp/screens/FirmwareValidation.cpp index 34a43a9f..eef8f919 100644 --- a/src/displayapp/screens/FirmwareValidation.cpp +++ b/src/displayapp/screens/FirmwareValidation.cpp @@ -63,10 +63,6 @@ FirmwareValidation::~FirmwareValidation() { lv_obj_clean(lv_scr_act()); } -bool FirmwareValidation::Refresh() { - return running; -} - void FirmwareValidation::OnButtonEvent(lv_obj_t* object, lv_event_t event) { if (object == buttonValidate && event == LV_EVENT_CLICKED) { validator.Validate(); diff --git a/src/displayapp/screens/FirmwareValidation.h b/src/displayapp/screens/FirmwareValidation.h index 1ef5ba0a..bfdb096d 100644 --- a/src/displayapp/screens/FirmwareValidation.h +++ b/src/displayapp/screens/FirmwareValidation.h @@ -16,8 +16,6 @@ namespace Pinetime { FirmwareValidation(DisplayApp* app, Pinetime::Controllers::FirmwareValidator& validator); ~FirmwareValidation() override; - bool Refresh() override; - void OnButtonEvent(lv_obj_t* object, lv_event_t event); private: diff --git a/src/displayapp/screens/FlashLight.cpp b/src/displayapp/screens/FlashLight.cpp index 63b2345e..4bc5b558 100644 --- a/src/displayapp/screens/FlashLight.cpp +++ b/src/displayapp/screens/FlashLight.cpp @@ -65,10 +65,6 @@ void FlashLight::OnClickEvent(lv_obj_t* obj, lv_event_t event) { } } -bool FlashLight::Refresh() { - return running; -} - bool FlashLight::OnTouchEvent(Pinetime::Applications::TouchEvents event) { return false; } diff --git a/src/displayapp/screens/FlashLight.h b/src/displayapp/screens/FlashLight.h index a862ffdb..7f5ca6c5 100644 --- a/src/displayapp/screens/FlashLight.h +++ b/src/displayapp/screens/FlashLight.h @@ -16,8 +16,6 @@ namespace Pinetime { FlashLight(DisplayApp* app, System::SystemTask& systemTask, Controllers::BrightnessController& brightness); ~FlashLight() override; - bool Refresh() override; - bool OnTouchEvent(Pinetime::Applications::TouchEvents event) override; void OnClickEvent(lv_obj_t* obj, lv_event_t event); diff --git a/src/displayapp/screens/HeartRate.cpp b/src/displayapp/screens/HeartRate.cpp index 5689b63e..b6ece27f 100644 --- a/src/displayapp/screens/HeartRate.cpp +++ b/src/displayapp/screens/HeartRate.cpp @@ -64,14 +64,17 @@ HeartRate::HeartRate(Pinetime::Applications::DisplayApp* app, UpdateStartStopButton(isHrRunning); if (isHrRunning) systemTask.PushMessage(Pinetime::System::Messages::DisableSleeping); + + taskRefresh = lv_task_create(RefreshTaskCallback, 100, LV_TASK_PRIO_MID, this); } HeartRate::~HeartRate() { + lv_task_del(taskRefresh); lv_obj_clean(lv_scr_act()); systemTask.PushMessage(Pinetime::System::Messages::EnableSleeping); } -bool HeartRate::Refresh() { +void HeartRate::Refresh() { auto state = heartRateController.State(); switch (state) { @@ -86,8 +89,6 @@ bool HeartRate::Refresh() { lv_label_set_text(label_status, ToString(state)); lv_obj_align(label_status, label_hr, LV_ALIGN_OUT_BOTTOM_MID, 0, 10); - - return running; } void HeartRate::OnStartStopEvent(lv_event_t event) { diff --git a/src/displayapp/screens/HeartRate.h b/src/displayapp/screens/HeartRate.h index a23c5af8..7f7d3ad3 100644 --- a/src/displayapp/screens/HeartRate.h +++ b/src/displayapp/screens/HeartRate.h @@ -20,7 +20,7 @@ namespace Pinetime { HeartRate(DisplayApp* app, Controllers::HeartRateController& HeartRateController, System::SystemTask& systemTask); ~HeartRate() override; - bool Refresh() override; + void Refresh() override; void OnStartStopEvent(lv_event_t event); @@ -33,6 +33,8 @@ namespace Pinetime { lv_obj_t* label_status; lv_obj_t* btn_startStop; lv_obj_t* label_startStop; + + lv_task_t* taskRefresh; }; } } diff --git a/src/displayapp/screens/InfiniPaint.cpp b/src/displayapp/screens/InfiniPaint.cpp index 58bfa558..85a5e826 100644 --- a/src/displayapp/screens/InfiniPaint.cpp +++ b/src/displayapp/screens/InfiniPaint.cpp @@ -12,10 +12,6 @@ InfiniPaint::~InfiniPaint() { lv_obj_clean(lv_scr_act()); } -bool InfiniPaint::Refresh() { - return running; -} - bool InfiniPaint::OnTouchEvent(Pinetime::Applications::TouchEvents event) { switch (event) { case Pinetime::Applications::TouchEvents::LongTap: diff --git a/src/displayapp/screens/InfiniPaint.h b/src/displayapp/screens/InfiniPaint.h index 6251752a..0a70e033 100644 --- a/src/displayapp/screens/InfiniPaint.h +++ b/src/displayapp/screens/InfiniPaint.h @@ -17,8 +17,6 @@ namespace Pinetime { ~InfiniPaint() override; - bool Refresh() override; - bool OnTouchEvent(TouchEvents event) override; bool OnTouchEvent(uint16_t x, uint16_t y) override; diff --git a/src/displayapp/screens/Label.cpp b/src/displayapp/screens/Label.cpp index f724fd48..1761a7b5 100644 --- a/src/displayapp/screens/Label.cpp +++ b/src/displayapp/screens/Label.cpp @@ -36,7 +36,3 @@ Label::Label(uint8_t screenID, uint8_t numScreens, Pinetime::Applications::Displ Label::~Label() { lv_obj_clean(lv_scr_act()); } - -bool Label::Refresh() { - return running; -} diff --git a/src/displayapp/screens/Label.h b/src/displayapp/screens/Label.h index 834f8c88..f1e49079 100644 --- a/src/displayapp/screens/Label.h +++ b/src/displayapp/screens/Label.h @@ -12,8 +12,6 @@ namespace Pinetime { Label(uint8_t screenID, uint8_t numScreens, DisplayApp* app, lv_obj_t* labelText); ~Label() override; - bool Refresh() override; - private: lv_obj_t* labelText = nullptr; lv_point_t pageIndicatorBasePoints[2]; diff --git a/src/displayapp/screens/List.cpp b/src/displayapp/screens/List.cpp index 91cab9f0..064b47a6 100644 --- a/src/displayapp/screens/List.cpp +++ b/src/displayapp/screens/List.cpp @@ -98,11 +98,6 @@ List::~List() { lv_obj_clean(lv_scr_act()); } -bool List::Refresh() { - - return running; -} - void List::OnButtonEvent(lv_obj_t* object, lv_event_t event) { if (event == LV_EVENT_CLICKED) { for (int i = 0; i < MAXLISTITEMS; i++) { diff --git a/src/displayapp/screens/List.h b/src/displayapp/screens/List.h index a45fd1d3..d9f61f29 100644 --- a/src/displayapp/screens/List.h +++ b/src/displayapp/screens/List.h @@ -27,8 +27,6 @@ namespace Pinetime { std::array<Applications, MAXLISTITEMS>& applications); ~List() override; - bool Refresh() override; - void OnButtonEvent(lv_obj_t* object, lv_event_t event); private: diff --git a/src/displayapp/screens/Meter.cpp b/src/displayapp/screens/Meter.cpp index e0dbdfad..57cde9cf 100644 --- a/src/displayapp/screens/Meter.cpp +++ b/src/displayapp/screens/Meter.cpp @@ -20,17 +20,17 @@ Meter::Meter(Pinetime::Applications::DisplayApp* app) : Screen(app) { lv_obj_set_size(lmeter, 200, 200); lv_obj_align(lmeter, nullptr, LV_ALIGN_CENTER, 0, 0); + + taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this); } Meter::~Meter() { - + lv_task_del(taskRefresh); lv_obj_clean(lv_scr_act()); } -bool Meter::Refresh() { +void Meter::Refresh() { lv_linemeter_set_value(lmeter, value++); /*Set the current value*/ if (value >= 60) value = 0; - - return running; } diff --git a/src/displayapp/screens/Meter.h b/src/displayapp/screens/Meter.h index 24af15ad..9b3d1d48 100644 --- a/src/displayapp/screens/Meter.h +++ b/src/displayapp/screens/Meter.h @@ -14,13 +14,15 @@ namespace Pinetime { Meter(DisplayApp* app); ~Meter() override; - bool Refresh() override; + void Refresh() override; private: lv_style_t style_lmeter; lv_obj_t* lmeter; uint32_t value = 0; + + lv_task_t* taskRefresh; }; } } diff --git a/src/displayapp/screens/Metronome.cpp b/src/displayapp/screens/Metronome.cpp index 5fbe5f36..52cb8519 100644 --- a/src/displayapp/screens/Metronome.cpp +++ b/src/displayapp/screens/Metronome.cpp @@ -66,16 +66,19 @@ Metronome::Metronome(DisplayApp* app, Controllers::MotorController& motorControl lv_obj_set_size(playPause, 115, 50); lv_obj_align(playPause, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0); lv_obj_set_style_local_value_str(playPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Symbols::play); + + taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this); } Metronome::~Metronome() { + lv_task_del(taskRefresh); systemTask.PushMessage(System::Messages::EnableSleeping); lv_obj_clean(lv_scr_act()); } -bool Metronome::Refresh() { +void Metronome::Refresh() { if (metronomeStarted) { - if (xTaskGetTickCount() - startTime > 60 * configTICK_RATE_HZ / bpm) { + if (xTaskGetTickCount() - startTime > 60u * configTICK_RATE_HZ / static_cast<uint16_t>(bpm)) { startTime += 60 * configTICK_RATE_HZ / bpm; counter--; if (counter == 0) { @@ -86,7 +89,6 @@ bool Metronome::Refresh() { } } } - return running; } void Metronome::OnEvent(lv_obj_t* obj, lv_event_t event) { diff --git a/src/displayapp/screens/Metronome.h b/src/displayapp/screens/Metronome.h index a4baa096..f3a84dc8 100644 --- a/src/displayapp/screens/Metronome.h +++ b/src/displayapp/screens/Metronome.h @@ -11,7 +11,7 @@ namespace Pinetime { public: Metronome(DisplayApp* app, Controllers::MotorController& motorController, System::SystemTask& systemTask); ~Metronome() override; - bool Refresh() override; + void Refresh() override; void OnEvent(lv_obj_t* obj, lv_event_t event); private: @@ -28,6 +28,8 @@ namespace Pinetime { lv_obj_t *bpmArc, *bpmTap, *bpmValue; lv_obj_t *bpbDropdown, *currentBpbText; lv_obj_t *playPause; + + lv_task_t* taskRefresh; }; } } diff --git a/src/displayapp/screens/Motion.cpp b/src/displayapp/screens/Motion.cpp index 43a5575e..2f1f7c21 100644 --- a/src/displayapp/screens/Motion.cpp +++ b/src/displayapp/screens/Motion.cpp @@ -36,13 +36,16 @@ Motion::Motion(Pinetime::Applications::DisplayApp* app, Controllers::MotionContr labelStep = lv_label_create(lv_scr_act(), NULL); lv_obj_align(labelStep, chart, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0); lv_label_set_text(labelStep, "Steps ---"); + + taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this); } Motion::~Motion() { + lv_task_del(taskRefresh); lv_obj_clean(lv_scr_act()); } -bool Motion::Refresh() { +void Motion::Refresh() { lv_chart_set_next(chart, ser1, motionController.X()); lv_chart_set_next(chart, ser2, motionController.Y()); lv_chart_set_next(chart, ser3, motionController.Z()); @@ -55,6 +58,4 @@ bool Motion::Refresh() { motionController.Y() / 0x10, motionController.Z() / 0x10); lv_obj_align(label, NULL, LV_ALIGN_IN_TOP_MID, 0, 10); - - return running; } diff --git a/src/displayapp/screens/Motion.h b/src/displayapp/screens/Motion.h index 7e65197b..20a18d02 100644 --- a/src/displayapp/screens/Motion.h +++ b/src/displayapp/screens/Motion.h @@ -17,7 +17,7 @@ namespace Pinetime { Motion(DisplayApp* app, Controllers::MotionController& motionController); ~Motion() override; - bool Refresh() override; + void Refresh() override; private: Controllers::MotionController& motionController; @@ -28,6 +28,7 @@ namespace Pinetime { lv_obj_t* label; lv_obj_t* labelStep; + lv_task_t* taskRefresh; }; } } diff --git a/src/displayapp/screens/Music.cpp b/src/displayapp/screens/Music.cpp index 257e9aea..47ddb655 100644 --- a/src/displayapp/screens/Music.cpp +++ b/src/displayapp/screens/Music.cpp @@ -139,14 +139,17 @@ Music::Music(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Mus frameB = false; musicService.event(Controllers::MusicService::EVENT_MUSIC_OPEN); + + taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this); } Music::~Music() { + lv_task_del(taskRefresh); lv_style_reset(&btn_style); lv_obj_clean(lv_scr_act()); } -bool Music::Refresh() { +void Music::Refresh() { if (artist != musicService.getArtist()) { artist = musicService.getArtist(); currentLength = 0; @@ -210,8 +213,6 @@ bool Music::Refresh() { } else { lv_label_set_text(txtPlayPause, Symbols::play); } - - return running; } void Music::UpdateLength() { diff --git a/src/displayapp/screens/Music.h b/src/displayapp/screens/Music.h index 00d3ad92..6f2d80a0 100644 --- a/src/displayapp/screens/Music.h +++ b/src/displayapp/screens/Music.h @@ -35,7 +35,7 @@ namespace Pinetime { ~Music() override; - bool Refresh() override; + void Refresh() override; void OnObjectEvent(lv_obj_t* obj, lv_event_t event); @@ -79,6 +79,8 @@ namespace Pinetime { bool playing; + lv_task_t* taskRefresh; + /** Watchapp */ }; } diff --git a/src/displayapp/screens/Navigation.cpp b/src/displayapp/screens/Navigation.cpp index 79b04e21..d437cc6d 100644 --- a/src/displayapp/screens/Navigation.cpp +++ b/src/displayapp/screens/Navigation.cpp @@ -161,13 +161,16 @@ Navigation::Navigation(Pinetime::Applications::DisplayApp* app, Pinetime::Contro lv_bar_set_anim_time(barProgress, 500); lv_bar_set_range(barProgress, 0, 100); lv_bar_set_value(barProgress, 0, LV_ANIM_OFF); + + taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this); } Navigation::~Navigation() { + lv_task_del(taskRefresh); lv_obj_clean(lv_scr_act()); } -bool Navigation::Refresh() { +void Navigation::Refresh() { if (flag != navService.getFlag()) { flag = navService.getFlag(); lv_label_set_text(imgFlag, iconForName(flag)); @@ -192,8 +195,4 @@ bool Navigation::Refresh() { lv_obj_set_style_local_bg_color(barProgress, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_ORANGE); } } - - return running; } - - diff --git a/src/displayapp/screens/Navigation.h b/src/displayapp/screens/Navigation.h index eb7e00c4..48f00a76 100644 --- a/src/displayapp/screens/Navigation.h +++ b/src/displayapp/screens/Navigation.h @@ -35,7 +35,7 @@ namespace Pinetime { Navigation(DisplayApp* app, Pinetime::Controllers::NavigationService& nav); ~Navigation() override; - bool Refresh() override; + void Refresh() override; private: lv_obj_t* imgFlag; @@ -49,6 +49,8 @@ namespace Pinetime { std::string narrative; std::string manDist; int progress; + + lv_task_t* taskRefresh; }; } } diff --git a/src/displayapp/screens/Notifications.cpp b/src/displayapp/screens/Notifications.cpp index c061c146..4f475813 100644 --- a/src/displayapp/screens/Notifications.cpp +++ b/src/displayapp/screens/Notifications.cpp @@ -52,15 +52,18 @@ Notifications::Notifications(DisplayApp* app, timeoutTickCountEnd = timeoutTickCountStart + (5 * 1024); } } + + taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this); } Notifications::~Notifications() { + lv_task_del(taskRefresh); // make sure we stop any vibrations before exiting Controllers::MotorController::StopRinging(); lv_obj_clean(lv_scr_act()); } -bool Notifications::Refresh() { +void Notifications::Refresh() { if (mode == Modes::Preview && timeoutLine != nullptr) { auto tick = xTaskGetTickCount(); int32_t pos = 240 - ((tick - timeoutTickCountStart) / ((timeoutTickCountEnd - timeoutTickCountStart) / 240)); @@ -70,7 +73,6 @@ bool Notifications::Refresh() { timeoutLinePoints[1].x = pos; lv_line_set_points(timeoutLine, timeoutLinePoints, 2); } - return running && currentItem->IsRunning(); } bool Notifications::OnTouchEvent(Pinetime::Applications::TouchEvents event) { @@ -127,10 +129,6 @@ bool Notifications::OnTouchEvent(Pinetime::Applications::TouchEvents event) { alertNotificationService); } return true; - case Pinetime::Applications::TouchEvents::LongTap: { - // notificationManager.ToggleVibrations(); - return true; - } default: return false; } @@ -150,7 +148,7 @@ Notifications::NotificationItem::NotificationItem(const char* title, uint8_t notifNb, Modes mode, Pinetime::Controllers::AlertNotificationService& alertNotificationService) - : notifNr {notifNr}, notifNb {notifNb}, mode {mode}, alertNotificationService {alertNotificationService} { + : mode {mode}, alertNotificationService {alertNotificationService} { lv_obj_t* container1 = lv_cont_create(lv_scr_act(), NULL); lv_obj_set_style_local_bg_color(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x222222)); diff --git a/src/displayapp/screens/Notifications.h b/src/displayapp/screens/Notifications.h index a02d9b46..0b5271e7 100644 --- a/src/displayapp/screens/Notifications.h +++ b/src/displayapp/screens/Notifications.h @@ -24,7 +24,7 @@ namespace Pinetime { Modes mode); ~Notifications() override; - bool Refresh() override; + void Refresh() override; bool OnTouchEvent(Pinetime::Applications::TouchEvents event) override; class NotificationItem { @@ -43,21 +43,13 @@ namespace Pinetime { void OnCallButtonEvent(lv_obj_t*, lv_event_t event); private: - uint8_t notifNr = 0; - uint8_t notifNb = 0; - char pageText[4]; - lv_obj_t* container1; - lv_obj_t* t1; - lv_obj_t* l1; - lv_obj_t* l2; lv_obj_t* bt_accept; lv_obj_t* bt_mute; lv_obj_t* bt_reject; lv_obj_t* label_accept; lv_obj_t* label_mute; lv_obj_t* label_reject; - lv_obj_t* bottomPlaceholder; Modes mode; Pinetime::Controllers::AlertNotificationService& alertNotificationService; bool running = true; @@ -79,6 +71,8 @@ namespace Pinetime { lv_obj_t* timeoutLine = nullptr; uint32_t timeoutTickCountStart; uint32_t timeoutTickCountEnd; + + lv_task_t* taskRefresh; }; } } diff --git a/src/displayapp/screens/Paddle.cpp b/src/displayapp/screens/Paddle.cpp index 79e0c3d3..26c2368b 100644 --- a/src/displayapp/screens/Paddle.cpp +++ b/src/displayapp/screens/Paddle.cpp @@ -27,13 +27,16 @@ Paddle::Paddle(Pinetime::Applications::DisplayApp* app, Pinetime::Components::Li lv_obj_set_style_local_bg_color(ball, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); lv_obj_set_style_local_radius(ball, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); lv_obj_set_size(ball, ballSize, ballSize); + + taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this); } Paddle::~Paddle() { + lv_task_del(taskRefresh); lv_obj_clean(lv_scr_act()); } -bool Paddle::Refresh() { +void Paddle::Refresh() { ballX += dx; ballY += dy; @@ -44,8 +47,8 @@ bool Paddle::Refresh() { dy *= -1; } - // checks if it has touched the side (left side) - if (ballX >= LV_VER_RES - ballSize - 1) { + // checks if it has touched the side (right side) + if (ballX >= LV_HOR_RES - ballSize - 1) { dx *= -1; } @@ -65,7 +68,6 @@ bool Paddle::Refresh() { } } lv_label_set_text_fmt(points, "%04d", score); - return running; } bool Paddle::OnTouchEvent(Pinetime::Applications::TouchEvents event) { diff --git a/src/displayapp/screens/Paddle.h b/src/displayapp/screens/Paddle.h index 30ab8f94..fc2131a1 100644 --- a/src/displayapp/screens/Paddle.h +++ b/src/displayapp/screens/Paddle.h @@ -16,7 +16,7 @@ namespace Pinetime { Paddle(DisplayApp* app, Pinetime::Components::LittleVgl& lvgl); ~Paddle() override; - bool Refresh() override; + void Refresh() override; bool OnTouchEvent(TouchEvents event) override; bool OnTouchEvent(uint16_t x, uint16_t y) override; @@ -40,6 +40,8 @@ namespace Pinetime { lv_obj_t* paddle; lv_obj_t* ball; lv_obj_t* background; + + lv_task_t* taskRefresh; }; } } diff --git a/src/displayapp/screens/PineTimeStyle.cpp b/src/displayapp/screens/PineTimeStyle.cpp index 98fd976c..fa88d459 100644 --- a/src/displayapp/screens/PineTimeStyle.cpp +++ b/src/displayapp/screens/PineTimeStyle.cpp @@ -1,5 +1,5 @@ /* - * This file is part of the Infinitime distribution (https://github.com/JF002/Infinitime). + * This file is part of the Infinitime distribution (https://github.com/InfiniTimeOrg/Infinitime). * Copyright (c) 2021 Kieran Cawthray. * * This program is free software: you can redistribute it and/or modify @@ -23,6 +23,7 @@ #include <date/date.h> #include <lvgl/lvgl.h> #include <cstdio> +#include <displayapp/Colors.h> #include "BatteryIcon.h" #include "BleIcon.h" #include "NotificationIcon.h" @@ -51,7 +52,8 @@ PineTimeStyle::PineTimeStyle(DisplayApp* app, notificatioManager {notificatioManager}, settingsController {settingsController}, motionController {motionController} { - /* This sets the watchface number to return to after leaving the menu */ + + // This sets the watchface number to return to after leaving the menu settingsController.SetClockFace(2); displayedChar[0] = 0; @@ -60,48 +62,45 @@ PineTimeStyle::PineTimeStyle(DisplayApp* app, displayedChar[3] = 0; displayedChar[4] = 0; - /* Create a 200px wide background rectangle */ + //Create a 200px wide background rectangle timebar = lv_obj_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_bg_color(timebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000)); + lv_obj_set_style_local_bg_color(timebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Convert(settingsController.GetPTSColorBG())); lv_obj_set_style_local_radius(timebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0); lv_obj_set_size(timebar, 200, 240); lv_obj_align(timebar, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 5, 0); - /* Display the time */ + // Display the time timeDD1 = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_font(timeDD1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &open_sans_light); - lv_obj_set_style_local_text_color(timeDD1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x008080)); + lv_obj_set_style_local_text_color(timeDD1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(settingsController.GetPTSColorTime())); lv_label_set_text(timeDD1, "12"); lv_obj_align(timeDD1, timebar, LV_ALIGN_IN_TOP_MID, 5, 5); timeDD2 = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_font(timeDD2, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &open_sans_light); - lv_obj_set_style_local_text_color(timeDD2, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x008080)); + lv_obj_set_style_local_text_color(timeDD2, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(settingsController.GetPTSColorTime())); lv_label_set_text(timeDD2, "34"); lv_obj_align(timeDD2, timebar, LV_ALIGN_IN_BOTTOM_MID, 5, -5); timeAMPM = lv_label_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_text_color(timeAMPM, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x008080)); + lv_obj_set_style_local_text_color(timeAMPM, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(settingsController.GetPTSColorTime())); lv_obj_set_style_local_text_line_space(timeAMPM, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, -3); lv_label_set_text(timeAMPM, ""); lv_obj_align(timeAMPM, timebar, LV_ALIGN_IN_BOTTOM_LEFT, 2, -20); - /* Create a 40px wide bar down the right side of the screen */ + // Create a 40px wide bar down the right side of the screen sidebar = lv_obj_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_bg_color(sidebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x008080)); + lv_obj_set_style_local_bg_color(sidebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Convert(settingsController.GetPTSColorBar())); lv_obj_set_style_local_radius(sidebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0); lv_obj_set_size(sidebar, 40, 240); lv_obj_align(sidebar, lv_scr_act(), LV_ALIGN_IN_TOP_RIGHT, 0, 0); - /* Display icons */ + // Display icons batteryIcon = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_color(batteryIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000)); lv_label_set_text(batteryIcon, Symbols::batteryFull); lv_obj_align(batteryIcon, sidebar, LV_ALIGN_IN_TOP_MID, 0, 2); - - batteryPlug = lv_label_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_text_color(batteryPlug, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000)); - lv_obj_align(batteryPlug, sidebar, LV_ALIGN_IN_TOP_MID, 0, 2); + lv_obj_set_auto_realign(batteryIcon, true); bleIcon = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_color(bleIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000)); @@ -111,7 +110,7 @@ PineTimeStyle::PineTimeStyle(DisplayApp* app, lv_obj_set_style_local_text_color(notificationIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000)); lv_obj_align(notificationIcon, sidebar, LV_ALIGN_IN_TOP_MID, 0, 40); - /* Calendar icon */ + // Calendar icon calendarOuter = lv_obj_create(lv_scr_act(), nullptr); lv_obj_set_style_local_bg_color(calendarOuter, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000)); lv_obj_set_style_local_radius(calendarOuter, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0); @@ -148,7 +147,7 @@ PineTimeStyle::PineTimeStyle(DisplayApp* app, lv_obj_set_size(calendarCrossBar2, 8, 3); lv_obj_align(calendarCrossBar2, calendarBar2, LV_ALIGN_IN_BOTTOM_MID, 0, 0); - /* Display date */ + // Display date dateDayOfWeek = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_color(dateDayOfWeek, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000)); lv_label_set_text(dateDayOfWeek, "THU"); @@ -184,7 +183,7 @@ PineTimeStyle::PineTimeStyle(DisplayApp* app, lv_obj_set_style_local_line_width(stepGauge, LV_GAUGE_PART_MAIN, LV_STATE_DEFAULT, 4); lv_obj_set_style_local_line_color(stepGauge, LV_GAUGE_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK); lv_obj_set_style_local_line_opa(stepGauge, LV_GAUGE_PART_NEEDLE, LV_STATE_DEFAULT, LV_OPA_COVER); - lv_obj_set_style_local_line_width(stepGauge, LV_GAUGE_PART_NEEDLE, LV_STATE_DEFAULT, 4); + lv_obj_set_style_local_line_width(stepGauge, LV_GAUGE_PART_NEEDLE, LV_STATE_DEFAULT, 3); lv_obj_set_style_local_pad_inner(stepGauge, LV_GAUGE_PART_NEEDLE, LV_STATE_DEFAULT, 4); backgroundLabel = lv_label_create(lv_scr_act(), nullptr); @@ -193,24 +192,34 @@ PineTimeStyle::PineTimeStyle(DisplayApp* app, lv_obj_set_size(backgroundLabel, 240, 240); lv_obj_set_pos(backgroundLabel, 0, 0); lv_label_set_text(backgroundLabel, ""); + + taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this); + Refresh(); } PineTimeStyle::~PineTimeStyle() { + lv_task_del(taskRefresh); lv_obj_clean(lv_scr_act()); } -bool PineTimeStyle::Refresh() { - batteryPercentRemaining = batteryController.PercentRemaining(); - if (batteryPercentRemaining.IsUpdated()) { - auto batteryPercent = batteryPercentRemaining.Get(); - if (batteryController.IsCharging()) { - auto isCharging = batteryController.IsCharging() || batteryController.IsPowerPresent(); - lv_label_set_text(batteryPlug, BatteryIcon::GetPlugIcon(isCharging)); - lv_obj_realign(batteryPlug); - lv_label_set_text(batteryIcon, ""); +void PineTimeStyle::SetBatteryIcon() { + auto batteryPercent = batteryPercentRemaining.Get(); + lv_label_set_text(batteryIcon, BatteryIcon::GetBatteryIcon(batteryPercent)); +} + +void PineTimeStyle::Refresh() { + isCharging = batteryController.IsCharging(); + if (isCharging.IsUpdated()) { + if (isCharging.Get()) { + lv_label_set_text(batteryIcon, Symbols::plug); } else { - lv_label_set_text(batteryIcon, BatteryIcon::GetBatteryIcon(batteryPercent)); - lv_label_set_text(batteryPlug, ""); + SetBatteryIcon(); + } + } + if (!isCharging.Get()) { + batteryPercentRemaining = batteryController.PercentRemaining(); + if (batteryPercentRemaining.IsUpdated()) { + SetBatteryIcon(); } } @@ -303,6 +312,4 @@ bool PineTimeStyle::Refresh() { lv_obj_set_style_local_scale_grad_color(stepGauge, LV_GAUGE_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); } } - - return running; -}
\ No newline at end of file +} diff --git a/src/displayapp/screens/PineTimeStyle.h b/src/displayapp/screens/PineTimeStyle.h index f4cd28e4..ba473806 100644 --- a/src/displayapp/screens/PineTimeStyle.h +++ b/src/displayapp/screens/PineTimeStyle.h @@ -30,7 +30,7 @@ namespace Pinetime { Controllers::MotionController& motionController); ~PineTimeStyle() override; - bool Refresh() override; + void Refresh() override; private: char displayedChar[5]; @@ -41,6 +41,7 @@ namespace Pinetime { uint8_t currentDay = 0; DirtyValue<uint8_t> batteryPercentRemaining {}; + DirtyValue<bool> isCharging {}; DirtyValue<bool> bleState {}; DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>> currentDateTime {}; DirtyValue<bool> motionSensorOk {}; @@ -58,7 +59,6 @@ namespace Pinetime { lv_obj_t* backgroundLabel; lv_obj_t* batteryIcon; lv_obj_t* bleIcon; - lv_obj_t* batteryPlug; lv_obj_t* calendarOuter; lv_obj_t* calendarInner; lv_obj_t* calendarBar1; @@ -75,6 +75,10 @@ namespace Pinetime { Controllers::NotificationManager& notificatioManager; Controllers::Settings& settingsController; Controllers::MotionController& motionController; + + void SetBatteryIcon(); + + lv_task_t* taskRefresh; }; } } diff --git a/src/displayapp/screens/Screen.cpp b/src/displayapp/screens/Screen.cpp index 1467df33..6ae5b7bb 100644 --- a/src/displayapp/screens/Screen.cpp +++ b/src/displayapp/screens/Screen.cpp @@ -1,2 +1,6 @@ #include "Screen.h" -using namespace Pinetime::Applications::Screens;
\ No newline at end of file +using namespace Pinetime::Applications::Screens; + +void Screen::RefreshTaskCallback(lv_task_t* task) { + static_cast<Screen*>(task->user_data)->Refresh(); +} diff --git a/src/displayapp/screens/Screen.h b/src/displayapp/screens/Screen.h index 420f2015..ce5741b2 100644 --- a/src/displayapp/screens/Screen.h +++ b/src/displayapp/screens/Screen.h @@ -2,6 +2,7 @@ #include <cstdint> #include "../TouchEvents.h" +#include <lvgl/lvgl.h> namespace Pinetime { namespace Applications { @@ -38,25 +39,20 @@ namespace Pinetime { }; class Screen { + private: + virtual void Refresh() { + } + public: explicit Screen(DisplayApp* app) : app {app} { } virtual ~Screen() = default; - /** - * Most of the time, apps only react to events (touch events, for example). - * In this case you don't need to do anything in this method. - * - * For example, InfiniPaint does nothing in Refresh(). - * But, if you want to update your display periodically, draw an animation... - * you cannot do it in a touch event handler because these handlers are not - * called if the user does not touch the screen. - * - * That's why Refresh() is there: update the display periodically. - * - * @return false if the app can be closed, true if it must continue to run - **/ - virtual bool Refresh() = 0; + static void RefreshTaskCallback(lv_task_t* task); + + bool IsRunning() const { + return running; + } /** @return false if the button hasn't been handled by the app, true if it has been handled */ virtual bool OnButtonPushed() { diff --git a/src/displayapp/screens/ScreenList.h b/src/displayapp/screens/ScreenList.h index 50d66328..a9d747aa 100644 --- a/src/displayapp/screens/ScreenList.h +++ b/src/displayapp/screens/ScreenList.h @@ -30,11 +30,6 @@ namespace Pinetime { lv_obj_clean(lv_scr_act()); } - bool Refresh() override { - running = current->Refresh(); - return running; - } - bool OnTouchEvent(TouchEvents event) override { if (mode == ScreenListModes::UpDown) { diff --git a/src/displayapp/screens/Steps.cpp b/src/displayapp/screens/Steps.cpp index d72e8333..c41163ab 100644 --- a/src/displayapp/screens/Steps.cpp +++ b/src/displayapp/screens/Steps.cpp @@ -47,20 +47,20 @@ Steps::Steps(Pinetime::Applications::DisplayApp* app, lv_obj_set_size(backgroundLabel, 240, 240); lv_obj_set_pos(backgroundLabel, 0, 0); lv_label_set_text_static(backgroundLabel, ""); + + taskRefresh = lv_task_create(RefreshTaskCallback, 100, LV_TASK_PRIO_MID, this); } Steps::~Steps() { + lv_task_del(taskRefresh); lv_obj_clean(lv_scr_act()); } -bool Steps::Refresh() { - +void Steps::Refresh() { stepsCount = motionController.NbSteps(); lv_label_set_text_fmt(lSteps, "%li", stepsCount); lv_obj_align(lSteps, nullptr, LV_ALIGN_CENTER, 0, -20); lv_arc_set_value(stepsArc, int16_t(500 * stepsCount / settingsController.GetStepsGoal())); - - return running; } diff --git a/src/displayapp/screens/Steps.h b/src/displayapp/screens/Steps.h index 9c135e26..d7cf31e1 100644 --- a/src/displayapp/screens/Steps.h +++ b/src/displayapp/screens/Steps.h @@ -15,24 +15,23 @@ namespace Pinetime { namespace Screens { class Steps : public Screen { - public: - Steps(DisplayApp* app, Controllers::MotionController& motionController, Controllers::Settings &settingsController); - ~Steps() override; + public: + Steps(DisplayApp* app, Controllers::MotionController& motionController, Controllers::Settings& settingsController); + ~Steps() override; - bool Refresh() override; - + void Refresh() override; - private: + private: + Controllers::MotionController& motionController; + Controllers::Settings& settingsController; - Controllers::MotionController& motionController; - Controllers::Settings& settingsController; + lv_obj_t* lSteps; + lv_obj_t* lStepsIcon; + lv_obj_t* stepsArc; - lv_obj_t * lSteps; - lv_obj_t * lStepsIcon; - lv_obj_t * stepsArc; - - uint32_t stepsCount; + uint32_t stepsCount; + lv_task_t* taskRefresh; }; } } diff --git a/src/displayapp/screens/StopWatch.cpp b/src/displayapp/screens/StopWatch.cpp index e3db6299..9b27a89d 100644 --- a/src/displayapp/screens/StopWatch.cpp +++ b/src/displayapp/screens/StopWatch.cpp @@ -48,7 +48,6 @@ static void stop_lap_event_handler(lv_obj_t* obj, lv_event_t event) { StopWatch::StopWatch(DisplayApp* app, System::SystemTask& systemTask) : Screen(app), systemTask {systemTask}, - running {true}, currentState {States::Init}, startTime {}, oldTimeElapsed {}, @@ -101,9 +100,12 @@ StopWatch::StopWatch(DisplayApp* app, System::SystemTask& systemTask) lv_obj_set_style_local_text_color(lapTwoText, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_YELLOW); lv_obj_align(lapTwoText, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 50, 55); lv_label_set_text(lapTwoText, ""); + + taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this); } StopWatch::~StopWatch() { + lv_task_del(taskRefresh); systemTask.PushMessage(Pinetime::System::Messages::EnableSleeping); lv_obj_clean(lv_scr_act()); } @@ -149,7 +151,7 @@ void StopWatch::pause() { systemTask.PushMessage(Pinetime::System::Messages::EnableSleeping); } -bool StopWatch::Refresh() { +void StopWatch::Refresh() { if (currentState == States::Running) { timeElapsed = calculateDelta(startTime, xTaskGetTickCount()); currentTimeSeparated = convertTicksToTimeSegments((oldTimeElapsed + timeElapsed)); @@ -157,7 +159,6 @@ bool StopWatch::Refresh() { lv_label_set_text_fmt(time, "%02d:%02d", currentTimeSeparated.mins, currentTimeSeparated.secs); lv_label_set_text_fmt(msecTime, "%02d", currentTimeSeparated.hundredths); } - return running; } void StopWatch::playPauseBtnEventHandler(lv_event_t event) { @@ -196,8 +197,7 @@ void StopWatch::stopLapBtnEventHandler(lv_event_t event) { bool StopWatch::OnButtonPushed() { if (currentState == States::Running) { pause(); - } else { - running = false; + return true; } - return true; + return false; } diff --git a/src/displayapp/screens/StopWatch.h b/src/displayapp/screens/StopWatch.h index e132f158..25634e92 100644 --- a/src/displayapp/screens/StopWatch.h +++ b/src/displayapp/screens/StopWatch.h @@ -64,7 +64,7 @@ namespace Pinetime::Applications::Screens { public: StopWatch(DisplayApp* app, System::SystemTask& systemTask); ~StopWatch() override; - bool Refresh() override; + void Refresh() override; void playPauseBtnEventHandler(lv_event_t event); void stopLapBtnEventHandler(lv_event_t event); @@ -77,7 +77,6 @@ namespace Pinetime::Applications::Screens { private: Pinetime::System::SystemTask& systemTask; TickType_t timeElapsed; - bool running; States currentState; TickType_t startTime; TickType_t oldTimeElapsed; @@ -86,5 +85,7 @@ namespace Pinetime::Applications::Screens { int lapNr = 0; lv_obj_t *time, *msecTime, *btnPlayPause, *btnStopLap, *txtPlayPause, *txtStopLap; lv_obj_t *lapOneText, *lapTwoText; + + lv_task_t* taskRefresh; }; } diff --git a/src/displayapp/screens/SystemInfo.cpp b/src/displayapp/screens/SystemInfo.cpp index ad758a8b..343b72bf 100644 --- a/src/displayapp/screens/SystemInfo.cpp +++ b/src/displayapp/screens/SystemInfo.cpp @@ -33,7 +33,8 @@ SystemInfo::SystemInfo(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::BrightnessController& brightnessController, Pinetime::Controllers::Ble& bleController, Pinetime::Drivers::WatchdogView& watchdog, - Pinetime::Controllers::MotionController& motionController) + Pinetime::Controllers::MotionController& motionController, + Pinetime::Drivers::Cst816S& touchPanel) : Screen(app), dateTimeController {dateTimeController}, batteryController {batteryController}, @@ -41,6 +42,7 @@ SystemInfo::SystemInfo(Pinetime::Applications::DisplayApp* app, bleController {bleController}, watchdog {watchdog}, motionController{motionController}, + touchPanel{touchPanel}, screens {app, 0, {[this]() -> std::unique_ptr<Screen> { @@ -65,13 +67,6 @@ SystemInfo::~SystemInfo() { lv_obj_clean(lv_scr_act()); } -bool SystemInfo::Refresh() { - if (running) { - screens.Refresh(); - } - return running; -} - bool SystemInfo::OnTouchEvent(Pinetime::Applications::TouchEvents event) { return screens.OnTouchEvent(event); } @@ -148,7 +143,8 @@ std::unique_ptr<Screen> SystemInfo::CreateScreen2() { "#444444 Battery# %d%%/%03imV\n" "#444444 Backlight# %s\n" "#444444 Last reset# %s\n" - "#444444 Accel.# %s\n", + "#444444 Accel.# %s\n" + "#444444 Touch.# %x.%x.%x\n", dateTimeController.Day(), static_cast<uint8_t>(dateTimeController.Month()), dateTimeController.Year(), @@ -163,7 +159,10 @@ std::unique_ptr<Screen> SystemInfo::CreateScreen2() { batteryController.Voltage(), brightnessController.ToString(), resetReason, - ToString(motionController.DeviceType())); + ToString(motionController.DeviceType()), + touchPanel.GetChipId(), + touchPanel.GetVendorId(), + touchPanel.GetFwVersion()); lv_obj_align(label, lv_scr_act(), LV_ALIGN_CENTER, 0, 0); return std::make_unique<Screens::Label>(1, 5, app, label); } @@ -271,7 +270,8 @@ std::unique_ptr<Screen> SystemInfo::CreateScreen5() { "Public License v3\n" "#444444 Source code#\n" "#FFFF00 https://github.com/#\n" - "#FFFF00 JF002/InfiniTime#"); + "#FFFF00 InfiniTimeOrg/#\n" + "#FFFF00 InfiniTime#"); lv_label_set_align(label, LV_LABEL_ALIGN_CENTER); lv_obj_align(label, lv_scr_act(), LV_ALIGN_CENTER, 0, 0); return std::make_unique<Screens::Label>(4, 5, app, label); diff --git a/src/displayapp/screens/SystemInfo.h b/src/displayapp/screens/SystemInfo.h index a9ad652d..bfcc3aa4 100644 --- a/src/displayapp/screens/SystemInfo.h +++ b/src/displayapp/screens/SystemInfo.h @@ -28,9 +28,9 @@ namespace Pinetime { Pinetime::Controllers::BrightnessController& brightnessController, Pinetime::Controllers::Ble& bleController, Pinetime::Drivers::WatchdogView& watchdog, - Pinetime::Controllers::MotionController& motionController); + Pinetime::Controllers::MotionController& motionController, + Pinetime::Drivers::Cst816S& touchPanel); ~SystemInfo() override; - bool Refresh() override; bool OnTouchEvent(TouchEvents event) override; private: @@ -40,6 +40,7 @@ namespace Pinetime { Pinetime::Controllers::Ble& bleController; Pinetime::Drivers::WatchdogView& watchdog; Pinetime::Controllers::MotionController& motionController; + Pinetime::Drivers::Cst816S& touchPanel; ScreenList<5> screens; diff --git a/src/displayapp/screens/Tile.cpp b/src/displayapp/screens/Tile.cpp index 2ffbfbc2..1d4f0d0e 100644 --- a/src/displayapp/screens/Tile.cpp +++ b/src/displayapp/screens/Tile.cpp @@ -123,10 +123,6 @@ void Tile::UpdateScreen() { lv_label_set_text(batteryIcon, BatteryIcon::GetBatteryIcon(batteryController.PercentRemaining())); } -bool Tile::Refresh() { - return running; -} - void Tile::OnValueChangedEvent(lv_obj_t* obj, uint32_t buttonId) { if(obj != btnm1) return; diff --git a/src/displayapp/screens/Tile.h b/src/displayapp/screens/Tile.h index 765a8def..83d3fdf5 100644 --- a/src/displayapp/screens/Tile.h +++ b/src/displayapp/screens/Tile.h @@ -30,7 +30,6 @@ namespace Pinetime { ~Tile() override; - bool Refresh() override; void UpdateScreen(); void OnValueChangedEvent(lv_obj_t* obj, uint32_t buttonId); diff --git a/src/displayapp/screens/Timer.cpp b/src/displayapp/screens/Timer.cpp index 99e979ba..ff3099d5 100644 --- a/src/displayapp/screens/Timer.cpp +++ b/src/displayapp/screens/Timer.cpp @@ -4,10 +4,8 @@ #include "Symbols.h" #include "lvgl/lvgl.h" - using namespace Pinetime::Applications::Screens; - static void btnEventHandler(lv_obj_t* obj, lv_event_t event) { Timer* screen = static_cast<Timer*>(obj->user_data); screen->OnButtonEvent(obj, event); @@ -22,7 +20,7 @@ void Timer::createButtons() { lv_obj_set_width(btnMinutesUp, 60); txtMUp = lv_label_create(btnMinutesUp, nullptr); lv_label_set_text(txtMUp, "+"); - + btnMinutesDown = lv_btn_create(lv_scr_act(), nullptr); btnMinutesDown->user_data = this; lv_obj_set_event_cb(btnMinutesDown, btnEventHandler); @@ -31,7 +29,7 @@ void Timer::createButtons() { lv_obj_set_width(btnMinutesDown, 60); txtMDown = lv_label_create(btnMinutesDown, nullptr); lv_label_set_text(txtMDown, "-"); - + btnSecondsUp = lv_btn_create(lv_scr_act(), nullptr); btnSecondsUp->user_data = this; lv_obj_set_event_cb(btnSecondsUp, btnEventHandler); @@ -40,7 +38,7 @@ void Timer::createButtons() { lv_obj_set_width(btnSecondsUp, 60); txtSUp = lv_label_create(btnSecondsUp, nullptr); lv_label_set_text(txtSUp, "+"); - + btnSecondsDown = lv_btn_create(lv_scr_act(), nullptr); btnSecondsDown->user_data = this; lv_obj_set_event_cb(btnSecondsDown, btnEventHandler); @@ -49,24 +47,20 @@ void Timer::createButtons() { lv_obj_set_width(btnSecondsDown, 60); txtSDown = lv_label_create(btnSecondsDown, nullptr); lv_label_set_text(txtSDown, "-"); - } - Timer::Timer(DisplayApp* app, Controllers::TimerController& timerController) - : Screen(app), - running{true}, - timerController{timerController} { - + : Screen(app), running {true}, timerController {timerController} { + time = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_font(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76); lv_obj_set_style_local_text_color(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY); - + uint32_t seconds = timerController.GetTimeRemaining() / 1000; lv_label_set_text_fmt(time, "%02lu:%02lu", seconds / 60, seconds % 60); lv_obj_align(time, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, -20); - + btnPlayPause = lv_btn_create(lv_scr_act(), nullptr); btnPlayPause->user_data = this; lv_obj_set_event_cb(btnPlayPause, btnEventHandler); @@ -79,20 +73,20 @@ Timer::Timer(DisplayApp* app, Controllers::TimerController& timerController) lv_label_set_text(txtPlayPause, Symbols::play); createButtons(); } - + + taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this); } Timer::~Timer() { + lv_task_del(taskRefresh); lv_obj_clean(lv_scr_act()); - } -bool Timer::Refresh() { +void Timer::Refresh() { if (timerController.IsRunning()) { uint32_t seconds = timerController.GetTimeRemaining() / 1000; lv_label_set_text_fmt(time, "%02lu:%02lu", seconds / 60, seconds % 60); } - return running; } void Timer::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { @@ -105,11 +99,11 @@ void Timer::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { secondsToSet = seconds % 60; timerController.StopTimer(); createButtons(); - + } else if (secondsToSet + minutesToSet > 0) { lv_label_set_text(txtPlayPause, Symbols::pause); timerController.StartTimer((secondsToSet + minutesToSet * 60) * 1000); - + lv_obj_del(btnSecondsDown); btnSecondsDown = nullptr; lv_obj_del(btnSecondsUp); @@ -118,7 +112,6 @@ void Timer::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { btnMinutesDown = nullptr; lv_obj_del(btnMinutesUp); btnMinutesUp = nullptr; - } } else { if (!timerController.IsRunning()) { @@ -129,7 +122,7 @@ void Timer::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { minutesToSet++; } lv_label_set_text_fmt(time, "%02d:%02d", minutesToSet, secondsToSet); - + } else if (obj == btnMinutesDown) { if (minutesToSet == 0) { minutesToSet = 59; @@ -137,7 +130,7 @@ void Timer::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { minutesToSet--; } lv_label_set_text_fmt(time, "%02d:%02d", minutesToSet, secondsToSet); - + } else if (obj == btnSecondsUp) { if (secondsToSet >= 59) { secondsToSet = 0; @@ -145,7 +138,7 @@ void Timer::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { secondsToSet++; } lv_label_set_text_fmt(time, "%02d:%02d", minutesToSet, secondsToSet); - + } else if (obj == btnSecondsDown) { if (secondsToSet == 0) { secondsToSet = 59; @@ -153,21 +146,16 @@ void Timer::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { secondsToSet--; } lv_label_set_text_fmt(time, "%02d:%02d", minutesToSet, secondsToSet); - } } - } - } - } - void Timer::setDone() { lv_label_set_text(time, "00:00"); lv_label_set_text(txtPlayPause, Symbols::play); secondsToSet = 0; minutesToSet = 0; createButtons(); -}
\ No newline at end of file +} diff --git a/src/displayapp/screens/Timer.h b/src/displayapp/screens/Timer.h index 0d66f2d4..d0fc8ed1 100644 --- a/src/displayapp/screens/Timer.h +++ b/src/displayapp/screens/Timer.h @@ -8,35 +8,32 @@ #include "components/timer/TimerController.h" namespace Pinetime::Applications::Screens { - - + class Timer : public Screen { public: - - enum class Modes { - Normal, Done - }; - + enum class Modes { Normal, Done }; + Timer(DisplayApp* app, Controllers::TimerController& timerController); - + ~Timer() override; - - bool Refresh() override; - + + void Refresh() override; + void setDone(); - + void OnButtonEvent(lv_obj_t* obj, lv_event_t event); - + private: - bool running; uint8_t secondsToSet = 0; uint8_t minutesToSet = 0; Controllers::TimerController& timerController; - + void createButtons(); - - lv_obj_t* time, * msecTime, * btnPlayPause, * txtPlayPause, * btnMinutesUp, * btnMinutesDown, * btnSecondsUp, * btnSecondsDown, * txtMUp, - * txtMDown, * txtSUp, * txtSDown; + + lv_obj_t *time, *msecTime, *btnPlayPause, *txtPlayPause, *btnMinutesUp, *btnMinutesDown, *btnSecondsUp, *btnSecondsDown, *txtMUp, + *txtMDown, *txtSUp, *txtSDown; + + lv_task_t* taskRefresh; }; -}
\ No newline at end of file +} diff --git a/src/displayapp/screens/Twos.cpp b/src/displayapp/screens/Twos.cpp index eb268077..4201d501 100644 --- a/src/displayapp/screens/Twos.cpp +++ b/src/displayapp/screens/Twos.cpp @@ -102,10 +102,6 @@ Twos::~Twos() { lv_obj_clean(lv_scr_act()); } -bool Twos::Refresh() { - return running; -} - bool Twos::placeNewTile() { std::vector<std::pair<int, int>> availableCells; for (int row = 0; row < 4; row++) { @@ -295,4 +291,4 @@ void Twos::updateGridDisplay(Tile grid[][4]) { } } } -}
\ No newline at end of file +} diff --git a/src/displayapp/screens/Twos.h b/src/displayapp/screens/Twos.h index 3367618f..6d85cff6 100644 --- a/src/displayapp/screens/Twos.h +++ b/src/displayapp/screens/Twos.h @@ -14,7 +14,6 @@ namespace Pinetime { public: Twos(DisplayApp* app); ~Twos() override; - bool Refresh() override; bool OnTouchEvent(TouchEvents event) override; @@ -36,4 +35,4 @@ namespace Pinetime { }; } } -}
\ No newline at end of file +} diff --git a/src/displayapp/screens/WatchFaceAnalog.cpp b/src/displayapp/screens/WatchFaceAnalog.cpp index 1410fc28..53e7faf7 100644 --- a/src/displayapp/screens/WatchFaceAnalog.cpp +++ b/src/displayapp/screens/WatchFaceAnalog.cpp @@ -68,6 +68,7 @@ WatchFaceAnalog::WatchFaceAnalog(Pinetime::Applications::DisplayApp* app, batteryIcon = lv_label_create(lv_scr_act(), nullptr); lv_label_set_text(batteryIcon, Symbols::batteryHalf); lv_obj_align(batteryIcon, NULL, LV_ALIGN_IN_TOP_RIGHT, 0, 0); + lv_obj_set_auto_realign(batteryIcon, true); notificationIcon = lv_label_create(lv_scr_act(), NULL); lv_obj_set_style_local_text_color(notificationIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x00FF00)); @@ -118,10 +119,13 @@ WatchFaceAnalog::WatchFaceAnalog(Pinetime::Applications::DisplayApp* app, lv_style_set_line_rounded(&hour_line_style_trace, LV_STATE_DEFAULT, false); lv_obj_add_style(hour_body_trace, LV_LINE_PART_MAIN, &hour_line_style_trace); + taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this); UpdateClock(); } WatchFaceAnalog::~WatchFaceAnalog() { + lv_task_del(taskRefresh); + lv_style_reset(&hour_line_style); lv_style_reset(&hour_line_style_trace); lv_style_reset(&minute_line_style); @@ -173,11 +177,31 @@ void WatchFaceAnalog::UpdateClock() { } } -bool WatchFaceAnalog::Refresh() { - batteryPercentRemaining = batteryController.PercentRemaining(); - if (batteryPercentRemaining.IsUpdated()) { - auto batteryPercent = batteryPercentRemaining.Get(); - lv_label_set_text(batteryIcon, BatteryIcon::GetBatteryIcon(batteryPercent)); +void WatchFaceAnalog::SetBatteryIcon() { + auto batteryPercent = batteryPercentRemaining.Get(); + if (batteryPercent == 100) { + lv_obj_set_style_local_text_color(batteryIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GREEN); + } else { + lv_obj_set_style_local_text_color(batteryIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); + } + lv_label_set_text(batteryIcon, BatteryIcon::GetBatteryIcon(batteryPercent)); +} + +void WatchFaceAnalog::Refresh() { + isCharging = batteryController.IsCharging(); + if (isCharging.IsUpdated()) { + if (isCharging.Get()) { + lv_obj_set_style_local_text_color(batteryIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED); + lv_label_set_text(batteryIcon, Symbols::plug); + } else { + SetBatteryIcon(); + } + } + if (!isCharging.Get()) { + batteryPercentRemaining = batteryController.PercentRemaining(); + if (batteryPercentRemaining.IsUpdated()) { + SetBatteryIcon(); + } } notificationState = notificationManager.AreNewNotificationsAvailable(); @@ -203,6 +227,4 @@ bool WatchFaceAnalog::Refresh() { currentDay = day; } } - - return true; } diff --git a/src/displayapp/screens/WatchFaceAnalog.h b/src/displayapp/screens/WatchFaceAnalog.h index 5d8c6a24..001414a6 100644 --- a/src/displayapp/screens/WatchFaceAnalog.h +++ b/src/displayapp/screens/WatchFaceAnalog.h @@ -32,7 +32,7 @@ namespace Pinetime { ~WatchFaceAnalog() override; - bool Refresh() override; + void Refresh() override; private: uint8_t sHour, sMinute, sSecond; @@ -49,6 +49,7 @@ namespace Pinetime { uint8_t currentDay = 0; DirtyValue<uint8_t> batteryPercentRemaining {0}; + DirtyValue<bool> isCharging {}; DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>> currentDateTime; DirtyValue<bool> notificationState {false}; @@ -81,6 +82,9 @@ namespace Pinetime { Controllers::Settings& settingsController; void UpdateClock(); + void SetBatteryIcon(); + + lv_task_t* taskRefresh; }; } } diff --git a/src/displayapp/screens/WatchFaceDigital.cpp b/src/displayapp/screens/WatchFaceDigital.cpp index 2b902b3b..2ecab609 100644 --- a/src/displayapp/screens/WatchFaceDigital.cpp +++ b/src/displayapp/screens/WatchFaceDigital.cpp @@ -91,19 +91,31 @@ WatchFaceDigital::WatchFaceDigital(DisplayApp* app, lv_obj_set_style_local_text_color(stepIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x00FFE7)); lv_label_set_text(stepIcon, Symbols::shoe); lv_obj_align(stepIcon, stepValue, LV_ALIGN_OUT_LEFT_MID, -5, 0); + + taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this); + Refresh(); } WatchFaceDigital::~WatchFaceDigital() { + lv_task_del(taskRefresh); lv_obj_clean(lv_scr_act()); } -bool WatchFaceDigital::Refresh() { +void WatchFaceDigital::Refresh() { + powerPresent = batteryController.IsPowerPresent(); + if (powerPresent.IsUpdated()) { + lv_label_set_text(batteryPlug, BatteryIcon::GetPlugIcon(powerPresent.Get())); + } + batteryPercentRemaining = batteryController.PercentRemaining(); if (batteryPercentRemaining.IsUpdated()) { auto batteryPercent = batteryPercentRemaining.Get(); + if (batteryPercent == 100) { + lv_obj_set_style_local_text_color(batteryIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GREEN); + } else { + lv_obj_set_style_local_text_color(batteryIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); + } lv_label_set_text(batteryIcon, BatteryIcon::GetBatteryIcon(batteryPercent)); - auto isCharging = batteryController.IsCharging() or batteryController.IsPowerPresent(); - lv_label_set_text(batteryPlug, BatteryIcon::GetPlugIcon(isCharging)); } bleState = bleController.IsConnected(); @@ -219,6 +231,4 @@ bool WatchFaceDigital::Refresh() { lv_obj_align(stepValue, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0); lv_obj_align(stepIcon, stepValue, LV_ALIGN_OUT_LEFT_MID, -5, 0); } - - return running; } diff --git a/src/displayapp/screens/WatchFaceDigital.h b/src/displayapp/screens/WatchFaceDigital.h index 6a6e1ac6..e27545f3 100644 --- a/src/displayapp/screens/WatchFaceDigital.h +++ b/src/displayapp/screens/WatchFaceDigital.h @@ -33,7 +33,7 @@ namespace Pinetime { Controllers::MotionController& motionController); ~WatchFaceDigital() override; - bool Refresh() override; + void Refresh() override; private: char displayedChar[5] {}; @@ -44,6 +44,7 @@ namespace Pinetime { uint8_t currentDay = 0; DirtyValue<uint8_t> batteryPercentRemaining {}; + DirtyValue<bool> powerPresent {}; DirtyValue<bool> bleState {}; DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>> currentDateTime {}; DirtyValue<bool> motionSensorOk {}; @@ -72,6 +73,8 @@ namespace Pinetime { Controllers::Settings& settingsController; Controllers::HeartRateController& heartRateController; Controllers::MotionController& motionController; + + lv_task_t* taskRefresh; }; } } diff --git a/src/displayapp/screens/settings/QuickSettings.cpp b/src/displayapp/screens/settings/QuickSettings.cpp index 8190f9d7..691c40c8 100644 --- a/src/displayapp/screens/settings/QuickSettings.cpp +++ b/src/displayapp/screens/settings/QuickSettings.cpp @@ -88,7 +88,7 @@ QuickSettings::QuickSettings(Pinetime::Applications::DisplayApp* app, btn3_lvl = lv_label_create(btn3, nullptr); lv_obj_set_style_local_text_font(btn3_lvl, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &lv_font_sys_48); - if (settingsController.GetVibrationStatus() == Controllers::Settings::Vibration::ON) { + if (settingsController.GetNotificationStatus() == Controllers::Settings::Notification::ON) { lv_obj_add_state(btn3, LV_STATE_CHECKED); lv_label_set_text_static(btn3_lvl, Symbols::notificationsOn); } else { @@ -142,11 +142,11 @@ void QuickSettings::OnButtonEvent(lv_obj_t* object, lv_event_t event) { } else if (object == btn3 && event == LV_EVENT_VALUE_CHANGED) { if (lv_obj_get_state(btn3, LV_BTN_PART_MAIN) & LV_STATE_CHECKED) { - settingsController.SetVibrationStatus(Controllers::Settings::Vibration::ON); + settingsController.SetNotificationStatus(Controllers::Settings::Notification::ON); motorController.RunForDuration(35); lv_label_set_text_static(btn3_lvl, Symbols::notificationsOn); } else { - settingsController.SetVibrationStatus(Controllers::Settings::Vibration::OFF); + settingsController.SetNotificationStatus(Controllers::Settings::Notification::OFF); lv_label_set_text_static(btn3_lvl, Symbols::notificationsOff); } @@ -156,7 +156,3 @@ void QuickSettings::OnButtonEvent(lv_obj_t* object, lv_event_t event) { app->StartApp(Apps::Settings, DisplayApp::FullRefreshDirections::Up); } } - -bool QuickSettings::Refresh() { - return running; -} diff --git a/src/displayapp/screens/settings/QuickSettings.h b/src/displayapp/screens/settings/QuickSettings.h index 2eefe1a7..c036fa5c 100644 --- a/src/displayapp/screens/settings/QuickSettings.h +++ b/src/displayapp/screens/settings/QuickSettings.h @@ -27,8 +27,6 @@ namespace Pinetime { ~QuickSettings() override; - bool Refresh() override; - void OnButtonEvent(lv_obj_t* object, lv_event_t event); void UpdateScreen(); diff --git a/src/displayapp/screens/settings/SettingDisplay.cpp b/src/displayapp/screens/settings/SettingDisplay.cpp index aaf6a9f0..d8d6c767 100644 --- a/src/displayapp/screens/settings/SettingDisplay.cpp +++ b/src/displayapp/screens/settings/SettingDisplay.cpp @@ -80,10 +80,6 @@ SettingDisplay::~SettingDisplay() { settingsController.SaveSettings(); } -bool SettingDisplay::Refresh() { - return running; -} - void SettingDisplay::UpdateSelected(lv_obj_t* object, lv_event_t event) { if (event == LV_EVENT_CLICKED) { for (int i = 0; i < optionsTotal; i++) { diff --git a/src/displayapp/screens/settings/SettingDisplay.h b/src/displayapp/screens/settings/SettingDisplay.h index b8ed87ec..51b23aca 100644 --- a/src/displayapp/screens/settings/SettingDisplay.h +++ b/src/displayapp/screens/settings/SettingDisplay.h @@ -15,7 +15,6 @@ namespace Pinetime { SettingDisplay(DisplayApp* app, Pinetime::Controllers::Settings& settingsController); ~SettingDisplay() override; - bool Refresh() override; void UpdateSelected(lv_obj_t* object, lv_event_t event); private: diff --git a/src/displayapp/screens/settings/SettingPineTimeStyle.cpp b/src/displayapp/screens/settings/SettingPineTimeStyle.cpp new file mode 100644 index 00000000..c9af19b6 --- /dev/null +++ b/src/displayapp/screens/settings/SettingPineTimeStyle.cpp @@ -0,0 +1,318 @@ +#include "SettingPineTimeStyle.h" +#include <lvgl/lvgl.h> +#include <displayapp/Colors.h> +#include "displayapp/DisplayApp.h" +#include "displayapp/screens/Symbols.h" + +using namespace Pinetime::Applications::Screens; + +namespace { + static void event_handler(lv_obj_t* obj, lv_event_t event) { + SettingPineTimeStyle* screen = static_cast<SettingPineTimeStyle*>(obj->user_data); + screen->UpdateSelected(obj, event); + } +} + +SettingPineTimeStyle::SettingPineTimeStyle(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Settings& settingsController) + : Screen(app), settingsController {settingsController} { + timebar = lv_obj_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_bg_color(timebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Convert(settingsController.GetPTSColorBG())); + lv_obj_set_style_local_radius(timebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0); + lv_obj_set_size(timebar, 200, 240); + lv_obj_align(timebar, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 5, 0); + + // Display the time + + timeDD1 = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_font(timeDD1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &open_sans_light); + lv_obj_set_style_local_text_color(timeDD1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(settingsController.GetPTSColorTime())); + lv_label_set_text(timeDD1, "12"); + lv_obj_align(timeDD1, timebar, LV_ALIGN_IN_TOP_MID, 5, 5); + + timeDD2 = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_font(timeDD2, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &open_sans_light); + lv_obj_set_style_local_text_color(timeDD2, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(settingsController.GetPTSColorTime())); + lv_label_set_text(timeDD2, "34"); + lv_obj_align(timeDD2, timebar, LV_ALIGN_IN_BOTTOM_MID, 5, -5); + + timeAMPM = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(timeAMPM, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(settingsController.GetPTSColorTime())); + lv_obj_set_style_local_text_line_space(timeAMPM, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, -3); + lv_label_set_text(timeAMPM, "A\nM"); + lv_obj_align(timeAMPM, timebar, LV_ALIGN_IN_BOTTOM_LEFT, 2, -20); + + // Create a 40px wide bar down the right side of the screen + + sidebar = lv_obj_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_bg_color(sidebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Convert(settingsController.GetPTSColorBar())); + lv_obj_set_style_local_radius(sidebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0); + lv_obj_set_size(sidebar, 40, 240); + lv_obj_align(sidebar, lv_scr_act(), LV_ALIGN_IN_TOP_RIGHT, 0, 0); + + // Display icons + + batteryIcon = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(batteryIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000)); + lv_label_set_text(batteryIcon, Symbols::batteryFull); + lv_obj_align(batteryIcon, sidebar, LV_ALIGN_IN_TOP_MID, 0, 2); + + bleIcon = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(bleIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000)); + lv_label_set_text(bleIcon, Symbols::bluetooth); + lv_obj_align(bleIcon, sidebar, LV_ALIGN_IN_TOP_MID, 0, 25); + + // Calendar icon + + calendarOuter = lv_obj_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_bg_color(calendarOuter, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000)); + lv_obj_set_style_local_radius(calendarOuter, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0); + lv_obj_set_size(calendarOuter, 34, 34); + lv_obj_align(calendarOuter, sidebar, LV_ALIGN_CENTER, 0, 0); + + calendarInner = lv_obj_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_bg_color(calendarInner, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xffffff)); + lv_obj_set_style_local_radius(calendarInner, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0); + lv_obj_set_size(calendarInner, 27, 27); + lv_obj_align(calendarInner, calendarOuter, LV_ALIGN_CENTER, 0, 0); + + calendarBar1 = lv_obj_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_bg_color(calendarBar1, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000)); + lv_obj_set_style_local_radius(calendarBar1, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0); + lv_obj_set_size(calendarBar1, 3, 12); + lv_obj_align(calendarBar1, calendarOuter, LV_ALIGN_IN_TOP_MID, -6, -3); + + calendarBar2 = lv_obj_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_bg_color(calendarBar2, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000)); + lv_obj_set_style_local_radius(calendarBar2, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0); + lv_obj_set_size(calendarBar2, 3, 12); + lv_obj_align(calendarBar2, calendarOuter, LV_ALIGN_IN_TOP_MID, 6, -3); + + calendarCrossBar1 = lv_obj_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_bg_color(calendarCrossBar1, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000)); + lv_obj_set_style_local_radius(calendarCrossBar1, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0); + lv_obj_set_size(calendarCrossBar1, 8, 3); + lv_obj_align(calendarCrossBar1, calendarBar1, LV_ALIGN_IN_BOTTOM_MID, 0, 0); + + calendarCrossBar2 = lv_obj_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_bg_color(calendarCrossBar2, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000)); + lv_obj_set_style_local_radius(calendarCrossBar2, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0); + lv_obj_set_size(calendarCrossBar2, 8, 3); + lv_obj_align(calendarCrossBar2, calendarBar2, LV_ALIGN_IN_BOTTOM_MID, 0, 0); + + // Display date + + dateDayOfWeek = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(dateDayOfWeek, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000)); + lv_label_set_text(dateDayOfWeek, "THU"); + lv_obj_align(dateDayOfWeek, sidebar, LV_ALIGN_CENTER, 0, -34); + + dateDay = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(dateDay, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000)); + lv_label_set_text(dateDay, "25"); + lv_obj_align(dateDay, sidebar, LV_ALIGN_CENTER, 0, 3); + + dateMonth = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(dateMonth, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000)); + lv_label_set_text(dateMonth, "MAR"); + lv_obj_align(dateMonth, sidebar, LV_ALIGN_CENTER, 0, 32); + + // Step count gauge + needle_colors[0] = LV_COLOR_WHITE; + stepGauge = lv_gauge_create(lv_scr_act(), nullptr); + lv_gauge_set_needle_count(stepGauge, 1, needle_colors); + lv_obj_set_size(stepGauge, 40, 40); + lv_obj_align(stepGauge, sidebar, LV_ALIGN_IN_BOTTOM_MID, 0, 0); + lv_gauge_set_scale(stepGauge, 360, 11, 0); + lv_gauge_set_angle_offset(stepGauge, 180); + lv_gauge_set_critical_value(stepGauge, (100)); + lv_gauge_set_range(stepGauge, 0, (100)); + lv_gauge_set_value(stepGauge, 0, 0); + + lv_obj_set_style_local_pad_right(stepGauge, LV_GAUGE_PART_MAIN, LV_STATE_DEFAULT, 3); + lv_obj_set_style_local_pad_left(stepGauge, LV_GAUGE_PART_MAIN, LV_STATE_DEFAULT, 3); + lv_obj_set_style_local_pad_bottom(stepGauge, LV_GAUGE_PART_MAIN, LV_STATE_DEFAULT, 3); + lv_obj_set_style_local_line_opa(stepGauge, LV_GAUGE_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_COVER); + lv_obj_set_style_local_scale_width(stepGauge, LV_GAUGE_PART_MAIN, LV_STATE_DEFAULT, 4); + lv_obj_set_style_local_line_width(stepGauge, LV_GAUGE_PART_MAIN, LV_STATE_DEFAULT, 4); + lv_obj_set_style_local_line_color(stepGauge, LV_GAUGE_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK); + lv_obj_set_style_local_line_opa(stepGauge, LV_GAUGE_PART_NEEDLE, LV_STATE_DEFAULT, LV_OPA_COVER); + lv_obj_set_style_local_line_width(stepGauge, LV_GAUGE_PART_NEEDLE, LV_STATE_DEFAULT, 3); + lv_obj_set_style_local_pad_inner(stepGauge, LV_GAUGE_PART_NEEDLE, LV_STATE_DEFAULT, 4); + + backgroundLabel = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_click(backgroundLabel, true); + lv_label_set_long_mode(backgroundLabel, LV_LABEL_LONG_CROP); + lv_obj_set_size(backgroundLabel, 240, 240); + lv_obj_set_pos(backgroundLabel, 0, 0); + lv_label_set_text(backgroundLabel, ""); + + btnNextTime = lv_btn_create(lv_scr_act(), nullptr); + btnNextTime->user_data = this; + lv_obj_set_size(btnNextTime, 60, 60); + lv_obj_align(btnNextTime, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, -15, -80); + lv_obj_set_style_local_bg_opa(btnNextTime, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_30); + lv_obj_set_style_local_value_str(btnNextTime, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, ">"); + lv_obj_set_event_cb(btnNextTime, event_handler); + + btnPrevTime = lv_btn_create(lv_scr_act(), nullptr); + btnPrevTime->user_data = this; + lv_obj_set_size(btnPrevTime, 60, 60); + lv_obj_align(btnPrevTime, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 15, -80); + lv_obj_set_style_local_bg_opa(btnPrevTime, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_30); + lv_obj_set_style_local_value_str(btnPrevTime, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "<"); + lv_obj_set_event_cb(btnPrevTime, event_handler); + + btnNextBar = lv_btn_create(lv_scr_act(), nullptr); + btnNextBar->user_data = this; + lv_obj_set_size(btnNextBar, 60, 60); + lv_obj_align(btnNextBar, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, -15, 0); + lv_obj_set_style_local_bg_opa(btnNextBar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_30); + lv_obj_set_style_local_value_str(btnNextBar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, ">"); + lv_obj_set_event_cb(btnNextBar, event_handler); + + btnPrevBar = lv_btn_create(lv_scr_act(), nullptr); + btnPrevBar->user_data = this; + lv_obj_set_size(btnPrevBar, 60, 60); + lv_obj_align(btnPrevBar, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 15, 0); + lv_obj_set_style_local_bg_opa(btnPrevBar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_30); + lv_obj_set_style_local_value_str(btnPrevBar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "<"); + lv_obj_set_event_cb(btnPrevBar, event_handler); + + btnNextBG = lv_btn_create(lv_scr_act(), nullptr); + btnNextBG->user_data = this; + lv_obj_set_size(btnNextBG, 60, 60); + lv_obj_align(btnNextBG, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, -15, 80); + lv_obj_set_style_local_bg_opa(btnNextBG, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_30); + lv_obj_set_style_local_value_str(btnNextBG, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, ">"); + lv_obj_set_event_cb(btnNextBG, event_handler); + + btnPrevBG = lv_btn_create(lv_scr_act(), nullptr); + btnPrevBG->user_data = this; + lv_obj_set_size(btnPrevBG, 60, 60); + lv_obj_align(btnPrevBG, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 15, 80); + lv_obj_set_style_local_bg_opa(btnPrevBG, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_30); + lv_obj_set_style_local_value_str(btnPrevBG, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "<"); + lv_obj_set_event_cb(btnPrevBG, event_handler); + + btnReset = lv_btn_create(lv_scr_act(), nullptr); + btnReset->user_data = this; + lv_obj_set_size(btnReset, 60, 60); + lv_obj_align(btnReset, lv_scr_act(), LV_ALIGN_CENTER, 0, 80); + lv_obj_set_style_local_bg_opa(btnReset, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_30); + lv_obj_set_style_local_value_str(btnReset, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "Rst"); + lv_obj_set_event_cb(btnReset, event_handler); + + btnRandom = lv_btn_create(lv_scr_act(), nullptr); + btnRandom->user_data = this; + lv_obj_set_size(btnRandom, 60, 60); + lv_obj_align(btnRandom, lv_scr_act(), LV_ALIGN_CENTER, 0, 0); + lv_obj_set_style_local_bg_opa(btnRandom, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_30); + lv_obj_set_style_local_value_str(btnRandom, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "Rnd"); + lv_obj_set_event_cb(btnRandom, event_handler); +} + +SettingPineTimeStyle::~SettingPineTimeStyle() { + lv_obj_clean(lv_scr_act()); + settingsController.SaveSettings(); +} + +void SettingPineTimeStyle::UpdateSelected(lv_obj_t* object, lv_event_t event) { + auto valueTime = settingsController.GetPTSColorTime(); + auto valueBar = settingsController.GetPTSColorBar(); + auto valueBG = settingsController.GetPTSColorBG(); + + if (event == LV_EVENT_CLICKED) { + if (object == btnNextTime) { + valueTime = GetNext(valueTime); + + settingsController.SetPTSColorTime(valueTime); + lv_obj_set_style_local_text_color(timeDD1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(valueTime)); + lv_obj_set_style_local_text_color(timeDD2, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(valueTime)); + lv_obj_set_style_local_text_color(timeAMPM, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(valueTime)); + } + if (object == btnPrevTime) { + valueTime = GetPrevious(valueTime); + settingsController.SetPTSColorTime(valueTime); + lv_obj_set_style_local_text_color(timeDD1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(valueTime)); + lv_obj_set_style_local_text_color(timeDD2, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(valueTime)); + lv_obj_set_style_local_text_color(timeAMPM, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(valueTime)); + } + if (object == btnNextBar) { + valueBar = GetNext(valueBar); + if(valueBar == Controllers::Settings::Colors::Black) + valueBar = GetNext(valueBar); + settingsController.SetPTSColorBar(valueBar); + lv_obj_set_style_local_bg_color(sidebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Convert(valueBar)); + } + if (object == btnPrevBar) { + valueBar = GetPrevious(valueBar); + if(valueBar == Controllers::Settings::Colors::Black) + valueBar = GetPrevious(valueBar); + settingsController.SetPTSColorBar(valueBar); + lv_obj_set_style_local_bg_color(sidebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Convert(valueBar)); + } + if (object == btnNextBG) { + valueBG = GetNext(valueBG); + settingsController.SetPTSColorBG(valueBG); + lv_obj_set_style_local_bg_color(timebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Convert(valueBG)); + } + if (object == btnPrevBG) { + valueBG = GetPrevious(valueBG); + settingsController.SetPTSColorBG(valueBG); + lv_obj_set_style_local_bg_color(timebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Convert(valueBG)); + } + if (object == btnReset) { + settingsController.SetPTSColorTime(Controllers::Settings::Colors::Teal); + lv_obj_set_style_local_text_color(timeDD1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(Controllers::Settings::Colors::Teal)); + lv_obj_set_style_local_text_color(timeDD2, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(Controllers::Settings::Colors::Teal)); + lv_obj_set_style_local_text_color(timeAMPM, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(Controllers::Settings::Colors::Teal)); + settingsController.SetPTSColorBar(Controllers::Settings::Colors::Teal); + lv_obj_set_style_local_bg_color(sidebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Convert(Controllers::Settings::Colors::Teal)); + settingsController.SetPTSColorBG(Controllers::Settings::Colors::Black); + lv_obj_set_style_local_bg_color(timebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Convert(Controllers::Settings::Colors::Black)); + } + if (object == btnRandom) { + uint8_t randTime = rand() % 17; + uint8_t randBar = rand() % 17; + uint8_t randBG = rand() % 17; + // Check if the time color is the same as its background, or if the sidebar is black. If so, change them to more useful values. + if (randTime == randBG) { + randBG += 1; + } + if (randBar == 3) { + randBar -= 1; + } + settingsController.SetPTSColorTime(static_cast<Controllers::Settings::Colors>(randTime)); + lv_obj_set_style_local_text_color(timeDD1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(static_cast<Controllers::Settings::Colors>(randTime))); + lv_obj_set_style_local_text_color(timeDD2, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(static_cast<Controllers::Settings::Colors>(randTime))); + lv_obj_set_style_local_text_color(timeAMPM, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(static_cast<Controllers::Settings::Colors>(randTime))); + settingsController.SetPTSColorBar(static_cast<Controllers::Settings::Colors>(randBar)); + lv_obj_set_style_local_bg_color(sidebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Convert(static_cast<Controllers::Settings::Colors>(randBar))); + settingsController.SetPTSColorBG(static_cast<Controllers::Settings::Colors>(randBG)); + lv_obj_set_style_local_bg_color(timebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Convert(static_cast<Controllers::Settings::Colors>(randBG))); + } + } +} + +Pinetime::Controllers::Settings::Colors SettingPineTimeStyle::GetNext(Pinetime::Controllers::Settings::Colors color) { + auto colorAsInt = static_cast<uint8_t>(color); + Pinetime::Controllers::Settings::Colors nextColor; + if (colorAsInt < 16) { + nextColor = static_cast<Controllers::Settings::Colors>(colorAsInt + 1); + } else { + nextColor = static_cast<Controllers::Settings::Colors>(0); + } + return nextColor; +} + +Pinetime::Controllers::Settings::Colors SettingPineTimeStyle::GetPrevious(Pinetime::Controllers::Settings::Colors color) { + auto colorAsInt = static_cast<uint8_t>(color); + Pinetime::Controllers::Settings::Colors prevColor; + + if (colorAsInt > 0) { + prevColor = static_cast<Controllers::Settings::Colors>(colorAsInt - 1); + } else { + prevColor = static_cast<Controllers::Settings::Colors>(16); + } + return prevColor; +} diff --git a/src/displayapp/screens/settings/SettingPineTimeStyle.h b/src/displayapp/screens/settings/SettingPineTimeStyle.h new file mode 100644 index 00000000..397bd86d --- /dev/null +++ b/src/displayapp/screens/settings/SettingPineTimeStyle.h @@ -0,0 +1,56 @@ +#pragma once + +#include <cstdint> +#include <lvgl/lvgl.h> +#include "components/settings/Settings.h" +#include "displayapp/screens/Screen.h" + +namespace Pinetime { + + namespace Applications { + namespace Screens { + + class SettingPineTimeStyle : public Screen{ + public: + SettingPineTimeStyle(DisplayApp* app, Pinetime::Controllers::Settings &settingsController); + ~SettingPineTimeStyle() override; + + void UpdateSelected(lv_obj_t *object, lv_event_t event); + + private: + Controllers::Settings& settingsController; + + Pinetime::Controllers::Settings::Colors GetNext(Controllers::Settings::Colors color); + Pinetime::Controllers::Settings::Colors GetPrevious(Controllers::Settings::Colors color); + + lv_obj_t * btnNextTime; + lv_obj_t * btnPrevTime; + lv_obj_t * btnNextBar; + lv_obj_t * btnPrevBar; + lv_obj_t * btnNextBG; + lv_obj_t * btnPrevBG; + lv_obj_t * btnReset; + lv_obj_t * btnRandom; + lv_obj_t * timebar; + lv_obj_t * sidebar; + lv_obj_t * timeDD1; + lv_obj_t * timeDD2; + lv_obj_t * timeAMPM; + lv_obj_t * dateDayOfWeek; + lv_obj_t * dateDay; + lv_obj_t * dateMonth; + lv_obj_t * backgroundLabel; + lv_obj_t * batteryIcon; + lv_obj_t * bleIcon; + lv_obj_t * calendarOuter; + lv_obj_t * calendarInner; + lv_obj_t * calendarBar1; + lv_obj_t * calendarBar2; + lv_obj_t * calendarCrossBar1; + lv_obj_t * calendarCrossBar2; + lv_obj_t * stepGauge; + lv_color_t needle_colors[1]; + }; + } + } +} diff --git a/src/displayapp/screens/settings/SettingSetDate.cpp b/src/displayapp/screens/settings/SettingSetDate.cpp new file mode 100644 index 00000000..ba3413ef --- /dev/null +++ b/src/displayapp/screens/settings/SettingSetDate.cpp @@ -0,0 +1,198 @@ +#include "SettingSetDate.h" +#include <lvgl/lvgl.h> +#include <hal/nrf_rtc.h> +#include <nrf_log.h> +#include "displayapp/DisplayApp.h" +#include "displayapp/screens/Symbols.h" + +using namespace Pinetime::Applications::Screens; + +namespace { + constexpr int16_t POS_X_DAY = -72; + constexpr int16_t POS_X_MONTH = 0; + constexpr int16_t POS_X_YEAR = 72; + constexpr int16_t POS_Y_PLUS = -50; + constexpr int16_t POS_Y_TEXT = -6; + constexpr int16_t POS_Y_MINUS = 40; + + void event_handler(lv_obj_t * obj, lv_event_t event) { + auto* screen = static_cast<SettingSetDate *>(obj->user_data); + screen->HandleButtonPress(obj, event); + } +} + +SettingSetDate::SettingSetDate(Pinetime::Applications::DisplayApp *app, Pinetime::Controllers::DateTime &dateTimeController) : + Screen(app), + dateTimeController {dateTimeController} { + lv_obj_t * title = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_text_static(title, "Set current date"); + lv_label_set_align(title, LV_LABEL_ALIGN_CENTER); + lv_obj_align(title, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 15, 15); + + lv_obj_t * icon = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(icon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_ORANGE); + + lv_label_set_text_static(icon, Symbols::clock); + lv_label_set_align(icon, LV_LABEL_ALIGN_CENTER); + lv_obj_align(icon, title, LV_ALIGN_OUT_LEFT_MID, -10, 0); + + dayValue = static_cast<int>(dateTimeController.Day()); + lblDay = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_text_fmt(lblDay, "%d", dayValue); + lv_label_set_align(lblDay, LV_LABEL_ALIGN_CENTER); + lv_obj_align(lblDay, lv_scr_act(), LV_ALIGN_CENTER, POS_X_DAY, POS_Y_TEXT); + lv_obj_set_auto_realign(lblDay, true); + + monthValue = static_cast<int>(dateTimeController.Month()); + lblMonth = lv_label_create(lv_scr_act(), nullptr); + UpdateMonthLabel(); + lv_label_set_align(lblMonth, LV_LABEL_ALIGN_CENTER); + lv_obj_align(lblMonth, lv_scr_act(), LV_ALIGN_CENTER, POS_X_MONTH, POS_Y_TEXT); + lv_obj_set_auto_realign(lblMonth, true); + + yearValue = static_cast<int>(dateTimeController.Year()); + if (yearValue < 2021) + yearValue = 2021; + lblYear = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_text_fmt(lblYear, "%d", yearValue); + lv_label_set_align(lblYear, LV_LABEL_ALIGN_CENTER); + lv_obj_align(lblYear, lv_scr_act(), LV_ALIGN_CENTER, POS_X_YEAR, POS_Y_TEXT); + lv_obj_set_auto_realign(lblYear, true); + + btnDayPlus = lv_btn_create(lv_scr_act(), nullptr); + btnDayPlus->user_data = this; + lv_obj_set_size(btnDayPlus, 50, 40); + lv_obj_align(btnDayPlus, lv_scr_act(), LV_ALIGN_CENTER, POS_X_DAY, POS_Y_PLUS); + lv_obj_set_style_local_value_str(btnDayPlus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "+"); + lv_obj_set_event_cb(btnDayPlus, event_handler); + + btnDayMinus = lv_btn_create(lv_scr_act(), nullptr); + btnDayMinus->user_data = this; + lv_obj_set_size(btnDayMinus, 50, 40); + lv_obj_align(btnDayMinus, lv_scr_act(), LV_ALIGN_CENTER, POS_X_DAY, POS_Y_MINUS); + lv_obj_set_style_local_value_str(btnDayMinus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "-"); + lv_obj_set_event_cb(btnDayMinus, event_handler); + + btnMonthPlus = lv_btn_create(lv_scr_act(), nullptr); + btnMonthPlus->user_data = this; + lv_obj_set_size(btnMonthPlus, 50, 40); + lv_obj_align(btnMonthPlus, lv_scr_act(), LV_ALIGN_CENTER, POS_X_MONTH, POS_Y_PLUS); + lv_obj_set_style_local_value_str(btnMonthPlus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "+"); + lv_obj_set_event_cb(btnMonthPlus, event_handler); + + btnMonthMinus = lv_btn_create(lv_scr_act(), nullptr); + btnMonthMinus->user_data = this; + lv_obj_set_size(btnMonthMinus, 50, 40); + lv_obj_align(btnMonthMinus, lv_scr_act(), LV_ALIGN_CENTER, POS_X_MONTH, POS_Y_MINUS); + lv_obj_set_style_local_value_str(btnMonthMinus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "-"); + lv_obj_set_event_cb(btnMonthMinus, event_handler); + + btnYearPlus = lv_btn_create(lv_scr_act(), nullptr); + btnYearPlus->user_data = this; + lv_obj_set_size(btnYearPlus, 50, 40); + lv_obj_align(btnYearPlus, lv_scr_act(), LV_ALIGN_CENTER, POS_X_YEAR, POS_Y_PLUS); + lv_obj_set_style_local_value_str(btnYearPlus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "+"); + lv_obj_set_event_cb(btnYearPlus, event_handler); + + btnYearMinus = lv_btn_create(lv_scr_act(), nullptr); + btnYearMinus->user_data = this; + lv_obj_set_size(btnYearMinus, 50, 40); + lv_obj_align(btnYearMinus, lv_scr_act(), LV_ALIGN_CENTER, POS_X_YEAR, POS_Y_MINUS); + lv_obj_set_style_local_value_str(btnYearMinus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "-"); + lv_obj_set_event_cb(btnYearMinus, event_handler); + + btnSetTime = lv_btn_create(lv_scr_act(), nullptr); + btnSetTime->user_data = this; + lv_obj_set_size(btnSetTime, 120, 48); + lv_obj_align(btnSetTime, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 0, 0); + lv_obj_set_style_local_value_str(btnSetTime, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "Set"); + lv_obj_set_event_cb(btnSetTime, event_handler); +} + +SettingSetDate::~SettingSetDate() { + lv_obj_clean(lv_scr_act()); +} + +void SettingSetDate::HandleButtonPress(lv_obj_t *object, lv_event_t event) { + if (event != LV_EVENT_CLICKED) + return; + + if (object == btnDayPlus) { + dayValue++; + if (dayValue > MaximumDayOfMonth()) + dayValue = 1; + lv_label_set_text_fmt(lblDay, "%d", dayValue); + lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED); + } else if (object == btnDayMinus) { + dayValue--; + if (dayValue < 1) + dayValue = MaximumDayOfMonth(); + lv_label_set_text_fmt(lblDay, "%d", dayValue); + lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED); + } else if (object == btnMonthPlus) { + monthValue++; + if (monthValue > 12) + monthValue = 1; + UpdateMonthLabel(); + lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED); + CheckDay(); + } else if (object == btnMonthMinus) { + monthValue--; + if (monthValue < 1) + monthValue = 12; + UpdateMonthLabel(); + lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED); + CheckDay(); + } else if (object == btnYearPlus) { + yearValue++; + lv_label_set_text_fmt(lblYear, "%d", yearValue); + lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED); + CheckDay(); + } else if (object == btnYearMinus) { + yearValue--; + lv_label_set_text_fmt(lblYear, "%d", yearValue); + lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED); + CheckDay(); + } else if (object == btnSetTime) { + NRF_LOG_INFO("Setting date (manually) to %04d-%02d-%02d", yearValue, monthValue, dayValue); + dateTimeController.SetTime(static_cast<uint16_t>(yearValue), + static_cast<uint8_t>(monthValue), + static_cast<uint8_t>(dayValue), + 0, + dateTimeController.Hours(), + dateTimeController.Minutes(), + dateTimeController.Seconds(), + nrf_rtc_counter_get(portNRF_RTC_REG)); + lv_btn_set_state(btnSetTime, LV_BTN_STATE_DISABLED); + } +} + +int SettingSetDate::MaximumDayOfMonth() const { + switch (monthValue) { + case 2: + if ((((yearValue % 4) == 0) && ((yearValue % 100) != 0)) || ((yearValue % 400) == 0)) + return 29; + return 28; + case 4: + case 6: + case 9: + case 11: + return 30; + default: + return 31; + } +} + +void SettingSetDate::CheckDay() { + int maxDay = MaximumDayOfMonth(); + if (dayValue > maxDay) { + dayValue = maxDay; + lv_label_set_text_fmt(lblDay, "%d", dayValue); + lv_obj_align(lblDay, lv_scr_act(), LV_ALIGN_CENTER, POS_X_DAY, POS_Y_TEXT); + } +} + +void SettingSetDate::UpdateMonthLabel() { + lv_label_set_text_static( + lblMonth, Pinetime::Controllers::DateTime::MonthShortToStringLow(static_cast<Pinetime::Controllers::DateTime::Months>(monthValue))); +} diff --git a/src/displayapp/screens/settings/SettingSetDate.h b/src/displayapp/screens/settings/SettingSetDate.h new file mode 100644 index 00000000..477337ff --- /dev/null +++ b/src/displayapp/screens/settings/SettingSetDate.h @@ -0,0 +1,41 @@ +#pragma once + +#include <cstdint> +#include <lvgl/lvgl.h> +#include "components/datetime/DateTimeController.h" +#include "displayapp/screens/Screen.h" + +namespace Pinetime { + namespace Applications { + namespace Screens { + class SettingSetDate : public Screen{ + public: + SettingSetDate(DisplayApp* app, Pinetime::Controllers::DateTime &dateTimeController); + ~SettingSetDate() override; + + void HandleButtonPress(lv_obj_t *object, lv_event_t event); + + private: + Controllers::DateTime& dateTimeController; + + int dayValue; + int monthValue; + int yearValue; + lv_obj_t * lblDay; + lv_obj_t * lblMonth; + lv_obj_t * lblYear; + lv_obj_t * btnDayPlus; + lv_obj_t * btnDayMinus; + lv_obj_t * btnMonthPlus; + lv_obj_t * btnMonthMinus; + lv_obj_t * btnYearPlus; + lv_obj_t * btnYearMinus; + lv_obj_t * btnSetTime; + + int MaximumDayOfMonth() const; + void CheckDay(); + void UpdateMonthLabel(); + }; + } + } +} diff --git a/src/displayapp/screens/settings/SettingSetTime.cpp b/src/displayapp/screens/settings/SettingSetTime.cpp new file mode 100644 index 00000000..194bf5eb --- /dev/null +++ b/src/displayapp/screens/settings/SettingSetTime.cpp @@ -0,0 +1,154 @@ +#include "SettingSetTime.h" +#include <lvgl/lvgl.h> +#include <hal/nrf_rtc.h> +#include <nrf_log.h> +#include "displayapp/DisplayApp.h" +#include "displayapp/screens/Symbols.h" + +using namespace Pinetime::Applications::Screens; + +namespace { + constexpr int16_t POS_X_HOURS = -72; + constexpr int16_t POS_X_MINUTES = 0; + constexpr int16_t POS_X_SECONDS = 72; + constexpr int16_t POS_Y_PLUS = -50; + constexpr int16_t POS_Y_TEXT = -6; + constexpr int16_t POS_Y_MINUS = 40; + constexpr int16_t OFS_Y_COLON = -2; + + void event_handler(lv_obj_t * obj, lv_event_t event) { + auto* screen = static_cast<SettingSetTime *>(obj->user_data); + screen->HandleButtonPress(obj, event); + } +} + +SettingSetTime::SettingSetTime(Pinetime::Applications::DisplayApp *app, Pinetime::Controllers::DateTime &dateTimeController) : + Screen(app), + dateTimeController {dateTimeController} { + lv_obj_t * title = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_text_static(title, "Set current time"); + lv_label_set_align(title, LV_LABEL_ALIGN_CENTER); + lv_obj_align(title, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 15, 15); + + lv_obj_t * icon = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(icon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_ORANGE); + + lv_label_set_text_static(icon, Symbols::clock); + lv_label_set_align(icon, LV_LABEL_ALIGN_CENTER); + lv_obj_align(icon, title, LV_ALIGN_OUT_LEFT_MID, -10, 0); + + hoursValue = static_cast<int>(dateTimeController.Hours()); + lblHours = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_font(lblHours, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42); + lv_label_set_text_fmt(lblHours, "%02d", hoursValue); + lv_label_set_align(lblHours, LV_LABEL_ALIGN_CENTER); + lv_obj_align(lblHours, lv_scr_act(), LV_ALIGN_CENTER, POS_X_HOURS, POS_Y_TEXT); + lv_obj_set_auto_realign(lblHours, true); + + lv_obj_t * lblColon1 = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_font(lblColon1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42); + lv_label_set_text_static(lblColon1, ":"); + lv_label_set_align(lblColon1, LV_LABEL_ALIGN_CENTER); + lv_obj_align(lblColon1, lv_scr_act(), LV_ALIGN_CENTER, (POS_X_HOURS + POS_X_MINUTES) / 2, POS_Y_TEXT + OFS_Y_COLON); + + minutesValue = static_cast<int>(dateTimeController.Minutes()); + lblMinutes = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_font(lblMinutes, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42); + lv_label_set_text_fmt(lblMinutes, "%02d", minutesValue); + lv_label_set_align(lblMinutes, LV_LABEL_ALIGN_CENTER); + lv_obj_align(lblMinutes, lv_scr_act(), LV_ALIGN_CENTER, POS_X_MINUTES, POS_Y_TEXT); + lv_obj_set_auto_realign(lblMinutes, true); + + lv_obj_t * lblColon2 = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_font(lblColon2, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42); + lv_label_set_text_static(lblColon2, ":"); + lv_label_set_align(lblColon2, LV_LABEL_ALIGN_CENTER); + lv_obj_align(lblColon2, lv_scr_act(), LV_ALIGN_CENTER, (POS_X_MINUTES + POS_X_SECONDS) / 2, POS_Y_TEXT + OFS_Y_COLON); + + lv_obj_t * lblSeconds = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_font(lblSeconds, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42); + lv_label_set_text_static(lblSeconds, "00"); + lv_label_set_align(lblSeconds, LV_LABEL_ALIGN_CENTER); + lv_obj_align(lblSeconds, lv_scr_act(), LV_ALIGN_CENTER, POS_X_SECONDS, POS_Y_TEXT); + + btnHoursPlus = lv_btn_create(lv_scr_act(), nullptr); + btnHoursPlus->user_data = this; + lv_obj_set_size(btnHoursPlus, 50, 40); + lv_obj_align(btnHoursPlus, lv_scr_act(), LV_ALIGN_CENTER, -72, -50); + lv_obj_set_style_local_value_str(btnHoursPlus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "+"); + lv_obj_set_event_cb(btnHoursPlus, event_handler); + + btnHoursMinus = lv_btn_create(lv_scr_act(), nullptr); + btnHoursMinus->user_data = this; + lv_obj_set_size(btnHoursMinus, 50, 40); + lv_obj_align(btnHoursMinus, lv_scr_act(), LV_ALIGN_CENTER, -72, 40); + lv_obj_set_style_local_value_str(btnHoursMinus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "-"); + lv_obj_set_event_cb(btnHoursMinus, event_handler); + + btnMinutesPlus = lv_btn_create(lv_scr_act(), nullptr); + btnMinutesPlus->user_data = this; + lv_obj_set_size(btnMinutesPlus, 50, 40); + lv_obj_align(btnMinutesPlus, lv_scr_act(), LV_ALIGN_CENTER, 0, -50); + lv_obj_set_style_local_value_str(btnMinutesPlus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "+"); + lv_obj_set_event_cb(btnMinutesPlus, event_handler); + + btnMinutesMinus = lv_btn_create(lv_scr_act(), nullptr); + btnMinutesMinus->user_data = this; + lv_obj_set_size(btnMinutesMinus, 50, 40); + lv_obj_align(btnMinutesMinus, lv_scr_act(), LV_ALIGN_CENTER, 0, 40); + lv_obj_set_style_local_value_str(btnMinutesMinus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "-"); + lv_obj_set_event_cb(btnMinutesMinus, event_handler); + + btnSetTime = lv_btn_create(lv_scr_act(), nullptr); + btnSetTime->user_data = this; + lv_obj_set_size(btnSetTime, 120, 48); + lv_obj_align(btnSetTime, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 0, 0); + lv_obj_set_style_local_value_str(btnSetTime, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "Set"); + lv_obj_set_event_cb(btnSetTime, event_handler); +} + +SettingSetTime::~SettingSetTime() { + lv_obj_clean(lv_scr_act()); +} + +void SettingSetTime::HandleButtonPress(lv_obj_t *object, lv_event_t event) { + if (event != LV_EVENT_CLICKED) + return; + + if (object == btnHoursPlus) { + hoursValue++; + if (hoursValue > 23) + hoursValue = 0; + lv_label_set_text_fmt(lblHours, "%02d", hoursValue); + lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED); + } else if (object == btnHoursMinus) { + hoursValue--; + if (hoursValue < 0) + hoursValue = 23; + lv_label_set_text_fmt(lblHours, "%02d", hoursValue); + lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED); + } else if (object == btnMinutesPlus) { + minutesValue++; + if (minutesValue > 59) + minutesValue = 0; + lv_label_set_text_fmt(lblMinutes, "%02d", minutesValue); + lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED); + } else if (object == btnMinutesMinus) { + minutesValue--; + if (minutesValue < 0) + minutesValue = 59; + lv_label_set_text_fmt(lblMinutes, "%02d", minutesValue); + lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED); + } else if (object == btnSetTime) { + NRF_LOG_INFO("Setting time (manually) to %02d:%02d:00", hoursValue, minutesValue); + dateTimeController.SetTime(dateTimeController.Year(), + static_cast<uint8_t>(dateTimeController.Month()), + dateTimeController.Day(), + static_cast<uint8_t>(dateTimeController.DayOfWeek()), + static_cast<uint8_t>(hoursValue), + static_cast<uint8_t>(minutesValue), + 0, + nrf_rtc_counter_get(portNRF_RTC_REG)); + lv_btn_set_state(btnSetTime, LV_BTN_STATE_DISABLED); + } +} diff --git a/src/displayapp/screens/settings/SettingSetTime.h b/src/displayapp/screens/settings/SettingSetTime.h new file mode 100644 index 00000000..8ba41eae --- /dev/null +++ b/src/displayapp/screens/settings/SettingSetTime.h @@ -0,0 +1,33 @@ +#pragma once + +#include <cstdint> +#include <lvgl/lvgl.h> +#include "components/datetime/DateTimeController.h" +#include "displayapp/screens/Screen.h" + +namespace Pinetime { + namespace Applications { + namespace Screens { + class SettingSetTime : public Screen{ + public: + SettingSetTime(DisplayApp* app, Pinetime::Controllers::DateTime &dateTimeController); + ~SettingSetTime() override; + + void HandleButtonPress(lv_obj_t *object, lv_event_t event); + + private: + Controllers::DateTime& dateTimeController; + + int hoursValue; + int minutesValue; + lv_obj_t * lblHours; + lv_obj_t * lblMinutes; + lv_obj_t * btnHoursPlus; + lv_obj_t * btnHoursMinus; + lv_obj_t * btnMinutesPlus; + lv_obj_t * btnMinutesMinus; + lv_obj_t * btnSetTime; + }; + } + } +} diff --git a/src/displayapp/screens/settings/SettingSteps.cpp b/src/displayapp/screens/settings/SettingSteps.cpp index faa843e6..bec7972b 100644 --- a/src/displayapp/screens/settings/SettingSteps.cpp +++ b/src/displayapp/screens/settings/SettingSteps.cpp @@ -70,11 +70,6 @@ SettingSteps::~SettingSteps() { settingsController.SaveSettings(); } -bool SettingSteps::Refresh() { - return running; -} - - void SettingSteps::UpdateSelected(lv_obj_t *object, lv_event_t event) { uint32_t value = settingsController.GetStepsGoal(); if(object == btnPlus && (event == LV_EVENT_PRESSED)) { @@ -95,4 +90,4 @@ void SettingSteps::UpdateSelected(lv_obj_t *object, lv_event_t event) { } } -}
\ No newline at end of file +} diff --git a/src/displayapp/screens/settings/SettingSteps.h b/src/displayapp/screens/settings/SettingSteps.h index 0a4c2056..5fc05dee 100644 --- a/src/displayapp/screens/settings/SettingSteps.h +++ b/src/displayapp/screens/settings/SettingSteps.h @@ -10,22 +10,19 @@ namespace Pinetime { namespace Applications { namespace Screens { - class SettingSteps : public Screen{ - public: - SettingSteps(DisplayApp* app, Pinetime::Controllers::Settings &settingsController); - ~SettingSteps() override; + class SettingSteps : public Screen { + public: + SettingSteps(DisplayApp* app, Pinetime::Controllers::Settings& settingsController); + ~SettingSteps() override; - bool Refresh() override; - void UpdateSelected(lv_obj_t *object, lv_event_t event); - - private: + void UpdateSelected(lv_obj_t* object, lv_event_t event); - Controllers::Settings& settingsController; + private: + Controllers::Settings& settingsController; - lv_obj_t * stepValue; - lv_obj_t * btnPlus; - lv_obj_t * btnMinus; - + lv_obj_t* stepValue; + lv_obj_t* btnPlus; + lv_obj_t* btnMinus; }; } } diff --git a/src/displayapp/screens/settings/SettingTimeFormat.cpp b/src/displayapp/screens/settings/SettingTimeFormat.cpp index 031a2a72..c99e3a0e 100644 --- a/src/displayapp/screens/settings/SettingTimeFormat.cpp +++ b/src/displayapp/screens/settings/SettingTimeFormat.cpp @@ -64,10 +64,6 @@ SettingTimeFormat::~SettingTimeFormat() { settingsController.SaveSettings(); } -bool SettingTimeFormat::Refresh() { - return running; -} - void SettingTimeFormat::UpdateSelected(lv_obj_t* object, lv_event_t event) { if (event == LV_EVENT_VALUE_CHANGED) { for (int i = 0; i < optionsTotal; i++) { @@ -86,4 +82,4 @@ void SettingTimeFormat::UpdateSelected(lv_obj_t* object, lv_event_t event) { } } } -}
\ No newline at end of file +} diff --git a/src/displayapp/screens/settings/SettingTimeFormat.h b/src/displayapp/screens/settings/SettingTimeFormat.h index 9203b45b..eac4bdc9 100644 --- a/src/displayapp/screens/settings/SettingTimeFormat.h +++ b/src/displayapp/screens/settings/SettingTimeFormat.h @@ -15,7 +15,6 @@ namespace Pinetime { SettingTimeFormat(DisplayApp* app, Pinetime::Controllers::Settings& settingsController); ~SettingTimeFormat() override; - bool Refresh() override; void UpdateSelected(lv_obj_t* object, lv_event_t event); private: diff --git a/src/displayapp/screens/settings/SettingWakeUp.cpp b/src/displayapp/screens/settings/SettingWakeUp.cpp index cce9a60d..d999004b 100644 --- a/src/displayapp/screens/settings/SettingWakeUp.cpp +++ b/src/displayapp/screens/settings/SettingWakeUp.cpp @@ -72,10 +72,6 @@ SettingWakeUp::~SettingWakeUp() { settingsController.SaveSettings(); } -bool SettingWakeUp::Refresh() { - return running; -} - void SettingWakeUp::UpdateSelected(lv_obj_t* object, lv_event_t event) { using WakeUpMode = Pinetime::Controllers::Settings::WakeUpMode; if (event == LV_EVENT_VALUE_CHANGED && !ignoringEvents) { diff --git a/src/displayapp/screens/settings/SettingWakeUp.h b/src/displayapp/screens/settings/SettingWakeUp.h index 248dd9ac..b9a31dc9 100644 --- a/src/displayapp/screens/settings/SettingWakeUp.h +++ b/src/displayapp/screens/settings/SettingWakeUp.h @@ -15,7 +15,6 @@ namespace Pinetime { SettingWakeUp(DisplayApp* app, Pinetime::Controllers::Settings& settingsController); ~SettingWakeUp() override; - bool Refresh() override; void UpdateSelected(lv_obj_t* object, lv_event_t event); private: diff --git a/src/displayapp/screens/settings/SettingWatchFace.cpp b/src/displayapp/screens/settings/SettingWatchFace.cpp index 02b90816..cdec704c 100644 --- a/src/displayapp/screens/settings/SettingWatchFace.cpp +++ b/src/displayapp/screens/settings/SettingWatchFace.cpp @@ -75,10 +75,6 @@ SettingWatchFace::~SettingWatchFace() { settingsController.SaveSettings(); } -bool SettingWatchFace::Refresh() { - return running; -} - void SettingWatchFace::UpdateSelected(lv_obj_t* object, lv_event_t event) { if (event == LV_EVENT_VALUE_CHANGED) { for (uint8_t i = 0; i < optionsTotal; i++) { diff --git a/src/displayapp/screens/settings/SettingWatchFace.h b/src/displayapp/screens/settings/SettingWatchFace.h index 1930a228..d4a96c6d 100644 --- a/src/displayapp/screens/settings/SettingWatchFace.h +++ b/src/displayapp/screens/settings/SettingWatchFace.h @@ -15,7 +15,6 @@ namespace Pinetime { SettingWatchFace(DisplayApp* app, Pinetime::Controllers::Settings& settingsController); ~SettingWatchFace() override; - bool Refresh() override; void UpdateSelected(lv_obj_t* object, lv_event_t event); private: diff --git a/src/displayapp/screens/settings/Settings.cpp b/src/displayapp/screens/settings/Settings.cpp index 0ab21377..1daf311e 100644 --- a/src/displayapp/screens/settings/Settings.cpp +++ b/src/displayapp/screens/settings/Settings.cpp @@ -18,6 +18,9 @@ Settings::Settings(Pinetime::Applications::DisplayApp* app, Pinetime::Controller }, [this]() -> std::unique_ptr<Screen> { return CreateScreen2(); + }, + [this]() -> std::unique_ptr<Screen> { + return CreateScreen3(); }}, Screens::ScreenListModes::UpDown} { } @@ -26,13 +29,6 @@ Settings::~Settings() { lv_obj_clean(lv_scr_act()); } -bool Settings::Refresh() { - - if (running) - running = screens.Refresh(); - return running; -} - bool Settings::OnTouchEvent(Pinetime::Applications::TouchEvents event) { return screens.OnTouchEvent(event); } @@ -46,17 +42,29 @@ std::unique_ptr<Screen> Settings::CreateScreen1() { {Symbols::home, "Watch face", Apps::SettingWatchFace}, }}; - return std::make_unique<Screens::List>(0, 2, app, settingsController, applications); + return std::make_unique<Screens::List>(0, 3, app, settingsController, applications); } std::unique_ptr<Screen> Settings::CreateScreen2() { std::array<Screens::List::Applications, 4> applications {{ {Symbols::shoe, "Steps", Apps::SettingSteps}, - {Symbols::batteryHalf, "Battery", Apps::BatteryInfo}, + {Symbols::clock, "Set date", Apps::SettingSetDate}, + {Symbols::clock, "Set time", Apps::SettingSetTime}, + {Symbols::batteryHalf, "Battery", Apps::BatteryInfo} + }}; + + return std::make_unique<Screens::List>(1, 3, app, settingsController, applications); +} + +std::unique_ptr<Screen> Settings::CreateScreen3() { + + std::array<Screens::List::Applications, 4> applications {{ + {Symbols::paintbrush, "PTS Colors", Apps::SettingPineTimeStyle}, {Symbols::check, "Firmware", Apps::FirmwareValidation}, {Symbols::list, "About", Apps::SysInfo}, + {Symbols::none, "None", Apps::None}, }}; - return std::make_unique<Screens::List>(1, 2, app, settingsController, applications); + return std::make_unique<Screens::List>(2, 3, app, settingsController, applications); } diff --git a/src/displayapp/screens/settings/Settings.h b/src/displayapp/screens/settings/Settings.h index 711a6be6..6c54cdeb 100644 --- a/src/displayapp/screens/settings/Settings.h +++ b/src/displayapp/screens/settings/Settings.h @@ -14,17 +14,16 @@ namespace Pinetime { Settings(DisplayApp* app, Pinetime::Controllers::Settings& settingsController); ~Settings() override; - bool Refresh() override; - bool OnTouchEvent(Pinetime::Applications::TouchEvents event) override; private: Controllers::Settings& settingsController; - ScreenList<2> screens; + ScreenList<3> screens; std::unique_ptr<Screen> CreateScreen1(); std::unique_ptr<Screen> CreateScreen2(); + std::unique_ptr<Screen> CreateScreen3(); }; } } diff --git a/src/drivers/Cst816s.cpp b/src/drivers/Cst816s.cpp index b8f8e45d..49d6ed0e 100644 --- a/src/drivers/Cst816s.cpp +++ b/src/drivers/Cst816s.cpp @@ -3,6 +3,7 @@ #include <legacy/nrf_drv_gpiote.h> #include <nrfx_log.h> #include <task.h> +#include "drivers/PinMap.h" using namespace Pinetime::Drivers; @@ -17,13 +18,13 @@ using namespace Pinetime::Drivers; Cst816S::Cst816S(TwiMaster& twiMaster, uint8_t twiAddress) : twiMaster {twiMaster}, twiAddress {twiAddress} { } -void Cst816S::Init() { - nrf_gpio_cfg_output(pinReset); - nrf_gpio_pin_set(pinReset); +bool Cst816S::Init() { + nrf_gpio_cfg_output(PinMap::Cst816sReset); + nrf_gpio_pin_set(PinMap::Cst816sReset); vTaskDelay(50); - nrf_gpio_pin_clear(pinReset); + nrf_gpio_pin_clear(PinMap::Cst816sReset); vTaskDelay(5); - nrf_gpio_pin_set(pinReset); + nrf_gpio_pin_set(PinMap::Cst816sReset); vTaskDelay(50); // Wake the touchpanel up @@ -50,10 +51,27 @@ void Cst816S::Init() { */ static constexpr uint8_t irqCtl = 0b01110000; twiMaster.Write(twiAddress, 0xFA, &irqCtl, 1); + + // There's mixed information about which register contains which information + if (twiMaster.Read(twiAddress, 0xA7, &chipId, 1) == TwiMaster::ErrorCodes::TransactionFailed) { + chipId = 0xFF; + return false; + } + if (twiMaster.Read(twiAddress, 0xA8, &vendorId, 1) == TwiMaster::ErrorCodes::TransactionFailed) { + vendorId = 0xFF; + return false; + } + if (twiMaster.Read(twiAddress, 0xA9, &fwVersion, 1) == TwiMaster::ErrorCodes::TransactionFailed) { + fwVersion = 0xFF; + return false; + } + + return chipId == 0xb4 && vendorId == 0 && fwVersion == 1; } Cst816S::TouchInfos Cst816S::GetTouchInfo() { Cst816S::TouchInfos info; + uint8_t touchData[7]; auto ret = twiMaster.Read(twiAddress, 0, touchData, sizeof(touchData)); if (ret != TwiMaster::ErrorCodes::NoError) { @@ -61,18 +79,17 @@ Cst816S::TouchInfos Cst816S::GetTouchInfo() { return info; } - auto nbTouchPoints = touchData[2] & 0x0f; + // This can only be 0 or 1 + uint8_t nbTouchPoints = touchData[touchPointNumIndex] & 0x0f; - auto xHigh = touchData[touchXHighIndex] & 0x0f; - auto xLow = touchData[touchXLowIndex]; - uint16_t x = (xHigh << 8) | xLow; + uint8_t xHigh = touchData[touchXHighIndex] & 0x0f; + uint8_t xLow = touchData[touchXLowIndex]; + info.x = (xHigh << 8) | xLow; - auto yHigh = touchData[touchYHighIndex] & 0x0f; - auto yLow = touchData[touchYLowIndex]; - uint16_t y = (yHigh << 8) | yLow; + uint8_t yHigh = touchData[touchYHighIndex] & 0x0f; + uint8_t yLow = touchData[touchYLowIndex]; + info.y = (yHigh << 8) | yLow; - info.x = x; - info.y = y; info.touching = (nbTouchPoints > 0); info.gesture = static_cast<Gestures>(touchData[gestureIndex]); @@ -80,9 +97,9 @@ Cst816S::TouchInfos Cst816S::GetTouchInfo() { } void Cst816S::Sleep() { - nrf_gpio_pin_clear(pinReset); + nrf_gpio_pin_clear(PinMap::Cst816sReset); vTaskDelay(5); - nrf_gpio_pin_set(pinReset); + nrf_gpio_pin_set(PinMap::Cst816sReset); vTaskDelay(50); static constexpr uint8_t sleepValue = 0x03; twiMaster.Write(twiAddress, 0xA5, &sleepValue, 1); diff --git a/src/drivers/Cst816s.h b/src/drivers/Cst816s.h index d4c17bb8..0fec8419 100644 --- a/src/drivers/Cst816s.h +++ b/src/drivers/Cst816s.h @@ -30,15 +30,21 @@ namespace Pinetime { Cst816S(Cst816S&&) = delete; Cst816S& operator=(Cst816S&&) = delete; - void Init(); + bool Init(); TouchInfos GetTouchInfo(); void Sleep(); void Wakeup(); + uint8_t GetChipId() const { + return chipId; + } + uint8_t GetVendorId() const { + return vendorId; + } + uint8_t GetFwVersion() const { + return fwVersion; + } private: - static constexpr uint8_t pinIrq = 28; - static constexpr uint8_t pinReset = 10; - // Unused/Unavailable commented out static constexpr uint8_t gestureIndex = 1; static constexpr uint8_t touchPointNumIndex = 2; @@ -52,9 +58,12 @@ namespace Pinetime { //static constexpr uint8_t touchXYIndex = 7; //static constexpr uint8_t touchMiscIndex = 8; - uint8_t touchData[7]; TwiMaster& twiMaster; uint8_t twiAddress; + + uint8_t chipId; + uint8_t vendorId; + uint8_t fwVersion; }; } diff --git a/src/drivers/PinMap.h b/src/drivers/PinMap.h new file mode 100644 index 00000000..57964020 --- /dev/null +++ b/src/drivers/PinMap.h @@ -0,0 +1,38 @@ +#pragma once + +namespace Pinetime { + namespace PinMap { + + #ifdef WATCH_P8 + // COLMI P8 + static constexpr uint8_t Charging = 19; + static constexpr uint8_t Cst816sReset = 13; + static constexpr uint8_t Button = 17; + #else + // Pinetime + static constexpr uint8_t Charging = 12; + static constexpr uint8_t Cst816sReset = 10; + static constexpr uint8_t Button = 13; + #endif + + static constexpr uint8_t Cst816sIrq = 28; + static constexpr uint8_t PowerPresent = 19; + + static constexpr uint8_t Motor = 16; + + static constexpr uint8_t LcdBacklightLow = 14; + static constexpr uint8_t LcdBacklightMedium = 22; + static constexpr uint8_t LcdBacklightHigh = 23; + + static constexpr uint8_t SpiSck = 2; + static constexpr uint8_t SpiMosi = 3; + static constexpr uint8_t SpiMiso = 4; + + static constexpr uint8_t SpiFlashCsn = 5; + static constexpr uint8_t SpiLcdCsn = 25; + static constexpr uint8_t LcdDataCommand = 18; + + static constexpr uint8_t TwiScl = 7; + static constexpr uint8_t TwiSda = 6; + } +} diff --git a/src/libs/mynewt-nimble/nimble/controller/include/controller/ble_ll_rfmgmt.h b/src/libs/mynewt-nimble/nimble/controller/include/controller/ble_ll_rfmgmt.h index 37b81a88..5e2d636f 100644 --- a/src/libs/mynewt-nimble/nimble/controller/include/controller/ble_ll_rfmgmt.h +++ b/src/libs/mynewt-nimble/nimble/controller/include/controller/ble_ll_rfmgmt.h @@ -51,7 +51,7 @@ static inline void ble_ll_rfmgmt_reset(void) { } static inline void ble_ll_rfmgmt_scan_changed(bool e, uint32_t n) { } static inline void ble_ll_rfmgmt_sched_changed(struct ble_ll_sched_item *f) { } static inline void ble_ll_rfmgmt_release(void) { } -static inline uint32_t ble_ll_rfmgmt_enable_now(void) { return 0; } +static inline uint32_t ble_ll_rfmgmt_enable_now(void) { return os_cputime_get32(); } static inline bool ble_ll_rfmgmt_is_enabled(void) { return true; } #endif diff --git a/src/main.cpp b/src/main.cpp index 79e2ad86..fc772355 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -43,7 +43,9 @@ #include "drivers/St7789.h" #include "drivers/TwiMaster.h" #include "drivers/Cst816s.h" +#include "drivers/PinMap.h" #include "systemtask/SystemTask.h" +#include "drivers/PinMap.h" #include "touchhandler/TouchHandler.h" #if NRF_LOG_ENABLED @@ -54,14 +56,6 @@ Pinetime::Logging::NrfLogger logger; Pinetime::Logging::DummyLogger logger; #endif -static constexpr uint8_t pinSpiSck = 2; -static constexpr uint8_t pinSpiMosi = 3; -static constexpr uint8_t pinSpiMiso = 4; -static constexpr uint8_t pinSpiFlashCsn = 5; -static constexpr uint8_t pinLcdCsn = 25; -static constexpr uint8_t pinLcdDataCommand = 18; -static constexpr uint8_t pinTwiScl = 7; -static constexpr uint8_t pinTwiSda = 6; static constexpr uint8_t touchPanelTwiAddress = 0x15; static constexpr uint8_t motionSensorTwiAddress = 0x18; static constexpr uint8_t heartRateSensorTwiAddress = 0x44; @@ -70,33 +64,30 @@ Pinetime::Drivers::SpiMaster spi {Pinetime::Drivers::SpiMaster::SpiModule::SPI0, {Pinetime::Drivers::SpiMaster::BitOrder::Msb_Lsb, Pinetime::Drivers::SpiMaster::Modes::Mode3, Pinetime::Drivers::SpiMaster::Frequencies::Freq8Mhz, - pinSpiSck, - pinSpiMosi, - pinSpiMiso}}; + Pinetime::PinMap::SpiSck, + Pinetime::PinMap::SpiMosi, + Pinetime::PinMap::SpiMiso}}; -Pinetime::Drivers::Spi lcdSpi {spi, pinLcdCsn}; -Pinetime::Drivers::St7789 lcd {lcdSpi, pinLcdDataCommand}; +Pinetime::Drivers::Spi lcdSpi {spi, Pinetime::PinMap::SpiLcdCsn}; +Pinetime::Drivers::St7789 lcd {lcdSpi, Pinetime::PinMap::LcdDataCommand}; -Pinetime::Drivers::Spi flashSpi {spi, pinSpiFlashCsn}; +Pinetime::Drivers::Spi flashSpi {spi, Pinetime::PinMap::SpiFlashCsn}; Pinetime::Drivers::SpiNorFlash spiNorFlash {flashSpi}; // The TWI device should work @ up to 400Khz but there is a HW bug which prevent it from // respecting correct timings. According to erratas heet, this magic value makes it run // at ~390Khz with correct timings. static constexpr uint32_t MaxTwiFrequencyWithoutHardwareBug {0x06200000}; -Pinetime::Drivers::TwiMaster twiMaster {NRF_TWIM1, MaxTwiFrequencyWithoutHardwareBug, pinTwiSda, pinTwiScl}; +Pinetime::Drivers::TwiMaster twiMaster {NRF_TWIM1, MaxTwiFrequencyWithoutHardwareBug, Pinetime::PinMap::TwiSda, Pinetime::PinMap::TwiScl}; Pinetime::Drivers::Cst816S touchPanel {twiMaster, touchPanelTwiAddress}; #ifdef PINETIME_IS_RECOVERY -static constexpr bool isFactory = true; #include "displayapp/DummyLittleVgl.h" #include "displayapp/DisplayAppRecovery.h" -Pinetime::Components::LittleVgl lvgl {lcd, touchPanel}; #else -static constexpr bool isFactory = false; #include "displayapp/LittleVgl.h" #include "displayapp/DisplayApp.h" -Pinetime::Components::LittleVgl lvgl {lcd, touchPanel}; #endif +Pinetime::Components::LittleVgl lvgl {lcd, touchPanel}; Pinetime::Drivers::Bma421 motionSensor {twiMaster, motionSensorTwiAddress}; Pinetime::Drivers::Hrs3300 heartRateSensor {twiMaster, heartRateSensorTwiAddress}; @@ -105,10 +96,8 @@ TimerHandle_t debounceTimer; TimerHandle_t debounceChargeTimer; Pinetime::Controllers::Battery batteryController; Pinetime::Controllers::Ble bleController; -void ble_manager_set_ble_connection_callback(void (*connection)()); -void ble_manager_set_ble_disconnection_callback(void (*disconnection)()); -static constexpr uint8_t pinTouchIrq = 28; -static constexpr uint8_t pinPowerPresentIrq = 19; +static constexpr uint8_t pinTouchIrq = Pinetime::PinMap::Cst816sIrq; +static constexpr uint8_t pinPowerPresentIrq = Pinetime::PinMap::PowerPresent; Pinetime::Controllers::HeartRateController heartRateController; Pinetime::Applications::HeartRateTask heartRateApp(heartRateSensor, heartRateController); @@ -119,12 +108,12 @@ Pinetime::Drivers::WatchdogView watchdogView(watchdog); Pinetime::Controllers::NotificationManager notificationManager; Pinetime::Controllers::MotionController motionController; Pinetime::Controllers::TimerController timerController; +Pinetime::Controllers::AlarmController alarmController {dateTimeController}; Pinetime::Controllers::TouchHandler touchHandler(touchPanel, lvgl); Pinetime::Controllers::FS fs {spiNorFlash}; Pinetime::Controllers::Settings settingsController {fs}; -Pinetime::Controllers::MotorController motorController {settingsController}; - +Pinetime::Controllers::MotorController motorController {}; Pinetime::Applications::DisplayApp displayApp(lcd, lvgl, @@ -139,6 +128,7 @@ Pinetime::Applications::DisplayApp displayApp(lcd, motorController, motionController, timerController, + alarmController, touchHandler); Pinetime::System::SystemTask systemTask(spi, @@ -151,6 +141,7 @@ Pinetime::System::SystemTask systemTask(spi, bleController, dateTimeController, timerController, + alarmController, watchdog, notificationManager, motorController, @@ -164,15 +155,25 @@ Pinetime::System::SystemTask systemTask(spi, fs, touchHandler); +/* Variable Declarations for variables in noinit SRAM + Increment NoInit_MagicValue upon adding variables to this area +*/ +extern uint32_t __start_noinit_data; +extern uint32_t __stop_noinit_data; +static constexpr uint32_t NoInit_MagicValue = 0xDEAD0000; +uint32_t NoInit_MagicWord __attribute__((section(".noinit"))); +std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> NoInit_BackUpTime __attribute__((section(".noinit"))); + + void nrfx_gpiote_evt_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) { - if (pin == pinTouchIrq) { + if (pin == Pinetime::PinMap::Cst816sIrq) { systemTask.OnTouchEvent(); return; } BaseType_t xHigherPriorityTaskWoken = pdFALSE; - if (pin == pinPowerPresentIrq and action == NRF_GPIOTE_POLARITY_TOGGLE) { + if (pin == Pinetime::PinMap::PowerPresent and action == NRF_GPIOTE_POLARITY_TOGGLE) { xTimerStartFromISR(debounceChargeTimer, &xHigherPriorityTaskWoken); portYIELD_FROM_ISR(xHigherPriorityTaskWoken); return; @@ -305,18 +306,18 @@ int main(void) { nrf_drv_clock_init(); // Unblock i2c? - nrf_gpio_cfg(pinTwiScl, + nrf_gpio_cfg(Pinetime::PinMap::TwiScl, NRF_GPIO_PIN_DIR_OUTPUT, NRF_GPIO_PIN_INPUT_DISCONNECT, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_S0D1, NRF_GPIO_PIN_NOSENSE); - nrf_gpio_pin_set(pinTwiScl); + nrf_gpio_pin_set(Pinetime::PinMap::TwiScl); for (uint8_t i = 0; i < 16; i++) { - nrf_gpio_pin_toggle(pinTwiScl); + nrf_gpio_pin_toggle(Pinetime::PinMap::TwiScl); nrf_delay_us(5); } - nrf_gpio_cfg_default(pinTwiScl); + nrf_gpio_cfg_default(Pinetime::PinMap::TwiScl); debounceTimer = xTimerCreate("debounceTimer", 200, pdFALSE, (void*) 0, DebounceTimerCallback); debounceChargeTimer = xTimerCreate("debounceTimerCharge", 200, pdFALSE, (void*) 0, DebounceTimerChargeCallback); @@ -324,6 +325,15 @@ int main(void) { // retrieve version stored by bootloader Pinetime::BootloaderVersion::SetVersion(NRF_TIMER2->CC[0]); + + if (NoInit_MagicWord == NoInit_MagicValue) { + dateTimeController.SetCurrentTime(NoInit_BackUpTime); + } else { + //Clear Memory to known state + memset(&__start_noinit_data,0,(uintptr_t)&__stop_noinit_data-(uintptr_t)&__start_noinit_data); + NoInit_MagicWord = NoInit_MagicValue; + } + lvgl.Init(); systemTask.Start(); diff --git a/src/recoveryLoader.cpp b/src/recoveryLoader.cpp index 9818179d..acec14c8 100644 --- a/src/recoveryLoader.cpp +++ b/src/recoveryLoader.cpp @@ -15,6 +15,7 @@ #include <components/brightness/BrightnessController.h> #include <algorithm> #include "recoveryImage.h" +#include "drivers/PinMap.h" #include "displayapp/icons/infinitime/infinitime-nb.c" #include "components/rle/RleDecoder.h" @@ -27,12 +28,6 @@ Pinetime::Logging::NrfLogger logger; Pinetime::Logging::DummyLogger logger; #endif -static constexpr uint8_t pinSpiSck = 2; -static constexpr uint8_t pinSpiMosi = 3; -static constexpr uint8_t pinSpiMiso = 4; -static constexpr uint8_t pinSpiFlashCsn = 5; -static constexpr uint8_t pinLcdCsn = 25; -static constexpr uint8_t pinLcdDataCommand = 18; static constexpr uint8_t displayWidth = 240; static constexpr uint8_t displayHeight = 240; @@ -45,14 +40,14 @@ Pinetime::Drivers::SpiMaster spi {Pinetime::Drivers::SpiMaster::SpiModule::SPI0, {Pinetime::Drivers::SpiMaster::BitOrder::Msb_Lsb, Pinetime::Drivers::SpiMaster::Modes::Mode3, Pinetime::Drivers::SpiMaster::Frequencies::Freq8Mhz, - pinSpiSck, - pinSpiMosi, - pinSpiMiso}}; -Pinetime::Drivers::Spi flashSpi {spi, pinSpiFlashCsn}; + Pinetime::PinMap::SpiSck, + Pinetime::PinMap::SpiMosi, + Pinetime::PinMap::SpiMiso}}; +Pinetime::Drivers::Spi flashSpi {spi, Pinetime::PinMap::SpiFlashCsn}; Pinetime::Drivers::SpiNorFlash spiNorFlash {flashSpi}; -Pinetime::Drivers::Spi lcdSpi {spi, pinLcdCsn}; -Pinetime::Drivers::St7789 lcd {lcdSpi, pinLcdDataCommand}; +Pinetime::Drivers::Spi lcdSpi {spi, Pinetime::PinMap::SpiLcdCsn}; +Pinetime::Drivers::St7789 lcd {lcdSpi, Pinetime::PinMap::LcdDataCommand}; Pinetime::Components::Gfx gfx {lcd}; Pinetime::Controllers::BrightnessController brightnessController; diff --git a/src/systemtask/Messages.h b/src/systemtask/Messages.h index 3a195e2d..5aa218d2 100644 --- a/src/systemtask/Messages.h +++ b/src/systemtask/Messages.h @@ -20,7 +20,11 @@ namespace Pinetime { EnableSleeping, DisableSleeping, OnNewDay, - OnChargingEvent + OnChargingEvent, + SetOffAlarm, + StopRinging, + MeasureBatteryTimerExpired, + BatteryPercentageUpdated, }; } } diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp index 03bf6706..f79fd8e5 100644 --- a/src/systemtask/SystemTask.cpp +++ b/src/systemtask/SystemTask.cpp @@ -21,7 +21,10 @@ #include "drivers/SpiNorFlash.h" #include "drivers/TwiMaster.h" #include "drivers/Hrs3300.h" +#include "drivers/PinMap.h" #include "main.h" +#include "BootErrors.h" + #include <memory> @@ -47,6 +50,11 @@ void IdleTimerCallback(TimerHandle_t xTimer) { sysTask->OnIdle(); } +void MeasureBatteryTimerCallback(TimerHandle_t xTimer) { + auto* sysTask = static_cast<SystemTask*>(pvTimerGetTimerID(xTimer)); + sysTask->PushMessage(Pinetime::System::Messages::MeasureBatteryTimerExpired); +} + SystemTask::SystemTask(Drivers::SpiMaster& spi, Drivers::St7789& lcd, Pinetime::Drivers::SpiNorFlash& spiNorFlash, @@ -57,6 +65,7 @@ SystemTask::SystemTask(Drivers::SpiMaster& spi, Controllers::Ble& bleController, Controllers::DateTime& dateTimeController, Controllers::TimerController& timerController, + Controllers::AlarmController& alarmController, Drivers::Watchdog& watchdog, Pinetime::Controllers::NotificationManager& notificationManager, Pinetime::Controllers::MotorController& motorController, @@ -79,6 +88,7 @@ SystemTask::SystemTask(Drivers::SpiMaster& spi, bleController {bleController}, dateTimeController {dateTimeController}, timerController {timerController}, + alarmController {alarmController}, watchdog {watchdog}, notificationManager {notificationManager}, motorController {motorController}, @@ -107,6 +117,8 @@ void SystemTask::Process(void* instance) { } void SystemTask::Work() { + BootErrors bootError = BootErrors::None; + watchdog.Setup(7); watchdog.Start(); NRF_LOG_INFO("Last reset reason : %s", Pinetime::Drivers::Watchdog::ResetReasonToString(watchdog.ResetReason())); @@ -121,17 +133,19 @@ void SystemTask::Work() { fs.Init(); nimbleController.Init(); - nimbleController.StartAdvertising(); lcd.Init(); twiMaster.Init(); - touchPanel.Init(); + if (!touchPanel.Init()) { + bootError = BootErrors::TouchController; + } dateTimeController.Register(this); - batteryController.Init(); + batteryController.Register(this); motorController.Init(); motionSensor.SoftReset(); timerController.Register(this); timerController.Init(); + alarmController.Init(this); // Reset the TWI device because the motion sensor chip most probably crashed it... twiMaster.Sleep(); @@ -142,28 +156,28 @@ void SystemTask::Work() { settingsController.Init(); displayApp.Register(this); - displayApp.Start(); - - displayApp.PushMessage(Pinetime::Applications::Display::Messages::UpdateBatteryLevel); + displayApp.Start(bootError); heartRateSensor.Init(); heartRateSensor.Disable(); heartRateApp.Start(); - nrf_gpio_cfg_sense_input(pinButton, (nrf_gpio_pin_pull_t) GPIO_PIN_CNF_PULL_Pulldown, (nrf_gpio_pin_sense_t) GPIO_PIN_CNF_SENSE_High); + // Button nrf_gpio_cfg_output(15); nrf_gpio_pin_set(15); nrfx_gpiote_in_config_t pinConfig; - pinConfig.skip_gpio_setup = true; + pinConfig.skip_gpio_setup = false; pinConfig.hi_accuracy = false; pinConfig.is_watcher = false; - pinConfig.sense = (nrf_gpiote_polarity_t) NRF_GPIOTE_POLARITY_HITOLO; + pinConfig.sense = (nrf_gpiote_polarity_t) NRF_GPIOTE_POLARITY_TOGGLE; pinConfig.pull = (nrf_gpio_pin_pull_t) GPIO_PIN_CNF_PULL_Pulldown; - nrfx_gpiote_in_init(pinButton, &pinConfig, nrfx_gpiote_evt_handler); + nrfx_gpiote_in_init(PinMap::Button, &pinConfig, nrfx_gpiote_evt_handler); + nrfx_gpiote_in_event_enable(PinMap::Button, true); - nrf_gpio_cfg_sense_input(pinTouchIrq, (nrf_gpio_pin_pull_t) GPIO_PIN_CNF_PULL_Pullup, (nrf_gpio_pin_sense_t) GPIO_PIN_CNF_SENSE_Low); + // Touchscreen + nrf_gpio_cfg_sense_input(PinMap::Cst816sIrq, (nrf_gpio_pin_pull_t) GPIO_PIN_CNF_PULL_Pullup, (nrf_gpio_pin_sense_t) GPIO_PIN_CNF_SENSE_Low); pinConfig.skip_gpio_setup = true; pinConfig.hi_accuracy = false; @@ -171,24 +185,24 @@ void SystemTask::Work() { pinConfig.sense = (nrf_gpiote_polarity_t) NRF_GPIOTE_POLARITY_HITOLO; pinConfig.pull = (nrf_gpio_pin_pull_t) GPIO_PIN_CNF_PULL_Pullup; - nrfx_gpiote_in_init(pinTouchIrq, &pinConfig, nrfx_gpiote_evt_handler); + nrfx_gpiote_in_init(PinMap::Cst816sIrq, &pinConfig, nrfx_gpiote_evt_handler); + // Power present pinConfig.sense = NRF_GPIOTE_POLARITY_TOGGLE; pinConfig.pull = NRF_GPIO_PIN_NOPULL; pinConfig.is_watcher = false; pinConfig.hi_accuracy = false; - pinConfig.skip_gpio_setup = true; - nrfx_gpiote_in_init(pinPowerPresentIrq, &pinConfig, nrfx_gpiote_evt_handler); + pinConfig.skip_gpio_setup = false; + nrfx_gpiote_in_init(PinMap::PowerPresent, &pinConfig, nrfx_gpiote_evt_handler); + nrfx_gpiote_in_event_enable(PinMap::PowerPresent, true); - if (nrf_gpio_pin_read(pinPowerPresentIrq)) { - nrf_gpio_cfg_sense_input(pinPowerPresentIrq, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_SENSE_LOW); - } else { - nrf_gpio_cfg_sense_input(pinPowerPresentIrq, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_SENSE_HIGH); - } + batteryController.MeasureVoltage(); idleTimer = xTimerCreate("idleTimer", pdMS_TO_TICKS(2000), pdFALSE, this, IdleTimerCallback); dimTimer = xTimerCreate("dimTimer", pdMS_TO_TICKS(settingsController.GetScreenTimeOut() - 2000), pdFALSE, this, DimTimerCallback); + measureBatteryTimer = xTimerCreate("measureBattery", batteryMeasurementPeriod, pdTRUE, this, MeasureBatteryTimerCallback); xTimerStart(dimTimer, 0); + xTimerStart(measureBatteryTimer, portMAX_DELAY); // Suppress endless loop diagnostic #pragma clang diagnostic push @@ -198,11 +212,6 @@ void SystemTask::Work() { uint8_t msg; if (xQueueReceive(systemTasksMsgQueue, &msg, 100)) { - - batteryController.Update(); - // the battery does not emit events when changing charge levels, so we piggyback - // on any system event to read and update the current values - Messages message = static_cast<Messages>(msg); switch (message) { case Messages::EnableSleeping: @@ -226,26 +235,29 @@ void SystemTask::Work() { touchPanel.Wakeup(); } - nimbleController.StartAdvertising(); xTimerStart(dimTimer, 0); spiNorFlash.Wakeup(); lcd.Wakeup(); displayApp.PushMessage(Pinetime::Applications::Display::Messages::GoToRunning); - displayApp.PushMessage(Pinetime::Applications::Display::Messages::UpdateBatteryLevel); heartRateApp.PushMessage(Pinetime::Applications::HeartRateTask::Messages::WakeUp); + if (!bleController.IsConnected()) + nimbleController.RestartFastAdv(); + isSleeping = false; isWakingUp = false; isDimmed = false; break; case Messages::TouchWakeUp: { - auto touchInfo = touchPanel.GetTouchInfo(); - if (touchInfo.touching and ((touchInfo.gesture == Pinetime::Drivers::Cst816S::Gestures::DoubleTap and - settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::DoubleTap)) or - (touchInfo.gesture == Pinetime::Drivers::Cst816S::Gestures::SingleTap and - settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::SingleTap)))) { - GoToRunning(); + if(touchHandler.GetNewTouchInfo()) { + auto gesture = touchHandler.GestureGet(); + if (gesture != Pinetime::Drivers::Cst816S::Gestures::None and ((gesture == Pinetime::Drivers::Cst816S::Gestures::DoubleTap and + settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::DoubleTap)) or + (gesture == Pinetime::Drivers::Cst816S::Gestures::SingleTap and + settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::SingleTap)))) { + GoToRunning(); + } } } break; case Messages::GoToSleep: @@ -261,10 +273,12 @@ void SystemTask::Work() { displayApp.PushMessage(Pinetime::Applications::Display::Messages::UpdateDateTime); break; case Messages::OnNewNotification: - if (isSleeping && !isWakingUp) { - GoToRunning(); + if (settingsController.GetNotificationStatus() == Pinetime::Controllers::Settings::Notification::ON) { + if (isSleeping && !isWakingUp) { + GoToRunning(); + } + displayApp.PushMessage(Pinetime::Applications::Display::Messages::NewNotification); } - displayApp.PushMessage(Pinetime::Applications::Display::Messages::NewNotification); break; case Messages::OnTimerDone: if (isSleeping && !isWakingUp) { @@ -273,6 +287,16 @@ void SystemTask::Work() { motorController.RunForDuration(35); displayApp.PushMessage(Pinetime::Applications::Display::Messages::TimerDone); break; + case Messages::SetOffAlarm: + if (isSleeping && !isWakingUp) { + GoToRunning(); + } + motorController.StartRinging(); + displayApp.PushMessage(Pinetime::Applications::Display::Messages::AlarmTriggered); + break; + case Messages::StopRinging: + motorController.StopRinging(); + break; case Messages::BleConnected: ReloadIdleTimer(); isBleDiscoveryTimerRunning = true; @@ -325,8 +349,18 @@ void SystemTask::Work() { stepCounterMustBeReset = true; break; case Messages::OnChargingEvent: + batteryController.ReadPowerState(); motorController.RunForDuration(15); - // Battery level is updated on every message - there's no need to do anything + ReloadIdleTimer(); + if (isSleeping && !isWakingUp) { + GoToRunning(); + } + break; + case Messages::MeasureBatteryTimerExpired: + batteryController.MeasureVoltage(); + break; + case Messages::BatteryPercentageUpdated: + nimbleController.NotifyBatteryLevel(batteryController.PercentRemaining()); break; default: @@ -338,22 +372,18 @@ void SystemTask::Work() { if (bleDiscoveryTimer == 0) { isBleDiscoveryTimerRunning = false; // Services discovery is deffered from 3 seconds to avoid the conflicts between the host communicating with the - // tharget and vice-versa. I'm not sure if this is the right way to handle this... + // target and vice-versa. I'm not sure if this is the right way to handle this... nimbleController.StartDiscovery(); } else { bleDiscoveryTimer--; } } - if (xTaskGetTickCount() - batteryNotificationTick > batteryNotificationPeriod) { - nimbleController.NotifyBatteryLevel(batteryController.PercentRemaining()); - batteryNotificationTick = xTaskGetTickCount(); - } - monitor.Process(); uint32_t systick_counter = nrf_rtc_counter_get(portNRF_RTC_REG); dateTimeController.UpdateTime(systick_counter); - if (!nrf_gpio_pin_read(pinButton)) + NoInit_BackUpTime = dateTimeController.CurrentDateTime(); + if (!nrf_gpio_pin_read(PinMap::Button)) watchdog.Kick(); } // Clear diagnostic suppression diff --git a/src/systemtask/SystemTask.h b/src/systemtask/SystemTask.h index 0266ba8a..879c1be8 100644 --- a/src/systemtask/SystemTask.h +++ b/src/systemtask/SystemTask.h @@ -8,6 +8,7 @@ #include <heartratetask/HeartRateTask.h> #include <components/settings/Settings.h> #include <drivers/Bma421.h> +#include <drivers/PinMap.h> #include <components/motion/MotionController.h> #include "SystemMonitor.h" @@ -16,6 +17,7 @@ #include "components/ble/NotificationManager.h" #include "components/motor/MotorController.h" #include "components/timer/TimerController.h" +#include "components/alarm/AlarmController.h" #include "components/fs/FS.h" #include "touchhandler/TouchHandler.h" @@ -31,6 +33,7 @@ #include "drivers/Watchdog.h" #include "Messages.h" +extern std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> NoInit_BackUpTime; namespace Pinetime { namespace Drivers { class Cst816S; @@ -56,6 +59,7 @@ namespace Pinetime { Controllers::Ble& bleController, Controllers::DateTime& dateTimeController, Controllers::TimerController& timerController, + Controllers::AlarmController& alarmController, Drivers::Watchdog& watchdog, Pinetime::Controllers::NotificationManager& notificationManager, Pinetime::Controllers::MotorController& motorController, @@ -100,6 +104,7 @@ namespace Pinetime { Pinetime::Controllers::Ble& bleController; Pinetime::Controllers::DateTime& dateTimeController; Pinetime::Controllers::TimerController& timerController; + Pinetime::Controllers::AlarmController& alarmController; QueueHandle_t systemTasksMsgQueue; std::atomic<bool> isSleeping {false}; std::atomic<bool> isGoingToSleep {false}; @@ -120,15 +125,6 @@ namespace Pinetime { Pinetime::Controllers::TouchHandler& touchHandler; Pinetime::Controllers::NimbleController nimbleController; - static constexpr uint8_t pinSpiSck = 2; - static constexpr uint8_t pinSpiMosi = 3; - static constexpr uint8_t pinSpiMiso = 4; - static constexpr uint8_t pinSpiCsn = 25; - static constexpr uint8_t pinLcdDataCommand = 18; - static constexpr uint8_t pinButton = 13; - static constexpr uint8_t pinTouchIrq = 28; - static constexpr uint8_t pinPowerPresentIrq = 19; - static void Process(void* instance); void Work(); void ReloadIdleTimer(); @@ -136,13 +132,13 @@ namespace Pinetime { uint8_t bleDiscoveryTimer = 0; TimerHandle_t dimTimer; TimerHandle_t idleTimer; + TimerHandle_t measureBatteryTimer; bool doNotGoToSleep = false; void GoToRunning(); void UpdateMotion(); bool stepCounterMustBeReset = false; - static constexpr TickType_t batteryNotificationPeriod = 1000 * 60 * 10; // 1 tick ~= 1ms. 1ms * 60 * 10 = 10 minutes - TickType_t batteryNotificationTick = 0; + static constexpr TickType_t batteryMeasurementPeriod = pdMS_TO_TICKS(10 * 60 * 1000); #if configUSE_TRACE_FACILITY == 1 SystemMonitor<FreeRtosMonitor> monitor; |
