summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJean-François Milants <jf@codingfield.com>2021-11-11 09:08:20 (GMT)
committerJean-François Milants <jf@codingfield.com>2021-11-11 09:08:20 (GMT)
commitf6d0ec49e6f2669c64729b081eb3342f02151f4a (patch)
tree7e21c83726bd3e0d18ec4ebe871274b1dbe2eb38 /src
parentf41aaad6836ae348d1b5b084b4533b636f516b93 (diff)
parenta57fda6ba4a29866083a1254ffdf92939d00e182 (diff)
Merge branch 'develop'
# Conflicts: # doc/buildAndProgram.md
Diffstat (limited to 'src')
-rw-r--r--src/BootErrors.h10
-rw-r--r--src/CMakeLists.txt9
-rw-r--r--src/buttonhandler/ButtonActions.h7
-rw-r--r--src/buttonhandler/ButtonHandler.cpp78
-rw-r--r--src/buttonhandler/ButtonHandler.h24
-rw-r--r--src/components/battery/BatteryController.cpp29
-rw-r--r--src/components/battery/BatteryController.h9
-rw-r--r--src/components/ble/AlertNotificationClient.cpp14
-rw-r--r--src/components/ble/AlertNotificationService.cpp11
-rw-r--r--src/components/ble/BatteryInformationService.cpp6
-rw-r--r--src/components/ble/CurrentTimeClient.cpp4
-rw-r--r--src/components/ble/CurrentTimeService.cpp4
-rw-r--r--src/components/ble/DeviceInformationService.cpp14
-rw-r--r--src/components/ble/DfuService.cpp26
-rw-r--r--src/components/ble/HeartRateService.cpp20
-rw-r--r--src/components/ble/HeartRateService.h7
-rw-r--r--src/components/ble/ImmediateAlertService.cpp6
-rw-r--r--src/components/ble/MotionService.cpp124
-rw-r--r--src/components/ble/MotionService.h39
-rw-r--r--src/components/ble/NavigationService.cpp77
-rw-r--r--src/components/ble/NavigationService.h17
-rw-r--r--src/components/ble/NimbleController.cpp18
-rw-r--r--src/components/ble/NimbleController.h5
-rw-r--r--src/components/datetime/DateTimeController.cpp44
-rw-r--r--src/components/datetime/DateTimeController.h16
-rw-r--r--src/components/fs/FS.h2
-rw-r--r--src/components/motion/MotionController.cpp11
-rw-r--r--src/components/motion/MotionController.h3
-rw-r--r--src/displayapp/Apps.h5
-rw-r--r--src/displayapp/DisplayApp.cpp69
-rw-r--r--src/displayapp/DisplayApp.h7
-rw-r--r--src/displayapp/DisplayAppRecovery.h2
-rw-r--r--src/displayapp/Messages.h3
-rw-r--r--src/displayapp/screens/Alarm.cpp19
-rw-r--r--src/displayapp/screens/Alarm.h6
-rw-r--r--src/displayapp/screens/BatteryInfo.cpp2
-rw-r--r--src/displayapp/screens/Error.cpp50
-rw-r--r--src/displayapp/screens/Error.h21
-rw-r--r--src/displayapp/screens/FlashLight.cpp114
-rw-r--r--src/displayapp/screens/FlashLight.h16
-rw-r--r--src/displayapp/screens/Paddle.cpp4
-rw-r--r--src/displayapp/screens/PineTimeStyle.cpp33
-rw-r--r--src/displayapp/screens/PineTimeStyle.h4
-rw-r--r--src/displayapp/screens/SystemInfo.cpp54
-rw-r--r--src/displayapp/screens/SystemInfo.h4
-rw-r--r--src/displayapp/screens/Twos.cpp12
-rw-r--r--src/displayapp/screens/WatchFaceAnalog.cpp29
-rw-r--r--src/displayapp/screens/WatchFaceAnalog.h2
-rw-r--r--src/displayapp/screens/WatchFaceDigital.cpp12
-rw-r--r--src/displayapp/screens/WatchFaceDigital.h1
-rw-r--r--src/displayapp/screens/settings/QuickSettings.cpp2
-rw-r--r--src/displayapp/screens/settings/SettingSetDate.cpp198
-rw-r--r--src/displayapp/screens/settings/SettingSetDate.h41
-rw-r--r--src/displayapp/screens/settings/SettingSetTime.cpp154
-rw-r--r--src/displayapp/screens/settings/SettingSetTime.h33
-rw-r--r--src/displayapp/screens/settings/Settings.cpp10
-rw-r--r--src/drivers/Cst816s.cpp69
-rw-r--r--src/drivers/Cst816s.h23
-rw-r--r--src/drivers/St7789.cpp9
-rw-r--r--src/main.cpp23
-rw-r--r--src/systemtask/Messages.h5
-rw-r--r--src/systemtask/SystemTask.cpp138
-rw-r--r--src/systemtask/SystemTask.h13
63 files changed, 1446 insertions, 375 deletions
diff --git a/src/BootErrors.h b/src/BootErrors.h
new file mode 100644
index 0000000..d00418c
--- /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 37ee084..e727b2b 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -421,6 +421,7 @@ 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
@@ -433,6 +434,8 @@ list(APPEND SOURCE_FILES
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
@@ -474,6 +477,7 @@ list(APPEND SOURCE_FILES
components/ble/ImmediateAlertService.cpp
components/ble/ServiceDiscovery.cpp
components/ble/HeartRateService.cpp
+ components/ble/MotionService.cpp
components/firmwarevalidator/FirmwareValidator.cpp
components/motor/MotorController.cpp
components/settings/Settings.cpp
@@ -503,6 +507,7 @@ list(APPEND SOURCE_FILES
components/heartrate/Ptagc.cpp
components/heartrate/HeartRateController.cpp
+ buttonhandler/ButtonHandler.cpp
touchhandler/TouchHandler.cpp
)
@@ -542,6 +547,7 @@ list(APPEND RECOVERY_SOURCE_FILES
components/ble/ServiceDiscovery.cpp
components/ble/NavigationService.cpp
components/ble/HeartRateService.cpp
+ components/ble/MotionService.cpp
components/firmwarevalidator/FirmwareValidator.cpp
components/settings/Settings.cpp
components/timer/TimerController.cpp
@@ -562,6 +568,7 @@ list(APPEND RECOVERY_SOURCE_FILES
components/heartrate/Ptagc.cpp
components/motor/MotorController.cpp
components/fs/FS.cpp
+ buttonhandler/ButtonHandler.cpp
touchhandler/TouchHandler.cpp
)
@@ -649,6 +656,7 @@ set(INCLUDE_FILES
components/ble/ServiceDiscovery.h
components/ble/BleClient.h
components/ble/HeartRateService.h
+ components/ble/MotionService.h
components/settings/Settings.h
components/timer/TimerController.h
components/alarm/AlarmController.h
@@ -675,6 +683,7 @@ set(INCLUDE_FILES
components/heartrate/Ptagc.h
components/heartrate/HeartRateController.h
components/motor/MotorController.h
+ buttonhandler/ButtonHandler.h
touchhandler/TouchHandler.h
)
diff --git a/src/buttonhandler/ButtonActions.h b/src/buttonhandler/ButtonActions.h
new file mode 100644
index 0000000..21be441
--- /dev/null
+++ b/src/buttonhandler/ButtonActions.h
@@ -0,0 +1,7 @@
+#pragma once
+
+namespace Pinetime {
+ namespace Controllers {
+ enum class ButtonActions { None, Click, DoubleClick, LongPress, LongerPress };
+ }
+}
diff --git a/src/buttonhandler/ButtonHandler.cpp b/src/buttonhandler/ButtonHandler.cpp
new file mode 100644
index 0000000..91e8bbd
--- /dev/null
+++ b/src/buttonhandler/ButtonHandler.cpp
@@ -0,0 +1,78 @@
+#include "ButtonHandler.h"
+
+using namespace Pinetime::Controllers;
+
+void ButtonTimerCallback(TimerHandle_t xTimer) {
+ auto* sysTask = static_cast<Pinetime::System::SystemTask*>(pvTimerGetTimerID(xTimer));
+ sysTask->PushMessage(Pinetime::System::Messages::HandleButtonTimerEvent);
+}
+
+void ButtonHandler::Init(Pinetime::System::SystemTask* systemTask) {
+ buttonTimer = xTimerCreate("buttonTimer", 0, pdFALSE, systemTask, ButtonTimerCallback);
+}
+
+ButtonActions ButtonHandler::HandleEvent(Events event) {
+ static constexpr TickType_t doubleClickTime = pdMS_TO_TICKS(200);
+ static constexpr TickType_t longPressTime = pdMS_TO_TICKS(400);
+ static constexpr TickType_t longerPressTime = pdMS_TO_TICKS(2000);
+
+ if (event == Events::Press) {
+ buttonPressed = true;
+ } else if (event == Events::Release) {
+ releaseTime = xTaskGetTickCount();
+ buttonPressed = false;
+ }
+
+ switch (state) {
+ case States::Idle:
+ if (event == Events::Press) {
+ xTimerChangePeriod(buttonTimer, doubleClickTime, 0);
+ xTimerStart(buttonTimer, 0);
+ state = States::Pressed;
+ }
+ break;
+ case States::Pressed:
+ if (event == Events::Press) {
+ if (xTaskGetTickCount() - releaseTime < doubleClickTime) {
+ xTimerStop(buttonTimer, 0);
+ state = States::Idle;
+ return ButtonActions::DoubleClick;
+ }
+ } else if (event == Events::Release) {
+ xTimerChangePeriod(buttonTimer, doubleClickTime, 0);
+ xTimerStart(buttonTimer, 0);
+ } else if (event == Events::Timer) {
+ if (buttonPressed) {
+ xTimerChangePeriod(buttonTimer, longPressTime - doubleClickTime, 0);
+ xTimerStart(buttonTimer, 0);
+ state = States::Holding;
+ } else {
+ state = States::Idle;
+ return ButtonActions::Click;
+ }
+ }
+ break;
+ case States::Holding:
+ if (event == Events::Release) {
+ xTimerStop(buttonTimer, 0);
+ state = States::Idle;
+ return ButtonActions::Click;
+ } else if (event == Events::Timer) {
+ xTimerChangePeriod(buttonTimer, longerPressTime - longPressTime - doubleClickTime, 0);
+ xTimerStart(buttonTimer, 0);
+ state = States::LongHeld;
+ return ButtonActions::LongPress;
+ }
+ break;
+ case States::LongHeld:
+ if (event == Events::Release) {
+ xTimerStop(buttonTimer, 0);
+ state = States::Idle;
+ } else if (event == Events::Timer) {
+ state = States::Idle;
+ return ButtonActions::LongerPress;
+ }
+ break;
+ }
+ return ButtonActions::None;
+}
diff --git a/src/buttonhandler/ButtonHandler.h b/src/buttonhandler/ButtonHandler.h
new file mode 100644
index 0000000..44b20f1
--- /dev/null
+++ b/src/buttonhandler/ButtonHandler.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include "ButtonActions.h"
+#include "systemtask/SystemTask.h"
+#include <FreeRTOS.h>
+#include <timers.h>
+
+namespace Pinetime {
+ namespace Controllers {
+ class ButtonHandler {
+ public:
+ enum class Events : uint8_t { Press, Release, Timer };
+ void Init(Pinetime::System::SystemTask* systemTask);
+ ButtonActions HandleEvent(Events event);
+
+ private:
+ enum class States : uint8_t { Idle, Pressed, Holding, LongHeld };
+ TickType_t releaseTime = 0;
+ TimerHandle_t buttonTimer;
+ bool buttonPressed = false;
+ States state = States::Idle;
+ };
+ }
+}
diff --git a/src/components/battery/BatteryController.cpp b/src/components/battery/BatteryController.cpp
index 4ef20a2..e807f03 100644
--- a/src/components/battery/BatteryController.cpp
+++ b/src/components/battery/BatteryController.cpp
@@ -13,10 +13,20 @@ Battery::Battery() {
nrf_gpio_cfg_input(PinMap::Charging, static_cast<nrf_gpio_pin_pull_t> GPIO_PIN_CNF_PULL_Disabled);
}
-void Battery::Update() {
+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::MeasureVoltage() {
+ ReadPowerState();
+
if (isReading) {
return;
}
@@ -63,18 +73,23 @@ 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;
-
- systemTask->PushMessage(System::Messages::BatteryMeasurementDone);
}
}
diff --git a/src/components/battery/BatteryController.h b/src/components/battery/BatteryController.h
index 8af27ea..5a7394c 100644
--- a/src/components/battery/BatteryController.h
+++ b/src/components/battery/BatteryController.h
@@ -10,7 +10,8 @@ namespace Pinetime {
public:
Battery();
- void Update();
+ void ReadPowerState();
+ void MeasureVoltage();
void Register(System::SystemTask* systemTask);
uint8_t PercentRemaining() const {
@@ -22,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 {
@@ -37,8 +40,10 @@ namespace Pinetime {
uint16_t voltage = 0;
uint8_t percentRemaining = 0;
+ bool isFull = false;
bool isCharging = false;
bool isPowerPresent = false;
+ bool firstMeasurement = true;
void SaadcInit();
diff --git a/src/components/ble/AlertNotificationClient.cpp b/src/components/ble/AlertNotificationClient.cpp
index c3d1d69..5e5c25c 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 d5fc7f6..56fc595 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*) &notificationEventUuid,
+ : characteristicDefinition {{.uuid = &ansCharUuid.u, .access_cb = AlertNotificationCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE},
+ {.uuid = &notificationEventUuid.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 7f17690..2917866 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 c6e6831..90d1f0c 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*) &currentTimeCharacteristicUuid), &characteristic->uuid.u) == 0) {
+ if (characteristic != nullptr && ble_uuid_cmp(&currentTimeCharacteristicUuid.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 b49be39..eefb7ec 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 cf48207..778d6e3 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 4179994..3d6416f 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 c556566..75a038a 100644
--- a/src/components/ble/HeartRateService.cpp
+++ b/src/components/ble/HeartRateService.cpp
@@ -8,7 +8,7 @@ constexpr ble_uuid16_t HeartRateService::heartRateServiceUuid;
constexpr ble_uuid16_t HeartRateService::heartRateMeasurementUuid;
namespace {
- int HeartRateServiceServiceCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
+ int HeartRateServiceCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
auto* heartRateService = static_cast<HeartRateService*>(arg);
return heartRateService->OnHeartRateRequested(conn_handle, attr_handle, ctxt);
}
@@ -18,8 +18,8 @@ namespace {
HeartRateService::HeartRateService(Pinetime::System::SystemTask& system, Controllers::HeartRateController& heartRateController)
: system {system},
heartRateController {heartRateController},
- characteristicDefinition {{.uuid = (ble_uuid_t*) &heartRateMeasurementUuid,
- .access_cb = HeartRateServiceServiceCallback,
+ characteristicDefinition {{.uuid = &heartRateMeasurementUuid.u,
+ .access_cb = HeartRateServiceCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY,
.val_handle = &heartRateMeasurementHandle},
@@ -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},
} {
@@ -56,6 +56,8 @@ int HeartRateService::OnHeartRateRequested(uint16_t connectionHandle, uint16_t a
}
void HeartRateService::OnNewHeartRateValue(uint8_t heartRateValue) {
+ if(!heartRateMeasurementNotificationEnable) return;
+
uint8_t buffer[2] = {0, heartRateController.HeartRate()}; // [0] = flags, [1] = hr value
auto* om = ble_hs_mbuf_from_flat(buffer, 2);
@@ -67,3 +69,13 @@ void HeartRateService::OnNewHeartRateValue(uint8_t heartRateValue) {
ble_gattc_notify_custom(connectionHandle, heartRateMeasurementHandle, om);
}
+
+void HeartRateService::SubscribeNotification(uint16_t connectionHandle, uint16_t attributeHandle) {
+ if(attributeHandle == heartRateMeasurementHandle)
+ heartRateMeasurementNotificationEnable = true;
+}
+
+void HeartRateService::UnsubscribeNotification(uint16_t connectionHandle, uint16_t attributeHandle) {
+ if(attributeHandle == heartRateMeasurementHandle)
+ heartRateMeasurementNotificationEnable = false;
+} \ No newline at end of file
diff --git a/src/components/ble/HeartRateService.h b/src/components/ble/HeartRateService.h
index 0b16703..4e4a5a4 100644
--- a/src/components/ble/HeartRateService.h
+++ b/src/components/ble/HeartRateService.h
@@ -2,6 +2,7 @@
#define min // workaround: nimble's min/max macros conflict with libstdc++
#define max
#include <host/ble_gap.h>
+#include <atomic>
#undef max
#undef min
@@ -18,6 +19,9 @@ namespace Pinetime {
int OnHeartRateRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context);
void OnNewHeartRateValue(uint8_t hearRateValue);
+ void SubscribeNotification(uint16_t connectionHandle, uint16_t attributeHandle);
+ void UnsubscribeNotification(uint16_t connectionHandle, uint16_t attributeHandle);
+
private:
Pinetime::System::SystemTask& system;
Controllers::HeartRateController& heartRateController;
@@ -28,10 +32,11 @@ namespace Pinetime {
static constexpr ble_uuid16_t heartRateMeasurementUuid {.u {.type = BLE_UUID_TYPE_16}, .value = heartRateMeasurementId};
- struct ble_gatt_chr_def characteristicDefinition[3];
+ struct ble_gatt_chr_def characteristicDefinition[2];
struct ble_gatt_svc_def serviceDefinition[2];
uint16_t heartRateMeasurementHandle;
+ std::atomic_bool heartRateMeasurementNotificationEnable {false};
};
}
}
diff --git a/src/components/ble/ImmediateAlertService.cpp b/src/components/ble/ImmediateAlertService.cpp
index 820d3b6..17ed1a9 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/MotionService.cpp b/src/components/ble/MotionService.cpp
new file mode 100644
index 0000000..b4786ab
--- /dev/null
+++ b/src/components/ble/MotionService.cpp
@@ -0,0 +1,124 @@
+#include "MotionService.h"
+#include "components/motion//MotionController.h"
+#include "systemtask/SystemTask.h"
+
+using namespace Pinetime::Controllers;
+
+namespace {
+ // 0002yyxx-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, 0x03, 0x00 }
+ };
+ }
+
+ // 00020000-78fc-48fe-8e23-433b3a1942d0
+ constexpr ble_uuid128_t BaseUuid() {
+ return CharUuid(0x00, 0x00);
+ }
+
+ constexpr ble_uuid128_t motionServiceUuid {BaseUuid()};
+ constexpr ble_uuid128_t stepCountCharUuid {CharUuid(0x01, 0x00)};
+ constexpr ble_uuid128_t motionValuesCharUuid {CharUuid(0x02, 0x00)};
+
+ int MotionServiceCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
+ auto* motionService = static_cast<MotionService*>(arg);
+ return motionService->OnStepCountRequested(conn_handle, attr_handle, ctxt);
+ }
+}
+
+// TODO Refactoring - remove dependency to SystemTask
+MotionService::MotionService(Pinetime::System::SystemTask& system, Controllers::MotionController& motionController)
+ : system {system},
+ motionController {motionController},
+ characteristicDefinition {{.uuid = &stepCountCharUuid.u,
+ .access_cb = MotionServiceCallback,
+ .arg = this,
+ .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY,
+ .val_handle = &stepCountHandle},
+ {.uuid = &motionValuesCharUuid.u,
+ .access_cb = MotionServiceCallback,
+ .arg = this,
+ .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY,
+ .val_handle = &motionValuesHandle},
+ {0}},
+ serviceDefinition {
+ {
+ .type = BLE_GATT_SVC_TYPE_PRIMARY,
+ .uuid = &motionServiceUuid.u,
+ .characteristics = characteristicDefinition
+ },
+ {0},
+ } {
+ // TODO refactor to prevent this loop dependency (service depends on controller and controller depends on service)
+ motionController.SetService(this);
+}
+
+void MotionService::Init() {
+ int res = 0;
+ res = ble_gatts_count_cfg(serviceDefinition);
+ ASSERT(res == 0);
+
+ res = ble_gatts_add_svcs(serviceDefinition);
+ ASSERT(res == 0);
+}
+
+int MotionService::OnStepCountRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context) {
+ if (attributeHandle == stepCountHandle) {
+ NRF_LOG_INFO("Motion-stepcount : handle = %d", stepCountHandle);
+ uint32_t buffer = motionController.NbSteps();
+
+ int res = os_mbuf_append(context->om, &buffer, 4);
+ return (res == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
+ } else if(attributeHandle == motionValuesHandle) {
+ int16_t buffer[3] = { motionController.X(), motionController.Y(), motionController.Z() };
+
+ int res = os_mbuf_append(context->om, buffer, 3 * sizeof(int16_t));
+ return (res == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
+ }
+ return 0;
+}
+
+void MotionService::OnNewStepCountValue(uint32_t stepCount) {
+ if(!stepCountNoficationEnabled) return;
+
+ uint32_t buffer = stepCount;
+ auto* om = ble_hs_mbuf_from_flat(&buffer, 4);
+
+ uint16_t connectionHandle = system.nimble().connHandle();
+
+ if (connectionHandle == 0 || connectionHandle == BLE_HS_CONN_HANDLE_NONE) {
+ return;
+ }
+
+ ble_gattc_notify_custom(connectionHandle, stepCountHandle, om);
+}
+void MotionService::OnNewMotionValues(int16_t x, int16_t y, int16_t z) {
+ if(!motionValuesNoficationEnabled) return;
+
+ int16_t buffer[3] = { motionController.X(), motionController.Y(), motionController.Z() };
+ auto* om = ble_hs_mbuf_from_flat(buffer, 3 * sizeof(int16_t));
+
+ uint16_t connectionHandle = system.nimble().connHandle();
+
+ if (connectionHandle == 0 || connectionHandle == BLE_HS_CONN_HANDLE_NONE) {
+ return;
+ }
+
+ ble_gattc_notify_custom(connectionHandle, motionValuesHandle, om);
+}
+
+void MotionService::SubscribeNotification(uint16_t connectionHandle, uint16_t attributeHandle) {
+ if(attributeHandle == stepCountHandle)
+ stepCountNoficationEnabled = true;
+ else if(attributeHandle == motionValuesHandle)
+ motionValuesNoficationEnabled = true;
+}
+
+void MotionService::UnsubscribeNotification(uint16_t connectionHandle, uint16_t attributeHandle) {
+ if(attributeHandle == stepCountHandle)
+ stepCountNoficationEnabled = false;
+ else if(attributeHandle == motionValuesHandle)
+ motionValuesNoficationEnabled = false;
+}
diff --git a/src/components/ble/MotionService.h b/src/components/ble/MotionService.h
new file mode 100644
index 0000000..1b4ac0a
--- /dev/null
+++ b/src/components/ble/MotionService.h
@@ -0,0 +1,39 @@
+#pragma once
+#define min // workaround: nimble's min/max macros conflict with libstdc++
+#define max
+#include <host/ble_gap.h>
+#include <atomic>
+#undef max
+#undef min
+
+namespace Pinetime {
+ namespace System {
+ class SystemTask;
+ }
+ namespace Controllers {
+ class MotionController;
+ class MotionService {
+ public:
+ MotionService(Pinetime::System::SystemTask& system, Controllers::MotionController& motionController);
+ void Init();
+ int OnStepCountRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context);
+ void OnNewStepCountValue(uint32_t stepCount);
+ void OnNewMotionValues(int16_t x, int16_t y, int16_t z);
+
+ void SubscribeNotification(uint16_t connectionHandle, uint16_t attributeHandle);
+ void UnsubscribeNotification(uint16_t connectionHandle, uint16_t attributeHandle);
+
+ private:
+ Pinetime::System::SystemTask& system;
+ Controllers::MotionController& motionController;
+
+ struct ble_gatt_chr_def characteristicDefinition[3];
+ struct ble_gatt_svc_def serviceDefinition[2];
+
+ uint16_t stepCountHandle;
+ uint16_t motionValuesHandle;
+ std::atomic_bool stepCountNoficationEnabled {false};
+ std::atomic_bool motionValuesNoficationEnabled {false};
+ };
+ }
+}
diff --git a/src/components/ble/NavigationService.cpp b/src/components/ble/NavigationService.cpp
index e1c20bf..b49148d 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};
-
- 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};
+ .uuid = &navFlagCharUuid.u, .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 5aab263..c0c77f3 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 879421e..1bcae1b 100644
--- a/src/components/ble/NimbleController.cpp
+++ b/src/components/ble/NimbleController.cpp
@@ -23,7 +23,8 @@ NimbleController::NimbleController(Pinetime::System::SystemTask& systemTask,
Pinetime::Controllers::NotificationManager& notificationManager,
Controllers::Battery& batteryController,
Pinetime::Drivers::SpiNorFlash& spiNorFlash,
- Controllers::HeartRateController& heartRateController)
+ Controllers::HeartRateController& heartRateController,
+ Controllers::MotionController& motionController)
: systemTask {systemTask},
bleController {bleController},
dateTimeController {dateTimeController},
@@ -39,6 +40,7 @@ NimbleController::NimbleController(Pinetime::System::SystemTask& systemTask,
batteryInformationService {batteryController},
immediateAlertService {systemTask, notificationManager},
heartRateService {systemTask, heartRateController},
+ motionService{systemTask, motionController},
serviceDiscovery({&currentTimeClient, &alertNotificationClient}) {
}
@@ -81,6 +83,7 @@ void NimbleController::Init() {
batteryInformationService.Init();
immediateAlertService.Init();
heartRateService.Init();
+ motionService.Init();
int rc;
rc = ble_hs_util_ensure_addr(0);
@@ -215,6 +218,19 @@ int NimbleController::OnGAPEvent(ble_gap_event* event) {
event->subscribe.prev_notify,
event->subscribe.cur_notify,
event->subscribe.prev_indicate);
+
+ if(event->subscribe.reason == BLE_GAP_SUBSCRIBE_REASON_TERM) {
+ heartRateService.UnsubscribeNotification(event->subscribe.conn_handle, event->subscribe.attr_handle);
+ motionService.UnsubscribeNotification(event->subscribe.conn_handle, event->subscribe.attr_handle);
+ }
+ else if(event->subscribe.prev_notify == 0 && event->subscribe.cur_notify == 1) {
+ heartRateService.SubscribeNotification(event->subscribe.conn_handle, event->subscribe.attr_handle);
+ motionService.SubscribeNotification(event->subscribe.conn_handle, event->subscribe.attr_handle);
+ }
+ else if(event->subscribe.prev_notify == 1 && event->subscribe.cur_notify == 0) {
+ heartRateService.UnsubscribeNotification(event->subscribe.conn_handle, event->subscribe.attr_handle);
+ motionService.UnsubscribeNotification(event->subscribe.conn_handle, event->subscribe.attr_handle);
+ }
break;
case BLE_GAP_EVENT_MTU:
diff --git a/src/components/ble/NimbleController.h b/src/components/ble/NimbleController.h
index 473bb1a..76f89ba 100644
--- a/src/components/ble/NimbleController.h
+++ b/src/components/ble/NimbleController.h
@@ -19,6 +19,7 @@
#include "NavigationService.h"
#include "ServiceDiscovery.h"
#include "HeartRateService.h"
+#include "MotionService.h"
namespace Pinetime {
namespace Drivers {
@@ -43,7 +44,8 @@ namespace Pinetime {
Pinetime::Controllers::NotificationManager& notificationManager,
Controllers::Battery& batteryController,
Pinetime::Drivers::SpiNorFlash& spiNorFlash,
- Controllers::HeartRateController& heartRateController);
+ Controllers::HeartRateController& heartRateController,
+ Controllers::MotionController& motionController);
void Init();
void StartAdvertising();
int OnGAPEvent(ble_gap_event* event);
@@ -95,6 +97,7 @@ namespace Pinetime {
BatteryInformationService batteryInformationService;
ImmediateAlertService immediateAlertService;
HeartRateService heartRateService;
+ MotionService motionService;
uint8_t addrType; // 1 = Random, 0 = PUBLIC
uint16_t connectionHandle = BLE_HS_CONN_HANDLE_NONE;
diff --git a/src/components/datetime/DateTimeController.cpp b/src/components/datetime/DateTimeController.cpp
index 0756d38..e9c5d87 100644
--- a/src/components/datetime/DateTimeController.cpp
+++ b/src/components/datetime/DateTimeController.cpp
@@ -5,6 +5,12 @@
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
@@ -80,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)];
+ return DaysStringShort[static_cast<uint8_t>(dayOfWeek)];
}
-const char* DateTime::DayOfWeekToStringLow() {
- return DateTime::DaysStringLow[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 061c303..77ed68e 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;
@@ -91,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 1f2eb7e..75ba16c 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/motion/MotionController.cpp b/src/components/motion/MotionController.cpp
index b0dbada..a2384d7 100644
--- a/src/components/motion/MotionController.cpp
+++ b/src/components/motion/MotionController.cpp
@@ -3,6 +3,14 @@
using namespace Pinetime::Controllers;
void MotionController::Update(int16_t x, int16_t y, int16_t z, uint32_t nbSteps) {
+ if (this->nbSteps != nbSteps && service != nullptr) {
+ service->OnNewStepCountValue(nbSteps);
+ }
+
+ if(service != nullptr && (this->x != x || this->y != y || this->z != z)) {
+ service->OnNewMotionValues(x, y, z);
+ }
+
this->x = x;
this->y = y;
this->z = z;
@@ -41,3 +49,6 @@ void MotionController::Init(Pinetime::Drivers::Bma421::DeviceTypes types) {
default: this->deviceType = DeviceTypes::Unknown; break;
}
}
+void MotionController::SetService(Pinetime::Controllers::MotionService* service) {
+ this->service = service;
+}
diff --git a/src/components/motion/MotionController.h b/src/components/motion/MotionController.h
index ff71509..c72d8a4 100644
--- a/src/components/motion/MotionController.h
+++ b/src/components/motion/MotionController.h
@@ -2,6 +2,7 @@
#include <cstdint>
#include <drivers/Bma421.h>
+#include <components/ble/MotionService.h>
namespace Pinetime {
namespace Controllers {
@@ -39,6 +40,7 @@ namespace Pinetime {
}
void Init(Pinetime::Drivers::Bma421::DeviceTypes types);
+ void SetService(Pinetime::Controllers::MotionService* service);
private:
uint32_t nbSteps;
@@ -48,6 +50,7 @@ namespace Pinetime {
int16_t lastYForWakeUp = 0;
bool isSensorOk = false;
DeviceTypes deviceType = DeviceTypes::Unknown;
+ Pinetime::Controllers::MotionService* service = nullptr;
};
}
} \ No newline at end of file
diff --git a/src/displayapp/Apps.h b/src/displayapp/Apps.h
index e3aca8c..d340efe 100644
--- a/src/displayapp/Apps.h
+++ b/src/displayapp/Apps.h
@@ -32,7 +32,10 @@ namespace Pinetime {
SettingDisplay,
SettingWakeUp,
SettingSteps,
- SettingPineTimeStyle
+ SettingPineTimeStyle,
+ SettingSetDate,
+ SettingSetTime,
+ Error,
};
}
}
diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp
index 9d47310..13ee004 100644
--- a/src/displayapp/DisplayApp.cpp
+++ b/src/displayapp/DisplayApp.cpp
@@ -29,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"
@@ -44,6 +45,8 @@
#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"
@@ -110,11 +113,16 @@ DisplayApp::DisplayApp(Drivers::St7789& lcd,
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);
@@ -141,19 +149,15 @@ void DisplayApp::InitHw() {
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;
@@ -161,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
@@ -258,6 +260,20 @@ void DisplayApp::Refresh() {
}
}
break;
+ case Messages::ButtonLongPressed:
+ if (currentApp != Apps::Clock) {
+ LoadApp(Apps::Clock, DisplayApp::FullRefreshDirections::Down);
+ }
+ break;
+ case Messages::ButtonLongerPressed:
+ // Create reboot app and open it instead
+ LoadApp(Apps::SysInfo, DisplayApp::FullRefreshDirections::Up);
+ break;
+ case Messages::ButtonDoubleClicked:
+ if (currentApp != Apps::Notifications && currentApp != Apps::NotificationsPreview) {
+ LoadApp(Apps::Notifications, DisplayApp::FullRefreshDirections::Down);
+ }
+ break;
case Messages::BleFirmwareUpdateStarted:
LoadApp(Apps::FirmwareUpdate, DisplayApp::FullRefreshDirections::Down);
@@ -279,13 +295,6 @@ void DisplayApp::Refresh() {
}
}
-void DisplayApp::RunningState() {
- if (!currentScreen->IsRunning()) {
- LoadApp(returnToApp, returnDirection);
- }
- lv_task_handler();
-}
-
void DisplayApp::StartApp(Apps app, DisplayApp::FullRefreshDirections direction) {
nextApp = app;
nextDirection = direction;
@@ -322,6 +331,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);
@@ -378,6 +392,14 @@ 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);
@@ -388,12 +410,12 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction)
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:
currentScreen = std::make_unique<Screens::FlashLight>(this, *systemTask, brightnessController);
- ReturnApp(Apps::Clock, FullRefreshDirections::Down, TouchEvents::None);
+ ReturnApp(Apps::QuickSettings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
break;
case Apps::StopWatch:
currentScreen = std::make_unique<Screens::StopWatch>(this, *systemTask);
@@ -430,9 +452,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 4254523..a87cab0 100644
--- a/src/displayapp/DisplayApp.h
+++ b/src/displayapp/DisplayApp.h
@@ -18,6 +18,7 @@
#include "touchhandler/TouchHandler.h"
#include "Messages.h"
+#include "BootErrors.h"
namespace Pinetime {
@@ -61,7 +62,7 @@ namespace Pinetime {
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);
@@ -107,8 +108,6 @@ namespace Pinetime {
TouchEvents returnTouchEvent = TouchEvents::None;
TouchEvents GetGesture();
- void RunningState();
- void IdleState();
static void Process(void* instance);
void InitHw();
void Refresh();
@@ -118,7 +117,7 @@ namespace Pinetime {
Apps nextApp = Apps::None;
DisplayApp::FullRefreshDirections nextDirection;
- TickType_t lastWakeTime;
+ System::BootErrors bootError;
};
}
}
diff --git a/src/displayapp/DisplayAppRecovery.h b/src/displayapp/DisplayAppRecovery.h
index 425e0ac..7286815 100644
--- a/src/displayapp/DisplayAppRecovery.h
+++ b/src/displayapp/DisplayAppRecovery.h
@@ -10,6 +10,7 @@
#include <date/date.h>
#include <drivers/Watchdog.h>
#include <components/motor/MotorController.h>
+#include "BootErrors.h"
#include "TouchEvents.h"
#include "Apps.h"
#include "Messages.h"
@@ -58,6 +59,7 @@ namespace Pinetime {
Pinetime::Controllers::AlarmController& alarmController,
Pinetime::Controllers::TouchHandler& touchHandler);
void Start();
+ void Start(Pinetime::System::BootErrors){ Start(); };
void PushMessage(Pinetime::Applications::Display::Messages msg);
void Register(Pinetime::System::SystemTask* systemTask);
diff --git a/src/displayapp/Messages.h b/src/displayapp/Messages.h
index d48b646..ab0a060 100644
--- a/src/displayapp/Messages.h
+++ b/src/displayapp/Messages.h
@@ -9,6 +9,9 @@ namespace Pinetime {
UpdateBleConnection,
TouchEvent,
ButtonPushed,
+ ButtonLongPressed,
+ ButtonLongerPressed,
+ ButtonDoubleClicked,
NewNotification,
TimerDone,
BleFirmwareUpdateStarted,
diff --git a/src/displayapp/screens/Alarm.cpp b/src/displayapp/screens/Alarm.cpp
index 959cb0b..6b45a36 100644
--- a/src/displayapp/screens/Alarm.cpp
+++ b/src/displayapp/screens/Alarm.cpp
@@ -120,10 +120,7 @@ void Alarm::OnButtonEvent(lv_obj_t* obj, lv_event_t event) {
return;
}
if (obj == btnMessage) {
- lv_obj_del(txtMessage);
- lv_obj_del(btnMessage);
- txtMessage = nullptr;
- btnMessage = nullptr;
+ HideInfo();
return;
}
// If any other button was pressed, disable the alarm
@@ -174,6 +171,14 @@ void Alarm::OnButtonEvent(lv_obj_t* obj, lv_event_t event) {
}
}
+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);
@@ -224,6 +229,12 @@ void Alarm::ShowInfo() {
}
}
+void Alarm::HideInfo() {
+ lv_obj_del(btnMessage);
+ txtMessage = nullptr;
+ btnMessage = nullptr;
+}
+
void Alarm::SetRecurButtonState() {
using Pinetime::Controllers::AlarmController;
switch (alarmController.Recurrence()) {
diff --git a/src/displayapp/screens/Alarm.h b/src/displayapp/screens/Alarm.h
index abf97eb..487ba1d 100644
--- a/src/displayapp/screens/Alarm.h
+++ b/src/displayapp/screens/Alarm.h
@@ -31,6 +31,7 @@ namespace Pinetime {
~Alarm() override;
void SetAlerting();
void OnButtonEvent(lv_obj_t* obj, lv_event_t event);
+ bool OnButtonPushed() override;
private:
bool running;
@@ -39,13 +40,16 @@ namespace Pinetime {
Controllers::AlarmController& alarmController;
lv_obj_t *time, *btnEnable, *txtEnable, *btnMinutesUp, *btnMinutesDown, *btnHoursUp, *btnHoursDown, *txtMinUp, *txtMinDown,
- *txtHrUp, *txtHrDown, *btnRecur, *txtRecur, *btnMessage, *txtMessage, *btnInfo, *txtInfo;
+ *txtHrUp, *txtHrDown, *btnRecur, *txtRecur, *btnInfo, *txtInfo;
+ lv_obj_t* txtMessage = nullptr;
+ lv_obj_t* btnMessage = nullptr;
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/BatteryInfo.cpp b/src/displayapp/screens/BatteryInfo.cpp
index ad9af15..44ea7f5 100644
--- a/src/displayapp/screens/BatteryInfo.cpp
+++ b/src/displayapp/screens/BatteryInfo.cpp
@@ -58,7 +58,7 @@ 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) {
diff --git a/src/displayapp/screens/Error.cpp b/src/displayapp/screens/Error.cpp
new file mode 100644
index 0000000..75946ab
--- /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 0000000..20dde7e
--- /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/FlashLight.cpp b/src/displayapp/screens/FlashLight.cpp
index 4bc5b55..dcb31a7 100644
--- a/src/displayapp/screens/FlashLight.cpp
+++ b/src/displayapp/screens/FlashLight.cpp
@@ -5,30 +5,41 @@
using namespace Pinetime::Applications::Screens;
namespace {
- static void event_handler(lv_obj_t* obj, lv_event_t event) {
- FlashLight* screen = static_cast<FlashLight*>(obj->user_data);
+ void event_handler(lv_obj_t* obj, lv_event_t event) {
+ auto* screen = static_cast<FlashLight*>(obj->user_data);
screen->OnClickEvent(obj, event);
}
}
FlashLight::FlashLight(Pinetime::Applications::DisplayApp* app,
System::SystemTask& systemTask,
- Controllers::BrightnessController& brightness)
+ Controllers::BrightnessController& brightnessController)
: Screen(app),
systemTask {systemTask},
- brightness {brightness}
+ brightnessController {brightnessController}
{
- brightness.Backup();
- brightness.Set(Controllers::BrightnessController::Levels::High);
- // Set the background
- lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xFFFFFF));
+ brightnessController.Backup();
- flashLight = lv_label_create(lv_scr_act(), NULL);
- lv_obj_set_style_local_text_color(flashLight, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
+ brightnessLevel = brightnessController.Level();
+
+ flashLight = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_font(flashLight, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &lv_font_sys_48);
lv_label_set_text_static(flashLight, Symbols::highlight);
- lv_obj_align(flashLight, NULL, LV_ALIGN_CENTER, 0, 0);
+ lv_obj_align(flashLight, nullptr, LV_ALIGN_CENTER, 0, 0);
+
+ for (auto & i : indicators) {
+ i = lv_obj_create(lv_scr_act(), nullptr);
+ lv_obj_set_size(i, 15, 10);
+ lv_obj_set_style_local_border_width(i, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, 2);
+ }
+
+ lv_obj_align(indicators[1], flashLight, LV_ALIGN_OUT_BOTTOM_MID, 0, 5);
+ lv_obj_align(indicators[0], indicators[1], LV_ALIGN_OUT_LEFT_MID, -8, 0);
+ lv_obj_align(indicators[2], indicators[1], LV_ALIGN_OUT_RIGHT_MID, 8, 0);
+
+ SetIndicators();
+ SetColors();
backgroundAction = lv_label_create(lv_scr_act(), nullptr);
lv_label_set_long_mode(backgroundAction, LV_LABEL_LONG_CROP);
@@ -44,27 +55,80 @@ FlashLight::FlashLight(Pinetime::Applications::DisplayApp* app,
FlashLight::~FlashLight() {
lv_obj_clean(lv_scr_act());
- lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
- brightness.Restore();
+ lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
+ brightnessController.Restore();
systemTask.PushMessage(Pinetime::System::Messages::EnableSleeping);
}
-void FlashLight::OnClickEvent(lv_obj_t* obj, lv_event_t event) {
- if (obj == backgroundAction) {
- if (event == LV_EVENT_CLICKED) {
- isOn = !isOn;
-
- if (isOn) {
- lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xFFFFFF));
- lv_obj_set_style_local_text_color(flashLight, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
- } else {
- lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
- lv_obj_set_style_local_text_color(flashLight, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xFFFFFF));
- }
+void FlashLight::SetColors() {
+ if (isOn) {
+ lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
+ lv_obj_set_style_local_text_color(flashLight, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
+ for (auto & i : indicators) {
+ lv_obj_set_style_local_bg_color(i, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
+ lv_obj_set_style_local_bg_color(i, LV_OBJ_PART_MAIN, LV_STATE_DISABLED, LV_COLOR_WHITE);
+ lv_obj_set_style_local_border_color(i, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
}
+ } else {
+ lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
+ lv_obj_set_style_local_text_color(flashLight, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
+ for (auto & i : indicators) {
+ lv_obj_set_style_local_bg_color(i, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
+ lv_obj_set_style_local_bg_color(i, LV_OBJ_PART_MAIN, LV_STATE_DISABLED, LV_COLOR_BLACK);
+ lv_obj_set_style_local_border_color(i, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
+ }
+ }
+}
+
+void FlashLight::SetIndicators() {
+ using namespace Pinetime::Controllers;
+
+ if (brightnessLevel == BrightnessController::Levels::High) {
+ lv_obj_set_state(indicators[1], LV_STATE_DEFAULT);
+ lv_obj_set_state(indicators[2], LV_STATE_DEFAULT);
+ } else if (brightnessLevel == BrightnessController::Levels::Medium) {
+ lv_obj_set_state(indicators[1], LV_STATE_DEFAULT);
+ lv_obj_set_state(indicators[2], LV_STATE_DISABLED);
+ } else {
+ lv_obj_set_state(indicators[1], LV_STATE_DISABLED);
+ lv_obj_set_state(indicators[2], LV_STATE_DISABLED);
+ }
+}
+
+void FlashLight::OnClickEvent(lv_obj_t* obj, lv_event_t event) {
+ if (obj == backgroundAction && event == LV_EVENT_CLICKED) {
+ isOn = !isOn;
+ SetColors();
}
}
bool FlashLight::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
+ using namespace Pinetime::Controllers;
+
+ if (event == TouchEvents::SwipeLeft) {
+ if (brightnessLevel == BrightnessController::Levels::High) {
+ brightnessLevel = BrightnessController::Levels::Medium;
+ brightnessController.Set(brightnessLevel);
+ SetIndicators();
+ } else if (brightnessLevel == BrightnessController::Levels::Medium) {
+ brightnessLevel = BrightnessController::Levels::Low;
+ brightnessController.Set(brightnessLevel);
+ SetIndicators();
+ }
+ return true;
+ }
+ if (event == TouchEvents::SwipeRight) {
+ if (brightnessLevel == BrightnessController::Levels::Low) {
+ brightnessLevel = BrightnessController::Levels::Medium;
+ brightnessController.Set(brightnessLevel);
+ SetIndicators();
+ } else if (brightnessLevel == BrightnessController::Levels::Medium) {
+ brightnessLevel = BrightnessController::Levels::High;
+ brightnessController.Set(brightnessLevel);
+ SetIndicators();
+ }
+ return true;
+ }
+
return false;
}
diff --git a/src/displayapp/screens/FlashLight.h b/src/displayapp/screens/FlashLight.h
index 7f5ca6c..f2c65bb 100644
--- a/src/displayapp/screens/FlashLight.h
+++ b/src/displayapp/screens/FlashLight.h
@@ -1,10 +1,10 @@
#pragma once
-#include <cstdint>
#include "Screen.h"
-#include <lvgl/lvgl.h>
-#include "systemtask/SystemTask.h"
#include "components/brightness/BrightnessController.h"
+#include "systemtask/SystemTask.h"
+#include <cstdint>
+#include <lvgl/lvgl.h>
namespace Pinetime {
@@ -20,12 +20,18 @@ namespace Pinetime {
void OnClickEvent(lv_obj_t* obj, lv_event_t event);
private:
+ void SetIndicators();
+ void SetColors();
+
Pinetime::System::SystemTask& systemTask;
- Controllers::BrightnessController& brightness;
+ Controllers::BrightnessController& brightnessController;
+
+ Controllers::BrightnessController::Levels brightnessLevel;
lv_obj_t* flashLight;
lv_obj_t* backgroundAction;
- bool isOn = true;
+ lv_obj_t* indicators[3];
+ bool isOn = false;
};
}
}
diff --git a/src/displayapp/screens/Paddle.cpp b/src/displayapp/screens/Paddle.cpp
index 3b6d60e..26c2368 100644
--- a/src/displayapp/screens/Paddle.cpp
+++ b/src/displayapp/screens/Paddle.cpp
@@ -47,8 +47,8 @@ void 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;
}
diff --git a/src/displayapp/screens/PineTimeStyle.cpp b/src/displayapp/screens/PineTimeStyle.cpp
index 7a712f4..fa88d45 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
@@ -100,10 +100,7 @@ PineTimeStyle::PineTimeStyle(DisplayApp* app,
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));
@@ -205,18 +202,24 @@ PineTimeStyle::~PineTimeStyle() {
lv_obj_clean(lv_scr_act());
}
+void PineTimeStyle::SetBatteryIcon() {
+ auto batteryPercent = batteryPercentRemaining.Get();
+ lv_label_set_text(batteryIcon, BatteryIcon::GetBatteryIcon(batteryPercent));
+}
+
void 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, "");
+ 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();
}
}
diff --git a/src/displayapp/screens/PineTimeStyle.h b/src/displayapp/screens/PineTimeStyle.h
index cb74ead..ba47380 100644
--- a/src/displayapp/screens/PineTimeStyle.h
+++ b/src/displayapp/screens/PineTimeStyle.h
@@ -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;
@@ -76,6 +76,8 @@ namespace Pinetime {
Controllers::Settings& settingsController;
Controllers::MotionController& motionController;
+ void SetBatteryIcon();
+
lv_task_t* taskRefresh;
};
}
diff --git a/src/displayapp/screens/SystemInfo.cpp b/src/displayapp/screens/SystemInfo.cpp
index b7a4fc6..dd223b2 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> {
@@ -141,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(),
@@ -156,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);
}
@@ -200,11 +206,14 @@ bool SystemInfo::sortById(const TaskStatus_t& lhs, const TaskStatus_t& rhs) {
}
std::unique_ptr<Screen> SystemInfo::CreateScreen4() {
- TaskStatus_t tasksStatus[10];
- lv_obj_t* infoTask = lv_table_create(lv_scr_act(), NULL);
+ static constexpr uint8_t maxTaskCount = 9;
+ TaskStatus_t tasksStatus[maxTaskCount];
+
+ lv_obj_t* infoTask = lv_table_create(lv_scr_act(), nullptr);
lv_table_set_col_cnt(infoTask, 4);
- lv_table_set_row_cnt(infoTask, 8);
- lv_obj_set_pos(infoTask, 0, 10);
+ lv_table_set_row_cnt(infoTask, maxTaskCount + 1);
+ lv_obj_set_style_local_pad_all(infoTask, LV_TABLE_PART_CELL1, LV_STATE_DEFAULT, 0);
+ lv_obj_set_style_local_border_color(infoTask, LV_TABLE_PART_CELL1, LV_STATE_DEFAULT, LV_COLOR_GRAY);
lv_table_set_cell_value(infoTask, 0, 0, "#");
lv_table_set_col_width(infoTask, 0, 30);
@@ -215,38 +224,40 @@ std::unique_ptr<Screen> SystemInfo::CreateScreen4() {
lv_table_set_cell_value(infoTask, 0, 3, "Free");
lv_table_set_col_width(infoTask, 3, 90);
- auto nb = uxTaskGetSystemState(tasksStatus, sizeof(tasksStatus) / sizeof(tasksStatus[0]), nullptr);
+ auto nb = uxTaskGetSystemState(tasksStatus, maxTaskCount, nullptr);
std::sort(tasksStatus, tasksStatus + nb, sortById);
- for (uint8_t i = 0; i < nb && i < 7; i++) {
+ for (uint8_t i = 0; i < nb && i < maxTaskCount; i++) {
+ char buffer[7] = {0};
- lv_table_set_cell_value(infoTask, i + 1, 0, std::to_string(tasksStatus[i].xTaskNumber).c_str());
- char state[2] = {0};
+ sprintf(buffer, "%lu", tasksStatus[i].xTaskNumber);
+ lv_table_set_cell_value(infoTask, i + 1, 0, buffer);
switch (tasksStatus[i].eCurrentState) {
case eReady:
case eRunning:
- state[0] = 'R';
+ buffer[0] = 'R';
break;
case eBlocked:
- state[0] = 'B';
+ buffer[0] = 'B';
break;
case eSuspended:
- state[0] = 'S';
+ buffer[0] = 'S';
break;
case eDeleted:
- state[0] = 'D';
+ buffer[0] = 'D';
break;
default:
- state[0] = 'I'; // Invalid
+ buffer[0] = 'I'; // Invalid
break;
}
- lv_table_set_cell_value(infoTask, i + 1, 1, state);
+ buffer[1] = '\0';
+ lv_table_set_cell_value(infoTask, i + 1, 1, buffer);
lv_table_set_cell_value(infoTask, i + 1, 2, tasksStatus[i].pcTaskName);
if (tasksStatus[i].usStackHighWaterMark < 20) {
- std::string str1 = std::to_string(tasksStatus[i].usStackHighWaterMark) + " low";
- lv_table_set_cell_value(infoTask, i + 1, 3, str1.c_str());
+ sprintf(buffer, "%d low", tasksStatus[i].usStackHighWaterMark);
} else {
- lv_table_set_cell_value(infoTask, i + 1, 3, std::to_string(tasksStatus[i].usStackHighWaterMark).c_str());
+ sprintf(buffer, "%d", tasksStatus[i].usStackHighWaterMark);
}
+ lv_table_set_cell_value(infoTask, i + 1, 3, buffer);
}
return std::make_unique<Screens::Label>(3, 5, app, infoTask);
}
@@ -261,7 +272,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 5eb7054..bfcc3aa 100644
--- a/src/displayapp/screens/SystemInfo.h
+++ b/src/displayapp/screens/SystemInfo.h
@@ -28,7 +28,8 @@ 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 OnTouchEvent(TouchEvents event) override;
@@ -39,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/Twos.cpp b/src/displayapp/screens/Twos.cpp
index 4201d50..d12ef90 100644
--- a/src/displayapp/screens/Twos.cpp
+++ b/src/displayapp/screens/Twos.cpp
@@ -1,10 +1,10 @@
#include "Twos.h"
-#include <lvgl/lvgl.h>
-#include <string>
-#include <charconv>
#include <array>
-#include <vector>
+#include <cstdio>
+#include <cstdlib>
+#include <lvgl/lvgl.h>
#include <utility>
+#include <vector>
using namespace Pinetime::Applications::Screens;
@@ -265,7 +265,9 @@ void Twos::updateGridDisplay(Tile grid[][4]) {
for (int row = 0; row < 4; row++) {
for (int col = 0; col < 4; col++) {
if (grid[row][col].value) {
- lv_table_set_cell_value(gridDisplay, row, col, (std::to_string(grid[row][col].value)).c_str());
+ char buffer[7];
+ sprintf(buffer, "%d", grid[row][col].value);
+ lv_table_set_cell_value(gridDisplay, row, col, buffer);
} else {
lv_table_set_cell_value(gridDisplay, row, col, "");
}
diff --git a/src/displayapp/screens/WatchFaceAnalog.cpp b/src/displayapp/screens/WatchFaceAnalog.cpp
index 75e35c1..53e7faf 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));
@@ -176,11 +177,31 @@ void WatchFaceAnalog::UpdateClock() {
}
}
+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() {
- batteryPercentRemaining = batteryController.PercentRemaining();
- if (batteryPercentRemaining.IsUpdated()) {
- auto batteryPercent = batteryPercentRemaining.Get();
- lv_label_set_text(batteryIcon, BatteryIcon::GetBatteryIcon(batteryPercent));
+ 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();
diff --git a/src/displayapp/screens/WatchFaceAnalog.h b/src/displayapp/screens/WatchFaceAnalog.h
index 406f4d5..001414a 100644
--- a/src/displayapp/screens/WatchFaceAnalog.h
+++ b/src/displayapp/screens/WatchFaceAnalog.h
@@ -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,7 @@ 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 58ab619..2ecab60 100644
--- a/src/displayapp/screens/WatchFaceDigital.cpp
+++ b/src/displayapp/screens/WatchFaceDigital.cpp
@@ -102,12 +102,20 @@ WatchFaceDigital::~WatchFaceDigital() {
}
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();
diff --git a/src/displayapp/screens/WatchFaceDigital.h b/src/displayapp/screens/WatchFaceDigital.h
index 48dc137..e27545f 100644
--- a/src/displayapp/screens/WatchFaceDigital.h
+++ b/src/displayapp/screens/WatchFaceDigital.h
@@ -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 {};
diff --git a/src/displayapp/screens/settings/QuickSettings.cpp b/src/displayapp/screens/settings/QuickSettings.cpp
index 691c40c..dd62607 100644
--- a/src/displayapp/screens/settings/QuickSettings.cpp
+++ b/src/displayapp/screens/settings/QuickSettings.cpp
@@ -131,7 +131,7 @@ void QuickSettings::OnButtonEvent(lv_obj_t* object, lv_event_t event) {
if (object == btn2 && event == LV_EVENT_CLICKED) {
running = false;
- app->StartApp(Apps::FlashLight, DisplayApp::FullRefreshDirections::None);
+ app->StartApp(Apps::FlashLight, DisplayApp::FullRefreshDirections::Up);
} else if (object == btn1 && event == LV_EVENT_CLICKED) {
diff --git a/src/displayapp/screens/settings/SettingSetDate.cpp b/src/displayapp/screens/settings/SettingSetDate.cpp
new file mode 100644
index 0000000..ba3413e
--- /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 0000000..477337f
--- /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 0000000..194bf5e
--- /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 0000000..8ba41ea
--- /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/Settings.cpp b/src/displayapp/screens/settings/Settings.cpp
index e3319f0..1daf311 100644
--- a/src/displayapp/screens/settings/Settings.cpp
+++ b/src/displayapp/screens/settings/Settings.cpp
@@ -49,9 +49,9 @@ std::unique_ptr<Screen> Settings::CreateScreen2() {
std::array<Screens::List::Applications, 4> applications {{
{Symbols::shoe, "Steps", Apps::SettingSteps},
- {Symbols::batteryHalf, "Battery", Apps::BatteryInfo},
- {Symbols::paintbrush, "PTS Colors", Apps::SettingPineTimeStyle},
- {Symbols::check, "Firmware", Apps::FirmwareValidation},
+ {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);
@@ -60,10 +60,10 @@ std::unique_ptr<Screen> Settings::CreateScreen2() {
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},
- {Symbols::none, "None", Apps::None},
- {Symbols::none, "None", Apps::None},
}};
return std::make_unique<Screens::List>(2, 3, app, settingsController, applications);
diff --git a/src/drivers/Cst816s.cpp b/src/drivers/Cst816s.cpp
index 1ff163b..4aac19f 100644
--- a/src/drivers/Cst816s.cpp
+++ b/src/drivers/Cst816s.cpp
@@ -18,10 +18,8 @@ using namespace Pinetime::Drivers;
Cst816S::Cst816S(TwiMaster& twiMaster, uint8_t twiAddress) : twiMaster {twiMaster}, twiAddress {twiAddress} {
}
-void Cst816S::Init() {
+bool Cst816S::Init() {
nrf_gpio_cfg_output(PinMap::Cst816sReset);
- nrf_gpio_pin_set(PinMap::Cst816sReset);
- vTaskDelay(50);
nrf_gpio_pin_clear(PinMap::Cst816sReset);
vTaskDelay(5);
nrf_gpio_pin_set(PinMap::Cst816sReset);
@@ -34,6 +32,18 @@ void Cst816S::Init() {
twiMaster.Read(twiAddress, 0xa7, &dummy, 1);
vTaskDelay(5);
+ static constexpr uint8_t maxRetries = 3;
+ bool isDeviceOk;
+ uint8_t retries = 0;
+ do {
+ isDeviceOk = CheckDeviceIds();
+ retries++;
+ } while (!isDeviceOk && retries < maxRetries);
+
+ if (!isDeviceOk) {
+ return false;
+ }
+
/*
[2] EnConLR - Continuous operation can slide around
[1] EnConUD - Slide up and down to enable continuous operation
@@ -51,10 +61,13 @@ void Cst816S::Init() {
*/
static constexpr uint8_t irqCtl = 0b01110000;
twiMaster.Write(twiAddress, 0xFA, &irqCtl, 1);
+
+ return true;
}
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) {
@@ -62,21 +75,35 @@ Cst816S::TouchInfos Cst816S::GetTouchInfo() {
return info;
}
- auto nbTouchPoints = touchData[2] & 0x0f;
-
- auto xHigh = touchData[touchXHighIndex] & 0x0f;
- auto xLow = touchData[touchXLowIndex];
+ // This can only be 0 or 1
+ uint8_t nbTouchPoints = touchData[touchPointNumIndex] & 0x0f;
+ uint8_t xHigh = touchData[touchXHighIndex] & 0x0f;
+ uint8_t xLow = touchData[touchXLowIndex];
uint16_t x = (xHigh << 8) | xLow;
-
- auto yHigh = touchData[touchYHighIndex] & 0x0f;
- auto yLow = touchData[touchYLowIndex];
+ uint8_t yHigh = touchData[touchYHighIndex] & 0x0f;
+ uint8_t yLow = touchData[touchYLowIndex];
uint16_t y = (yHigh << 8) | yLow;
+ Gestures gesture = static_cast<Gestures>(touchData[gestureIndex]);
+
+ // Validity check
+ if(x >= maxX || y >= maxY ||
+ (gesture != Gestures::None &&
+ gesture != Gestures::SlideDown &&
+ gesture != Gestures::SlideUp &&
+ gesture != Gestures::SlideLeft &&
+ gesture != Gestures::SlideRight &&
+ gesture != Gestures::SingleTap &&
+ gesture != Gestures::DoubleTap &&
+ gesture != Gestures::LongPress)) {
+ info.isValid = false;
+ return info;
+ }
info.x = x;
info.y = y;
info.touching = (nbTouchPoints > 0);
- info.gesture = static_cast<Gestures>(touchData[gestureIndex]);
-
+ info.gesture = gesture;
+ info.isValid = true;
return info;
}
@@ -94,3 +121,21 @@ void Cst816S::Wakeup() {
Init();
NRF_LOG_INFO("[TOUCHPANEL] Wakeup");
}
+
+bool Cst816S::CheckDeviceIds() {
+ // 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;
+}
diff --git a/src/drivers/Cst816s.h b/src/drivers/Cst816s.h
index 7b46c5d..507dd4f 100644
--- a/src/drivers/Cst816s.h
+++ b/src/drivers/Cst816s.h
@@ -21,7 +21,7 @@ namespace Pinetime {
uint16_t y = 0;
Gestures gesture = Gestures::None;
bool touching = false;
- bool isValid = true;
+ bool isValid = false;
};
Cst816S(TwiMaster& twiMaster, uint8_t twiAddress);
@@ -30,12 +30,23 @@ 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:
+ bool CheckDeviceIds();
+
// Unused/Unavailable commented out
static constexpr uint8_t gestureIndex = 1;
static constexpr uint8_t touchPointNumIndex = 2;
@@ -49,9 +60,15 @@ namespace Pinetime {
//static constexpr uint8_t touchXYIndex = 7;
//static constexpr uint8_t touchMiscIndex = 8;
- uint8_t touchData[7];
+ static constexpr uint8_t maxX = 240;
+ static constexpr uint8_t maxY = 240;
+
TwiMaster& twiMaster;
uint8_t twiAddress;
+
+ uint8_t chipId;
+ uint8_t vendorId;
+ uint8_t fwVersion;
};
}
diff --git a/src/drivers/St7789.cpp b/src/drivers/St7789.cpp
index 0f1dc02..4d81cf2 100644
--- a/src/drivers/St7789.cpp
+++ b/src/drivers/St7789.cpp
@@ -170,16 +170,7 @@ void St7789::Sleep() {
void St7789::Wakeup() {
nrf_gpio_cfg_output(pinDataCommand);
- // TODO why do we need to reset the controller?
- HardwareReset();
- SoftwareReset();
SleepOut();
- ColMod();
- MemoryDataAccessControl();
- ColumnAddressSet();
- RowAddressSet();
- DisplayInversionOn();
- NormalModeOn();
VerticalScrollStartAddress(verticalScrollingStartAddress);
DisplayOn();
NRF_LOG_INFO("[LCD] Wakeup")
diff --git a/src/main.cpp b/src/main.cpp
index fc77235..53f78ce 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -47,6 +47,7 @@
#include "systemtask/SystemTask.h"
#include "drivers/PinMap.h"
#include "touchhandler/TouchHandler.h"
+#include "buttonhandler/ButtonHandler.h"
#if NRF_LOG_ENABLED
#include "logging/NrfLogger.h"
@@ -96,8 +97,6 @@ TimerHandle_t debounceTimer;
TimerHandle_t debounceChargeTimer;
Pinetime::Controllers::Battery batteryController;
Pinetime::Controllers::Ble bleController;
-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);
@@ -110,6 +109,7 @@ Pinetime::Controllers::MotionController motionController;
Pinetime::Controllers::TimerController timerController;
Pinetime::Controllers::AlarmController alarmController {dateTimeController};
Pinetime::Controllers::TouchHandler touchHandler(touchPanel, lvgl);
+Pinetime::Controllers::ButtonHandler buttonHandler;
Pinetime::Controllers::FS fs {spiNorFlash};
Pinetime::Controllers::Settings settingsController {fs};
@@ -153,7 +153,8 @@ Pinetime::System::SystemTask systemTask(spi,
displayApp,
heartRateApp,
fs,
- touchHandler);
+ touchHandler,
+ buttonHandler);
/* Variable Declarations for variables in noinit SRAM
Increment NoInit_MagicValue upon adding variables to this area
@@ -176,11 +177,10 @@ void nrfx_gpiote_evt_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action
if (pin == Pinetime::PinMap::PowerPresent and action == NRF_GPIOTE_POLARITY_TOGGLE) {
xTimerStartFromISR(debounceChargeTimer, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
- return;
+ } else if (pin == Pinetime::PinMap::Button) {
+ xTimerStartFromISR(debounceTimer, &xHigherPriorityTaskWoken);
+ portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
-
- xTimerStartFromISR(debounceTimer, &xHigherPriorityTaskWoken);
- portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
void DebounceTimerChargeCallback(TimerHandle_t xTimer) {
@@ -188,9 +188,8 @@ void DebounceTimerChargeCallback(TimerHandle_t xTimer) {
systemTask.PushMessage(Pinetime::System::Messages::OnChargingEvent);
}
-void DebounceTimerCallback(TimerHandle_t xTimer) {
- xTimerStop(xTimer, 0);
- systemTask.OnButtonPushed();
+void DebounceTimerCallback(TimerHandle_t /*unused*/) {
+ systemTask.PushMessage(Pinetime::System::Messages::HandleButtonEvent);
}
void SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler(void) {
@@ -319,8 +318,8 @@ int main(void) {
}
nrf_gpio_cfg_default(Pinetime::PinMap::TwiScl);
- debounceTimer = xTimerCreate("debounceTimer", 200, pdFALSE, (void*) 0, DebounceTimerCallback);
- debounceChargeTimer = xTimerCreate("debounceTimerCharge", 200, pdFALSE, (void*) 0, DebounceTimerChargeCallback);
+ debounceTimer = xTimerCreate("debounceTimer", 10, pdFALSE, nullptr, DebounceTimerCallback);
+ debounceChargeTimer = xTimerCreate("debounceTimerCharge", 200, pdFALSE, nullptr, DebounceTimerChargeCallback);
// retrieve version stored by bootloader
Pinetime::BootloaderVersion::SetVersion(NRF_TIMER2->CC[0]);
diff --git a/src/systemtask/Messages.h b/src/systemtask/Messages.h
index bd1de23..b714270 100644
--- a/src/systemtask/Messages.h
+++ b/src/systemtask/Messages.h
@@ -15,7 +15,8 @@ namespace Pinetime {
BleFirmwareUpdateStarted,
BleFirmwareUpdateFinished,
OnTouchEvent,
- OnButtonEvent,
+ HandleButtonEvent,
+ HandleButtonTimerEvent,
OnDisplayTaskSleeping,
EnableSleeping,
DisableSleeping,
@@ -24,7 +25,7 @@ namespace Pinetime {
SetOffAlarm,
StopRinging,
MeasureBatteryTimerExpired,
- BatteryMeasurementDone,
+ BatteryPercentageUpdated,
};
}
}
diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp
index 5441c16..4b03f9a 100644
--- a/src/systemtask/SystemTask.cpp
+++ b/src/systemtask/SystemTask.cpp
@@ -23,7 +23,7 @@
#include "drivers/Hrs3300.h"
#include "drivers/PinMap.h"
#include "main.h"
-
+#include "BootErrors.h"
#include <memory>
@@ -76,7 +76,8 @@ SystemTask::SystemTask(Drivers::SpiMaster& spi,
Pinetime::Applications::DisplayApp& displayApp,
Pinetime::Applications::HeartRateTask& heartRateApp,
Pinetime::Controllers::FS& fs,
- Pinetime::Controllers::TouchHandler& touchHandler)
+ Pinetime::Controllers::TouchHandler& touchHandler,
+ Pinetime::Controllers::ButtonHandler& buttonHandler)
: spi {spi},
lcd {lcd},
spiNorFlash {spiNorFlash},
@@ -100,7 +101,15 @@ SystemTask::SystemTask(Drivers::SpiMaster& spi,
heartRateApp(heartRateApp),
fs {fs},
touchHandler {touchHandler},
- nimbleController(*this, bleController, dateTimeController, notificationManager, batteryController, spiNorFlash, heartRateController) {
+ buttonHandler {buttonHandler},
+ nimbleController(*this,
+ bleController,
+ dateTimeController,
+ notificationManager,
+ batteryController,
+ spiNorFlash,
+ heartRateController,
+ motionController) {
}
void SystemTask::Start() {
@@ -116,6 +125,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()));
@@ -133,10 +144,17 @@ void SystemTask::Work() {
lcd.Init();
twiMaster.Init();
+ /*
+ * TODO We disable this warning message until we ensure it won't be displayed
+ * on legitimate PineTime equipped with a compatible touch controller.
+ * (some users reported false positive). See https://github.com/InfiniTimeOrg/InfiniTime/issues/763
+ if (!touchPanel.Init()) {
+ bootError = BootErrors::TouchController;
+ }
+ */
touchPanel.Init();
dateTimeController.Register(this);
batteryController.Register(this);
- batteryController.Update();
motorController.Init();
motionSensor.SoftReset();
timerController.Register(this);
@@ -152,25 +170,29 @@ void SystemTask::Work() {
settingsController.Init();
displayApp.Register(this);
- displayApp.Start();
+ displayApp.Start(bootError);
heartRateSensor.Init();
heartRateSensor.Disable();
heartRateApp.Start();
- nrf_gpio_cfg_sense_input(PinMap::Button, (nrf_gpio_pin_pull_t) GPIO_PIN_CNF_PULL_Pulldown, (nrf_gpio_pin_sense_t) GPIO_PIN_CNF_SENSE_High);
+ buttonHandler.Init(this);
+
+ // 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(PinMap::Button, &pinConfig, nrfx_gpiote_evt_handler);
+ nrfx_gpiote_in_event_enable(PinMap::Button, true);
+ // 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;
@@ -181,18 +203,16 @@ void SystemTask::Work() {
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;
+ 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(PinMap::PowerPresent)) {
- nrf_gpio_cfg_sense_input(PinMap::PowerPresent, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_SENSE_LOW);
- } else {
- nrf_gpio_cfg_sense_input(PinMap::PowerPresent, 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);
@@ -246,12 +266,13 @@ void SystemTask::Work() {
isDimmed = false;
break;
case Messages::TouchWakeUp: {
- if(touchHandler.GetNewTouchInfo()) {
+ 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)))) {
+ 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();
}
}
@@ -272,6 +293,8 @@ void SystemTask::Work() {
if (settingsController.GetNotificationStatus() == Pinetime::Controllers::Settings::Notification::ON) {
if (isSleeping && !isWakingUp) {
GoToRunning();
+ } else {
+ ReloadIdleTimer();
}
displayApp.PushMessage(Pinetime::Applications::Display::Messages::NewNotification);
}
@@ -318,10 +341,25 @@ void SystemTask::Work() {
ReloadIdleTimer();
displayApp.PushMessage(Pinetime::Applications::Display::Messages::TouchEvent);
break;
- case Messages::OnButtonEvent:
- ReloadIdleTimer();
- displayApp.PushMessage(Pinetime::Applications::Display::Messages::ButtonPushed);
- break;
+ case Messages::HandleButtonEvent: {
+ Controllers::ButtonActions action;
+ if (nrf_gpio_pin_read(Pinetime::PinMap::Button) == 0) {
+ action = buttonHandler.HandleEvent(Controllers::ButtonHandler::Events::Release);
+ } else {
+ action = buttonHandler.HandleEvent(Controllers::ButtonHandler::Events::Press);
+ // This is for faster wakeup, sacrificing special longpress and doubleclick handling while sleeping
+ if (IsSleeping()) {
+ fastWakeUpDone = true;
+ GoToRunning();
+ break;
+ }
+ }
+ HandleButtonAction(action);
+ } break;
+ case Messages::HandleButtonTimerEvent: {
+ auto action = buttonHandler.HandleEvent(Controllers::ButtonHandler::Events::Timer);
+ HandleButtonAction(action);
+ } break;
case Messages::OnDisplayTaskSleeping:
if (BootloaderVersion::IsValid()) {
// First versions of the bootloader do not expose their version and cannot initialize the SPI NOR FLASH
@@ -345,18 +383,18 @@ void SystemTask::Work() {
stepCounterMustBeReset = true;
break;
case Messages::OnChargingEvent:
- batteryController.Update();
+ batteryController.ReadPowerState();
motorController.RunForDuration(15);
+ ReloadIdleTimer();
+ if (isSleeping && !isWakingUp) {
+ GoToRunning();
+ }
break;
case Messages::MeasureBatteryTimerExpired:
- sendBatteryNotification = true;
- batteryController.Update();
+ batteryController.MeasureVoltage();
break;
- case Messages::BatteryMeasurementDone:
- if (sendBatteryNotification) {
- sendBatteryNotification = false;
- nimbleController.NotifyBatteryLevel(batteryController.PercentRemaining());
- }
+ case Messages::BatteryPercentageUpdated:
+ nimbleController.NotifyBatteryLevel(batteryController.PercentRemaining());
break;
default:
@@ -406,18 +444,36 @@ void SystemTask::UpdateMotion() {
}
}
-void SystemTask::OnButtonPushed() {
- if (isGoingToSleep)
+void SystemTask::HandleButtonAction(Controllers::ButtonActions action) {
+ if (IsSleeping()) {
return;
- if (!isSleeping) {
- NRF_LOG_INFO("[systemtask] Button pushed");
- PushMessage(Messages::OnButtonEvent);
- } else {
- if (!isWakingUp) {
- NRF_LOG_INFO("[systemtask] Button pushed, waking up");
- GoToRunning();
- }
}
+
+ ReloadIdleTimer();
+
+ using Actions = Controllers::ButtonActions;
+
+ switch (action) {
+ case Actions::Click:
+ // If the first action after fast wakeup is a click, it should be ignored.
+ if (!fastWakeUpDone && !isGoingToSleep) {
+ displayApp.PushMessage(Applications::Display::Messages::ButtonPushed);
+ }
+ break;
+ case Actions::DoubleClick:
+ displayApp.PushMessage(Applications::Display::Messages::ButtonDoubleClicked);
+ break;
+ case Actions::LongPress:
+ displayApp.PushMessage(Applications::Display::Messages::ButtonLongPressed);
+ break;
+ case Actions::LongerPress:
+ displayApp.PushMessage(Applications::Display::Messages::ButtonLongerPressed);
+ break;
+ default:
+ return;
+ }
+
+ fastWakeUpDone = false;
}
void SystemTask::GoToRunning() {
diff --git a/src/systemtask/SystemTask.h b/src/systemtask/SystemTask.h
index 1fcfeb8..412878b 100644
--- a/src/systemtask/SystemTask.h
+++ b/src/systemtask/SystemTask.h
@@ -20,6 +20,8 @@
#include "components/alarm/AlarmController.h"
#include "components/fs/FS.h"
#include "touchhandler/TouchHandler.h"
+#include "buttonhandler/ButtonHandler.h"
+#include "buttonhandler/ButtonActions.h"
#ifdef PINETIME_IS_RECOVERY
#include "displayapp/DisplayAppRecovery.h"
@@ -45,6 +47,7 @@ namespace Pinetime {
}
namespace Controllers {
class TouchHandler;
+ class ButtonHandler;
}
namespace System {
class SystemTask {
@@ -71,12 +74,12 @@ namespace Pinetime {
Pinetime::Applications::DisplayApp& displayApp,
Pinetime::Applications::HeartRateTask& heartRateApp,
Pinetime::Controllers::FS& fs,
- Pinetime::Controllers::TouchHandler& touchHandler);
+ Pinetime::Controllers::TouchHandler& touchHandler,
+ Pinetime::Controllers::ButtonHandler& buttonHandler);
void Start();
void PushMessage(Messages msg);
- void OnButtonPushed();
void OnTouchEvent();
void OnIdle();
@@ -123,6 +126,7 @@ namespace Pinetime {
Pinetime::Applications::HeartRateTask& heartRateApp;
Pinetime::Controllers::FS& fs;
Pinetime::Controllers::TouchHandler& touchHandler;
+ Pinetime::Controllers::ButtonHandler& buttonHandler;
Pinetime::Controllers::NimbleController nimbleController;
static void Process(void* instance);
@@ -133,14 +137,15 @@ namespace Pinetime {
TimerHandle_t dimTimer;
TimerHandle_t idleTimer;
TimerHandle_t measureBatteryTimer;
- bool sendBatteryNotification = false;
bool doNotGoToSleep = false;
+ void HandleButtonAction(Controllers::ButtonActions action);
+ bool fastWakeUpDone = false;
+
void GoToRunning();
void UpdateMotion();
bool stepCounterMustBeReset = false;
static constexpr TickType_t batteryMeasurementPeriod = pdMS_TO_TICKS(10 * 60 * 1000);
- TickType_t lastBatteryNotificationTime = 0;
#if configUSE_TRACE_FACILITY == 1
SystemMonitor<FreeRtosMonitor> monitor;