Reformatted all the files according to clang-format style

This commit is contained in:
Avamander 2021-04-18 20:28:14 +03:00
parent e56ebb8bd6
commit 40d45d923b
179 changed files with 10119 additions and 10688 deletions

View File

@ -1,6 +1,6 @@
--- ---
Language: Cpp Language: Cpp
AccessModifierOffset: -2 AccessModifierOffset: 2
AlignAfterOpenBracket: Align AlignAfterOpenBracket: Align
AlignConsecutiveMacros: true AlignConsecutiveMacros: true
AlignConsecutiveAssignments: false AlignConsecutiveAssignments: false
@ -21,8 +21,8 @@ AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: MultiLine AlwaysBreakTemplateDeclarations: MultiLine
BinPackArguments: true BinPackArguments: false
BinPackParameters: true BinPackParameters: false
BraceWrapping: BraceWrapping:
AfterCaseLabel: false AfterCaseLabel: false
AfterClass: false AfterClass: false
@ -52,14 +52,14 @@ BreakStringLiterals: true
ColumnLimit: 140 ColumnLimit: 140
CommentPragmas: '^ IWYU pragma:' CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 2 ConstructorInitializerIndentWidth: 2
ContinuationIndentWidth: 2 ContinuationIndentWidth: 2
Cpp11BracedListStyle: true Cpp11BracedListStyle: true
DeriveLineEnding: false DeriveLineEnding: false
DerivePointerAlignment: false DerivePointerAlignment: false
DisableFormat: false DisableFormat: false
ExperimentalAutoDetectBinPacking: false ExperimentalAutoDetectBinPacking: true
FixNamespaceComments: false FixNamespaceComments: false
ForEachMacros: ForEachMacros:
- foreach - foreach
@ -90,10 +90,6 @@ MacroBlockBegin: ''
MacroBlockEnd: '' MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1 MaxEmptyLinesToKeep: 1
NamespaceIndentation: All NamespaceIndentation: All
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2 PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19 PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300 PenaltyBreakComment: 300

View File

@ -75,7 +75,7 @@ As of now, here is the list of achievements of this project:
- [Flash, upgrade (OTA), time synchronization,...](doc/gettingStarted/gettingStarted.md) - [Flash, upgrade (OTA), time synchronization,...](doc/gettingStarted/gettingStarted.md)
### Develop ### Develop
- [Generate the fonts and symbols](src/displayapp/fonts/Readme.md) - [Generate the fonts and symbols](src/displayapp/fonts/README.md)
- [Creating a stopwatch in Pinetime(article)](https://pankajraghav.com/2021/04/03/PINETIME-STOPCLOCK.html) - [Creating a stopwatch in Pinetime(article)](https://pankajraghav.com/2021/04/03/PINETIME-STOPCLOCK.html)
### Build, flash and debug ### Build, flash and debug

View File

@ -17,7 +17,7 @@ uint32_t BootloaderVersion::Patch() {
return 0; return 0;
} }
const char *BootloaderVersion::VersionString() { const char* BootloaderVersion::VersionString() {
return "0.0.0"; return "0.0.0";
} }

View File

@ -26,12 +26,11 @@
* 1 tab == 4 spaces! * 1 tab == 4 spaces!
*/ */
#ifndef FREERTOS_CONFIG_H #ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H #define FREERTOS_CONFIG_H
#ifdef SOFTDEVICE_PRESENT #ifdef SOFTDEVICE_PRESENT
#include "nrf_soc.h" #include "nrf_soc.h"
#endif #endif
#include "app_util_platform.h" #include "app_util_platform.h"
@ -59,12 +58,12 @@
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 #define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
#define configUSE_TICKLESS_IDLE 1 #define configUSE_TICKLESS_IDLE 1
#define configUSE_TICKLESS_IDLE_SIMPLE_DEBUG 0 /* See into vPortSuppressTicksAndSleep source code for explanation */ #define configUSE_TICKLESS_IDLE_SIMPLE_DEBUG 0 /* See into vPortSuppressTicksAndSleep source code for explanation */
#define configCPU_CLOCK_HZ ( SystemCoreClock ) #define configCPU_CLOCK_HZ (SystemCoreClock)
#define configTICK_RATE_HZ 1024 #define configTICK_RATE_HZ 1024
#define configMAX_PRIORITIES ( 3 ) #define configMAX_PRIORITIES (3)
#define configMINIMAL_STACK_SIZE ( 120 ) #define configMINIMAL_STACK_SIZE (120)
#define configTOTAL_HEAP_SIZE ( 1024*16 ) #define configTOTAL_HEAP_SIZE (1024 * 16)
#define configMAX_TASK_NAME_LEN ( 4 ) #define configMAX_TASK_NAME_LEN (4)
#define configUSE_16_BIT_TICKS 0 #define configUSE_16_BIT_TICKS 0
#define configIDLE_SHOULD_YIELD 1 #define configIDLE_SHOULD_YIELD 1
#define configUSE_MUTEXES 1 #define configUSE_MUTEXES 1
@ -90,23 +89,22 @@
/* Co-routine definitions. */ /* Co-routine definitions. */
#define configUSE_CO_ROUTINES 0 #define configUSE_CO_ROUTINES 0
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) #define configMAX_CO_ROUTINE_PRIORITIES (2)
/* Software timer definitions. */ /* Software timer definitions. */
#define configUSE_TIMERS 1 #define configUSE_TIMERS 1
#define configTIMER_TASK_PRIORITY ( 0 ) #define configTIMER_TASK_PRIORITY (0)
#define configTIMER_QUEUE_LENGTH 32 #define configTIMER_QUEUE_LENGTH 32
#define configTIMER_TASK_STACK_DEPTH ( 300 ) #define configTIMER_TASK_STACK_DEPTH (300)
/* Tickless Idle configuration. */ /* Tickless Idle configuration. */
#define configEXPECTED_IDLE_TIME_BEFORE_SLEEP 2 #define configEXPECTED_IDLE_TIME_BEFORE_SLEEP 2
/* Tickless idle/low power functionality. */ /* Tickless idle/low power functionality. */
/* Define to trap errors during development. */ /* Define to trap errors during development. */
#if defined(DEBUG_NRF) || defined(DEBUG_NRF_USER) #if defined(DEBUG_NRF) || defined(DEBUG_NRF_USER)
#define configASSERT( x ) ASSERT(x) #define configASSERT(x) ASSERT(x)
#endif #endif
/* FreeRTOS MPU specific definitions. */ /* FreeRTOS MPU specific definitions. */
@ -140,7 +138,6 @@ INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
PRIORITY THAN THIS! (higher priorities are lower numeric values. */ PRIORITY THAN THIS! (higher priorities are lower numeric values. */
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY _PRIO_APP_HIGH #define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY _PRIO_APP_HIGH
/* Interrupt priorities used by the kernel port layer itself. These are generic /* Interrupt priorities used by the kernel port layer itself. These are generic
to all Cortex-M ports, and do not rely on any particular library functions. */ to all Cortex-M ports, and do not rely on any particular library functions. */
#define configKERNEL_INTERRUPT_PRIORITY configLIBRARY_LOWEST_INTERRUPT_PRIORITY #define configKERNEL_INTERRUPT_PRIORITY configLIBRARY_LOWEST_INTERRUPT_PRIORITY
@ -154,7 +151,6 @@ standard names - or at least those used in the unmodified vector table. */
#define vPortSVCHandler SVC_Handler #define vPortSVCHandler SVC_Handler
#define xPortPendSVHandler PendSV_Handler #define xPortPendSVHandler PendSV_Handler
/*----------------------------------------------------------- /*-----------------------------------------------------------
* Settings that are generated automatically * Settings that are generated automatically
* basing on the settings above * basing on the settings above
@ -164,7 +160,7 @@ standard names - or at least those used in the unmodified vector table. */
// to CPU clock source // to CPU clock source
#define xPortSysTickHandler SysTick_Handler #define xPortSysTickHandler SysTick_Handler
#elif (configTICK_SOURCE == FREERTOS_USE_RTC) #elif (configTICK_SOURCE == FREERTOS_USE_RTC)
#define configSYSTICK_CLOCK_HZ ( 32768UL ) #define configSYSTICK_CLOCK_HZ (32768UL)
#define xPortSysTickHandler RTC1_IRQHandler #define xPortSysTickHandler RTC1_IRQHandler
#else #else
#error Unsupported configTICK_SOURCE value #error Unsupported configTICK_SOURCE value
@ -187,7 +183,7 @@ standard names - or at least those used in the unmodified vector table. */
/* Access to current system core clock is required only if we are ticking the system by systimer */ /* Access to current system core clock is required only if we are ticking the system by systimer */
#if (configTICK_SOURCE == FREERTOS_USE_SYSTICK) #if (configTICK_SOURCE == FREERTOS_USE_SYSTICK)
#include <stdint.h> #include <stdint.h>
extern uint32_t SystemCoreClock; extern uint32_t SystemCoreClock;
#endif #endif
#endif /* !assembler */ #endif /* !assembler */
@ -198,9 +194,9 @@ standard names - or at least those used in the unmodified vector table. */
* one or more RTC ticks are lost. The tick interrupt inside RTOS will detect this and make a correction needed. This is needed * one or more RTC ticks are lost. The tick interrupt inside RTOS will detect this and make a correction needed. This is needed
* for the RTOS internal timers to be more accurate. * for the RTOS internal timers to be more accurate.
* 1. The auto correction for RTOS tick is disabled even though few RTC tick interrupts were lost. This feature is desirable when debugging * 1. The auto correction for RTOS tick is disabled even though few RTC tick interrupts were lost. This feature is desirable when debugging
* the RTOS application and stepping though the code. After stepping when the application is continued in debug mode, the auto-corrections of * the RTOS application and stepping though the code. After stepping when the application is continued in debug mode, the
* RTOS tick might cause asserts. Setting configUSE_DISABLE_TICK_AUTO_CORRECTION_DEBUG to 1 will make RTC and RTOS go out of sync but could be * auto-corrections of RTOS tick might cause asserts. Setting configUSE_DISABLE_TICK_AUTO_CORRECTION_DEBUG to 1 will make RTC and RTOS go
* convenient for debugging. * out of sync but could be convenient for debugging.
*/ */
#define configUSE_DISABLE_TICK_AUTO_CORRECTION_DEBUG 0 #define configUSE_DISABLE_TICK_AUTO_CORRECTION_DEBUG 0

View File

@ -7,15 +7,15 @@
using namespace Pinetime::Controllers; using namespace Pinetime::Controllers;
Battery *Battery::instance = nullptr; Battery* Battery::instance = nullptr;
Battery::Battery() { Battery::Battery() {
instance = this; instance = this;
} }
void Battery::Init() { void Battery::Init() {
nrf_gpio_cfg_input(chargingPin, (nrf_gpio_pin_pull_t)GPIO_PIN_CNF_PULL_Pullup); nrf_gpio_cfg_input(chargingPin, (nrf_gpio_pin_pull_t) GPIO_PIN_CNF_PULL_Pullup);
nrf_gpio_cfg_input(powerPresentPin, (nrf_gpio_pin_pull_t)GPIO_PIN_CNF_PULL_Pullup); nrf_gpio_cfg_input(powerPresentPin, (nrf_gpio_pin_pull_t) GPIO_PIN_CNF_PULL_Pullup);
} }
void Battery::Update() { void Battery::Update() {
@ -23,17 +23,17 @@ void Battery::Update() {
isCharging = !nrf_gpio_pin_read(chargingPin); isCharging = !nrf_gpio_pin_read(chargingPin);
isPowerPresent = !nrf_gpio_pin_read(powerPresentPin); isPowerPresent = !nrf_gpio_pin_read(powerPresentPin);
if ( isReading ) return; if (isReading)
return;
// Non blocking read // Non blocking read
samples = 0; samples = 0;
isReading = true; isReading = true;
SaadcInit(); SaadcInit();
nrfx_saadc_sample(); nrfx_saadc_sample();
} }
void Battery::adcCallbackStatic(nrfx_saadc_evt_t const *event) { void Battery::adcCallbackStatic(nrfx_saadc_evt_t const* event) {
instance->SaadcEventHandler(event); instance->SaadcEventHandler(event);
} }
@ -41,8 +41,7 @@ void Battery::SaadcInit() {
nrfx_saadc_config_t adcConfig = NRFX_SAADC_DEFAULT_CONFIG; nrfx_saadc_config_t adcConfig = NRFX_SAADC_DEFAULT_CONFIG;
APP_ERROR_CHECK(nrfx_saadc_init(&adcConfig, adcCallbackStatic)); APP_ERROR_CHECK(nrfx_saadc_init(&adcConfig, adcCallbackStatic));
nrf_saadc_channel_config_t adcChannelConfig = { nrf_saadc_channel_config_t adcChannelConfig = {.resistor_p = NRF_SAADC_RESISTOR_DISABLED,
.resistor_p = NRF_SAADC_RESISTOR_DISABLED,
.resistor_n = NRF_SAADC_RESISTOR_DISABLED, .resistor_n = NRF_SAADC_RESISTOR_DISABLED,
.gain = NRF_SAADC_GAIN1_5, .gain = NRF_SAADC_GAIN1_5,
.reference = NRF_SAADC_REFERENCE_INTERNAL, .reference = NRF_SAADC_REFERENCE_INTERNAL,
@ -50,14 +49,12 @@ void Battery::SaadcInit() {
.mode = NRF_SAADC_MODE_SINGLE_ENDED, .mode = NRF_SAADC_MODE_SINGLE_ENDED,
.burst = NRF_SAADC_BURST_ENABLED, .burst = NRF_SAADC_BURST_ENABLED,
.pin_p = batteryVoltageAdcInput, .pin_p = batteryVoltageAdcInput,
.pin_n = NRF_SAADC_INPUT_DISABLED .pin_n = NRF_SAADC_INPUT_DISABLED};
};
APP_ERROR_CHECK(nrfx_saadc_channel_init(0, &adcChannelConfig)); APP_ERROR_CHECK(nrfx_saadc_channel_init(0, &adcChannelConfig));
APP_ERROR_CHECK(nrfx_saadc_buffer_convert(&saadc_value, 1)); APP_ERROR_CHECK(nrfx_saadc_buffer_convert(&saadc_value, 1));
} }
void Battery::SaadcEventHandler(nrfx_saadc_evt_t const * p_event) { void Battery::SaadcEventHandler(nrfx_saadc_evt_t const* p_event) {
const float battery_max = 4.18; // maximum voltage of battery ( max charging voltage is 4.21 ) const float battery_max = 4.18; // maximum voltage of battery ( max charging voltage is 4.21 )
const float battery_min = 3.20; // minimum voltage of battery before shutdown ( depends on the battery ) const float battery_min = 3.20; // minimum voltage of battery before shutdown ( depends on the battery )
@ -77,12 +74,11 @@ void Battery::SaadcEventHandler(nrfx_saadc_evt_t const * p_event) {
percentRemainingBuffer.insert(percentRemaining); percentRemainingBuffer.insert(percentRemaining);
samples++; samples++;
if ( samples > percentRemainingSamples ) { if (samples > percentRemainingSamples) {
nrfx_saadc_uninit(); nrfx_saadc_uninit();
isReading = false; isReading = false;
} else { } else {
nrfx_saadc_sample(); nrfx_saadc_sample();
} }
} }
} }

View File

@ -11,10 +11,10 @@ namespace Pinetime {
out the sensor values. The total capacity of the CircBuffer out the sensor values. The total capacity of the CircBuffer
is given as the template parameter N. is given as the template parameter N.
*/ */
template <int N> template <int N> class CircBuffer {
class CircBuffer {
public: public:
CircBuffer() : arr{}, sz{}, cap{N}, head{} {} CircBuffer() : arr {}, sz {}, cap {N}, head {} {
}
/** /**
insert member function overwrites the next data to the current insert member function overwrites the next data to the current
HEAD and moves the HEAD to the newly inserted value. HEAD and moves the HEAD to the newly inserted value.
@ -41,21 +41,28 @@ namespace Pinetime {
class Battery { class Battery {
public: public:
Battery(); Battery();
void Init(); void Init();
void Update(); void Update();
int PercentRemaining() const { return percentRemainingBuffer.GetAverage(); } int PercentRemaining() const {
return percentRemainingBuffer.GetAverage();
}
float Voltage() const { return voltage; } float Voltage() const {
return voltage;
}
bool IsCharging() const { return isCharging; } bool IsCharging() const {
bool IsPowerPresent() const { return isPowerPresent; } return isCharging;
}
bool IsPowerPresent() const {
return isPowerPresent;
}
private: private:
static Battery *instance; static Battery* instance;
nrf_saadc_value_t saadc_value; nrf_saadc_value_t saadc_value;
static constexpr uint8_t percentRemainingSamples = 5; static constexpr uint8_t percentRemainingSamples = 5;
@ -72,8 +79,8 @@ namespace Pinetime {
void SaadcInit(); void SaadcInit();
void SaadcEventHandler(nrfx_saadc_evt_t const * p_event); void SaadcEventHandler(nrfx_saadc_evt_t const* p_event);
static void adcCallbackStatic(nrfx_saadc_evt_t const *event); static void adcCallbackStatic(nrfx_saadc_evt_t const* event);
bool isReading = false; bool isReading = false;
uint8_t samples = 0; uint8_t samples = 0;

View File

@ -12,50 +12,42 @@ constexpr ble_uuid16_t AlertNotificationClient::unreadAlertStatusUuid;
constexpr ble_uuid16_t AlertNotificationClient::controlPointUuid; constexpr ble_uuid16_t AlertNotificationClient::controlPointUuid;
namespace { namespace {
int int OnDiscoveryEventCallback(uint16_t conn_handle, const struct ble_gatt_error* error, const struct ble_gatt_svc* service, void* arg) {
OnDiscoveryEventCallback(uint16_t conn_handle, const struct ble_gatt_error *error, const struct ble_gatt_svc *service, auto client = static_cast<AlertNotificationClient*>(arg);
void *arg) {
auto client = static_cast<AlertNotificationClient *>(arg);
return client->OnDiscoveryEvent(conn_handle, error, service); return client->OnDiscoveryEvent(conn_handle, error, service);
} }
int OnAlertNotificationCharacteristicDiscoveredCallback(uint16_t conn_handle, const struct ble_gatt_error *error, int OnAlertNotificationCharacteristicDiscoveredCallback(uint16_t conn_handle,
const struct ble_gatt_chr *chr, void *arg) { const struct ble_gatt_error* error,
auto client = static_cast<AlertNotificationClient *>(arg); const struct ble_gatt_chr* chr,
void* arg) {
auto client = static_cast<AlertNotificationClient*>(arg);
return client->OnCharacteristicsDiscoveryEvent(conn_handle, error, chr); return client->OnCharacteristicsDiscoveryEvent(conn_handle, error, chr);
} }
int OnAlertNotificationDescriptorDiscoveryEventCallback(uint16_t conn_handle, int OnAlertNotificationDescriptorDiscoveryEventCallback(
const struct ble_gatt_error *error, uint16_t conn_handle, const struct ble_gatt_error* error, uint16_t chr_val_handle, const struct ble_gatt_dsc* dsc, void* arg) {
uint16_t chr_val_handle, auto client = static_cast<AlertNotificationClient*>(arg);
const struct ble_gatt_dsc *dsc,
void *arg) {
auto client = static_cast<AlertNotificationClient *>(arg);
return client->OnDescriptorDiscoveryEventCallback(conn_handle, error, chr_val_handle, dsc); return client->OnDescriptorDiscoveryEventCallback(conn_handle, error, chr_val_handle, dsc);
} }
int NewAlertSubcribeCallback(uint16_t conn_handle, int NewAlertSubcribeCallback(uint16_t conn_handle, const struct ble_gatt_error* error, struct ble_gatt_attr* attr, void* arg) {
const struct ble_gatt_error *error, auto client = static_cast<AlertNotificationClient*>(arg);
struct ble_gatt_attr *attr,
void *arg) {
auto client = static_cast<AlertNotificationClient *>(arg);
return client->OnNewAlertSubcribe(conn_handle, error, attr); return client->OnNewAlertSubcribe(conn_handle, error, attr);
} }
} }
AlertNotificationClient::AlertNotificationClient(Pinetime::System::SystemTask &systemTask, AlertNotificationClient::AlertNotificationClient(Pinetime::System::SystemTask& systemTask,
Pinetime::Controllers::NotificationManager &notificationManager) : Pinetime::Controllers::NotificationManager& notificationManager)
systemTask{systemTask}, notificationManager{notificationManager} { : systemTask {systemTask}, notificationManager {notificationManager} {
} }
bool AlertNotificationClient::OnDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error *error, bool AlertNotificationClient::OnDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error* error, const ble_gatt_svc* service) {
const ble_gatt_svc *service) {
if (service == nullptr && error->status == BLE_HS_EDONE) { if (service == nullptr && error->status == BLE_HS_EDONE) {
if (isDiscovered) { if (isDiscovered) {
NRF_LOG_INFO("ANS Discovery found, starting characteristics discovery"); NRF_LOG_INFO("ANS Discovery found, starting characteristics discovery");
ble_gattc_disc_all_chrs(connectionHandle, ansStartHandle, ansEndHandle, ble_gattc_disc_all_chrs(connectionHandle, ansStartHandle, ansEndHandle, OnAlertNotificationCharacteristicDiscoveredCallback, this);
OnAlertNotificationCharacteristicDiscoveredCallback, this);
} else { } else {
NRF_LOG_INFO("ANS not found"); NRF_LOG_INFO("ANS not found");
onServiceDiscovered(connectionHandle); onServiceDiscovered(connectionHandle);
@ -63,7 +55,7 @@ bool AlertNotificationClient::OnDiscoveryEvent(uint16_t connectionHandle, const
return true; return true;
} }
if (service != nullptr && ble_uuid_cmp(((ble_uuid_t *) &ansServiceUuid), &service->uuid.u) == 0) { if (service != nullptr && ble_uuid_cmp(((ble_uuid_t*) &ansServiceUuid), &service->uuid.u) == 0) {
NRF_LOG_INFO("ANS discovered : 0x%x - 0x%x", service->start_handle, service->end_handle); NRF_LOG_INFO("ANS discovered : 0x%x - 0x%x", service->start_handle, service->end_handle);
ansStartHandle = service->start_handle; ansStartHandle = service->start_handle;
ansEndHandle = service->end_handle; ansEndHandle = service->end_handle;
@ -72,8 +64,9 @@ bool AlertNotificationClient::OnDiscoveryEvent(uint16_t connectionHandle, const
return false; return false;
} }
int AlertNotificationClient::OnCharacteristicsDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error *error, int AlertNotificationClient::OnCharacteristicsDiscoveryEvent(uint16_t connectionHandle,
const ble_gatt_chr *characteristic) { const ble_gatt_error* error,
const ble_gatt_chr* characteristic) {
if (error->status != 0 && error->status != BLE_HS_EDONE) { if (error->status != 0 && error->status != BLE_HS_EDONE) {
NRF_LOG_INFO("ANS Characteristic discovery ERROR"); NRF_LOG_INFO("ANS Characteristic discovery ERROR");
onServiceDiscovered(connectionHandle); onServiceDiscovered(connectionHandle);
@ -83,41 +76,34 @@ int AlertNotificationClient::OnCharacteristicsDiscoveryEvent(uint16_t connection
if (characteristic == nullptr && error->status == BLE_HS_EDONE) { if (characteristic == nullptr && error->status == BLE_HS_EDONE) {
NRF_LOG_INFO("ANS Characteristic discovery complete"); NRF_LOG_INFO("ANS Characteristic discovery complete");
if (isCharacteristicDiscovered) { if (isCharacteristicDiscovered) {
ble_gattc_disc_all_dscs(connectionHandle, ble_gattc_disc_all_dscs(connectionHandle, newAlertHandle, ansEndHandle, OnAlertNotificationDescriptorDiscoveryEventCallback, this);
newAlertHandle, ansEndHandle,
OnAlertNotificationDescriptorDiscoveryEventCallback, this);
} else } else
onServiceDiscovered(connectionHandle); onServiceDiscovered(connectionHandle);
} else { } else {
if (characteristic != nullptr && if (characteristic != nullptr && ble_uuid_cmp(((ble_uuid_t*) &supportedNewAlertCategoryUuid), &characteristic->uuid.u) == 0) {
ble_uuid_cmp(((ble_uuid_t *) &supportedNewAlertCategoryUuid), &characteristic->uuid.u) == 0) {
NRF_LOG_INFO("ANS Characteristic discovered : supportedNewAlertCategoryUuid"); NRF_LOG_INFO("ANS Characteristic discovered : supportedNewAlertCategoryUuid");
supportedNewAlertCategoryHandle = characteristic->val_handle; supportedNewAlertCategoryHandle = characteristic->val_handle;
} else if (characteristic != nullptr && } else if (characteristic != nullptr && ble_uuid_cmp(((ble_uuid_t*) &supportedUnreadAlertCategoryUuid), &characteristic->uuid.u) == 0) {
ble_uuid_cmp(((ble_uuid_t *) &supportedUnreadAlertCategoryUuid), &characteristic->uuid.u) == 0) {
NRF_LOG_INFO("ANS Characteristic discovered : supportedUnreadAlertCategoryUuid"); NRF_LOG_INFO("ANS Characteristic discovered : supportedUnreadAlertCategoryUuid");
supportedUnreadAlertCategoryHandle = characteristic->val_handle; supportedUnreadAlertCategoryHandle = characteristic->val_handle;
} else if (characteristic != nullptr && } else if (characteristic != nullptr && ble_uuid_cmp(((ble_uuid_t*) &newAlertUuid), &characteristic->uuid.u) == 0) {
ble_uuid_cmp(((ble_uuid_t *) &newAlertUuid), &characteristic->uuid.u) == 0) {
NRF_LOG_INFO("ANS Characteristic discovered : newAlertUuid"); NRF_LOG_INFO("ANS Characteristic discovered : newAlertUuid");
newAlertHandle = characteristic->val_handle; newAlertHandle = characteristic->val_handle;
newAlertDefHandle = characteristic->def_handle; newAlertDefHandle = characteristic->def_handle;
isCharacteristicDiscovered = true; isCharacteristicDiscovered = true;
} else if (characteristic != nullptr && } else if (characteristic != nullptr && ble_uuid_cmp(((ble_uuid_t*) &unreadAlertStatusUuid), &characteristic->uuid.u) == 0) {
ble_uuid_cmp(((ble_uuid_t *) &unreadAlertStatusUuid), &characteristic->uuid.u) == 0) {
NRF_LOG_INFO("ANS Characteristic discovered : unreadAlertStatusUuid"); NRF_LOG_INFO("ANS Characteristic discovered : unreadAlertStatusUuid");
unreadAlertStatusHandle = characteristic->val_handle; unreadAlertStatusHandle = characteristic->val_handle;
} else if (characteristic != nullptr && } else if (characteristic != nullptr && ble_uuid_cmp(((ble_uuid_t*) &controlPointUuid), &characteristic->uuid.u) == 0) {
ble_uuid_cmp(((ble_uuid_t *) &controlPointUuid), &characteristic->uuid.u) == 0) {
NRF_LOG_INFO("ANS Characteristic discovered : controlPointUuid"); NRF_LOG_INFO("ANS Characteristic discovered : controlPointUuid");
controlPointHandle = characteristic->val_handle; controlPointHandle = characteristic->val_handle;
} else NRF_LOG_INFO("ANS Characteristic discovered : 0x%x", characteristic->val_handle); } else
NRF_LOG_INFO("ANS Characteristic discovered : 0x%x", characteristic->val_handle);
} }
return 0; return 0;
} }
int AlertNotificationClient::OnNewAlertSubcribe(uint16_t connectionHandle, const ble_gatt_error *error, int AlertNotificationClient::OnNewAlertSubcribe(uint16_t connectionHandle, const ble_gatt_error* error, ble_gatt_attr* attribute) {
ble_gatt_attr *attribute) {
if (error->status == 0) { if (error->status == 0) {
NRF_LOG_INFO("ANS New alert subscribe OK"); NRF_LOG_INFO("ANS New alert subscribe OK");
} else { } else {
@ -128,12 +114,12 @@ int AlertNotificationClient::OnNewAlertSubcribe(uint16_t connectionHandle, const
return 0; return 0;
} }
int AlertNotificationClient::OnDescriptorDiscoveryEventCallback(uint16_t connectionHandle, const ble_gatt_error *error, int AlertNotificationClient::OnDescriptorDiscoveryEventCallback(uint16_t connectionHandle,
const ble_gatt_error* error,
uint16_t characteristicValueHandle, uint16_t characteristicValueHandle,
const ble_gatt_dsc *descriptor) { const ble_gatt_dsc* descriptor) {
if (error->status == 0) { if (error->status == 0) {
if (characteristicValueHandle == newAlertHandle && if (characteristicValueHandle == newAlertHandle && ble_uuid_cmp(((ble_uuid_t*) &newAlertUuid), &descriptor->uuid.u)) {
ble_uuid_cmp(((ble_uuid_t *) &newAlertUuid), &descriptor->uuid.u)) {
if (newAlertDescriptorHandle == 0) { if (newAlertDescriptorHandle == 0) {
NRF_LOG_INFO("ANS Descriptor discovered : %d", descriptor->handle); NRF_LOG_INFO("ANS Descriptor discovered : %d", descriptor->handle);
newAlertDescriptorHandle = descriptor->handle; newAlertDescriptorHandle = descriptor->handle;
@ -151,16 +137,17 @@ int AlertNotificationClient::OnDescriptorDiscoveryEventCallback(uint16_t connect
return 0; return 0;
} }
void AlertNotificationClient::OnNotification(ble_gap_event *event) { void AlertNotificationClient::OnNotification(ble_gap_event* event) {
if (event->notify_rx.attr_handle == newAlertHandle) { if (event->notify_rx.attr_handle == newAlertHandle) {
constexpr size_t stringTerminatorSize = 1; // end of string '\0' constexpr size_t stringTerminatorSize = 1; // end of string '\0'
constexpr size_t headerSize = 3; constexpr size_t headerSize = 3;
const auto maxMessageSize{NotificationManager::MaximumMessageSize()}; const auto maxMessageSize {NotificationManager::MaximumMessageSize()};
const auto maxBufferSize{maxMessageSize + headerSize}; const auto maxBufferSize {maxMessageSize + headerSize};
// Ignore notifications with empty message // Ignore notifications with empty message
const auto packetLen = OS_MBUF_PKTLEN(event->notify_rx.om); const auto packetLen = OS_MBUF_PKTLEN(event->notify_rx.om);
if(packetLen <= headerSize) return; if (packetLen <= headerSize)
return;
size_t bufferSize = std::min(packetLen + stringTerminatorSize, maxBufferSize); size_t bufferSize = std::min(packetLen + stringTerminatorSize, maxBufferSize);
auto messageSize = std::min(maxMessageSize, (bufferSize - headerSize)); auto messageSize = std::min(maxMessageSize, (bufferSize - headerSize));

View File

@ -20,51 +20,35 @@ namespace Pinetime {
class AlertNotificationClient : public BleClient { class AlertNotificationClient : public BleClient {
public: public:
explicit AlertNotificationClient(Pinetime::System::SystemTask &systemTask, explicit AlertNotificationClient(Pinetime::System::SystemTask& systemTask,
Pinetime::Controllers::NotificationManager &notificationManager); Pinetime::Controllers::NotificationManager& notificationManager);
bool OnDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error *error, const ble_gatt_svc *service); bool OnDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error* error, const ble_gatt_svc* service);
int OnCharacteristicsDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error *error, int OnCharacteristicsDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error* error, const ble_gatt_chr* characteristic);
const ble_gatt_chr *characteristic); int OnNewAlertSubcribe(uint16_t connectionHandle, const ble_gatt_error* error, ble_gatt_attr* attribute);
int OnNewAlertSubcribe(uint16_t connectionHandle, const ble_gatt_error *error, ble_gatt_attr *attribute); int OnDescriptorDiscoveryEventCallback(uint16_t connectionHandle,
int OnDescriptorDiscoveryEventCallback(uint16_t connectionHandle, const ble_gatt_error *error, const ble_gatt_error* error,
uint16_t characteristicValueHandle, const ble_gatt_dsc *descriptor); uint16_t characteristicValueHandle,
void OnNotification(ble_gap_event *event); const ble_gatt_dsc* descriptor);
void OnNotification(ble_gap_event* event);
void Reset(); void Reset();
void Discover(uint16_t connectionHandle, std::function<void(uint16_t)> lambda) override; void Discover(uint16_t connectionHandle, std::function<void(uint16_t)> lambda) override;
private: private:
static constexpr uint16_t ansServiceId{0x1811}; static constexpr uint16_t ansServiceId {0x1811};
static constexpr uint16_t supportedNewAlertCategoryId = 0x2a47; static constexpr uint16_t supportedNewAlertCategoryId = 0x2a47;
static constexpr uint16_t supportedUnreadAlertCategoryId = 0x2a48; static constexpr uint16_t supportedUnreadAlertCategoryId = 0x2a48;
static constexpr uint16_t newAlertId = 0x2a46; static constexpr uint16_t newAlertId = 0x2a46;
static constexpr uint16_t unreadAlertStatusId = 0x2a45; static constexpr uint16_t unreadAlertStatusId = 0x2a45;
static constexpr uint16_t controlPointId = 0x2a44; static constexpr uint16_t controlPointId = 0x2a44;
static constexpr ble_uuid16_t ansServiceUuid{ static constexpr ble_uuid16_t ansServiceUuid {.u {.type = BLE_UUID_TYPE_16}, .value = ansServiceId};
.u {.type = BLE_UUID_TYPE_16}, static constexpr ble_uuid16_t supportedNewAlertCategoryUuid {.u {.type = BLE_UUID_TYPE_16}, .value = supportedNewAlertCategoryId};
.value = ansServiceId static constexpr ble_uuid16_t supportedUnreadAlertCategoryUuid {.u {.type = BLE_UUID_TYPE_16},
}; .value = supportedUnreadAlertCategoryId};
static constexpr ble_uuid16_t supportedNewAlertCategoryUuid{ static constexpr ble_uuid16_t newAlertUuid {.u {.type = BLE_UUID_TYPE_16}, .value = newAlertId};
.u {.type = BLE_UUID_TYPE_16}, static constexpr ble_uuid16_t unreadAlertStatusUuid {.u {.type = BLE_UUID_TYPE_16}, .value = unreadAlertStatusId};
.value = supportedNewAlertCategoryId static constexpr ble_uuid16_t controlPointUuid {.u {.type = BLE_UUID_TYPE_16}, .value = controlPointId};
};
static constexpr ble_uuid16_t supportedUnreadAlertCategoryUuid{
.u {.type = BLE_UUID_TYPE_16},
.value = supportedUnreadAlertCategoryId
};
static constexpr ble_uuid16_t newAlertUuid{
.u {.type = BLE_UUID_TYPE_16},
.value = newAlertId
};
static constexpr ble_uuid16_t unreadAlertStatusUuid{
.u {.type = BLE_UUID_TYPE_16},
.value = unreadAlertStatusId
};
static constexpr ble_uuid16_t controlPointUuid{
.u {.type = BLE_UUID_TYPE_16},
.value = controlPointId
};
uint16_t ansStartHandle = 0; uint16_t ansStartHandle = 0;
uint16_t ansEndHandle = 0; uint16_t ansEndHandle = 0;
@ -76,8 +60,8 @@ namespace Pinetime {
uint16_t unreadAlertStatusHandle = 0; uint16_t unreadAlertStatusHandle = 0;
uint16_t controlPointHandle = 0; uint16_t controlPointHandle = 0;
bool isDiscovered = false; bool isDiscovered = false;
Pinetime::System::SystemTask &systemTask; Pinetime::System::SystemTask& systemTask;
Pinetime::Controllers::NotificationManager &notificationManager; Pinetime::Controllers::NotificationManager& notificationManager;
std::function<void(uint16_t)> onServiceDiscovered; std::function<void(uint16_t)> onServiceDiscovered;
bool isCharacteristicDiscovered = false; bool isCharacteristicDiscovered = false;
bool isDescriptorFound = false; bool isDescriptorFound = false;

View File

@ -11,8 +11,7 @@ constexpr ble_uuid16_t AlertNotificationService::ansUuid;
constexpr ble_uuid16_t AlertNotificationService::ansCharUuid; constexpr ble_uuid16_t AlertNotificationService::ansCharUuid;
constexpr ble_uuid128_t AlertNotificationService::notificationEventUuid; constexpr ble_uuid128_t AlertNotificationService::notificationEventUuid;
int AlertNotificationCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
int AlertNotificationCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) {
auto anService = static_cast<AlertNotificationService*>(arg); auto anService = static_cast<AlertNotificationService*>(arg);
return anService->OnAlert(conn_handle, attr_handle, ctxt); return anService->OnAlert(conn_handle, attr_handle, ctxt);
} }
@ -26,62 +25,52 @@ void AlertNotificationService::Init() {
ASSERT(res == 0); ASSERT(res == 0);
} }
AlertNotificationService::AlertNotificationService ( System::SystemTask& systemTask, NotificationManager& notificationManager ) AlertNotificationService::AlertNotificationService(System::SystemTask& systemTask, NotificationManager& notificationManager)
: characteristicDefinition{ : characteristicDefinition {{.uuid = (ble_uuid_t*) &ansCharUuid,
{
.uuid = (ble_uuid_t *) &ansCharUuid,
.access_cb = AlertNotificationCallback, .access_cb = AlertNotificationCallback,
.arg = this, .arg = this,
.flags = BLE_GATT_CHR_F_WRITE .flags = BLE_GATT_CHR_F_WRITE},
}, {.uuid = (ble_uuid_t*) &notificationEventUuid,
{
.uuid = (ble_uuid_t *) &notificationEventUuid,
.access_cb = AlertNotificationCallback, .access_cb = AlertNotificationCallback,
.arg = this, .arg = this,
.flags = BLE_GATT_CHR_F_NOTIFY, .flags = BLE_GATT_CHR_F_NOTIFY,
.val_handle = &eventHandle .val_handle = &eventHandle},
}, {0}},
{ serviceDefinition {
0 {/* Device Information Service */
}
},
serviceDefinition{
{
/* Device Information Service */
.type = BLE_GATT_SVC_TYPE_PRIMARY, .type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = (ble_uuid_t *) &ansUuid, .uuid = (ble_uuid_t*) &ansUuid,
.characteristics = characteristicDefinition .characteristics = characteristicDefinition},
{0},
}, },
{ systemTask {systemTask},
0 notificationManager {notificationManager} {
},
}, systemTask{systemTask}, notificationManager{notificationManager} {
} }
int AlertNotificationService::OnAlert(uint16_t conn_handle, uint16_t attr_handle, int AlertNotificationService::OnAlert(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) {
struct ble_gatt_access_ctxt *ctxt) {
if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
constexpr size_t stringTerminatorSize = 1; // end of string '\0' constexpr size_t stringTerminatorSize = 1; // end of string '\0'
constexpr size_t headerSize = 3; constexpr size_t headerSize = 3;
const auto maxMessageSize {NotificationManager::MaximumMessageSize()}; const auto maxMessageSize {NotificationManager::MaximumMessageSize()};
const auto maxBufferSize{maxMessageSize + headerSize}; const auto maxBufferSize {maxMessageSize + headerSize};
// Ignore notifications with empty message // Ignore notifications with empty message
const auto packetLen = OS_MBUF_PKTLEN(ctxt->om); const auto packetLen = OS_MBUF_PKTLEN(ctxt->om);
if(packetLen <= headerSize) return 0; if (packetLen <= headerSize)
return 0;
size_t bufferSize = std::min(packetLen + stringTerminatorSize, maxBufferSize); size_t bufferSize = std::min(packetLen + stringTerminatorSize, maxBufferSize);
auto messageSize = std::min(maxMessageSize, (bufferSize-headerSize)); auto messageSize = std::min(maxMessageSize, (bufferSize - headerSize));
Categories category; Categories category;
NotificationManager::Notification notif; NotificationManager::Notification notif;
os_mbuf_copydata(ctxt->om, headerSize, messageSize-1, notif.message.data()); os_mbuf_copydata(ctxt->om, headerSize, messageSize - 1, notif.message.data());
os_mbuf_copydata(ctxt->om, 0, 1, &category); os_mbuf_copydata(ctxt->om, 0, 1, &category);
notif.message[messageSize-1] = '\0'; notif.message[messageSize - 1] = '\0';
notif.size = messageSize; notif.size = messageSize;
// TODO convert all ANS categories to NotificationController categories // TODO convert all ANS categories to NotificationController categories
switch(category) { switch (category) {
case Categories::Call: case Categories::Call:
notif.category = Pinetime::Controllers::NotificationManager::Categories::IncomingCall; notif.category = Pinetime::Controllers::NotificationManager::Categories::IncomingCall;
break; break;
@ -99,7 +88,7 @@ int AlertNotificationService::OnAlert(uint16_t conn_handle, uint16_t attr_handle
void AlertNotificationService::AcceptIncomingCall() { void AlertNotificationService::AcceptIncomingCall() {
auto response = IncomingCallResponses::Answer; auto response = IncomingCallResponses::Answer;
auto *om = ble_hs_mbuf_from_flat(&response, 1); auto* om = ble_hs_mbuf_from_flat(&response, 1);
uint16_t connectionHandle = systemTask.nimble().connHandle(); uint16_t connectionHandle = systemTask.nimble().connHandle();
@ -112,7 +101,7 @@ void AlertNotificationService::AcceptIncomingCall() {
void AlertNotificationService::RejectIncomingCall() { void AlertNotificationService::RejectIncomingCall() {
auto response = IncomingCallResponses::Reject; auto response = IncomingCallResponses::Reject;
auto *om = ble_hs_mbuf_from_flat(&response, 1); auto* om = ble_hs_mbuf_from_flat(&response, 1);
uint16_t connectionHandle = systemTask.nimble().connHandle(); uint16_t connectionHandle = systemTask.nimble().connHandle();
@ -125,7 +114,7 @@ void AlertNotificationService::RejectIncomingCall() {
void AlertNotificationService::MuteIncomingCall() { void AlertNotificationService::MuteIncomingCall() {
auto response = IncomingCallResponses::Mute; auto response = IncomingCallResponses::Mute;
auto *om = ble_hs_mbuf_from_flat(&response, 1); auto* om = ble_hs_mbuf_from_flat(&response, 1);
uint16_t connectionHandle = systemTask.nimble().connHandle(); uint16_t connectionHandle = systemTask.nimble().connHandle();

View File

@ -7,8 +7,9 @@
#undef max #undef max
#undef min #undef min
//00020001-78fc-48fe-8e23-433b3a1942d0 // 00020001-78fc-48fe-8e23-433b3a1942d0
#define NOTIFICATION_EVENT_SERVICE_UUID_BASE {0xd0, 0x42, 0x19, 0x3a, 0x3b, 0x43, 0x23, 0x8e, 0xfe, 0x48, 0xfc, 0x78, 0x01, 0x00, 0x02, 0x00} #define NOTIFICATION_EVENT_SERVICE_UUID_BASE \
{ 0xd0, 0x42, 0x19, 0x3a, 0x3b, 0x43, 0x23, 0x8e, 0xfe, 0x48, 0xfc, 0x78, 0x01, 0x00, 0x02, 0x00 }
namespace Pinetime { namespace Pinetime {
@ -20,22 +21,16 @@ namespace Pinetime {
class AlertNotificationService { class AlertNotificationService {
public: public:
AlertNotificationService(Pinetime::System::SystemTask &systemTask, AlertNotificationService(Pinetime::System::SystemTask& systemTask, Pinetime::Controllers::NotificationManager& notificationManager);
Pinetime::Controllers::NotificationManager &notificationManager);
void Init(); void Init();
int OnAlert(uint16_t conn_handle, uint16_t attr_handle, int OnAlert(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt);
struct ble_gatt_access_ctxt *ctxt);
void AcceptIncomingCall(); void AcceptIncomingCall();
void RejectIncomingCall(); void RejectIncomingCall();
void MuteIncomingCall(); void MuteIncomingCall();
enum class IncomingCallResponses : uint8_t { enum class IncomingCallResponses : uint8_t { Reject = 0x00, Answer = 0x01, Mute = 0x02 };
Reject = 0x00,
Answer = 0x01,
Mute = 0x02
};
private: private:
enum class Categories : uint8_t { enum class Categories : uint8_t {
@ -55,26 +50,17 @@ namespace Pinetime {
static constexpr uint16_t ansId {0x1811}; static constexpr uint16_t ansId {0x1811};
static constexpr uint16_t ansCharId {0x2a46}; static constexpr uint16_t ansCharId {0x2a46};
static constexpr ble_uuid16_t ansUuid { static constexpr ble_uuid16_t ansUuid {.u {.type = BLE_UUID_TYPE_16}, .value = ansId};
.u { .type = BLE_UUID_TYPE_16 },
.value = ansId
};
static constexpr ble_uuid16_t ansCharUuid { static constexpr ble_uuid16_t ansCharUuid {.u {.type = BLE_UUID_TYPE_16}, .value = ansCharId};
.u { .type = BLE_UUID_TYPE_16 },
.value = ansCharId
};
static constexpr ble_uuid128_t notificationEventUuid { static constexpr ble_uuid128_t notificationEventUuid {.u {.type = BLE_UUID_TYPE_128}, .value = NOTIFICATION_EVENT_SERVICE_UUID_BASE};
.u { .type = BLE_UUID_TYPE_128 },
.value = NOTIFICATION_EVENT_SERVICE_UUID_BASE
};
struct ble_gatt_chr_def characteristicDefinition[3]; struct ble_gatt_chr_def characteristicDefinition[3];
struct ble_gatt_svc_def serviceDefinition[2]; struct ble_gatt_svc_def serviceDefinition[2];
Pinetime::System::SystemTask &systemTask; Pinetime::System::SystemTask& systemTask;
NotificationManager &notificationManager; NotificationManager& notificationManager;
uint16_t eventHandle; uint16_t eventHandle;
}; };

View File

@ -7,39 +7,26 @@ using namespace Pinetime::Controllers;
constexpr ble_uuid16_t BatteryInformationService::batteryInformationServiceUuid; constexpr ble_uuid16_t BatteryInformationService::batteryInformationServiceUuid;
constexpr ble_uuid16_t BatteryInformationService::batteryLevelUuid; constexpr ble_uuid16_t BatteryInformationService::batteryLevelUuid;
int BatteryInformationServiceCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
int BatteryInformationServiceCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) {
auto* batteryInformationService = static_cast<BatteryInformationService*>(arg); auto* batteryInformationService = static_cast<BatteryInformationService*>(arg);
return batteryInformationService->OnBatteryServiceRequested(conn_handle, attr_handle, ctxt); return batteryInformationService->OnBatteryServiceRequested(conn_handle, attr_handle, ctxt);
} }
BatteryInformationService::BatteryInformationService(Controllers::Battery& batteryController) : BatteryInformationService::BatteryInformationService(Controllers::Battery& batteryController)
batteryController{batteryController}, : batteryController {batteryController},
characteristicDefinition{ characteristicDefinition {{.uuid = (ble_uuid_t*) &batteryLevelUuid,
{
.uuid = (ble_uuid_t *) &batteryLevelUuid,
.access_cb = BatteryInformationServiceCallback, .access_cb = BatteryInformationServiceCallback,
.arg = this, .arg = this,
.flags = BLE_GATT_CHR_F_READ, .flags = BLE_GATT_CHR_F_READ,
.val_handle = &batteryLevelHandle .val_handle = &batteryLevelHandle},
}, {0}},
{ serviceDefinition {
0 {/* Device Information Service */
}
},
serviceDefinition{
{
/* Device Information Service */
.type = BLE_GATT_SVC_TYPE_PRIMARY, .type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = (ble_uuid_t *) &batteryInformationServiceUuid, .uuid = (ble_uuid_t*) &batteryInformationServiceUuid,
.characteristics = characteristicDefinition .characteristics = characteristicDefinition},
}, {0},
{ } {
0
},
}{
} }
void BatteryInformationService::Init() { void BatteryInformationService::Init() {
@ -51,9 +38,10 @@ void BatteryInformationService::Init() {
ASSERT(res == 0); ASSERT(res == 0);
} }
int BatteryInformationService::OnBatteryServiceRequested(uint16_t connectionHandle, uint16_t attributeHandle, int BatteryInformationService::OnBatteryServiceRequested(uint16_t connectionHandle,
ble_gatt_access_ctxt *context) { uint16_t attributeHandle,
if(attributeHandle == batteryLevelHandle) { ble_gatt_access_ctxt* context) {
if (attributeHandle == batteryLevelHandle) {
NRF_LOG_INFO("BATTERY : handle = %d", batteryLevelHandle); NRF_LOG_INFO("BATTERY : handle = %d", batteryLevelHandle);
static uint8_t batteryValue = batteryController.PercentRemaining(); static uint8_t batteryValue = batteryController.PercentRemaining();
int res = os_mbuf_append(context->om, &batteryValue, 1); int res = os_mbuf_append(context->om, &batteryValue, 1);

View File

@ -16,29 +16,21 @@ namespace Pinetime {
BatteryInformationService(Controllers::Battery& batteryController); BatteryInformationService(Controllers::Battery& batteryController);
void Init(); void Init();
int int OnBatteryServiceRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context);
OnBatteryServiceRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt *context);
private: private:
Controllers::Battery& batteryController; Controllers::Battery& batteryController;
static constexpr uint16_t batteryInformationServiceId {0x180F}; static constexpr uint16_t batteryInformationServiceId {0x180F};
static constexpr uint16_t batteryLevelId {0x2A19}; static constexpr uint16_t batteryLevelId {0x2A19};
static constexpr ble_uuid16_t batteryInformationServiceUuid { static constexpr ble_uuid16_t batteryInformationServiceUuid {.u {.type = BLE_UUID_TYPE_16}, .value = batteryInformationServiceId};
.u {.type = BLE_UUID_TYPE_16},
.value = batteryInformationServiceId
};
static constexpr ble_uuid16_t batteryLevelUuid { static constexpr ble_uuid16_t batteryLevelUuid {.u {.type = BLE_UUID_TYPE_16}, .value = batteryLevelId};
.u {.type = BLE_UUID_TYPE_16},
.value = batteryLevelId
};
struct ble_gatt_chr_def characteristicDefinition[3]; struct ble_gatt_chr_def characteristicDefinition[3];
struct ble_gatt_svc_def serviceDefinition[2]; struct ble_gatt_svc_def serviceDefinition[2];
uint16_t batteryLevelHandle; uint16_t batteryLevelHandle;
}; };
} }
} }

View File

@ -3,7 +3,7 @@
#include <functional> #include <functional>
namespace Pinetime { namespace Pinetime {
namespace Controllers{ namespace Controllers {
class BleClient { class BleClient {
public: public:
virtual void Discover(uint16_t connectionHandle, std::function<void(uint16_t)> lambda) = 0; virtual void Discover(uint16_t connectionHandle, std::function<void(uint16_t)> lambda) = 0;

View File

@ -25,5 +25,3 @@ void Ble::FirmwareUpdateTotalBytes(uint32_t totalBytes) {
void Ble::FirmwareUpdateCurrentBytes(uint32_t currentBytes) { void Ble::FirmwareUpdateCurrentBytes(uint32_t currentBytes) {
firmwareUpdateCurrentBytes = currentBytes; firmwareUpdateCurrentBytes = currentBytes;
} }

View File

@ -8,11 +8,13 @@ namespace Pinetime {
class Ble { class Ble {
public: public:
using BleAddress = std::array<uint8_t, 6>; using BleAddress = std::array<uint8_t, 6>;
enum class FirmwareUpdateStates {Idle, Running, Validated, Error}; enum class FirmwareUpdateStates { Idle, Running, Validated, Error };
enum class AddressTypes { Public, Random }; enum class AddressTypes { Public, Random };
Ble() = default; Ble() = default;
bool IsConnected() const {return isConnected;} bool IsConnected() const {
return isConnected;
}
void Connect(); void Connect();
void Disconnect(); void Disconnect();
@ -20,16 +22,33 @@ namespace Pinetime {
void StopFirmwareUpdate(); void StopFirmwareUpdate();
void FirmwareUpdateTotalBytes(uint32_t totalBytes); void FirmwareUpdateTotalBytes(uint32_t totalBytes);
void FirmwareUpdateCurrentBytes(uint32_t currentBytes); void FirmwareUpdateCurrentBytes(uint32_t currentBytes);
void State(FirmwareUpdateStates state) { firmwareUpdateState = state; } void State(FirmwareUpdateStates state) {
firmwareUpdateState = state;
}
bool IsFirmwareUpdating() const { return isFirmwareUpdating; } bool IsFirmwareUpdating() const {
uint32_t FirmwareUpdateTotalBytes() const { return firmwareUpdateTotalBytes; } return isFirmwareUpdating;
uint32_t FirmwareUpdateCurrentBytes() const { return firmwareUpdateCurrentBytes; } }
FirmwareUpdateStates State() const { return firmwareUpdateState; } uint32_t FirmwareUpdateTotalBytes() const {
return firmwareUpdateTotalBytes;
}
uint32_t FirmwareUpdateCurrentBytes() const {
return firmwareUpdateCurrentBytes;
}
FirmwareUpdateStates State() const {
return firmwareUpdateState;
}
void Address(BleAddress&& addr) {
address = addr;
}
const BleAddress& Address() const {
return address;
}
void AddressType(AddressTypes t) {
addressType = t;
}
void Address(BleAddress&& addr) { address = addr; }
const BleAddress& Address() const { return address; }
void AddressType(AddressTypes t) { addressType = t;}
private: private:
bool isConnected = false; bool isConnected = false;
bool isFirmwareUpdating = false; bool isFirmwareUpdating = false;
@ -38,7 +57,6 @@ namespace Pinetime {
FirmwareUpdateStates firmwareUpdateState = FirmwareUpdateStates::Idle; FirmwareUpdateStates firmwareUpdateState = FirmwareUpdateStates::Idle;
BleAddress address; BleAddress address;
AddressTypes addressType; AddressTypes addressType;
}; };
} }
} }

View File

@ -9,39 +9,37 @@ constexpr ble_uuid16_t CurrentTimeClient::ctsServiceUuid;
constexpr ble_uuid16_t CurrentTimeClient::currentTimeCharacteristicUuid; constexpr ble_uuid16_t CurrentTimeClient::currentTimeCharacteristicUuid;
namespace { namespace {
int OnDiscoveryEventCallback(uint16_t conn_handle, const struct ble_gatt_error *error, const struct ble_gatt_svc *service, void *arg) { int OnDiscoveryEventCallback(uint16_t conn_handle, const struct ble_gatt_error* error, const struct ble_gatt_svc* service, void* arg) {
auto client = static_cast<CurrentTimeClient *>(arg); auto client = static_cast<CurrentTimeClient*>(arg);
return client->OnDiscoveryEvent(conn_handle, error, service); return client->OnDiscoveryEvent(conn_handle, error, service);
} }
int OnCurrentTimeCharacteristicDiscoveredCallback(uint16_t conn_handle, const struct ble_gatt_error *error, int OnCurrentTimeCharacteristicDiscoveredCallback(uint16_t conn_handle,
const struct ble_gatt_chr *chr, void *arg) { const struct ble_gatt_error* error,
auto client = static_cast<CurrentTimeClient *>(arg); const struct ble_gatt_chr* chr,
void* arg) {
auto client = static_cast<CurrentTimeClient*>(arg);
return client->OnCharacteristicDiscoveryEvent(conn_handle, error, chr); return client->OnCharacteristicDiscoveryEvent(conn_handle, error, chr);
} }
int CurrentTimeReadCallback(uint16_t conn_handle, const struct ble_gatt_error *error, struct ble_gatt_attr *attr, void *arg) { int CurrentTimeReadCallback(uint16_t conn_handle, const struct ble_gatt_error* error, struct ble_gatt_attr* attr, void* arg) {
auto client = static_cast<CurrentTimeClient *>(arg); auto client = static_cast<CurrentTimeClient*>(arg);
return client->OnCurrentTimeReadResult(conn_handle, error, attr); return client->OnCurrentTimeReadResult(conn_handle, error, attr);
} }
} }
CurrentTimeClient::CurrentTimeClient(DateTime &dateTimeController) : dateTimeController{dateTimeController} { CurrentTimeClient::CurrentTimeClient(DateTime& dateTimeController) : dateTimeController {dateTimeController} {
} }
void CurrentTimeClient::Init() { void CurrentTimeClient::Init() {
} }
bool CurrentTimeClient::OnDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error *error, bool CurrentTimeClient::OnDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error* error, const ble_gatt_svc* service) {
const ble_gatt_svc *service) {
if (service == nullptr && error->status == BLE_HS_EDONE) { if (service == nullptr && error->status == BLE_HS_EDONE) {
if (isDiscovered) { if (isDiscovered) {
NRF_LOG_INFO("CTS found, starting characteristics discovery"); NRF_LOG_INFO("CTS found, starting characteristics discovery");
ble_gattc_disc_all_chrs(connectionHandle, ctsStartHandle, ctsEndHandle, ble_gattc_disc_all_chrs(connectionHandle, ctsStartHandle, ctsEndHandle, OnCurrentTimeCharacteristicDiscoveredCallback, this);
OnCurrentTimeCharacteristicDiscoveredCallback, this);
} else { } else {
NRF_LOG_INFO("CTS not found"); NRF_LOG_INFO("CTS not found");
onServiceDiscovered(connectionHandle); onServiceDiscovered(connectionHandle);
@ -49,7 +47,7 @@ bool CurrentTimeClient::OnDiscoveryEvent(uint16_t connectionHandle, const ble_ga
return true; return true;
} }
if (service != nullptr && ble_uuid_cmp(((ble_uuid_t *) &ctsServiceUuid), &service->uuid.u) == 0) { if (service != nullptr && ble_uuid_cmp(((ble_uuid_t*) &ctsServiceUuid), &service->uuid.u) == 0) {
NRF_LOG_INFO("CTS discovered : 0x%x - 0x%x", service->start_handle, service->end_handle); NRF_LOG_INFO("CTS discovered : 0x%x - 0x%x", service->start_handle, service->end_handle);
isDiscovered = true; isDiscovered = true;
ctsStartHandle = service->start_handle; ctsStartHandle = service->start_handle;
@ -59,8 +57,9 @@ bool CurrentTimeClient::OnDiscoveryEvent(uint16_t connectionHandle, const ble_ga
return false; return false;
} }
int CurrentTimeClient::OnCharacteristicDiscoveryEvent(uint16_t conn_handle, const ble_gatt_error *error, int CurrentTimeClient::OnCharacteristicDiscoveryEvent(uint16_t conn_handle,
const ble_gatt_chr *characteristic) { const ble_gatt_error* error,
const ble_gatt_chr* characteristic) {
if (characteristic == nullptr && error->status == BLE_HS_EDONE) { if (characteristic == nullptr && error->status == BLE_HS_EDONE) {
if (isCharacteristicDiscovered) { if (isCharacteristicDiscovered) {
NRF_LOG_INFO("CTS Characteristic discovery complete, fetching time"); NRF_LOG_INFO("CTS Characteristic discovery complete, fetching time");
@ -73,8 +72,7 @@ int CurrentTimeClient::OnCharacteristicDiscoveryEvent(uint16_t conn_handle, cons
return 0; return 0;
} }
if (characteristic != nullptr && if (characteristic != nullptr && ble_uuid_cmp(((ble_uuid_t*) &currentTimeCharacteristicUuid), &characteristic->uuid.u) == 0) {
ble_uuid_cmp(((ble_uuid_t *) &currentTimeCharacteristicUuid), &characteristic->uuid.u) == 0) {
NRF_LOG_INFO("CTS Characteristic discovered : 0x%x", characteristic->val_handle); NRF_LOG_INFO("CTS Characteristic discovered : 0x%x", characteristic->val_handle);
isCharacteristicDiscovered = true; isCharacteristicDiscovered = true;
currentTimeHandle = characteristic->val_handle; currentTimeHandle = characteristic->val_handle;
@ -82,17 +80,15 @@ int CurrentTimeClient::OnCharacteristicDiscoveryEvent(uint16_t conn_handle, cons
return 0; return 0;
} }
int CurrentTimeClient::OnCurrentTimeReadResult(uint16_t conn_handle, const ble_gatt_error *error, int CurrentTimeClient::OnCurrentTimeReadResult(uint16_t conn_handle, const ble_gatt_error* error, const ble_gatt_attr* attribute) {
const ble_gatt_attr *attribute) {
if (error->status == 0) { if (error->status == 0) {
// TODO check that attribute->handle equals the handle discovered in OnCharacteristicDiscoveryEvent // TODO check that attribute->handle equals the handle discovered in OnCharacteristicDiscoveryEvent
CtsData result; CtsData result;
os_mbuf_copydata(attribute->om, 0, sizeof(CtsData), &result); os_mbuf_copydata(attribute->om, 0, sizeof(CtsData), &result);
NRF_LOG_INFO("Received data: %d-%d-%d %d:%d:%d", result.year, NRF_LOG_INFO(
result.month, result.dayofmonth, "Received data: %d-%d-%d %d:%d:%d", result.year, result.month, result.dayofmonth, result.hour, result.minute, result.second);
result.hour, result.minute, result.second); dateTimeController.SetTime(
dateTimeController.SetTime(result.year, result.month, result.dayofmonth, result.year, result.month, result.dayofmonth, 0, result.hour, result.minute, result.second, nrf_rtc_counter_get(portNRF_RTC_REG));
0, result.hour, result.minute, result.second, nrf_rtc_counter_get(portNRF_RTC_REG));
} else { } else {
NRF_LOG_INFO("Error retrieving current time: %d", error->status); NRF_LOG_INFO("Error retrieving current time: %d", error->status);
} }

View File

@ -16,12 +16,15 @@ namespace Pinetime {
explicit CurrentTimeClient(DateTime& dateTimeController); explicit CurrentTimeClient(DateTime& dateTimeController);
void Init(); void Init();
void Reset(); void Reset();
bool OnDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error *error, const ble_gatt_svc *service); bool OnDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error* error, const ble_gatt_svc* service);
int OnCharacteristicDiscoveryEvent(uint16_t conn_handle, const ble_gatt_error *error, int OnCharacteristicDiscoveryEvent(uint16_t conn_handle, const ble_gatt_error* error, const ble_gatt_chr* characteristic);
const ble_gatt_chr *characteristic); int OnCurrentTimeReadResult(uint16_t conn_handle, const ble_gatt_error* error, const ble_gatt_attr* attribute);
int OnCurrentTimeReadResult(uint16_t conn_handle, const ble_gatt_error *error, const ble_gatt_attr *attribute); static constexpr const ble_uuid16_t* Uuid() {
static constexpr const ble_uuid16_t* Uuid() { return &CurrentTimeClient::ctsServiceUuid; } return &CurrentTimeClient::ctsServiceUuid;
static constexpr const ble_uuid16_t* CurrentTimeCharacteristicUuid() { return &CurrentTimeClient::currentTimeCharacteristicUuid; } }
static constexpr const ble_uuid16_t* CurrentTimeCharacteristicUuid() {
return &CurrentTimeClient::currentTimeCharacteristicUuid;
}
void Discover(uint16_t connectionHandle, std::function<void(uint16_t)> lambda) override; void Discover(uint16_t connectionHandle, std::function<void(uint16_t)> lambda) override;
private: private:
@ -39,14 +42,8 @@ namespace Pinetime {
static constexpr uint16_t ctsServiceId {0x1805}; static constexpr uint16_t ctsServiceId {0x1805};
static constexpr uint16_t currentTimeCharacteristicId {0x2a2b}; static constexpr uint16_t currentTimeCharacteristicId {0x2a2b};
static constexpr ble_uuid16_t ctsServiceUuid { static constexpr ble_uuid16_t ctsServiceUuid {.u {.type = BLE_UUID_TYPE_16}, .value = ctsServiceId};
.u { .type = BLE_UUID_TYPE_16 }, static constexpr ble_uuid16_t currentTimeCharacteristicUuid {.u {.type = BLE_UUID_TYPE_16}, .value = currentTimeCharacteristicId};
.value = ctsServiceId
};
static constexpr ble_uuid16_t currentTimeCharacteristicUuid {
.u { .type = BLE_UUID_TYPE_16 },
.value = currentTimeCharacteristicId
};
DateTime& dateTimeController; DateTime& dateTimeController;
bool isDiscovered = false; bool isDiscovered = false;

View File

@ -7,8 +7,7 @@ using namespace Pinetime::Controllers;
constexpr ble_uuid16_t CurrentTimeService::ctsUuid; constexpr ble_uuid16_t CurrentTimeService::ctsUuid;
constexpr ble_uuid16_t CurrentTimeService::ctChrUuid; constexpr ble_uuid16_t CurrentTimeService::ctChrUuid;
int CTSCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
int CTSCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) {
auto cts = static_cast<CurrentTimeService*>(arg); auto cts = static_cast<CurrentTimeService*>(arg);
return cts->OnTimeAccessed(conn_handle, attr_handle, ctxt); return cts->OnTimeAccessed(conn_handle, attr_handle, ctxt);
} }
@ -22,9 +21,7 @@ void CurrentTimeService::Init() {
ASSERT(res == 0); ASSERT(res == 0);
} }
int CurrentTimeService::OnTimeAccessed(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) {
int CurrentTimeService::OnTimeAccessed(uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt) {
NRF_LOG_INFO("Setting time..."); NRF_LOG_INFO("Setting time...");
@ -32,12 +29,11 @@ int CurrentTimeService::OnTimeAccessed(uint16_t conn_handle, uint16_t attr_handl
CtsData result; CtsData result;
os_mbuf_copydata(ctxt->om, 0, sizeof(CtsData), &result); os_mbuf_copydata(ctxt->om, 0, sizeof(CtsData), &result);
NRF_LOG_INFO("Received data: %d-%d-%d %d:%d:%d", result.year, NRF_LOG_INFO(
result.month, result.dayofmonth, "Received data: %d-%d-%d %d:%d:%d", result.year, result.month, result.dayofmonth, result.hour, result.minute, result.second);
result.hour, result.minute, result.second);
m_dateTimeController.SetTime(result.year, result.month, result.dayofmonth, m_dateTimeController.SetTime(
0, result.hour, result.minute, result.second, nrf_rtc_counter_get(portNRF_RTC_REG)); result.year, result.month, result.dayofmonth, 0, result.hour, result.minute, result.second, nrf_rtc_counter_get(portNRF_RTC_REG));
} else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { } else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
CtsData currentDateTime; CtsData currentDateTime;
@ -49,39 +45,26 @@ int CurrentTimeService::OnTimeAccessed(uint16_t conn_handle, uint16_t attr_handl
currentDateTime.second = m_dateTimeController.Seconds(); currentDateTime.second = m_dateTimeController.Seconds();
currentDateTime.millis = 0; currentDateTime.millis = 0;
int res = os_mbuf_append(ctxt->om, &currentDateTime, sizeof(CtsData)); int res = os_mbuf_append(ctxt->om, &currentDateTime, sizeof(CtsData));
return (res == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; return (res == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
} }
return 0; return 0;
} }
CurrentTimeService::CurrentTimeService(DateTime &dateTimeController) : CurrentTimeService::CurrentTimeService(DateTime& dateTimeController)
characteristicDefinition{ : characteristicDefinition {{.uuid = (ble_uuid_t*) &ctChrUuid,
{
.uuid = (ble_uuid_t *) &ctChrUuid,
.access_cb = CTSCallback, .access_cb = CTSCallback,
.arg = this, .arg = this,
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ},
}, {0}},
{ serviceDefinition {
0 {/* Device Information Service */
}
},
serviceDefinition{
{
/* Device Information Service */
.type = BLE_GATT_SVC_TYPE_PRIMARY, .type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = (ble_uuid_t *) &ctsUuid, .uuid = (ble_uuid_t*) &ctsUuid,
.characteristics = characteristicDefinition .characteristics = characteristicDefinition},
{0},
}, },
{ m_dateTimeController {dateTimeController} {
0
},
}, m_dateTimeController{dateTimeController} {
} }

View File

@ -13,25 +13,18 @@ namespace Pinetime {
namespace Controllers { namespace Controllers {
class CurrentTimeService { class CurrentTimeService {
public: public:
CurrentTimeService(DateTime &dateTimeController); CurrentTimeService(DateTime& dateTimeController);
void Init(); void Init();
int OnTimeAccessed(uint16_t conn_handle, uint16_t attr_handle, int OnTimeAccessed(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt);
struct ble_gatt_access_ctxt *ctxt);
private: private:
static constexpr uint16_t ctsId {0x1805}; static constexpr uint16_t ctsId {0x1805};
static constexpr uint16_t ctsCharId {0x2a2b}; static constexpr uint16_t ctsCharId {0x2a2b};
static constexpr ble_uuid16_t ctsUuid { static constexpr ble_uuid16_t ctsUuid {.u {.type = BLE_UUID_TYPE_16}, .value = ctsId};
.u { .type = BLE_UUID_TYPE_16 },
.value = ctsId
};
static constexpr ble_uuid16_t ctChrUuid { static constexpr ble_uuid16_t ctChrUuid {.u {.type = BLE_UUID_TYPE_16}, .value = ctsCharId};
.u { .type = BLE_UUID_TYPE_16 },
.value = ctsCharId
};
struct ble_gatt_chr_def characteristicDefinition[2]; struct ble_gatt_chr_def characteristicDefinition[2];
struct ble_gatt_svc_def serviceDefinition[2]; struct ble_gatt_svc_def serviceDefinition[2];
@ -47,7 +40,7 @@ namespace Pinetime {
uint8_t reason; uint8_t reason;
} CtsData; } CtsData;
DateTime &m_dateTimeController; DateTime& m_dateTimeController;
}; };
} }
} }

View File

@ -10,8 +10,7 @@ constexpr ble_uuid16_t DeviceInformationService::deviceInfoUuid;
constexpr ble_uuid16_t DeviceInformationService::hwRevisionUuid; constexpr ble_uuid16_t DeviceInformationService::hwRevisionUuid;
constexpr ble_uuid16_t DeviceInformationService::swRevisionUuid; constexpr ble_uuid16_t DeviceInformationService::swRevisionUuid;
int DeviceInformationCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
int DeviceInformationCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) {
auto deviceInformationService = static_cast<DeviceInformationService*>(arg); auto deviceInformationService = static_cast<DeviceInformationService*>(arg);
return deviceInformationService->OnDeviceInfoRequested(conn_handle, attr_handle, ctxt); return deviceInformationService->OnDeviceInfoRequested(conn_handle, attr_handle, ctxt);
} }
@ -25,10 +24,8 @@ void DeviceInformationService::Init() {
ASSERT(res == 0); ASSERT(res == 0);
} }
int DeviceInformationService::OnDeviceInfoRequested(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) {
int DeviceInformationService::OnDeviceInfoRequested(uint16_t conn_handle, uint16_t attr_handle, const char* str;
struct ble_gatt_access_ctxt *ctxt) {
const char *str;
switch (ble_uuid_u16(ctxt->chr->uuid)) { switch (ble_uuid_u16(ctxt->chr->uuid)) {
case manufacturerNameId: case manufacturerNameId:
@ -57,60 +54,49 @@ int DeviceInformationService::OnDeviceInfoRequested(uint16_t conn_handle, uint16
return (res == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; return (res == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
} }
DeviceInformationService::DeviceInformationService() : DeviceInformationService::DeviceInformationService()
characteristicDefinition{ : characteristicDefinition {{
{ .uuid = (ble_uuid_t*) &manufacturerNameUuid,
.uuid = (ble_uuid_t *) &manufacturerNameUuid,
.access_cb = DeviceInformationCallback, .access_cb = DeviceInformationCallback,
.arg = this, .arg = this,
.flags = BLE_GATT_CHR_F_READ, .flags = BLE_GATT_CHR_F_READ,
}, },
{ {
.uuid = (ble_uuid_t *) &modelNumberUuid, .uuid = (ble_uuid_t*) &modelNumberUuid,
.access_cb = DeviceInformationCallback, .access_cb = DeviceInformationCallback,
.arg = this, .arg = this,
.flags = BLE_GATT_CHR_F_READ, .flags = BLE_GATT_CHR_F_READ,
}, },
{ {
.uuid = (ble_uuid_t *) &serialNumberUuid, .uuid = (ble_uuid_t*) &serialNumberUuid,
.access_cb = DeviceInformationCallback, .access_cb = DeviceInformationCallback,
.arg = this, .arg = this,
.flags = BLE_GATT_CHR_F_READ, .flags = BLE_GATT_CHR_F_READ,
}, },
{ {
.uuid = (ble_uuid_t *) &fwRevisionUuid, .uuid = (ble_uuid_t*) &fwRevisionUuid,
.access_cb = DeviceInformationCallback, .access_cb = DeviceInformationCallback,
.arg = this, .arg = this,
.flags = BLE_GATT_CHR_F_READ, .flags = BLE_GATT_CHR_F_READ,
}, },
{ {
.uuid = (ble_uuid_t *) &hwRevisionUuid, .uuid = (ble_uuid_t*) &hwRevisionUuid,
.access_cb = DeviceInformationCallback, .access_cb = DeviceInformationCallback,
.arg = this, .arg = this,
.flags = BLE_GATT_CHR_F_READ, .flags = BLE_GATT_CHR_F_READ,
}, },
{ {
.uuid = (ble_uuid_t *) &swRevisionUuid, .uuid = (ble_uuid_t*) &swRevisionUuid,
.access_cb = DeviceInformationCallback, .access_cb = DeviceInformationCallback,
.arg = this, .arg = this,
.flags = BLE_GATT_CHR_F_READ, .flags = BLE_GATT_CHR_F_READ,
}, },
{ {0}},
0 serviceDefinition {
} {/* Device Information Service */
},
serviceDefinition{
{
/* Device Information Service */
.type = BLE_GATT_SVC_TYPE_PRIMARY, .type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = (ble_uuid_t *) &deviceInfoUuid, .uuid = (ble_uuid_t*) &deviceInfoUuid,
.characteristics = characteristicDefinition .characteristics = characteristicDefinition},
}, {0},
{ } {
0
},
}
{
} }

View File

@ -13,8 +13,7 @@ namespace Pinetime {
DeviceInformationService(); DeviceInformationService();
void Init(); void Init();
int OnDeviceInfoRequested(uint16_t conn_handle, uint16_t attr_handle, int OnDeviceInfoRequested(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt);
struct ble_gatt_access_ctxt *ctxt);
private: private:
static constexpr uint16_t deviceInfoId {0x180a}; static constexpr uint16_t deviceInfoId {0x180a};
@ -32,46 +31,22 @@ namespace Pinetime {
static constexpr const char* fwRevision = Version::VersionString(); static constexpr const char* fwRevision = Version::VersionString();
static constexpr const char* swRevision = "InfiniTime"; static constexpr const char* swRevision = "InfiniTime";
static constexpr ble_uuid16_t deviceInfoUuid {.u {.type = BLE_UUID_TYPE_16}, .value = deviceInfoId};
static constexpr ble_uuid16_t deviceInfoUuid { static constexpr ble_uuid16_t manufacturerNameUuid {.u {.type = BLE_UUID_TYPE_16}, .value = manufacturerNameId};
.u { .type = BLE_UUID_TYPE_16 },
.value = deviceInfoId
};
static constexpr ble_uuid16_t manufacturerNameUuid { static constexpr ble_uuid16_t modelNumberUuid {.u {.type = BLE_UUID_TYPE_16}, .value = modelNumberId};
.u { .type = BLE_UUID_TYPE_16 },
.value = manufacturerNameId
};
static constexpr ble_uuid16_t modelNumberUuid { static constexpr ble_uuid16_t serialNumberUuid {.u {.type = BLE_UUID_TYPE_16}, .value = serialNumberId};
.u { .type = BLE_UUID_TYPE_16 },
.value = modelNumberId
};
static constexpr ble_uuid16_t serialNumberUuid { static constexpr ble_uuid16_t fwRevisionUuid {.u {.type = BLE_UUID_TYPE_16}, .value = fwRevisionId};
.u { .type = BLE_UUID_TYPE_16 },
.value = serialNumberId
};
static constexpr ble_uuid16_t fwRevisionUuid { static constexpr ble_uuid16_t hwRevisionUuid {.u {.type = BLE_UUID_TYPE_16}, .value = hwRevisionId};
.u { .type = BLE_UUID_TYPE_16 },
.value = fwRevisionId
};
static constexpr ble_uuid16_t hwRevisionUuid { static constexpr ble_uuid16_t swRevisionUuid {.u {.type = BLE_UUID_TYPE_16}, .value = swRevisionId};
.u {.type = BLE_UUID_TYPE_16},
.value = hwRevisionId
};
static constexpr ble_uuid16_t swRevisionUuid {
.u {.type = BLE_UUID_TYPE_16},
.value = swRevisionId
};
struct ble_gatt_chr_def characteristicDefinition[7]; struct ble_gatt_chr_def characteristicDefinition[7];
struct ble_gatt_svc_def serviceDefinition[2]; struct ble_gatt_svc_def serviceDefinition[2];
}; };
} }
} }

View File

@ -11,67 +11,60 @@ constexpr ble_uuid128_t DfuService::controlPointCharacteristicUuid;
constexpr ble_uuid128_t DfuService::revisionCharacteristicUuid; constexpr ble_uuid128_t DfuService::revisionCharacteristicUuid;
constexpr ble_uuid128_t DfuService::packetCharacteristicUuid; constexpr ble_uuid128_t DfuService::packetCharacteristicUuid;
int DfuServiceCallback(uint16_t conn_handle, uint16_t attr_handle, int DfuServiceCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
struct ble_gatt_access_ctxt *ctxt, void *arg) { auto dfuService = static_cast<DfuService*>(arg);
auto dfuService = static_cast<DfuService *>(arg);
return dfuService->OnServiceData(conn_handle, attr_handle, ctxt); return dfuService->OnServiceData(conn_handle, attr_handle, ctxt);
} }
void NotificationTimerCallback(TimerHandle_t xTimer) { void NotificationTimerCallback(TimerHandle_t xTimer) {
auto notificationManager = static_cast<DfuService::NotificationManager *>(pvTimerGetTimerID(xTimer)); auto notificationManager = static_cast<DfuService::NotificationManager*>(pvTimerGetTimerID(xTimer));
notificationManager->OnNotificationTimer(); notificationManager->OnNotificationTimer();
} }
void TimeoutTimerCallback(TimerHandle_t xTimer) { void TimeoutTimerCallback(TimerHandle_t xTimer) {
auto dfuService = static_cast<DfuService *>(pvTimerGetTimerID(xTimer)); auto dfuService = static_cast<DfuService*>(pvTimerGetTimerID(xTimer));
dfuService->OnTimeout(); dfuService->OnTimeout();
} }
DfuService::DfuService(Pinetime::System::SystemTask &systemTask, Pinetime::Controllers::Ble &bleController, DfuService::DfuService(Pinetime::System::SystemTask& systemTask,
Pinetime::Drivers::SpiNorFlash &spiNorFlash) : Pinetime::Controllers::Ble& bleController,
systemTask{systemTask}, Pinetime::Drivers::SpiNorFlash& spiNorFlash)
bleController{bleController}, : systemTask {systemTask},
dfuImage{spiNorFlash}, bleController {bleController},
characteristicDefinition{ dfuImage {spiNorFlash},
{ characteristicDefinition {{
.uuid = (ble_uuid_t *) &packetCharacteristicUuid, .uuid = (ble_uuid_t*) &packetCharacteristicUuid,
.access_cb = DfuServiceCallback, .access_cb = DfuServiceCallback,
.arg = this, .arg = this,
.flags = BLE_GATT_CHR_F_WRITE_NO_RSP, .flags = BLE_GATT_CHR_F_WRITE_NO_RSP,
.val_handle = nullptr, .val_handle = nullptr,
}, },
{ {
.uuid = (ble_uuid_t *) &controlPointCharacteristicUuid, .uuid = (ble_uuid_t*) &controlPointCharacteristicUuid,
.access_cb = DfuServiceCallback, .access_cb = DfuServiceCallback,
.arg = this, .arg = this,
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_NOTIFY, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_NOTIFY,
.val_handle = nullptr, .val_handle = nullptr,
}, },
{ {
.uuid = (ble_uuid_t *) &revisionCharacteristicUuid, .uuid = (ble_uuid_t*) &revisionCharacteristicUuid,
.access_cb = DfuServiceCallback, .access_cb = DfuServiceCallback,
.arg = this, .arg = this,
.flags = BLE_GATT_CHR_F_READ, .flags = BLE_GATT_CHR_F_READ,
.val_handle = &revision, .val_handle = &revision,
}, },
{ {0}
0
}
}, },
serviceDefinition{ serviceDefinition {
{ {/* Device Information Service */
/* Device Information Service */
.type = BLE_GATT_SVC_TYPE_PRIMARY, .type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = (ble_uuid_t *) &serviceUuid, .uuid = (ble_uuid_t*) &serviceUuid,
.characteristics = characteristicDefinition .characteristics = characteristicDefinition},
}, {0},
{
0
},
} { } {
timeoutTimer = xTimerCreate ("notificationTimer", 10000, pdFALSE, this, TimeoutTimerCallback); timeoutTimer = xTimerCreate("notificationTimer", 10000, pdFALSE, this, TimeoutTimerCallback);
} }
void DfuService::Init() { void DfuService::Init() {
@ -83,55 +76,54 @@ void DfuService::Init() {
ASSERT(res == 0); ASSERT(res == 0);
} }
int DfuService::OnServiceData(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt *context) { int DfuService::OnServiceData(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context) {
if(bleController.IsFirmwareUpdating()){ if (bleController.IsFirmwareUpdating()) {
xTimerStart(timeoutTimer, 0); 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 *) &packetCharacteristicUuid, nullptr, ble_gatts_find_chr((ble_uuid_t*) &serviceUuid, (ble_uuid_t*) &controlPointCharacteristicUuid, nullptr, &controlPointCharacteristicHandle);
&packetCharacteristicHandle); ble_gatts_find_chr((ble_uuid_t*) &serviceUuid, (ble_uuid_t*) &revisionCharacteristicUuid, nullptr, &revisionCharacteristicHandle);
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);
if (attributeHandle == packetCharacteristicHandle) { if (attributeHandle == packetCharacteristicHandle) {
if (context->op == BLE_GATT_ACCESS_OP_WRITE_CHR) if (context->op == BLE_GATT_ACCESS_OP_WRITE_CHR)
return WritePacketHandler(connectionHandle, context->om); return WritePacketHandler(connectionHandle, context->om);
else return 0; else
return 0;
} else if (attributeHandle == controlPointCharacteristicHandle) { } else if (attributeHandle == controlPointCharacteristicHandle) {
if (context->op == BLE_GATT_ACCESS_OP_WRITE_CHR) if (context->op == BLE_GATT_ACCESS_OP_WRITE_CHR)
return ControlPointHandler(connectionHandle, context->om); return ControlPointHandler(connectionHandle, context->om);
else return 0; else
return 0;
} else if (attributeHandle == revisionCharacteristicHandle) { } else if (attributeHandle == revisionCharacteristicHandle) {
if (context->op == BLE_GATT_ACCESS_OP_READ_CHR) if (context->op == BLE_GATT_ACCESS_OP_READ_CHR)
return SendDfuRevision(context->om); return SendDfuRevision(context->om);
else return 0; else
return 0;
} else { } else {
NRF_LOG_INFO("[DFU] Unknown Characteristic : %d", attributeHandle); NRF_LOG_INFO("[DFU] Unknown Characteristic : %d", attributeHandle);
return 0; return 0;
} }
} }
int DfuService::SendDfuRevision(os_mbuf *om) const { int DfuService::SendDfuRevision(os_mbuf* om) const {
int res = os_mbuf_append(om, &revision, sizeof(revision)); int res = os_mbuf_append(om, &revision, sizeof(revision));
return (res == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; return (res == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
} }
int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf *om) { int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf* om) {
switch (state) { switch (state) {
case States::Start: { case States::Start: {
softdeviceSize = om->om_data[0] + (om->om_data[1] << 8) + (om->om_data[2] << 16) + (om->om_data[3] << 24); softdeviceSize = om->om_data[0] + (om->om_data[1] << 8) + (om->om_data[2] << 16) + (om->om_data[3] << 24);
bootloaderSize = om->om_data[4] + (om->om_data[5] << 8) + (om->om_data[6] << 16) + (om->om_data[7] << 24); bootloaderSize = om->om_data[4] + (om->om_data[5] << 8) + (om->om_data[6] << 16) + (om->om_data[7] << 24);
applicationSize = om->om_data[8] + (om->om_data[9] << 8) + (om->om_data[10] << 16) + (om->om_data[11] << 24); applicationSize = om->om_data[8] + (om->om_data[9] << 8) + (om->om_data[10] << 16) + (om->om_data[11] << 24);
bleController.FirmwareUpdateTotalBytes(applicationSize); bleController.FirmwareUpdateTotalBytes(applicationSize);
NRF_LOG_INFO("[DFU] -> Start data received : SD size : %d, BT size : %d, app size : %d", softdeviceSize, NRF_LOG_INFO(
bootloaderSize, applicationSize); "[DFU] -> Start data received : SD size : %d, BT size : %d, app size : %d", softdeviceSize, bootloaderSize, applicationSize);
dfuImage.Erase(); dfuImage.Erase();
uint8_t data[]{16, 1, 1}; uint8_t data[] {16, 1, 1};
notificationManager.Send(connectionHandle, controlPointCharacteristicHandle, data, 3); notificationManager.Send(connectionHandle, controlPointCharacteristicHandle, data, 3);
state = States::Init; state = States::Init;
} }
@ -139,19 +131,22 @@ int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf *om) {
case States::Init: { case States::Init: {
uint16_t deviceType = om->om_data[0] + (om->om_data[1] << 8); uint16_t deviceType = om->om_data[0] + (om->om_data[1] << 8);
uint16_t deviceRevision = om->om_data[2] + (om->om_data[3] << 8); uint16_t deviceRevision = om->om_data[2] + (om->om_data[3] << 8);
uint32_t applicationVersion = uint32_t applicationVersion = om->om_data[4] + (om->om_data[5] << 8) + (om->om_data[6] << 16) + (om->om_data[7] << 24);
om->om_data[4] + (om->om_data[5] << 8) + (om->om_data[6] << 16) + (om->om_data[7] << 24);
uint16_t softdeviceArrayLength = om->om_data[8] + (om->om_data[9] << 8); uint16_t softdeviceArrayLength = om->om_data[8] + (om->om_data[9] << 8);
uint16_t sd[softdeviceArrayLength]; uint16_t sd[softdeviceArrayLength];
for (int i = 0; i < softdeviceArrayLength; i++) { for (int i = 0; i < softdeviceArrayLength; i++) {
sd[i] = om->om_data[10 + (i * 2)] + (om->om_data[10 + (i * 2) + 1] << 8); sd[i] = om->om_data[10 + (i * 2)] + (om->om_data[10 + (i * 2) + 1] << 8);
} }
expectedCrc = expectedCrc = om->om_data[10 + (softdeviceArrayLength * 2)] + (om->om_data[10 + (softdeviceArrayLength * 2) + 1] << 8);
om->om_data[10 + (softdeviceArrayLength * 2)] + (om->om_data[10 + (softdeviceArrayLength * 2) + 1] << 8);
NRF_LOG_INFO( NRF_LOG_INFO(
"[DFU] -> Init data received : deviceType = %d, deviceRevision = %d, applicationVersion = %d, nb SD = %d, First SD = %d, CRC = %u", "[DFU] -> Init data received : deviceType = %d, deviceRevision = %d, applicationVersion = %d, nb SD = %d, First SD = %d, CRC = %u",
deviceType, deviceRevision, applicationVersion, softdeviceArrayLength, sd[0], expectedCrc); deviceType,
deviceRevision,
applicationVersion,
softdeviceArrayLength,
sd[0],
expectedCrc);
return 0; return 0;
} }
@ -163,14 +158,16 @@ int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf *om) {
bleController.FirmwareUpdateCurrentBytes(bytesReceived); bleController.FirmwareUpdateCurrentBytes(bytesReceived);
if ((nbPacketReceived % nbPacketsToNotify) == 0 && bytesReceived != applicationSize) { if ((nbPacketReceived % nbPacketsToNotify) == 0 && bytesReceived != applicationSize) {
uint8_t data[5]{static_cast<uint8_t>(Opcodes::PacketReceiptNotification), uint8_t data[5] {static_cast<uint8_t>(Opcodes::PacketReceiptNotification),
(uint8_t) (bytesReceived & 0x000000FFu), (uint8_t) (bytesReceived >> 8u), (uint8_t) (bytesReceived & 0x000000FFu),
(uint8_t) (bytesReceived >> 16u), (uint8_t) (bytesReceived >> 24u)}; (uint8_t) (bytesReceived >> 8u),
(uint8_t) (bytesReceived >> 16u),
(uint8_t) (bytesReceived >> 24u)};
NRF_LOG_INFO("[DFU] -> Send packet notification: %d bytes received", bytesReceived); NRF_LOG_INFO("[DFU] -> Send packet notification: %d bytes received", bytesReceived);
notificationManager.Send(connectionHandle, controlPointCharacteristicHandle, data, 5); notificationManager.Send(connectionHandle, controlPointCharacteristicHandle, data, 5);
} }
if (dfuImage.IsComplete()) { if (dfuImage.IsComplete()) {
uint8_t data[3]{static_cast<uint8_t>(Opcodes::Response), uint8_t data[3] {static_cast<uint8_t>(Opcodes::Response),
static_cast<uint8_t>(Opcodes::ReceiveFirmwareImage), static_cast<uint8_t>(Opcodes::ReceiveFirmwareImage),
static_cast<uint8_t>(ErrorCodes::NoError)}; static_cast<uint8_t>(ErrorCodes::NoError)};
NRF_LOG_INFO("[DFU] -> Send packet notification : all bytes received!"); NRF_LOG_INFO("[DFU] -> Send packet notification : all bytes received!");
@ -186,7 +183,7 @@ int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf *om) {
return 0; return 0;
} }
int DfuService::ControlPointHandler(uint16_t connectionHandle, os_mbuf *om) { int DfuService::ControlPointHandler(uint16_t connectionHandle, os_mbuf* om) {
auto opcode = static_cast<Opcodes>(om->om_data[0]); auto opcode = static_cast<Opcodes>(om->om_data[0]);
NRF_LOG_INFO("[DFU] -> ControlPointHandler"); NRF_LOG_INFO("[DFU] -> ControlPointHandler");
@ -214,8 +211,7 @@ int DfuService::ControlPointHandler(uint16_t connectionHandle, os_mbuf *om) {
NRF_LOG_INFO("[DFU] -> Start DFU, mode %d not supported!", imageType); NRF_LOG_INFO("[DFU] -> Start DFU, mode %d not supported!", imageType);
return 0; return 0;
} }
} } break;
break;
case Opcodes::InitDFUParameters: { case Opcodes::InitDFUParameters: {
if (state != States::Init) { if (state != States::Init) {
NRF_LOG_INFO("[DFU] -> Init DFU requested, but we are not in Init state"); NRF_LOG_INFO("[DFU] -> Init DFU requested, but we are not in Init state");
@ -225,11 +221,9 @@ int DfuService::ControlPointHandler(uint16_t connectionHandle, os_mbuf *om) {
NRF_LOG_INFO("[DFU] -> Init DFU parameters %s", isInitComplete ? " complete" : " not complete"); NRF_LOG_INFO("[DFU] -> Init DFU parameters %s", isInitComplete ? " complete" : " not complete");
if (isInitComplete) { if (isInitComplete) {
uint8_t data[3] { uint8_t data[3] {static_cast<uint8_t>(Opcodes::Response),
static_cast<uint8_t>(Opcodes::Response),
static_cast<uint8_t>(Opcodes::InitDFUParameters), static_cast<uint8_t>(Opcodes::InitDFUParameters),
(isInitComplete ? uint8_t{1} : uint8_t{0}) (isInitComplete ? uint8_t {1} : uint8_t {0})};
};
notificationManager.AsyncSend(connectionHandle, controlPointCharacteristicHandle, data, 3); notificationManager.AsyncSend(connectionHandle, controlPointCharacteristicHandle, data, 3);
return 0; return 0;
} }
@ -257,26 +251,22 @@ int DfuService::ControlPointHandler(uint16_t connectionHandle, os_mbuf *om) {
NRF_LOG_INFO("[DFU] -> Validate firmware image requested -- %d", connectionHandle); NRF_LOG_INFO("[DFU] -> Validate firmware image requested -- %d", connectionHandle);
if(dfuImage.Validate()){ if (dfuImage.Validate()) {
state = States::Validated; state = States::Validated;
bleController.State(Pinetime::Controllers::Ble::FirmwareUpdateStates::Validated); bleController.State(Pinetime::Controllers::Ble::FirmwareUpdateStates::Validated);
NRF_LOG_INFO("Image OK"); NRF_LOG_INFO("Image OK");
uint8_t data[3] { uint8_t data[3] {static_cast<uint8_t>(Opcodes::Response),
static_cast<uint8_t>(Opcodes::Response),
static_cast<uint8_t>(Opcodes::ValidateFirmware), static_cast<uint8_t>(Opcodes::ValidateFirmware),
static_cast<uint8_t>(ErrorCodes::NoError) static_cast<uint8_t>(ErrorCodes::NoError)};
};
notificationManager.AsyncSend(connectionHandle, controlPointCharacteristicHandle, data, 3); notificationManager.AsyncSend(connectionHandle, controlPointCharacteristicHandle, data, 3);
} else { } else {
bleController.State(Pinetime::Controllers::Ble::FirmwareUpdateStates::Error); bleController.State(Pinetime::Controllers::Ble::FirmwareUpdateStates::Error);
NRF_LOG_INFO("Image Error : bad CRC"); NRF_LOG_INFO("Image Error : bad CRC");
uint8_t data[3] { uint8_t data[3] {static_cast<uint8_t>(Opcodes::Response),
static_cast<uint8_t>(Opcodes::Response),
static_cast<uint8_t>(Opcodes::ValidateFirmware), static_cast<uint8_t>(Opcodes::ValidateFirmware),
static_cast<uint8_t>(ErrorCodes::CrcError) static_cast<uint8_t>(ErrorCodes::CrcError)};
};
notificationManager.AsyncSend(connectionHandle, controlPointCharacteristicHandle, data, 3); notificationManager.AsyncSend(connectionHandle, controlPointCharacteristicHandle, data, 3);
} }
@ -318,11 +308,11 @@ void DfuService::Reset() {
} }
DfuService::NotificationManager::NotificationManager() { DfuService::NotificationManager::NotificationManager() {
timer = xTimerCreate ("notificationTimer", 1000, pdFALSE, this, NotificationTimerCallback); timer = xTimerCreate("notificationTimer", 1000, pdFALSE, this, NotificationTimerCallback);
} }
bool DfuService::NotificationManager::AsyncSend(uint16_t connection, uint16_t charactHandle, uint8_t *data, size_t s) { bool DfuService::NotificationManager::AsyncSend(uint16_t connection, uint16_t charactHandle, uint8_t* data, size_t s) {
if(size != 0 || s > 10) if (size != 0 || s > 10)
return false; return false;
connectionHandle = connection; connectionHandle = connection;
@ -334,14 +324,14 @@ bool DfuService::NotificationManager::AsyncSend(uint16_t connection, uint16_t ch
} }
void DfuService::NotificationManager::OnNotificationTimer() { void DfuService::NotificationManager::OnNotificationTimer() {
if(size > 0) { if (size > 0) {
Send(connectionHandle, characteristicHandle, buffer, size); Send(connectionHandle, characteristicHandle, buffer, size);
size = 0; size = 0;
} }
} }
void DfuService::NotificationManager::Send(uint16_t connection, uint16_t charactHandle, const uint8_t *data, const size_t s) { void DfuService::NotificationManager::Send(uint16_t connection, uint16_t charactHandle, const uint8_t* data, const size_t s) {
auto *om = ble_hs_mbuf_from_flat(data, s); auto* om = ble_hs_mbuf_from_flat(data, s);
auto ret = ble_gattc_notify_custom(connection, charactHandle, om); auto ret = ble_gattc_notify_custom(connection, charactHandle, om);
ASSERT(ret == 0); ASSERT(ret == 0);
} }
@ -354,27 +344,29 @@ void DfuService::NotificationManager::Reset() {
} }
void DfuService::DfuImage::Init(size_t chunkSize, size_t totalSize, uint16_t expectedCrc) { void DfuService::DfuImage::Init(size_t chunkSize, size_t totalSize, uint16_t expectedCrc) {
if(chunkSize != 20) return; if (chunkSize != 20)
return;
this->chunkSize = chunkSize; this->chunkSize = chunkSize;
this->totalSize = totalSize; this->totalSize = totalSize;
this->expectedCrc = expectedCrc; this->expectedCrc = expectedCrc;
this->ready = true; this->ready = true;
} }
void DfuService::DfuImage::Append(uint8_t *data, size_t size) { void DfuService::DfuImage::Append(uint8_t* data, size_t size) {
if(!ready) return; if (!ready)
return;
ASSERT(size <= 20); ASSERT(size <= 20);
std::memcpy(tempBuffer + bufferWriteIndex, data, size); std::memcpy(tempBuffer + bufferWriteIndex, data, size);
bufferWriteIndex += size; bufferWriteIndex += size;
if(bufferWriteIndex == bufferSize) { if (bufferWriteIndex == bufferSize) {
spiNorFlash.Write(writeOffset + totalWriteIndex, tempBuffer, bufferWriteIndex); spiNorFlash.Write(writeOffset + totalWriteIndex, tempBuffer, bufferWriteIndex);
totalWriteIndex += bufferWriteIndex; totalWriteIndex += bufferWriteIndex;
bufferWriteIndex = 0; bufferWriteIndex = 0;
} }
if(bufferWriteIndex > 0 && totalWriteIndex + bufferWriteIndex == totalSize) { if (bufferWriteIndex > 0 && totalWriteIndex + bufferWriteIndex == totalSize) {
spiNorFlash.Write(writeOffset + totalWriteIndex, tempBuffer, bufferWriteIndex); spiNorFlash.Write(writeOffset + totalWriteIndex, tempBuffer, bufferWriteIndex);
totalWriteIndex += bufferWriteIndex; totalWriteIndex += bufferWriteIndex;
if (totalSize < maxSize) if (totalSize < maxSize)
@ -383,7 +375,8 @@ void DfuService::DfuImage::Append(uint8_t *data, size_t size) {
} }
void DfuService::DfuImage::WriteMagicNumber() { void DfuService::DfuImage::WriteMagicNumber() {
uint32_t magic[4] = { // TODO When this variable is a static constexpr, the values written to the memory are not correct. Why? uint32_t magic[4] = {
// TODO When this variable is a static constexpr, the values written to the memory are not correct. Why?
0xf395c277, 0xf395c277,
0x7fefd260, 0x7fefd260,
0x0f505235, 0x0f505235,
@ -391,7 +384,7 @@ void DfuService::DfuImage::WriteMagicNumber() {
}; };
uint32_t offset = writeOffset + (maxSize - (4 * sizeof(uint32_t))); uint32_t offset = writeOffset + (maxSize - (4 * sizeof(uint32_t)));
spiNorFlash.Write(offset, reinterpret_cast<const uint8_t *>(magic), 4 * sizeof(uint32_t)); spiNorFlash.Write(offset, reinterpret_cast<const uint8_t*>(magic), 4 * sizeof(uint32_t));
} }
void DfuService::DfuImage::Erase() { void DfuService::DfuImage::Erase() {
@ -421,7 +414,7 @@ bool DfuService::DfuImage::Validate() {
return (crc == expectedCrc); return (crc == expectedCrc);
} }
uint16_t DfuService::DfuImage::ComputeCrc(uint8_t const *p_data, uint32_t size, uint16_t const *p_crc) { uint16_t DfuService::DfuImage::ComputeCrc(uint8_t const* p_data, uint32_t size, uint16_t const* p_crc) {
uint16_t crc = (p_crc == NULL) ? 0xFFFF : *p_crc; uint16_t crc = (p_crc == NULL) ? 0xFFFF : *p_crc;
for (uint32_t i = 0; i < size; i++) { for (uint32_t i = 0; i < size; i++) {
@ -436,6 +429,7 @@ uint16_t DfuService::DfuImage::ComputeCrc(uint8_t const *p_data, uint32_t size,
} }
bool DfuService::DfuImage::IsComplete() { bool DfuService::DfuImage::IsComplete() {
if(!ready) return false; if (!ready)
return false;
return totalWriteIndex == totalSize; return totalWriteIndex == totalSize;
} }

View File

@ -21,31 +21,35 @@ namespace Pinetime {
class DfuService { class DfuService {
public: public:
DfuService(Pinetime::System::SystemTask &systemTask, Pinetime::Controllers::Ble &bleController, DfuService(Pinetime::System::SystemTask& systemTask,
Pinetime::Drivers::SpiNorFlash &spiNorFlash); Pinetime::Controllers::Ble& bleController,
Pinetime::Drivers::SpiNorFlash& spiNorFlash);
void Init(); void Init();
int OnServiceData(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt *context); int OnServiceData(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context);
void OnTimeout(); void OnTimeout();
void Reset(); void Reset();
class NotificationManager { class NotificationManager {
public: public:
NotificationManager(); NotificationManager();
bool AsyncSend(uint16_t connection, uint16_t charactHandle, uint8_t *data, size_t size); bool AsyncSend(uint16_t connection, uint16_t charactHandle, uint8_t* data, size_t size);
void Send(uint16_t connection, uint16_t characteristicHandle, const uint8_t *data, const size_t s); void Send(uint16_t connection, uint16_t characteristicHandle, const uint8_t* data, const size_t s);
private: private:
TimerHandle_t timer; TimerHandle_t timer;
uint16_t connectionHandle = 0; uint16_t connectionHandle = 0;
uint16_t characteristicHandle = 0; uint16_t characteristicHandle = 0;
size_t size = 0; size_t size = 0;
uint8_t buffer[10]; uint8_t buffer[10];
public: public:
void OnNotificationTimer(); void OnNotificationTimer();
void Reset(); void Reset();
}; };
class DfuImage { class DfuImage {
public: public:
DfuImage(Pinetime::Drivers::SpiNorFlash& spiNorFlash) : spiNorFlash{spiNorFlash} {} DfuImage(Pinetime::Drivers::SpiNorFlash& spiNorFlash) : spiNorFlash {spiNorFlash} {
}
void Init(size_t chunkSize, size_t totalSize, uint16_t expectedCrc); void Init(size_t chunkSize, size_t totalSize, uint16_t expectedCrc);
void Erase(); void Erase();
void Append(uint8_t* data, size_t size); void Append(uint8_t* data, size_t size);
@ -66,46 +70,37 @@ namespace Pinetime {
uint16_t expectedCrc = 0; uint16_t expectedCrc = 0;
void WriteMagicNumber(); void WriteMagicNumber();
uint16_t ComputeCrc(uint8_t const *p_data, uint32_t size, uint16_t const *p_crc); uint16_t ComputeCrc(uint8_t const* p_data, uint32_t size, uint16_t const* p_crc);
}; };
private: private:
Pinetime::System::SystemTask &systemTask; Pinetime::System::SystemTask& systemTask;
Pinetime::Controllers::Ble &bleController; Pinetime::Controllers::Ble& bleController;
DfuImage dfuImage; DfuImage dfuImage;
NotificationManager notificationManager; NotificationManager notificationManager;
static constexpr uint16_t dfuServiceId{0x1530}; static constexpr uint16_t dfuServiceId {0x1530};
static constexpr uint16_t packetCharacteristicId{0x1532}; static constexpr uint16_t packetCharacteristicId {0x1532};
static constexpr uint16_t controlPointCharacteristicId{0x1531}; static constexpr uint16_t controlPointCharacteristicId {0x1531};
static constexpr uint16_t revisionCharacteristicId{0x1534}; static constexpr uint16_t revisionCharacteristicId {0x1534};
uint16_t revision{0x0008}; uint16_t revision {0x0008};
static constexpr ble_uuid128_t serviceUuid{ static constexpr ble_uuid128_t serviceUuid {
.u {.type = BLE_UUID_TYPE_128}, .u {.type = BLE_UUID_TYPE_128},
.value = {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15, .value = {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15, 0xDE, 0xEF, 0x12, 0x12, 0x30, 0x15, 0x00, 0x00}};
0xDE, 0xEF, 0x12, 0x12, 0x30, 0x15, 0x00, 0x00}
};
static constexpr ble_uuid128_t packetCharacteristicUuid{ static constexpr ble_uuid128_t packetCharacteristicUuid {
.u {.type = BLE_UUID_TYPE_128}, .u {.type = BLE_UUID_TYPE_128},
.value = {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15, .value = {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15, 0xDE, 0xEF, 0x12, 0x12, 0x32, 0x15, 0x00, 0x00}};
0xDE, 0xEF, 0x12, 0x12, 0x32, 0x15, 0x00, 0x00}
};
static constexpr ble_uuid128_t controlPointCharacteristicUuid{ static constexpr ble_uuid128_t controlPointCharacteristicUuid {
.u {.type = BLE_UUID_TYPE_128}, .u {.type = BLE_UUID_TYPE_128},
.value = {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15, .value = {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15, 0xDE, 0xEF, 0x12, 0x12, 0x31, 0x15, 0x00, 0x00}};
0xDE, 0xEF, 0x12, 0x12, 0x31, 0x15, 0x00, 0x00}
};
static constexpr ble_uuid128_t revisionCharacteristicUuid{ static constexpr ble_uuid128_t revisionCharacteristicUuid {
.u {.type = BLE_UUID_TYPE_128}, .u {.type = BLE_UUID_TYPE_128},
.value = {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15, .value = {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15, 0xDE, 0xEF, 0x12, 0x12, 0x34, 0x15, 0x00, 0x00}};
0xDE, 0xEF, 0x12, 0x12, 0x34, 0x15, 0x00, 0x00}
};
struct ble_gatt_chr_def characteristicDefinition[4]; struct ble_gatt_chr_def characteristicDefinition[4];
struct ble_gatt_svc_def serviceDefinition[2]; struct ble_gatt_svc_def serviceDefinition[2];
@ -113,9 +108,7 @@ namespace Pinetime {
uint16_t controlPointCharacteristicHandle; uint16_t controlPointCharacteristicHandle;
uint16_t revisionCharacteristicHandle; uint16_t revisionCharacteristicHandle;
enum class States : uint8_t { enum class States : uint8_t { Idle, Init, Start, Data, Validate, Validated };
Idle, Init, Start, Data, Validate, Validated
};
States state = States::Idle; States state = States::Idle;
enum class ImageTypes : uint8_t { enum class ImageTypes : uint8_t {
@ -155,9 +148,9 @@ namespace Pinetime {
uint32_t applicationSize = 0; uint32_t applicationSize = 0;
uint16_t expectedCrc = 0; uint16_t expectedCrc = 0;
int SendDfuRevision(os_mbuf *om) const; int SendDfuRevision(os_mbuf* om) const;
int WritePacketHandler(uint16_t connectionHandle, os_mbuf *om); int WritePacketHandler(uint16_t connectionHandle, os_mbuf* om);
int ControlPointHandler(uint16_t connectionHandle, os_mbuf *om); int ControlPointHandler(uint16_t connectionHandle, os_mbuf* om);
TimerHandle_t timeoutTimer; TimerHandle_t timeoutTimer;
}; };

View File

@ -8,39 +8,29 @@ constexpr ble_uuid16_t HeartRateService::heartRateServiceUuid;
constexpr ble_uuid16_t HeartRateService::heartRateMeasurementUuid; constexpr ble_uuid16_t HeartRateService::heartRateMeasurementUuid;
namespace { namespace {
int HeartRateServiceServiceCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) { int HeartRateServiceServiceCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
auto* heartRateService = static_cast<HeartRateService*>(arg); auto* heartRateService = static_cast<HeartRateService*>(arg);
return heartRateService->OnHeartRateRequested(conn_handle, attr_handle, ctxt); return heartRateService->OnHeartRateRequested(conn_handle, attr_handle, ctxt);
} }
} }
// TODO Refactoring - remove dependency to SystemTask // TODO Refactoring - remove dependency to SystemTask
HeartRateService::HeartRateService(Pinetime::System::SystemTask &system, Controllers::HeartRateController& heartRateController) : HeartRateService::HeartRateService(Pinetime::System::SystemTask& system, Controllers::HeartRateController& heartRateController)
system{system}, : system {system},
heartRateController{heartRateController}, heartRateController {heartRateController},
characteristicDefinition{ characteristicDefinition {{.uuid = (ble_uuid_t*) &heartRateMeasurementUuid,
{
.uuid = (ble_uuid_t *) &heartRateMeasurementUuid,
.access_cb = HeartRateServiceServiceCallback, .access_cb = HeartRateServiceServiceCallback,
.arg = this, .arg = this,
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY, .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY,
.val_handle = &heartRateMeasurementHandle .val_handle = &heartRateMeasurementHandle},
}, {0}},
{ serviceDefinition {
0 {/* Device Information Service */
}
},
serviceDefinition{
{
/* Device Information Service */
.type = BLE_GATT_SVC_TYPE_PRIMARY, .type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = (ble_uuid_t *) &heartRateServiceUuid, .uuid = (ble_uuid_t*) &heartRateServiceUuid,
.characteristics = characteristicDefinition .characteristics = characteristicDefinition},
}, {0},
{ } {
0
},
}{
// TODO refactor to prevent this loop dependency (service depends on controller and controller depends on service) // TODO refactor to prevent this loop dependency (service depends on controller and controller depends on service)
heartRateController.SetService(this); heartRateController.SetService(this);
} }
@ -54,9 +44,8 @@ void HeartRateService::Init() {
ASSERT(res == 0); ASSERT(res == 0);
} }
int HeartRateService::OnHeartRateRequested(uint16_t connectionHandle, uint16_t attributeHandle, int HeartRateService::OnHeartRateRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context) {
ble_gatt_access_ctxt *context) { if (attributeHandle == heartRateMeasurementHandle) {
if(attributeHandle == heartRateMeasurementHandle) {
NRF_LOG_INFO("HEARTRATE : handle = %d", heartRateMeasurementHandle); NRF_LOG_INFO("HEARTRATE : handle = %d", heartRateMeasurementHandle);
uint8_t buffer[2] = {0, heartRateController.HeartRate()}; // [0] = flags, [1] = hr value uint8_t buffer[2] = {0, heartRateController.HeartRate()}; // [0] = flags, [1] = hr value
@ -68,7 +57,7 @@ int HeartRateService::OnHeartRateRequested(uint16_t connectionHandle, uint16_t a
void HeartRateService::OnNewHeartRateValue(uint8_t heartRateValue) { void HeartRateService::OnNewHeartRateValue(uint8_t heartRateValue) {
uint8_t buffer[2] = {0, heartRateController.HeartRate()}; // [0] = flags, [1] = hr value uint8_t buffer[2] = {0, heartRateController.HeartRate()}; // [0] = flags, [1] = hr value
auto *om = ble_hs_mbuf_from_flat(buffer, 2); auto* om = ble_hs_mbuf_from_flat(buffer, 2);
uint16_t connectionHandle = system.nimble().connHandle(); uint16_t connectionHandle = system.nimble().connHandle();

View File

@ -13,32 +13,25 @@ namespace Pinetime {
class HeartRateController; class HeartRateController;
class HeartRateService { class HeartRateService {
public: public:
HeartRateService(Pinetime::System::SystemTask &system, Controllers::HeartRateController& heartRateController); HeartRateService(Pinetime::System::SystemTask& system, Controllers::HeartRateController& heartRateController);
void Init(); void Init();
int OnHeartRateRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt *context); int OnHeartRateRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context);
void OnNewHeartRateValue(uint8_t hearRateValue); void OnNewHeartRateValue(uint8_t hearRateValue);
private: private:
Pinetime::System::SystemTask &system; Pinetime::System::SystemTask& system;
Controllers::HeartRateController& heartRateController; Controllers::HeartRateController& heartRateController;
static constexpr uint16_t heartRateServiceId {0x180D}; static constexpr uint16_t heartRateServiceId {0x180D};
static constexpr uint16_t heartRateMeasurementId {0x2A37}; static constexpr uint16_t heartRateMeasurementId {0x2A37};
static constexpr ble_uuid16_t heartRateServiceUuid { static constexpr ble_uuid16_t heartRateServiceUuid {.u {.type = BLE_UUID_TYPE_16}, .value = heartRateServiceId};
.u {.type = BLE_UUID_TYPE_16},
.value = heartRateServiceId
};
static constexpr ble_uuid16_t heartRateMeasurementUuid { static constexpr ble_uuid16_t heartRateMeasurementUuid {.u {.type = BLE_UUID_TYPE_16}, .value = heartRateMeasurementId};
.u {.type = BLE_UUID_TYPE_16},
.value = heartRateMeasurementId
};
struct ble_gatt_chr_def characteristicDefinition[3]; struct ble_gatt_chr_def characteristicDefinition[3];
struct ble_gatt_svc_def serviceDefinition[2]; struct ble_gatt_svc_def serviceDefinition[2];
uint16_t heartRateMeasurementHandle; uint16_t heartRateMeasurementHandle;
}; };
} }
} }

View File

@ -9,49 +9,42 @@ constexpr ble_uuid16_t ImmediateAlertService::immediateAlertServiceUuid;
constexpr ble_uuid16_t ImmediateAlertService::alertLevelUuid; constexpr ble_uuid16_t ImmediateAlertService::alertLevelUuid;
namespace { namespace {
int AlertLevelCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) { int AlertLevelCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
auto *immediateAlertService = static_cast<ImmediateAlertService *>(arg); auto* immediateAlertService = static_cast<ImmediateAlertService*>(arg);
return immediateAlertService->OnAlertLevelChanged(conn_handle, attr_handle, ctxt); return immediateAlertService->OnAlertLevelChanged(conn_handle, attr_handle, ctxt);
} }
const char* ToString(ImmediateAlertService::Levels level) { const char* ToString(ImmediateAlertService::Levels level) {
switch (level) { switch (level) {
case ImmediateAlertService::Levels::NoAlert: return "Alert : None"; case ImmediateAlertService::Levels::NoAlert:
case ImmediateAlertService::Levels::HighAlert: return "Alert : High"; return "Alert : None";
case ImmediateAlertService::Levels::MildAlert: return "Alert : Mild"; case ImmediateAlertService::Levels::HighAlert:
default: return ""; return "Alert : High";
case ImmediateAlertService::Levels::MildAlert:
return "Alert : Mild";
default:
return "";
} }
} }
} }
ImmediateAlertService::ImmediateAlertService(Pinetime::System::SystemTask &systemTask, ImmediateAlertService::ImmediateAlertService(Pinetime::System::SystemTask& systemTask,
Pinetime::Controllers::NotificationManager &notificationManager) : Pinetime::Controllers::NotificationManager& notificationManager)
systemTask{systemTask}, : systemTask {systemTask},
notificationManager{notificationManager}, notificationManager {notificationManager},
characteristicDefinition{ characteristicDefinition {{.uuid = (ble_uuid_t*) &alertLevelUuid,
{
.uuid = (ble_uuid_t *) &alertLevelUuid,
.access_cb = AlertLevelCallback, .access_cb = AlertLevelCallback,
.arg = this, .arg = this,
.flags = BLE_GATT_CHR_F_WRITE_NO_RSP, .flags = BLE_GATT_CHR_F_WRITE_NO_RSP,
.val_handle = &alertLevelHandle .val_handle = &alertLevelHandle},
}, {0}},
{ serviceDefinition {
0 {/* Device Information Service */
}
},
serviceDefinition{
{
/* Device Information Service */
.type = BLE_GATT_SVC_TYPE_PRIMARY, .type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = (ble_uuid_t *) &immediateAlertServiceUuid, .uuid = (ble_uuid_t*) &immediateAlertServiceUuid,
.characteristics = characteristicDefinition .characteristics = characteristicDefinition},
}, {0},
{ } {
0
},
}{
} }
void ImmediateAlertService::Init() { void ImmediateAlertService::Init() {
@ -63,9 +56,9 @@ void ImmediateAlertService::Init() {
ASSERT(res == 0); ASSERT(res == 0);
} }
int ImmediateAlertService::OnAlertLevelChanged(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt *context) { int ImmediateAlertService::OnAlertLevelChanged(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context) {
if(attributeHandle == alertLevelHandle) { if (attributeHandle == alertLevelHandle) {
if(context->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { if (context->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
auto alertLevel = static_cast<Levels>(context->om->om_data[0]); auto alertLevel = static_cast<Levels>(context->om->om_data[0]);
auto* alertString = ToString(alertLevel); auto* alertString = ToString(alertLevel);

View File

@ -13,16 +13,11 @@ namespace Pinetime {
class NotificationManager; class NotificationManager;
class ImmediateAlertService { class ImmediateAlertService {
public: public:
enum class Levels : uint8_t { enum class Levels : uint8_t { NoAlert = 0, MildAlert = 1, HighAlert = 2 };
NoAlert = 0,
MildAlert = 1,
HighAlert = 2
};
ImmediateAlertService(Pinetime::System::SystemTask &systemTask, ImmediateAlertService(Pinetime::System::SystemTask& systemTask, Pinetime::Controllers::NotificationManager& notificationManager);
Pinetime::Controllers::NotificationManager &notificationManager);
void Init(); void Init();
int OnAlertLevelChanged(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt *context); int OnAlertLevelChanged(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context);
private: private:
Pinetime::System::SystemTask& systemTask; Pinetime::System::SystemTask& systemTask;
@ -31,15 +26,9 @@ namespace Pinetime {
static constexpr uint16_t immediateAlertServiceId {0x1802}; static constexpr uint16_t immediateAlertServiceId {0x1802};
static constexpr uint16_t alertLevelId {0x2A06}; static constexpr uint16_t alertLevelId {0x2A06};
static constexpr ble_uuid16_t immediateAlertServiceUuid { static constexpr ble_uuid16_t immediateAlertServiceUuid {.u {.type = BLE_UUID_TYPE_16}, .value = immediateAlertServiceId};
.u {.type = BLE_UUID_TYPE_16},
.value = immediateAlertServiceId
};
static constexpr ble_uuid16_t alertLevelUuid { static constexpr ble_uuid16_t alertLevelUuid {.u {.type = BLE_UUID_TYPE_16}, .value = alertLevelId};
.u {.type = BLE_UUID_TYPE_16},
.value = alertLevelId
};
struct ble_gatt_chr_def characteristicDefinition[3]; struct ble_gatt_chr_def characteristicDefinition[3];
struct ble_gatt_svc_def serviceDefinition[2]; struct ble_gatt_svc_def serviceDefinition[2];

View File

@ -18,12 +18,12 @@
#include "MusicService.h" #include "MusicService.h"
#include "systemtask/SystemTask.h" #include "systemtask/SystemTask.h"
int MSCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) { int MSCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
auto musicService = static_cast<Pinetime::Controllers::MusicService *>(arg); auto musicService = static_cast<Pinetime::Controllers::MusicService*>(arg);
return musicService->OnCommand(conn_handle, attr_handle, ctxt); return musicService->OnCommand(conn_handle, attr_handle, ctxt);
} }
Pinetime::Controllers::MusicService::MusicService(Pinetime::System::SystemTask &system) : m_system(system) { Pinetime::Controllers::MusicService::MusicService(Pinetime::System::SystemTask& system) : m_system(system) {
msUuid.value[14] = msId[0]; msUuid.value[14] = msId[0];
msUuid.value[15] = msId[1]; msUuid.value[15] = msId[1];
@ -87,79 +87,48 @@ Pinetime::Controllers::MusicService::MusicService(Pinetime::System::SystemTask &
msShuffleCharUuid.value[14] = msId[0]; msShuffleCharUuid.value[14] = msId[0];
msShuffleCharUuid.value[15] = msId[1]; msShuffleCharUuid.value[15] = msId[1];
characteristicDefinition[0] = {.uuid = (ble_uuid_t *) (&msEventCharUuid), characteristicDefinition[0] = {.uuid = (ble_uuid_t*) (&msEventCharUuid),
.access_cb = MSCallback, .access_cb = MSCallback,
.arg = this, .arg = this,
.flags = BLE_GATT_CHR_F_NOTIFY, .flags = BLE_GATT_CHR_F_NOTIFY,
.val_handle = &eventHandle .val_handle = &eventHandle};
}; characteristicDefinition[1] = {
characteristicDefinition[1] = {.uuid = (ble_uuid_t *) (&msStatusCharUuid), .uuid = (ble_uuid_t*) (&msStatusCharUuid), .access_cb = MSCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
characteristicDefinition[2] = {
.uuid = (ble_uuid_t*) (&msTrackCharUuid), .access_cb = MSCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
characteristicDefinition[3] = {
.uuid = (ble_uuid_t*) (&msArtistCharUuid), .access_cb = MSCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
characteristicDefinition[4] = {
.uuid = (ble_uuid_t*) (&msAlbumCharUuid), .access_cb = MSCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
characteristicDefinition[5] = {
.uuid = (ble_uuid_t*) (&msPositionCharUuid), .access_cb = MSCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
characteristicDefinition[6] = {.uuid = (ble_uuid_t*) (&msTotalLengthCharUuid),
.access_cb = MSCallback, .access_cb = MSCallback,
.arg = this, .arg = this,
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
}; characteristicDefinition[7] = {.uuid = (ble_uuid_t*) (&msTotalLengthCharUuid),
characteristicDefinition[2] = {.uuid = (ble_uuid_t *) (&msTrackCharUuid),
.access_cb = MSCallback, .access_cb = MSCallback,
.arg = this, .arg = this,
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
}; characteristicDefinition[8] = {.uuid = (ble_uuid_t*) (&msTrackNumberCharUuid),
characteristicDefinition[3] = {.uuid = (ble_uuid_t *) (&msArtistCharUuid),
.access_cb = MSCallback, .access_cb = MSCallback,
.arg = this, .arg = this,
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
}; characteristicDefinition[9] = {.uuid = (ble_uuid_t*) (&msTrackTotalCharUuid),
characteristicDefinition[4] = {.uuid = (ble_uuid_t *) (&msAlbumCharUuid),
.access_cb = MSCallback, .access_cb = MSCallback,
.arg = this, .arg = this,
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
}; characteristicDefinition[10] = {.uuid = (ble_uuid_t*) (&msPlaybackSpeedCharUuid),
characteristicDefinition[5] = {.uuid = (ble_uuid_t *) (&msPositionCharUuid),
.access_cb = MSCallback, .access_cb = MSCallback,
.arg = this, .arg = this,
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
}; characteristicDefinition[11] = {
characteristicDefinition[6] = {.uuid = (ble_uuid_t *) (&msTotalLengthCharUuid), .uuid = (ble_uuid_t*) (&msRepeatCharUuid), .access_cb = MSCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
.access_cb = MSCallback, characteristicDefinition[12] = {
.arg = this, .uuid = (ble_uuid_t*) (&msShuffleCharUuid), .access_cb = MSCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
};
characteristicDefinition[7] = {.uuid = (ble_uuid_t *) (&msTotalLengthCharUuid),
.access_cb = MSCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
};
characteristicDefinition[8] = {.uuid = (ble_uuid_t *) (&msTrackNumberCharUuid),
.access_cb = MSCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
};
characteristicDefinition[9] = {.uuid = (ble_uuid_t *) (&msTrackTotalCharUuid),
.access_cb = MSCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
};
characteristicDefinition[10] = {.uuid = (ble_uuid_t *) (&msPlaybackSpeedCharUuid),
.access_cb = MSCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
};
characteristicDefinition[11] = {.uuid = (ble_uuid_t *) (&msRepeatCharUuid),
.access_cb = MSCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
};
characteristicDefinition[12] = {.uuid = (ble_uuid_t *) (&msShuffleCharUuid),
.access_cb = MSCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
};
characteristicDefinition[13] = {0}; characteristicDefinition[13] = {0};
serviceDefinition[0] = { serviceDefinition[0] = {.type = BLE_GATT_SVC_TYPE_PRIMARY, .uuid = (ble_uuid_t*) &msUuid, .characteristics = characteristicDefinition};
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = (ble_uuid_t *) &msUuid,
.characteristics = characteristicDefinition
};
serviceDefinition[1] = {0}; serviceDefinition[1] = {0};
artistName = "Waiting for"; artistName = "Waiting for";
@ -182,36 +151,35 @@ void Pinetime::Controllers::MusicService::Init() {
ASSERT(res == 0); ASSERT(res == 0);
} }
int Pinetime::Controllers::MusicService::OnCommand(uint16_t conn_handle, uint16_t attr_handle, int Pinetime::Controllers::MusicService::OnCommand(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) {
struct ble_gatt_access_ctxt *ctxt) {
if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
size_t notifSize = OS_MBUF_PKTLEN(ctxt->om); size_t notifSize = OS_MBUF_PKTLEN(ctxt->om);
uint8_t data[notifSize + 1]; uint8_t data[notifSize + 1];
data[notifSize] = '\0'; data[notifSize] = '\0';
os_mbuf_copydata(ctxt->om, 0, notifSize, data); os_mbuf_copydata(ctxt->om, 0, notifSize, data);
char *s = (char *) &data[0]; char* s = (char*) &data[0];
if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msArtistCharUuid) == 0) { if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msArtistCharUuid) == 0) {
artistName = s; artistName = s;
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msTrackCharUuid) == 0) { } else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msTrackCharUuid) == 0) {
trackName = s; trackName = s;
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msAlbumCharUuid) == 0) { } else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msAlbumCharUuid) == 0) {
albumName = s; albumName = s;
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msStatusCharUuid) == 0) { } else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msStatusCharUuid) == 0) {
playing = s[0]; playing = s[0];
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msRepeatCharUuid) == 0) { } else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msRepeatCharUuid) == 0) {
repeat = s[0]; repeat = s[0];
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msShuffleCharUuid) == 0) { } else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msShuffleCharUuid) == 0) {
shuffle = s[0]; shuffle = s[0];
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msPositionCharUuid) == 0) { } else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msPositionCharUuid) == 0) {
trackProgress = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3]; trackProgress = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msTotalLengthCharUuid) == 0) { } else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msTotalLengthCharUuid) == 0) {
trackLength = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3]; trackLength = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msTrackNumberCharUuid) == 0) { } else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msTrackNumberCharUuid) == 0) {
trackNumber = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3]; trackNumber = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msTrackTotalCharUuid) == 0) { } else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msTrackTotalCharUuid) == 0) {
tracksTotal = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3]; tracksTotal = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msPlaybackSpeedCharUuid) == 0) { } else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msPlaybackSpeedCharUuid) == 0) {
playbackSpeed = static_cast<float>(((s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3])) / 100.0f; playbackSpeed = static_cast<float>(((s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3])) / 100.0f;
} }
} }
@ -239,7 +207,7 @@ float Pinetime::Controllers::MusicService::getPlaybackSpeed() {
} }
void Pinetime::Controllers::MusicService::event(char event) { void Pinetime::Controllers::MusicService::event(char event) {
auto *om = ble_hs_mbuf_from_flat(&event, 1); auto* om = ble_hs_mbuf_from_flat(&event, 1);
uint16_t connectionHandle = m_system.nimble().connHandle(); uint16_t connectionHandle = m_system.nimble().connHandle();
@ -257,4 +225,3 @@ int Pinetime::Controllers::MusicService::getProgress() {
int Pinetime::Controllers::MusicService::getTrackLength() { int Pinetime::Controllers::MusicService::getTrackLength() {
return trackLength; return trackLength;
} }

View File

@ -26,8 +26,9 @@
#undef max #undef max
#undef min #undef min
//00000000-78fc-48fe-8e23-433b3a1942d0 // 00000000-78fc-48fe-8e23-433b3a1942d0
#define MUSIC_SERVICE_UUID_BASE {0xd0, 0x42, 0x19, 0x3a, 0x3b, 0x43, 0x23, 0x8e, 0xfe, 0x48, 0xfc, 0x78, 0x00, 0x00, 0x00, 0x00} #define MUSIC_SERVICE_UUID_BASE \
{ 0xd0, 0x42, 0x19, 0x3a, 0x3b, 0x43, 0x23, 0x8e, 0xfe, 0x48, 0xfc, 0x78, 0x00, 0x00, 0x00, 0x00 }
namespace Pinetime { namespace Pinetime {
namespace System { namespace System {
@ -37,12 +38,11 @@ namespace Pinetime {
class MusicService { class MusicService {
public: public:
explicit MusicService(Pinetime::System::SystemTask &system); explicit MusicService(Pinetime::System::SystemTask& system);
void Init(); void Init();
int OnCommand(uint16_t conn_handle, uint16_t attr_handle, int OnCommand(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt);
struct ble_gatt_access_ctxt *ctxt);
void event(char event); void event(char event);
@ -68,10 +68,8 @@ namespace Pinetime {
static const char EVENT_MUSIC_VOLUP = 0x05; static const char EVENT_MUSIC_VOLUP = 0x05;
static const char EVENT_MUSIC_VOLDOWN = 0x06; static const char EVENT_MUSIC_VOLDOWN = 0x06;
enum MusicStatus { enum MusicStatus { NotPlaying = 0x00, Playing = 0x01 };
NotPlaying = 0x00,
Playing = 0x01
};
private: private:
static constexpr uint8_t msId[2] = {0x00, 0x00}; static constexpr uint8_t msId[2] = {0x00, 0x00};
static constexpr uint8_t msEventCharId[2] = {0x01, 0x00}; static constexpr uint8_t msEventCharId[2] = {0x01, 0x00};
@ -87,59 +85,20 @@ namespace Pinetime {
static constexpr uint8_t msRepeatCharId[2] = {0x0b, 0x00}; static constexpr uint8_t msRepeatCharId[2] = {0x0b, 0x00};
static constexpr uint8_t msShuffleCharId[2] = {0x0c, 0x00}; static constexpr uint8_t msShuffleCharId[2] = {0x0c, 0x00};
ble_uuid128_t msUuid{ ble_uuid128_t msUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
.u = {.type = BLE_UUID_TYPE_128},
.value = MUSIC_SERVICE_UUID_BASE
};
ble_uuid128_t msEventCharUuid{ ble_uuid128_t msEventCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
.u = {.type = BLE_UUID_TYPE_128}, ble_uuid128_t msStatusCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
.value = MUSIC_SERVICE_UUID_BASE ble_uuid128_t msArtistCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
}; ble_uuid128_t msTrackCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
ble_uuid128_t msStatusCharUuid{ ble_uuid128_t msAlbumCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
.u = {.type = BLE_UUID_TYPE_128}, ble_uuid128_t msPositionCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
.value = MUSIC_SERVICE_UUID_BASE ble_uuid128_t msTotalLengthCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
}; ble_uuid128_t msTrackNumberCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
ble_uuid128_t msArtistCharUuid{ ble_uuid128_t msTrackTotalCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
.u = {.type = BLE_UUID_TYPE_128}, ble_uuid128_t msPlaybackSpeedCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
.value = MUSIC_SERVICE_UUID_BASE ble_uuid128_t msRepeatCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
}; ble_uuid128_t msShuffleCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
ble_uuid128_t msTrackCharUuid{
.u = {.type = BLE_UUID_TYPE_128},
.value = MUSIC_SERVICE_UUID_BASE
};
ble_uuid128_t msAlbumCharUuid{
.u = {.type = BLE_UUID_TYPE_128},
.value = MUSIC_SERVICE_UUID_BASE
};
ble_uuid128_t msPositionCharUuid{
.u = {.type = BLE_UUID_TYPE_128},
.value = MUSIC_SERVICE_UUID_BASE
};
ble_uuid128_t msTotalLengthCharUuid{
.u = {.type = BLE_UUID_TYPE_128},
.value = MUSIC_SERVICE_UUID_BASE
};
ble_uuid128_t msTrackNumberCharUuid{
.u = {.type = BLE_UUID_TYPE_128},
.value = MUSIC_SERVICE_UUID_BASE
};
ble_uuid128_t msTrackTotalCharUuid{
.u = {.type = BLE_UUID_TYPE_128},
.value = MUSIC_SERVICE_UUID_BASE
};
ble_uuid128_t msPlaybackSpeedCharUuid{
.u = {.type = BLE_UUID_TYPE_128},
.value = MUSIC_SERVICE_UUID_BASE
};
ble_uuid128_t msRepeatCharUuid{
.u = {.type = BLE_UUID_TYPE_128},
.value = MUSIC_SERVICE_UUID_BASE
};
ble_uuid128_t msShuffleCharUuid{
.u = {.type = BLE_UUID_TYPE_128},
.value = MUSIC_SERVICE_UUID_BASE
};
struct ble_gatt_chr_def characteristicDefinition[14]; struct ble_gatt_chr_def characteristicDefinition[14];
struct ble_gatt_svc_def serviceDefinition[2]; struct ble_gatt_svc_def serviceDefinition[2];
@ -162,8 +121,7 @@ namespace Pinetime {
bool repeat; bool repeat;
bool shuffle; bool shuffle;
Pinetime::System::SystemTask &m_system; Pinetime::System::SystemTask& m_system;
}; };
} }
} }

View File

@ -20,12 +20,12 @@
#include "systemtask/SystemTask.h" #include "systemtask/SystemTask.h"
int NAVCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) { 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); auto navService = static_cast<Pinetime::Controllers::NavigationService*>(arg);
return navService->OnCommand(conn_handle, attr_handle, ctxt); return navService->OnCommand(conn_handle, attr_handle, ctxt);
} }
Pinetime::Controllers::NavigationService::NavigationService(Pinetime::System::SystemTask &system) : m_system(system) { Pinetime::Controllers::NavigationService::NavigationService(Pinetime::System::SystemTask& system) : m_system(system) {
navUuid.value[14] = navId[0]; navUuid.value[14] = navId[0];
navUuid.value[15] = navId[1]; navUuid.value[15] = navId[1];
@ -49,35 +49,25 @@ Pinetime::Controllers::NavigationService::NavigationService(Pinetime::System::Sy
navProgressCharUuid.value[14] = navId[0]; navProgressCharUuid.value[14] = navId[0];
navProgressCharUuid.value[15] = navId[1]; navProgressCharUuid.value[15] = navId[1];
characteristicDefinition[0] = {.uuid = (ble_uuid_t *) (&navFlagCharUuid), characteristicDefinition[0] = {
.access_cb = NAVCallback, .uuid = (ble_uuid_t*) (&navFlagCharUuid), .access_cb = NAVCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
.arg = this,
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
};
characteristicDefinition[1] = {.uuid = (ble_uuid_t *) (&navNarrativeCharUuid), characteristicDefinition[1] = {.uuid = (ble_uuid_t*) (&navNarrativeCharUuid),
.access_cb = NAVCallback, .access_cb = NAVCallback,
.arg = this, .arg = this,
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
}; characteristicDefinition[2] = {.uuid = (ble_uuid_t*) (&navManDistCharUuid),
characteristicDefinition[2] = {.uuid = (ble_uuid_t *) (&navManDistCharUuid),
.access_cb = NAVCallback, .access_cb = NAVCallback,
.arg = this, .arg = this,
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
}; characteristicDefinition[3] = {.uuid = (ble_uuid_t*) (&navProgressCharUuid),
characteristicDefinition[3] = {.uuid = (ble_uuid_t *) (&navProgressCharUuid),
.access_cb = NAVCallback, .access_cb = NAVCallback,
.arg = this, .arg = this,
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
};
characteristicDefinition[4] = {0}; characteristicDefinition[4] = {0};
serviceDefinition[0] = { serviceDefinition[0] = {.type = BLE_GATT_SVC_TYPE_PRIMARY, .uuid = (ble_uuid_t*) &navUuid, .characteristics = characteristicDefinition};
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = (ble_uuid_t *) &navUuid,
.characteristics = characteristicDefinition
};
serviceDefinition[1] = {0}; serviceDefinition[1] = {0};
m_progress = 0; m_progress = 0;
@ -92,45 +82,39 @@ void Pinetime::Controllers::NavigationService::Init() {
ASSERT(res == 0); ASSERT(res == 0);
} }
int Pinetime::Controllers::NavigationService::OnCommand(uint16_t conn_handle, uint16_t attr_handle, int Pinetime::Controllers::NavigationService::OnCommand(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) {
struct ble_gatt_access_ctxt *ctxt) {
if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
size_t notifSize = OS_MBUF_PKTLEN(ctxt->om); size_t notifSize = OS_MBUF_PKTLEN(ctxt->om);
uint8_t data[notifSize + 1]; uint8_t data[notifSize + 1];
data[notifSize] = '\0'; data[notifSize] = '\0';
os_mbuf_copydata(ctxt->om, 0, notifSize, data); os_mbuf_copydata(ctxt->om, 0, notifSize, data);
char *s = (char *) &data[0]; char* s = (char*) &data[0];
if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &navFlagCharUuid) == 0) { if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &navFlagCharUuid) == 0) {
m_flag = s; m_flag = s;
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &navNarrativeCharUuid) == 0) { } else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &navNarrativeCharUuid) == 0) {
m_narrative = s; m_narrative = s;
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &navManDistCharUuid) == 0) { } else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &navManDistCharUuid) == 0) {
m_manDist = s; m_manDist = s;
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &navProgressCharUuid) == 0) { } else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &navProgressCharUuid) == 0) {
m_progress = data[0]; m_progress = data[0];
} }
} }
return 0; return 0;
} }
std::string Pinetime::Controllers::NavigationService::getFlag() std::string Pinetime::Controllers::NavigationService::getFlag() {
{
return m_flag; return m_flag;
} }
std::string Pinetime::Controllers::NavigationService::getNarrative() std::string Pinetime::Controllers::NavigationService::getNarrative() {
{
return m_narrative; return m_narrative;
} }
std::string Pinetime::Controllers::NavigationService::getManDist() std::string Pinetime::Controllers::NavigationService::getManDist() {
{
return m_manDist; return m_manDist;
} }
int Pinetime::Controllers::NavigationService::getProgress() int Pinetime::Controllers::NavigationService::getProgress() {
{
return m_progress; return m_progress;
} }

View File

@ -26,8 +26,9 @@
#undef max #undef max
#undef min #undef min
//c7e60000-78fc-48fe-8e23-433b3a1942d0 // 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} #define NAVIGATION_SERVICE_UUID_BASE \
{ 0xd0, 0x42, 0x19, 0x3a, 0x3b, 0x43, 0x23, 0x8e, 0xfe, 0x48, 0xfc, 0x78, 0x00, 0x00, 0x00, 0x00 }
namespace Pinetime { namespace Pinetime {
namespace System { namespace System {
@ -37,12 +38,11 @@ namespace Pinetime {
class NavigationService { class NavigationService {
public: public:
explicit NavigationService(Pinetime::System::SystemTask &system); explicit NavigationService(Pinetime::System::SystemTask& system);
void Init(); void Init();
int OnCommand(uint16_t conn_handle, uint16_t attr_handle, int OnCommand(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt);
struct ble_gatt_access_ctxt *ctxt);
std::string getFlag(); std::string getFlag();
@ -59,27 +59,12 @@ namespace Pinetime {
static constexpr uint8_t navManDistCharId[2] = {0x03, 0x00}; static constexpr uint8_t navManDistCharId[2] = {0x03, 0x00};
static constexpr uint8_t navProgressCharId[2] = {0x04, 0x00}; static constexpr uint8_t navProgressCharId[2] = {0x04, 0x00};
ble_uuid128_t navUuid{ ble_uuid128_t navUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = NAVIGATION_SERVICE_UUID_BASE};
.u = {.type = BLE_UUID_TYPE_128},
.value = NAVIGATION_SERVICE_UUID_BASE
};
ble_uuid128_t navFlagCharUuid{ ble_uuid128_t navFlagCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = NAVIGATION_SERVICE_UUID_BASE};
.u = {.type = BLE_UUID_TYPE_128}, ble_uuid128_t navNarrativeCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = NAVIGATION_SERVICE_UUID_BASE};
.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};
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_chr_def characteristicDefinition[5];
struct ble_gatt_svc_def serviceDefinition[2]; struct ble_gatt_svc_def serviceDefinition[2];
@ -89,8 +74,7 @@ namespace Pinetime {
std::string m_manDist; std::string m_manDist;
int m_progress; int m_progress;
Pinetime::System::SystemTask &m_system; Pinetime::System::SystemTask& m_system;
}; };
} }
} }

View File

@ -23,32 +23,33 @@ NimbleController::NimbleController(Pinetime::System::SystemTask& systemTask,
Pinetime::Controllers::NotificationManager& notificationManager, Pinetime::Controllers::NotificationManager& notificationManager,
Controllers::Battery& batteryController, Controllers::Battery& batteryController,
Pinetime::Drivers::SpiNorFlash& spiNorFlash, Pinetime::Drivers::SpiNorFlash& spiNorFlash,
Controllers::HeartRateController& heartRateController) : Controllers::HeartRateController& heartRateController)
systemTask{systemTask}, : systemTask {systemTask},
bleController{bleController}, bleController {bleController},
dateTimeController{dateTimeController}, dateTimeController {dateTimeController},
notificationManager{notificationManager}, notificationManager {notificationManager},
spiNorFlash{spiNorFlash}, spiNorFlash {spiNorFlash},
dfuService{systemTask, bleController, spiNorFlash}, dfuService {systemTask, bleController, spiNorFlash},
currentTimeClient{dateTimeController}, currentTimeClient {dateTimeController},
anService{systemTask, notificationManager}, anService {systemTask, notificationManager},
alertNotificationClient{systemTask, notificationManager}, alertNotificationClient {systemTask, notificationManager},
currentTimeService{dateTimeController}, currentTimeService {dateTimeController},
musicService{systemTask}, musicService {systemTask},
navService{systemTask}, navService {systemTask},
batteryInformationService{batteryController}, batteryInformationService {batteryController},
immediateAlertService{systemTask, notificationManager}, immediateAlertService {systemTask, notificationManager},
heartRateService{systemTask, heartRateController}, heartRateService {systemTask, heartRateController},
serviceDiscovery({&currentTimeClient, &alertNotificationClient}) { serviceDiscovery({&currentTimeClient, &alertNotificationClient}) {
} }
int GAPEventCallback(struct ble_gap_event *event, void *arg) { int GAPEventCallback(struct ble_gap_event* event, void* arg) {
auto nimbleController = static_cast<NimbleController*>(arg); auto nimbleController = static_cast<NimbleController*>(arg);
return nimbleController->OnGAPEvent(event); return nimbleController->OnGAPEvent(event);
} }
void NimbleController::Init() { void NimbleController::Init() {
while (!ble_hs_synced()) {} while (!ble_hs_synced()) {
}
ble_svc_gap_init(); ble_svc_gap_init();
ble_svc_gatt_init(); ble_svc_gatt_init();
@ -81,7 +82,8 @@ void NimbleController::Init() {
} }
void NimbleController::StartAdvertising() { void NimbleController::StartAdvertising() {
if(bleController.IsConnected() || ble_gap_conn_active() || ble_gap_adv_active()) return; if (bleController.IsConnected() || ble_gap_conn_active() || ble_gap_adv_active())
return;
ble_svc_gap_device_name_set(deviceName); ble_svc_gap_device_name_set(deviceName);
@ -101,29 +103,27 @@ void NimbleController::StartAdvertising() {
adv_params.conn_mode = BLE_GAP_CONN_MODE_UND; adv_params.conn_mode = BLE_GAP_CONN_MODE_UND;
adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN; adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN;
fields.flags = BLE_HS_ADV_F_DISC_GEN | fields.flags = BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP;
BLE_HS_ADV_F_BREDR_UNSUP; // fields.uuids128 = BLE_UUID128(BLE_UUID128_DECLARE(
// fields.uuids128 = BLE_UUID128(BLE_UUID128_DECLARE( // 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
// 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, // 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff));
// 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff));
fields.uuids128 = &dfuServiceUuid; fields.uuids128 = &dfuServiceUuid;
fields.num_uuids128 = 1; fields.num_uuids128 = 1;
fields.uuids128_is_complete = 1; fields.uuids128_is_complete = 1;
fields.tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO; fields.tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO;
rsp_fields.name = (uint8_t *)deviceName; rsp_fields.name = (uint8_t*) deviceName;
rsp_fields.name_len = strlen(deviceName); rsp_fields.name_len = strlen(deviceName);
rsp_fields.name_is_complete = 1; rsp_fields.name_is_complete = 1;
ble_gap_adv_set_fields(&fields); ble_gap_adv_set_fields(&fields);
// ASSERT(res == 0); // TODO this one sometimes fails with error 22 (notsync) // ASSERT(res == 0); // TODO this one sometimes fails with error 22 (notsync)
ble_gap_adv_rsp_set_fields(&rsp_fields); ble_gap_adv_rsp_set_fields(&rsp_fields);
// ASSERT(res == 0); // ASSERT(res == 0);
ble_gap_adv_start(addrType, NULL, 180000, ble_gap_adv_start(addrType, NULL, 180000, &adv_params, GAPEventCallback, this);
&adv_params, GAPEventCallback, this); // ASSERT(res == 0);// TODO I've disabled these ASSERT as they sometime asserts and reset the mcu.
// ASSERT(res == 0);// TODO I've disabled these ASSERT as they sometime asserts and reset the mcu.
// For now, the advertising is restarted as soon as it ends. There may be a race condition // For now, the advertising is restarted as soon as it ends. There may be a race condition
// that prevent the advertising from restarting reliably. // that prevent the advertising from restarting reliably.
// I remove the assert to prevent this uncesseray crash, but in the long term, the management of // I remove the assert to prevent this uncesseray crash, but in the long term, the management of
@ -131,7 +131,7 @@ void NimbleController::StartAdvertising() {
// the application has been woken up, for example. // the application has been woken up, for example.
} }
int NimbleController::OnGAPEvent(ble_gap_event *event) { int NimbleController::OnGAPEvent(ble_gap_event* event) {
switch (event->type) { switch (event->type) {
case BLE_GAP_EVENT_ADV_COMPLETE: case BLE_GAP_EVENT_ADV_COMPLETE:
NRF_LOG_INFO("Advertising event : BLE_GAP_EVENT_ADV_COMPLETE"); NRF_LOG_INFO("Advertising event : BLE_GAP_EVENT_ADV_COMPLETE");
@ -141,8 +141,7 @@ int NimbleController::OnGAPEvent(ble_gap_event *event) {
NRF_LOG_INFO("Advertising event : BLE_GAP_EVENT_CONNECT"); NRF_LOG_INFO("Advertising event : BLE_GAP_EVENT_CONNECT");
/* A new connection was established or a connection attempt failed. */ /* A new connection was established or a connection attempt failed. */
NRF_LOG_INFO("connection %s; status=%d ", event->connect.status == 0 ? "established" : "failed", NRF_LOG_INFO("connection %s; status=%d ", event->connect.status == 0 ? "established" : "failed", event->connect.status);
event->connect.status);
if (event->connect.status != 0) { if (event->connect.status != 0) {
/* Connection failed; resume advertising. */ /* Connection failed; resume advertising. */
@ -154,8 +153,7 @@ int NimbleController::OnGAPEvent(ble_gap_event *event) {
connectionHandle = event->connect.conn_handle; connectionHandle = event->connect.conn_handle;
// Service discovery is deffered via systemtask // Service discovery is deffered via systemtask
} }
} } break;
break;
case BLE_GAP_EVENT_DISCONNECT: case BLE_GAP_EVENT_DISCONNECT:
NRF_LOG_INFO("Advertising event : BLE_GAP_EVENT_DISCONNECT"); NRF_LOG_INFO("Advertising event : BLE_GAP_EVENT_DISCONNECT");
NRF_LOG_INFO("disconnect; reason=%d", event->disconnect.reason); NRF_LOG_INFO("disconnect; reason=%d", event->disconnect.reason);
@ -187,10 +185,7 @@ int NimbleController::OnGAPEvent(ble_gap_event *event) {
event->subscribe.prev_indicate); event->subscribe.prev_indicate);
return 0; return 0;
case BLE_GAP_EVENT_MTU: case BLE_GAP_EVENT_MTU:
NRF_LOG_INFO("mtu update event; conn_handle=%d cid=%d mtu=%d\n", NRF_LOG_INFO("mtu update event; conn_handle=%d cid=%d mtu=%d\n", event->mtu.conn_handle, event->mtu.channel_id, event->mtu.value);
event->mtu.conn_handle,
event->mtu.channel_id,
event->mtu.value);
return 0; return 0;
case BLE_GAP_EVENT_REPEAT_PAIRING: { case BLE_GAP_EVENT_REPEAT_PAIRING: {
@ -216,9 +211,7 @@ int NimbleController::OnGAPEvent(ble_gap_event *event) {
NRF_LOG_INFO("received %s; conn_handle=%d attr_handle=%d " NRF_LOG_INFO("received %s; conn_handle=%d attr_handle=%d "
"attr_len=%d", "attr_len=%d",
event->notify_rx.indication ? event->notify_rx.indication ? "indication" : "notification",
"indication" :
"notification",
event->notify_rx.conn_handle, event->notify_rx.conn_handle,
event->notify_rx.attr_handle, event->notify_rx.attr_handle,
notifSize); notifSize);
@ -229,7 +222,7 @@ int NimbleController::OnGAPEvent(ble_gap_event *event) {
/* Attribute data is contained in event->notify_rx.attr_data. */ /* Attribute data is contained in event->notify_rx.attr_data. */
default: default:
// NRF_LOG_INFO("Advertising event : %d", event->type); // NRF_LOG_INFO("Advertising event : %d", event->type);
break; break;
} }
return 0; return 0;
@ -239,8 +232,6 @@ void NimbleController::StartDiscovery() {
serviceDiscovery.StartDiscovery(connectionHandle); serviceDiscovery.StartDiscovery(connectionHandle);
} }
uint16_t NimbleController::connHandle() { uint16_t NimbleController::connHandle() {
return connectionHandle; return connectionHandle;
} }

View File

@ -37,28 +37,37 @@ namespace Pinetime {
class NimbleController { class NimbleController {
public: public:
NimbleController(Pinetime::System::SystemTask& systemTask, Pinetime::Controllers::Ble& bleController, NimbleController(Pinetime::System::SystemTask& systemTask,
DateTime& dateTimeController, Pinetime::Controllers::NotificationManager& notificationManager, Pinetime::Controllers::Ble& bleController,
Controllers::Battery& batteryController, Pinetime::Drivers::SpiNorFlash& spiNorFlash, DateTime& dateTimeController,
Pinetime::Controllers::NotificationManager& notificationManager,
Controllers::Battery& batteryController,
Pinetime::Drivers::SpiNorFlash& spiNorFlash,
Controllers::HeartRateController& heartRateController); Controllers::HeartRateController& heartRateController);
void Init(); void Init();
void StartAdvertising(); void StartAdvertising();
int OnGAPEvent(ble_gap_event *event); int OnGAPEvent(ble_gap_event* event);
int OnDiscoveryEvent(uint16_t i, const ble_gatt_error *pError, const ble_gatt_svc *pSvc); int OnDiscoveryEvent(uint16_t i, const ble_gatt_error* pError, const ble_gatt_svc* pSvc);
int OnCTSCharacteristicDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error *error, int OnCTSCharacteristicDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error* error, const ble_gatt_chr* characteristic);
const ble_gatt_chr *characteristic); int OnANSCharacteristicDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error* error, const ble_gatt_chr* characteristic);
int OnANSCharacteristicDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error *error, int OnCurrentTimeReadResult(uint16_t connectionHandle, const ble_gatt_error* error, ble_gatt_attr* attribute);
const ble_gatt_chr *characteristic); int OnANSDescriptorDiscoveryEventCallback(uint16_t connectionHandle,
int OnCurrentTimeReadResult(uint16_t connectionHandle, const ble_gatt_error *error, ble_gatt_attr *attribute); const ble_gatt_error* error,
int OnANSDescriptorDiscoveryEventCallback(uint16_t connectionHandle, const ble_gatt_error *error, uint16_t characteristicValueHandle,
uint16_t characteristicValueHandle, const ble_gatt_dsc *descriptor); const ble_gatt_dsc* descriptor);
void StartDiscovery(); void StartDiscovery();
Pinetime::Controllers::MusicService& music() {return musicService;}; Pinetime::Controllers::MusicService& music() {
Pinetime::Controllers::NavigationService& navigation() {return navService;}; return musicService;
Pinetime::Controllers::AlertNotificationService& alertService() {return anService;}; };
Pinetime::Controllers::NavigationService& navigation() {
return navService;
};
Pinetime::Controllers::AlertNotificationService& alertService() {
return anService;
};
uint16_t connHandle(); uint16_t connHandle();
@ -86,10 +95,8 @@ namespace Pinetime {
uint16_t connectionHandle = 0; uint16_t connectionHandle = 0;
ble_uuid128_t dfuServiceUuid { ble_uuid128_t dfuServiceUuid {
.u { .type = BLE_UUID_TYPE_128}, .u {.type = BLE_UUID_TYPE_128},
.value = {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15, .value = {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15, 0xDE, 0xEF, 0x12, 0x12, 0x30, 0x15, 0x00, 0x00}};
0xDE, 0xEF, 0x12, 0x12, 0x30, 0x15, 0x00, 0x00}
};
ServiceDiscovery serviceDiscovery; ServiceDiscovery serviceDiscovery;
}; };

View File

@ -6,15 +6,15 @@ using namespace Pinetime::Controllers;
constexpr uint8_t NotificationManager::MessageSize; constexpr uint8_t NotificationManager::MessageSize;
void NotificationManager::Push(NotificationManager::Notification&& notif) {
void NotificationManager::Push(NotificationManager::Notification &&notif) {
notif.id = GetNextId(); notif.id = GetNextId();
notif.valid = true; notif.valid = true;
notifications[writeIndex] = std::move(notif); notifications[writeIndex] = std::move(notif);
writeIndex = (writeIndex + 1 < TotalNbNotifications) ? writeIndex + 1 : 0; writeIndex = (writeIndex + 1 < TotalNbNotifications) ? writeIndex + 1 : 0;
if(!empty) if (!empty)
readIndex = (readIndex + 1 < TotalNbNotifications) ? readIndex + 1 : 0; readIndex = (readIndex + 1 < TotalNbNotifications) ? readIndex + 1 : 0;
else empty = false; else
empty = false;
newNotification = true; newNotification = true;
} }
@ -30,40 +30,48 @@ NotificationManager::Notification::Id NotificationManager::GetNextId() {
} }
NotificationManager::Notification NotificationManager::GetNext(NotificationManager::Notification::Id id) { NotificationManager::Notification NotificationManager::GetNext(NotificationManager::Notification::Id id) {
auto currentIterator = std::find_if(notifications.begin(), notifications.end(), [id](const Notification& n){return n.valid && n.id == id;}); auto currentIterator = std::find_if(notifications.begin(), notifications.end(), [id](const Notification& n) {
if(currentIterator == notifications.end() || currentIterator->id != id) return Notification{}; return n.valid && n.id == id;
});
if (currentIterator == notifications.end() || currentIterator->id != id)
return Notification {};
auto& lastNotification = notifications[readIndex]; auto& lastNotification = notifications[readIndex];
NotificationManager::Notification result; NotificationManager::Notification result;
if(currentIterator == (notifications.end()-1)) if (currentIterator == (notifications.end() - 1))
result = *(notifications.begin()); result = *(notifications.begin());
else else
result = *(currentIterator+1); result = *(currentIterator + 1);
if(result.id <= id) return {}; if (result.id <= id)
return {};
result.index = (lastNotification.id - result.id)+1; result.index = (lastNotification.id - result.id) + 1;
return result; return result;
} }
NotificationManager::Notification NotificationManager::GetPrevious(NotificationManager::Notification::Id id) { NotificationManager::Notification NotificationManager::GetPrevious(NotificationManager::Notification::Id id) {
auto currentIterator = std::find_if(notifications.begin(), notifications.end(), [id](const Notification& n){return n.valid && n.id == id;}); auto currentIterator = std::find_if(notifications.begin(), notifications.end(), [id](const Notification& n) {
if(currentIterator == notifications.end() || currentIterator->id != id) return Notification{}; return n.valid && n.id == id;
});
if (currentIterator == notifications.end() || currentIterator->id != id)
return Notification {};
auto& lastNotification = notifications[readIndex]; auto& lastNotification = notifications[readIndex];
NotificationManager::Notification result; NotificationManager::Notification result;
if(currentIterator == notifications.begin()) if (currentIterator == notifications.begin())
result = *(notifications.end()-1); result = *(notifications.end() - 1);
else else
result = *(currentIterator-1); result = *(currentIterator - 1);
if(result.id >= id) return {}; if (result.id >= id)
return {};
result.index = (lastNotification.id - result.id)+1; result.index = (lastNotification.id - result.id) + 1;
return result; return result;
} }
@ -84,21 +92,23 @@ bool NotificationManager::ClearNewNotificationFlag() {
} }
size_t NotificationManager::NbNotifications() const { size_t NotificationManager::NbNotifications() const {
return std::count_if(notifications.begin(), notifications.end(), [](const Notification& n){ return n.valid;}); return std::count_if(notifications.begin(), notifications.end(), [](const Notification& n) {
return n.valid;
});
} }
const char* NotificationManager::Notification::Message() const { const char* NotificationManager::Notification::Message() const {
const char* itField = std::find(message.begin(), message.begin()+size-1, '\0'); const char* itField = std::find(message.begin(), message.begin() + size - 1, '\0');
if(itField != message.begin()+size-1) { if (itField != message.begin() + size - 1) {
const char* ptr = (itField)+1; const char* ptr = (itField) + 1;
return ptr; return ptr;
} }
return const_cast<char*>(message.data()); return const_cast<char*>(message.data());
} }
const char* NotificationManager::Notification::Title() const { const char* NotificationManager::Notification::Title() const {
const char * itField = std::find(message.begin(), message.begin()+size-1, '\0'); const char* itField = std::find(message.begin(), message.begin() + size - 1, '\0');
if(itField != message.begin()+size-1) { if (itField != message.begin() + size - 1) {
return message.data(); return message.data();
} }
return {}; return {};

View File

@ -9,8 +9,20 @@ namespace Pinetime {
namespace Controllers { namespace Controllers {
class NotificationManager { class NotificationManager {
public: public:
enum class Categories {Unknown, SimpleAlert, Email, News, IncomingCall, MissedCall, Sms, VoiceMail, Schedule, HighProriotyAlert, InstantMessage }; enum class Categories {
static constexpr uint8_t MessageSize{100}; Unknown,
SimpleAlert,
Email,
News,
IncomingCall,
MissedCall,
Sms,
VoiceMail,
Schedule,
HighProriotyAlert,
InstantMessage
};
static constexpr uint8_t MessageSize {100};
struct Notification { struct Notification {
using Id = uint8_t; using Id = uint8_t;
@ -18,7 +30,7 @@ namespace Pinetime {
bool valid = false; bool valid = false;
uint8_t index; uint8_t index;
uint8_t size; uint8_t size;
std::array<char, MessageSize+1> message; std::array<char, MessageSize + 1> message;
Categories category = Categories::Unknown; Categories category = Categories::Unknown;
const char* Message() const; const char* Message() const;
@ -35,7 +47,9 @@ namespace Pinetime {
bool IsVibrationEnabled(); bool IsVibrationEnabled();
void ToggleVibrations(); void ToggleVibrations();
static constexpr size_t MaximumMessageSize() { return MessageSize; }; static constexpr size_t MaximumMessageSize() {
return MessageSize;
};
size_t NbNotifications() const; size_t NbNotifications() const;
private: private:
@ -45,7 +59,7 @@ namespace Pinetime {
uint8_t readIndex = 0; uint8_t readIndex = 0;
uint8_t writeIndex = 0; uint8_t writeIndex = 0;
bool empty = true; bool empty = true;
std::atomic<bool> newNotification{false}; std::atomic<bool> newNotification {false};
bool vibrationEnabled = true; bool vibrationEnabled = true;
}; };
} }

View File

@ -4,8 +4,7 @@
using namespace Pinetime::Controllers; using namespace Pinetime::Controllers;
ServiceDiscovery::ServiceDiscovery(std::array<BleClient*, 2>&& clients) : clients{clients} { ServiceDiscovery::ServiceDiscovery(std::array<BleClient*, 2>&& clients) : clients {clients} {
} }
void ServiceDiscovery::StartDiscovery(uint16_t connectionHandle) { void ServiceDiscovery::StartDiscovery(uint16_t connectionHandle) {
@ -16,7 +15,7 @@ void ServiceDiscovery::StartDiscovery(uint16_t connectionHandle) {
void ServiceDiscovery::OnServiceDiscovered(uint16_t connectionHandle) { void ServiceDiscovery::OnServiceDiscovered(uint16_t connectionHandle) {
clientIterator++; clientIterator++;
if(clientIterator != clients.end()) { if (clientIterator != clients.end()) {
DiscoverNextService(connectionHandle); DiscoverNextService(connectionHandle);
} else { } else {
NRF_LOG_INFO("End of service discovery"); NRF_LOG_INFO("End of service discovery");
@ -26,7 +25,7 @@ void ServiceDiscovery::OnServiceDiscovered(uint16_t connectionHandle) {
void ServiceDiscovery::DiscoverNextService(uint16_t connectionHandle) { void ServiceDiscovery::DiscoverNextService(uint16_t connectionHandle) {
NRF_LOG_INFO("[Discovery] Discover next service"); NRF_LOG_INFO("[Discovery] Discover next service");
auto discoverNextService = [this](uint16_t connectionHandle){ auto discoverNextService = [this](uint16_t connectionHandle) {
this->OnServiceDiscovered(connectionHandle); this->OnServiceDiscovered(connectionHandle);
}; };
(*clientIterator)->Discover(connectionHandle, discoverNextService); (*clientIterator)->Discover(connectionHandle, discoverNextService);

View File

@ -13,7 +13,6 @@ namespace Pinetime {
void StartDiscovery(uint16_t connectionHandle); void StartDiscovery(uint16_t connectionHandle);
private: private:
BleClient** clientIterator; BleClient** clientIterator;
std::array<BleClient*, 2> clients; std::array<BleClient*, 2> clients;

View File

@ -4,7 +4,6 @@
using namespace Pinetime::Controllers; using namespace Pinetime::Controllers;
void BrightnessController::Init() { void BrightnessController::Init() {
nrf_gpio_cfg_output(pinLcdBacklight1); nrf_gpio_cfg_output(pinLcdBacklight1);
nrf_gpio_cfg_output(pinLcdBacklight2); nrf_gpio_cfg_output(pinLcdBacklight2);
@ -14,7 +13,7 @@ void BrightnessController::Init() {
void BrightnessController::Set(BrightnessController::Levels level) { void BrightnessController::Set(BrightnessController::Levels level) {
this->level = level; this->level = level;
switch(level) { switch (level) {
default: default:
case Levels::High: case Levels::High:
nrf_gpio_pin_clear(pinLcdBacklight1); nrf_gpio_pin_clear(pinLcdBacklight1);
@ -40,20 +39,34 @@ void BrightnessController::Set(BrightnessController::Levels level) {
} }
void BrightnessController::Lower() { void BrightnessController::Lower() {
switch(level) { switch (level) {
case Levels::High: Set(Levels::Medium); break; case Levels::High:
case Levels::Medium: Set(Levels::Low); break; Set(Levels::Medium);
case Levels::Low: Set(Levels::Off); break; break;
default: break; case Levels::Medium:
Set(Levels::Low);
break;
case Levels::Low:
Set(Levels::Off);
break;
default:
break;
} }
} }
void BrightnessController::Higher() { void BrightnessController::Higher() {
switch(level) { switch (level) {
case Levels::Off: Set(Levels::Low); break; case Levels::Off:
case Levels::Low: Set(Levels::Medium); break; Set(Levels::Low);
case Levels::Medium: Set(Levels::High); break; break;
default: break; case Levels::Low:
Set(Levels::Medium);
break;
case Levels::Medium:
Set(Levels::High);
break;
default:
break;
} }
} }
@ -70,29 +83,44 @@ void BrightnessController::Restore() {
} }
void BrightnessController::Step() { void BrightnessController::Step() {
switch(level) { switch (level) {
case Levels::Low: Set(Levels::Medium); break; case Levels::Low:
case Levels::Medium: Set(Levels::High); break; Set(Levels::Medium);
case Levels::High: Set(Levels::Low); break; break;
default: break; case Levels::Medium:
Set(Levels::High);
break;
case Levels::High:
Set(Levels::Low);
break;
default:
break;
} }
} }
const char* BrightnessController::GetIcon() { const char* BrightnessController::GetIcon() {
switch(level) { switch (level) {
case Levels::Medium: return Applications::Screens::Symbols::brightnessMedium; case Levels::Medium:
case Levels::High: return Applications::Screens::Symbols::brightnessHigh; return Applications::Screens::Symbols::brightnessMedium;
default: break; case Levels::High:
return Applications::Screens::Symbols::brightnessHigh;
default:
break;
} }
return Applications::Screens::Symbols::brightnessLow; return Applications::Screens::Symbols::brightnessLow;
} }
const char* BrightnessController::ToString() { const char* BrightnessController::ToString() {
switch(level) { switch (level) {
case Levels::Off: return "Off"; case Levels::Off:
case Levels::Low: return "Low"; return "Off";
case Levels::Medium: return "Medium"; case Levels::Low:
case Levels::High: return "High"; return "Low";
default : return "???"; case Levels::Medium:
return "Medium";
case Levels::High:
return "High";
default:
return "???";
} }
} }

View File

@ -6,7 +6,7 @@ namespace Pinetime {
namespace Controllers { namespace Controllers {
class BrightnessController { class BrightnessController {
public: public:
enum class Levels {Off, Low, Medium, High}; enum class Levels { Off, Low, Medium, High };
void Init(); void Init();
void Set(Levels level); void Set(Levels level);

View File

@ -5,14 +5,13 @@
using namespace Pinetime::Controllers; using namespace Pinetime::Controllers;
DateTime::DateTime(System::SystemTask& systemTask) : systemTask{systemTask} { DateTime::DateTime(System::SystemTask& systemTask) : systemTask {systemTask} {
} }
void DateTime::SetTime(
void DateTime::SetTime(uint16_t year, uint8_t month, uint8_t day, uint8_t dayOfWeek, uint8_t hour, uint8_t minute, uint16_t year, uint8_t month, uint8_t day, uint8_t dayOfWeek, uint8_t hour, uint8_t minute, uint8_t second, uint32_t systickCounter) {
uint8_t second, uint32_t systickCounter) { std::tm tm = {
std::tm tm = { /* .tm_sec = */ second, /* .tm_sec = */ second,
/* .tm_min = */ minute, /* .tm_min = */ minute,
/* .tm_hour = */ hour, /* .tm_hour = */ hour,
/* .tm_mday = */ day, /* .tm_mday = */ day,
@ -34,7 +33,7 @@ void DateTime::SetTime(uint16_t year, uint8_t month, uint8_t day, uint8_t dayOfW
void DateTime::UpdateTime(uint32_t systickCounter) { void DateTime::UpdateTime(uint32_t systickCounter) {
// Handle systick counter overflow // Handle systick counter overflow
uint32_t systickDelta = 0; uint32_t systickDelta = 0;
if(systickCounter < previousSystickCounter) { if (systickCounter < previousSystickCounter) {
systickDelta = 0xffffff - previousSystickCounter; systickDelta = 0xffffff - previousSystickCounter;
systickDelta += systickCounter + 1; systickDelta += systickCounter + 1;
} else { } else {
@ -45,8 +44,8 @@ void DateTime::UpdateTime(uint32_t systickCounter) {
* 1000 ms = 1024 ticks * 1000 ms = 1024 ticks
*/ */
auto correctedDelta = systickDelta / 1024; auto correctedDelta = systickDelta / 1024;
auto rest = (systickDelta - (correctedDelta*1024)); auto rest = (systickDelta - (correctedDelta * 1024));
if(systickCounter >= rest) { if (systickCounter >= rest) {
previousSystickCounter = systickCounter - rest; previousSystickCounter = systickCounter - rest;
} else { } else {
previousSystickCounter = 0xffffff - (rest - systickCounter); previousSystickCounter = 0xffffff - (rest - systickCounter);
@ -56,12 +55,12 @@ void DateTime::UpdateTime(uint32_t systickCounter) {
uptime += std::chrono::seconds(correctedDelta); uptime += std::chrono::seconds(correctedDelta);
auto dp = date::floor<date::days>(currentDateTime); auto dp = date::floor<date::days>(currentDateTime);
auto time = date::make_time(currentDateTime-dp); auto time = date::make_time(currentDateTime - dp);
auto yearMonthDay = date::year_month_day(dp); auto yearMonthDay = date::year_month_day(dp);
year = (int)yearMonthDay.year(); year = (int) yearMonthDay.year();
month = static_cast<Months>((unsigned)yearMonthDay.month()); month = static_cast<Months>((unsigned) yearMonthDay.month());
day = (unsigned)yearMonthDay.day(); day = (unsigned) yearMonthDay.day();
dayOfWeek = static_cast<Days>(date::weekday(yearMonthDay).iso_encoding()); dayOfWeek = static_cast<Days>(date::weekday(yearMonthDay).iso_encoding());
hour = time.hours().count(); hour = time.hours().count();
@ -69,7 +68,7 @@ void DateTime::UpdateTime(uint32_t systickCounter) {
second = time.seconds().count(); second = time.seconds().count();
// Notify new day to SystemTask // Notify new day to SystemTask
if(hour == 0 and not isMidnightAlreadyNotified) { if (hour == 0 and not isMidnightAlreadyNotified) {
isMidnightAlreadyNotified = true; isMidnightAlreadyNotified = true;
systemTask.PushMessage(System::SystemTask::Messages::OnNewDay); systemTask.PushMessage(System::SystemTask::Messages::OnNewDay);
} else if (hour != 0) { } else if (hour != 0) {
@ -77,123 +76,45 @@ void DateTime::UpdateTime(uint32_t systickCounter) {
} }
} }
const char *DateTime::MonthShortToString() { const char* DateTime::MonthShortToString() {
return DateTime::MonthsString[(uint8_t)month]; return DateTime::MonthsString[(uint8_t) month];
} }
const char *DateTime::MonthShortToStringLow() { const char* DateTime::MonthShortToStringLow() {
return DateTime::MonthsStringLow[(uint8_t)month]; return DateTime::MonthsStringLow[(uint8_t) month];
} }
const char *DateTime::MonthsToStringLow() { const char* DateTime::MonthsToStringLow() {
return DateTime::MonthsLow[(uint8_t)month]; return DateTime::MonthsLow[(uint8_t) month];
} }
const char *DateTime::DayOfWeekToString() { const char* DateTime::DayOfWeekToString() {
return DateTime::DaysString[(uint8_t)dayOfWeek]; return DateTime::DaysString[(uint8_t) dayOfWeek];
} }
const char *DateTime::DayOfWeekShortToString() { const char* DateTime::DayOfWeekShortToString() {
return DateTime::DaysStringShort[(uint8_t)dayOfWeek]; return DateTime::DaysStringShort[(uint8_t) dayOfWeek];
} }
const char *DateTime::DayOfWeekToStringLow() { const char* DateTime::DayOfWeekToStringLow() {
return DateTime::DaysStringLow[(uint8_t)dayOfWeek]; return DateTime::DaysStringLow[(uint8_t) dayOfWeek];
} }
const char *DateTime::DayOfWeekShortToStringLow() { const char* DateTime::DayOfWeekShortToStringLow() {
return DateTime::DaysStringShortLow[(uint8_t)dayOfWeek]; return DateTime::DaysStringShortLow[(uint8_t) dayOfWeek];
} }
char const* DateTime::DaysStringLow[] = {"--", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"};
char const *DateTime::DaysStringLow[] = { char const* DateTime::DaysStringShortLow[] = {"--", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
"--",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
"Sunday"
};
char const *DateTime::DaysStringShortLow[] = { char const* DateTime::DaysStringShort[] = {"--", "MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"};
"--",
"Mon",
"Tue",
"Wed",
"Thu",
"Fri",
"Sat",
"Sun"
};
char const *DateTime::DaysStringShort[] = { char const* DateTime::DaysString[] = {"--", "MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY", "SUNDAY"};
"--",
"MON",
"TUE",
"WED",
"THU",
"FRI",
"SAT",
"SUN"
};
char const *DateTime::DaysString[] = { char const* DateTime::MonthsString[] = {"--", "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
"--",
"MONDAY",
"TUESDAY",
"WEDNESDAY",
"THURSDAY",
"FRIDAY",
"SATURDAY",
"SUNDAY"
};
char const *DateTime::MonthsString[] = { char const* DateTime::MonthsStringLow[] = {"--", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
"--",
"JAN",
"FEB",
"MAR",
"APR",
"MAY",
"JUN",
"JUL",
"AUG",
"SEP",
"OCT",
"NOV",
"DEC"
};
char const *DateTime::MonthsStringLow[] = { char const* DateTime::MonthsLow[] = {
"--", "--", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"};
"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"
};

View File

@ -10,31 +10,71 @@ namespace Pinetime {
namespace Controllers { namespace Controllers {
class DateTime { class DateTime {
public: public:
enum class Days : uint8_t {Unknown, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday}; enum class Days : uint8_t { Unknown, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday };
enum class Months : uint8_t {Unknown, January, February, March, April, May, June, July, August, September, October, November, December}; enum class Months : uint8_t {
Unknown,
January,
February,
March,
April,
May,
June,
July,
August,
September,
October,
November,
December
};
DateTime(System::SystemTask& systemTask); DateTime(System::SystemTask& systemTask);
void SetTime(uint16_t year, uint8_t month, uint8_t day, uint8_t dayOfWeek, uint8_t hour, uint8_t minute, uint8_t second, uint32_t systickCounter); void SetTime(uint16_t year,
uint8_t month,
uint8_t day,
uint8_t dayOfWeek,
uint8_t hour,
uint8_t minute,
uint8_t second,
uint32_t systickCounter);
void UpdateTime(uint32_t systickCounter); void UpdateTime(uint32_t systickCounter);
uint16_t Year() const { return year; } uint16_t Year() const {
Months Month() const { return month; } return year;
uint8_t Day() const { return day; } }
Days DayOfWeek() const { return dayOfWeek; } Months Month() const {
uint8_t Hours() const { return hour; } return month;
uint8_t Minutes() const { return minute; } }
uint8_t Seconds() const { return second; } uint8_t Day() const {
return day;
}
Days DayOfWeek() const {
return dayOfWeek;
}
uint8_t Hours() const {
return hour;
}
uint8_t Minutes() const {
return minute;
}
uint8_t Seconds() const {
return second;
}
const char *MonthShortToString(); const char* MonthShortToString();
const char *MonthShortToStringLow(); const char* MonthShortToStringLow();
const char *MonthsToStringLow(); const char* MonthsToStringLow();
const char *DayOfWeekToString(); const char* DayOfWeekToString();
const char *DayOfWeekShortToString(); const char* DayOfWeekShortToString();
const char *DayOfWeekToStringLow(); const char* DayOfWeekToStringLow();
const char *DayOfWeekShortToStringLow(); const char* DayOfWeekShortToStringLow();
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> CurrentDateTime() const {
return currentDateTime;
}
std::chrono::seconds Uptime() const {
return uptime;
}
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> CurrentDateTime() const { return currentDateTime; }
std::chrono::seconds Uptime() const { return uptime; }
private: private:
System::SystemTask& systemTask; System::SystemTask& systemTask;
uint16_t year = 0; uint16_t year = 0;
@ -51,14 +91,13 @@ namespace Pinetime {
bool isMidnightAlreadyNotified = false; bool isMidnightAlreadyNotified = false;
static char const *DaysString[]; static char const* DaysString[];
static char const *DaysStringShort[]; static char const* DaysStringShort[];
static char const *DaysStringLow[]; static char const* DaysStringLow[];
static char const *DaysStringShortLow[]; static char const* DaysStringShortLow[];
static char const *MonthsString[]; static char const* MonthsString[];
static char const *MonthsStringLow[]; static char const* MonthsStringLow[];
static char const *MonthsLow[]; static char const* MonthsLow[];
}; };
} }
} }

View File

@ -6,12 +6,12 @@
using namespace Pinetime::Controllers; using namespace Pinetime::Controllers;
bool FirmwareValidator::IsValidated() const { bool FirmwareValidator::IsValidated() const {
auto* imageOkPtr = reinterpret_cast<uint32_t *>(validBitAdress); auto* imageOkPtr = reinterpret_cast<uint32_t*>(validBitAdress);
return (*imageOkPtr) == validBitValue; return (*imageOkPtr) == validBitValue;
} }
void FirmwareValidator::Validate() { void FirmwareValidator::Validate() {
if(!IsValidated()) if (!IsValidated())
Pinetime::Drivers::InternalFlash::WriteWord(validBitAdress, validBitValue); Pinetime::Drivers::InternalFlash::WriteWord(validBitAdress, validBitValue);
} }

View File

@ -10,6 +10,7 @@ namespace Pinetime {
bool IsValidated() const; bool IsValidated() const;
void Reset(); void Reset();
private: private:
static constexpr uint32_t validBitAdress {0x7BFE8}; static constexpr uint32_t validBitAdress {0x7BFE8};
static constexpr uint32_t validBitValue {1}; static constexpr uint32_t validBitValue {1};

View File

@ -2,11 +2,10 @@
#include "drivers/St7789.h" #include "drivers/St7789.h"
using namespace Pinetime::Components; using namespace Pinetime::Components;
Gfx::Gfx(Pinetime::Drivers::St7789 &lcd) : lcd{lcd} { Gfx::Gfx(Pinetime::Drivers::St7789& lcd) : lcd {lcd} {
} }
void Gfx::Init() { void Gfx::Init() {
} }
void Gfx::ClearScreen() { void Gfx::ClearScreen() {
@ -18,9 +17,8 @@ void Gfx::ClearScreen() {
state.action = Action::FillRectangle; state.action = Action::FillRectangle;
state.taskToNotify = xTaskGetCurrentTaskHandle(); state.taskToNotify = xTaskGetCurrentTaskHandle();
lcd.DrawBuffer(0, 0, width, height, reinterpret_cast<const uint8_t *>(buffer), width * 2); lcd.DrawBuffer(0, 0, width, height, reinterpret_cast<const uint8_t*>(buffer), width * 2);
WaitTransferFinished(); WaitTransferFinished();
} }
void Gfx::FillRectangle(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint16_t color) { void Gfx::FillRectangle(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint16_t color) {
@ -33,7 +31,7 @@ void Gfx::FillRectangle(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint16_t col
state.color = color; state.color = color;
state.taskToNotify = xTaskGetCurrentTaskHandle(); state.taskToNotify = xTaskGetCurrentTaskHandle();
lcd.DrawBuffer(x, y, w, h, reinterpret_cast<const uint8_t *>(buffer), width * 2); lcd.DrawBuffer(x, y, w, h, reinterpret_cast<const uint8_t*>(buffer), width * 2);
WaitTransferFinished(); WaitTransferFinished();
} }
@ -46,12 +44,12 @@ void Gfx::FillRectangle(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t* b)
state.color = 0x00; state.color = 0x00;
state.taskToNotify = xTaskGetCurrentTaskHandle(); state.taskToNotify = xTaskGetCurrentTaskHandle();
lcd.DrawBuffer(x, y, w, h, reinterpret_cast<const uint8_t *>(b), width * 2); lcd.DrawBuffer(x, y, w, h, reinterpret_cast<const uint8_t*>(b), width * 2);
WaitTransferFinished(); WaitTransferFinished();
} }
void Gfx::DrawString(uint8_t x, uint8_t y, uint16_t color, const char *text, const FONT_INFO *p_font, bool wrap) { void Gfx::DrawString(uint8_t x, uint8_t y, uint16_t color, const char* text, const FONT_INFO* p_font, bool wrap) {
if (y > (height - p_font->height)) { if (y > (height - p_font->height)) {
// Not enough space to write even single char. // Not enough space to write even single char.
return; return;
@ -86,7 +84,7 @@ void Gfx::DrawString(uint8_t x, uint8_t y, uint16_t color, const char *text, con
} }
} }
void Gfx::DrawChar(const FONT_INFO *font, uint8_t c, uint8_t *x, uint8_t y, uint16_t color) { void Gfx::DrawChar(const FONT_INFO* font, uint8_t c, uint8_t* x, uint8_t y, uint16_t color) {
uint8_t char_idx = c - font->startChar; uint8_t char_idx = c - font->startChar;
uint16_t bytes_in_line = CEIL_DIV(font->charInfo[char_idx].widthBits, 8); uint16_t bytes_in_line = CEIL_DIV(font->charInfo[char_idx].widthBits, 8);
uint16_t bg = 0x0000; uint16_t bg = 0x0000;
@ -100,10 +98,9 @@ void Gfx::DrawChar(const FONT_INFO *font, uint8_t c, uint8_t *x, uint8_t y, uint
for (uint16_t j = 0; j < bytes_in_line; j++) { for (uint16_t j = 0; j < bytes_in_line; j++) {
for (uint8_t k = 0; k < 8; k++) { for (uint8_t k = 0; k < 8; k++) {
if ((1 << (7 - k)) & font->data[font->charInfo[char_idx].offset + j]) { if ((1 << (7 - k)) & font->data[font->charInfo[char_idx].offset + j]) {
buffer[(j*8)+k] = color; buffer[(j * 8) + k] = color;
} } else {
else { buffer[(j * 8) + k] = bg;
buffer[(j*8)+k] = bg;
} }
} }
} }
@ -112,12 +109,12 @@ void Gfx::DrawChar(const FONT_INFO *font, uint8_t c, uint8_t *x, uint8_t y, uint
state.currentIteration = 0; state.currentIteration = 0;
state.busy = true; state.busy = true;
state.action = Action::DrawChar; state.action = Action::DrawChar;
state.font = const_cast<FONT_INFO *>(font); state.font = const_cast<FONT_INFO*>(font);
state.character = c; state.character = c;
state.color = color; state.color = color;
state.taskToNotify = xTaskGetCurrentTaskHandle(); state.taskToNotify = xTaskGetCurrentTaskHandle();
lcd.DrawBuffer(*x, y, bytes_in_line*8, font->height, reinterpret_cast<const uint8_t *>(&buffer), bytes_in_line*8*2); lcd.DrawBuffer(*x, y, bytes_in_line * 8, font->height, reinterpret_cast<const uint8_t*>(&buffer), bytes_in_line * 8 * 2);
WaitTransferFinished(); WaitTransferFinished();
*x += font->charInfo[char_idx].widthBits + font->spacePixels; *x += font->charInfo[char_idx].widthBits + font->spacePixels;
@ -136,13 +133,14 @@ void Gfx::Wakeup() {
} }
void Gfx::SetBackgroundColor(uint16_t color) { void Gfx::SetBackgroundColor(uint16_t color) {
for(int i = 0; i < width; i++) { for (int i = 0; i < width; i++) {
buffer[i] = color; buffer[i] = color;
} }
} }
bool Gfx::GetNextBuffer(uint8_t **data, size_t &size) { bool Gfx::GetNextBuffer(uint8_t** data, size_t& size) {
if(!state.busy) return false; if (!state.busy)
return false;
state.remainingIterations--; state.remainingIterations--;
if (state.remainingIterations == 0) { if (state.remainingIterations == 0) {
state.busy = false; state.busy = false;
@ -150,27 +148,26 @@ bool Gfx::GetNextBuffer(uint8_t **data, size_t &size) {
return false; return false;
} }
if(state.action == Action::FillRectangle) { if (state.action == Action::FillRectangle) {
*data = reinterpret_cast<uint8_t *>(buffer); *data = reinterpret_cast<uint8_t*>(buffer);
size = width * 2; size = width * 2;
} else if(state.action == Action::DrawChar) { } else if (state.action == Action::DrawChar) {
uint16_t bg = 0x0000; uint16_t bg = 0x0000;
uint8_t char_idx = state.character - state.font->startChar; uint8_t char_idx = state.character - state.font->startChar;
uint16_t bytes_in_line = CEIL_DIV(state.font->charInfo[char_idx].widthBits, 8); uint16_t bytes_in_line = CEIL_DIV(state.font->charInfo[char_idx].widthBits, 8);
for (uint16_t j = 0; j < bytes_in_line; j++) { for (uint16_t j = 0; j < bytes_in_line; j++) {
for (uint8_t k = 0; k < 8; k++) { for (uint8_t k = 0; k < 8; k++) {
if ((1 << (7 - k)) & state.font->data[state.font->charInfo[char_idx].offset + ((state.currentIteration+1) * bytes_in_line) + j]) { if ((1 << (7 - k)) & state.font->data[state.font->charInfo[char_idx].offset + ((state.currentIteration + 1) * bytes_in_line) + j]) {
buffer[(j*8)+k] = state.color; buffer[(j * 8) + k] = state.color;
} } else {
else { buffer[(j * 8) + k] = bg;
buffer[(j*8)+k] = bg;
} }
} }
} }
*data = reinterpret_cast<uint8_t *>(buffer); *data = reinterpret_cast<uint8_t*>(buffer);
size = bytes_in_line*8*2; size = bytes_in_line * 8 * 2;
} }
state.currentIteration++; state.currentIteration++;
@ -179,7 +176,7 @@ bool Gfx::GetNextBuffer(uint8_t **data, size_t &size) {
} }
void Gfx::NotifyEndOfTransfer(TaskHandle_t task) { void Gfx::NotifyEndOfTransfer(TaskHandle_t task) {
if(task != nullptr) { if (task != nullptr) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE; BaseType_t xHigherPriorityTaskWoken = pdFALSE;
vTaskNotifyGiveFromISR(task, &xHigherPriorityTaskWoken); vTaskNotifyGiveFromISR(task, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken); portYIELD_FROM_ISR(xHigherPriorityTaskWoken);

View File

@ -16,32 +16,31 @@ namespace Pinetime {
explicit Gfx(Drivers::St7789& lcd); explicit Gfx(Drivers::St7789& lcd);
void Init(); void Init();
void ClearScreen(); void ClearScreen();
void DrawString(uint8_t x, uint8_t y, uint16_t color, const char* text, const FONT_INFO *p_font, bool wrap); void DrawString(uint8_t x, uint8_t y, uint16_t color, const char* text, const FONT_INFO* p_font, bool wrap);
void DrawChar(const FONT_INFO *font, uint8_t c, uint8_t *x, uint8_t y, uint16_t color); void DrawChar(const FONT_INFO* font, uint8_t c, uint8_t* x, uint8_t y, uint16_t color);
void FillRectangle(uint8_t x, uint8_t y, uint8_t width, uint8_t height, uint16_t color); void FillRectangle(uint8_t x, uint8_t y, uint8_t width, uint8_t height, uint16_t color);
void FillRectangle(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t* b); void FillRectangle(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t* b);
void SetScrollArea(uint16_t topFixedLines, uint16_t scrollLines, uint16_t bottomFixedLines); void SetScrollArea(uint16_t topFixedLines, uint16_t scrollLines, uint16_t bottomFixedLines);
void SetScrollStartLine(uint16_t line); void SetScrollStartLine(uint16_t line);
void Sleep(); void Sleep();
void Wakeup(); void Wakeup();
bool GetNextBuffer(uint8_t **buffer, size_t &size) override; bool GetNextBuffer(uint8_t** buffer, size_t& size) override;
void pixel_draw(uint8_t x, uint8_t y, uint16_t color); void pixel_draw(uint8_t x, uint8_t y, uint16_t color);
private: private:
static constexpr uint8_t width = 240; static constexpr uint8_t width = 240;
static constexpr uint8_t height = 240; static constexpr uint8_t height = 240;
enum class Action { None, FillRectangle, DrawChar}; enum class Action { None, FillRectangle, DrawChar };
struct State { struct State {
State() : busy{false}, action{Action::None}, remainingIterations{0}, currentIteration{0} {} State() : busy {false}, action {Action::None}, remainingIterations {0}, currentIteration {0} {
}
volatile bool busy; volatile bool busy;
volatile Action action; volatile Action action;
volatile uint16_t remainingIterations; volatile uint16_t remainingIterations;
volatile uint16_t currentIteration; volatile uint16_t currentIteration;
volatile FONT_INFO *font; volatile FONT_INFO* font;
volatile uint16_t color; volatile uint16_t color;
volatile uint8_t character; volatile uint8_t character;
volatile TaskHandle_t taskToNotify = nullptr; volatile TaskHandle_t taskToNotify = nullptr;

View File

@ -9,8 +9,7 @@
using namespace Pinetime::Controllers; using namespace Pinetime::Controllers;
/** Original implementation from wasp-os : https://github.com/daniel-thompson/wasp-os/blob/master/wasp/ppg.py */ /** Original implementation from wasp-os : https://github.com/daniel-thompson/wasp-os/blob/master/wasp/ppg.py */
Biquad::Biquad(float b0, float b1, float b2, float a1, float a2) : b0{b0}, b1{b1}, b2{b2}, a1{a1}, a2{a2} { Biquad::Biquad(float b0, float b1, float b2, float a1, float a2) : b0 {b0}, b1 {b1}, b2 {b2}, a1 {a1}, a2 {a2} {
} }
float Biquad::Step(float x) { float Biquad::Step(float x) {

View File

@ -4,38 +4,35 @@
using namespace Pinetime::Controllers; using namespace Pinetime::Controllers;
HeartRateController::HeartRateController(Pinetime::System::SystemTask &systemTask) : systemTask{systemTask} { HeartRateController::HeartRateController(Pinetime::System::SystemTask& systemTask) : systemTask {systemTask} {
} }
void HeartRateController::Update(HeartRateController::States newState, uint8_t heartRate) { void HeartRateController::Update(HeartRateController::States newState, uint8_t heartRate) {
this->state = newState; this->state = newState;
if(this->heartRate != heartRate) { if (this->heartRate != heartRate) {
this->heartRate = heartRate; this->heartRate = heartRate;
service->OnNewHeartRateValue(heartRate); service->OnNewHeartRateValue(heartRate);
} }
} }
void HeartRateController::Start() { void HeartRateController::Start() {
if(task != nullptr) { if (task != nullptr) {
state = States::NotEnoughData; state = States::NotEnoughData;
task->PushMessage(Pinetime::Applications::HeartRateTask::Messages::StartMeasurement); task->PushMessage(Pinetime::Applications::HeartRateTask::Messages::StartMeasurement);
} }
} }
void HeartRateController::Stop() { void HeartRateController::Stop() {
if(task != nullptr) { if (task != nullptr) {
state = States::Stopped; state = States::Stopped;
task->PushMessage(Pinetime::Applications::HeartRateTask::Messages::StopMeasurement); task->PushMessage(Pinetime::Applications::HeartRateTask::Messages::StopMeasurement);
} }
} }
void HeartRateController::SetHeartRateTask(Pinetime::Applications::HeartRateTask *task) { void HeartRateController::SetHeartRateTask(Pinetime::Applications::HeartRateTask* task) {
this->task = task; this->task = task;
} }
void HeartRateController::SetService(Pinetime::Controllers::HeartRateService *service) { void HeartRateController::SetService(Pinetime::Controllers::HeartRateService* service) {
this->service = service; this->service = service;
} }

View File

@ -13,7 +13,7 @@ namespace Pinetime {
namespace Controllers { namespace Controllers {
class HeartRateController { class HeartRateController {
public: public:
enum class States { Stopped, NotEnoughData, NoTouch, Running}; enum class States { Stopped, NotEnoughData, NoTouch, Running };
explicit HeartRateController(System::SystemTask& systemTask); explicit HeartRateController(System::SystemTask& systemTask);
@ -22,10 +22,14 @@ namespace Pinetime {
void Update(States newState, uint8_t heartRate); void Update(States newState, uint8_t heartRate);
void SetHeartRateTask(Applications::HeartRateTask* task); void SetHeartRateTask(Applications::HeartRateTask* task);
States State() const { return state; } States State() const {
uint8_t HeartRate() const { return heartRate; } return state;
}
uint8_t HeartRate() const {
return heartRate;
}
void SetService(Pinetime::Controllers::HeartRateService *service); void SetService(Pinetime::Controllers::HeartRateService* service);
private: private:
System::SystemTask& systemTask; System::SystemTask& systemTask;

View File

@ -13,7 +13,7 @@ using namespace Pinetime::Controllers;
namespace { namespace {
int Compare(int* d1, int* d2, size_t count) { int Compare(int* d1, int* d2, size_t count) {
int e = 0; int e = 0;
for(size_t i = 0; i < count; i++) { for (size_t i = 0; i < count; i++) {
auto d = d1[i] - d2[i]; auto d = d1[i] - d2[i];
e += d * d; e += d * d;
} }
@ -21,15 +21,15 @@ namespace {
} }
int CompareShift(int* d, int shift, size_t count) { int CompareShift(int* d, int shift, size_t count) {
return Compare(d +shift, d, count - shift); return Compare(d + shift, d, count - shift);
} }
int Trough(int* d, size_t size, float mn, float mx) { int Trough(int* d, size_t size, float mn, float mx) {
auto z2 = CompareShift(d, mn-2, size); auto z2 = CompareShift(d, mn - 2, size);
auto z1 = CompareShift(d, mn-1, size); auto z1 = CompareShift(d, mn - 1, size);
for(int i = mn; i < mx + 1; i++) { for (int i = mn; i < mx + 1; i++) {
auto z = CompareShift(d, i, size); auto z = CompareShift(d, i, size);
if(z2 > z1 && z1 < z) if (z2 > z1 && z1 < z)
return i; return i;
z2 = z1; z2 = z1;
z1 = z; z1 = z;
@ -38,11 +38,11 @@ namespace {
} }
} }
Ppg::Ppg(float spl) : offset{spl}, Ppg::Ppg(float spl)
hpf{0.87033078, -1.74066156, 0.87033078,-1.72377617, 0.75754694}, : offset {spl},
agc{20, 0.971, 2}, hpf {0.87033078, -1.74066156, 0.87033078, -1.72377617, 0.75754694},
lpf{0.11595249, 0.23190498, 0.11595249,-0.72168143, 0.18549138} { agc {20, 0.971, 2},
lpf {0.11595249, 0.23190498, 0.11595249, -0.72168143, 0.18549138} {
} }
int Ppg::Preprocess(float spl) { int Ppg::Preprocess(float spl) {
@ -53,13 +53,13 @@ int Ppg::Preprocess(float spl) {
auto spl_int = static_cast<int>(spl); auto spl_int = static_cast<int>(spl);
if(dataIndex < 200) if (dataIndex < 200)
data[dataIndex++] = spl_int; data[dataIndex++] = spl_int;
return spl_int; return spl_int;
} }
float Ppg::HeartRate() { float Ppg::HeartRate() {
if(dataIndex < 200) if (dataIndex < 200)
return 0; return 0;
NRF_LOG_INFO("PREPROCESS, offset = %d", offset); NRF_LOG_INFO("PREPROCESS, offset = %d", offset);
@ -71,26 +71,26 @@ float Ppg::HeartRate() {
int cccount = 0; int cccount = 0;
float Ppg::ProcessHeartRate() { float Ppg::ProcessHeartRate() {
if(cccount > 2) if (cccount > 2)
asm("nop"); asm("nop");
cccount ++; cccount++;
auto t0 = Trough(data.data(), dataIndex, 7, 48); auto t0 = Trough(data.data(), dataIndex, 7, 48);
if(t0 < 0) if (t0 < 0)
return 0; return 0;
float t1 = t0 * 2; float t1 = t0 * 2;
t1 = Trough(data.data(), dataIndex, t1-5, t1+5); t1 = Trough(data.data(), dataIndex, t1 - 5, t1 + 5);
if(t1 < 0) if (t1 < 0)
return 0; return 0;
float t2 = static_cast<int>(t1 * 3) / 2; float t2 = static_cast<int>(t1 * 3) / 2;
t2 = Trough(data.data(), dataIndex, t2 - 5, t2 + 5); t2 = Trough(data.data(), dataIndex, t2 - 5, t2 + 5);
if(t2 < 0) if (t2 < 0)
return 0; return 0;
float t3 = static_cast<int>(t2 * 4) / 3; float t3 = static_cast<int>(t2 * 4) / 3;
t3 = Trough(data.data(), dataIndex, t3 - 4, t3 + 4); t3 = Trough(data.data(), dataIndex, t3 - 4, t3 + 4);
if(t3 < 0) if (t3 < 0)
return static_cast<int>(60 * 24 * 3) / static_cast<int>(t2); return static_cast<int>(60 * 24 * 3) / static_cast<int>(t2);
return static_cast<int>(60 * 24 * 4) / static_cast<int>(t3); return static_cast<int>(60 * 24 * 4) / static_cast<int>(t3);

View File

@ -24,7 +24,6 @@ namespace Pinetime {
Ptagc agc; Ptagc agc;
Biquad lpf; Biquad lpf;
float ProcessHeartRate(); float ProcessHeartRate();
}; };
} }

View File

@ -10,17 +10,16 @@
using namespace Pinetime::Controllers; using namespace Pinetime::Controllers;
/** Original implementation from wasp-os : https://github.com/daniel-thompson/wasp-os/blob/master/wasp/ppg.py */ /** Original implementation from wasp-os : https://github.com/daniel-thompson/wasp-os/blob/master/wasp/ppg.py */
Ptagc::Ptagc(float start, float decay, float threshold) : peak{start}, decay{decay}, boost{1.0f/decay}, threshold{threshold} { Ptagc::Ptagc(float start, float decay, float threshold) : peak {start}, decay {decay}, boost {1.0f / decay}, threshold {threshold} {
} }
float Ptagc::Step(float spl) { float Ptagc::Step(float spl) {
if(std::abs(spl) > peak) if (std::abs(spl) > peak)
peak *= boost; peak *= boost;
else else
peak *= decay; peak *= decay;
if((spl > (peak * threshold)) || (spl < (peak * -threshold))) if ((spl > (peak * threshold)) || (spl < (peak * -threshold)))
return 0.0f; return 0.0f;
spl = 100.0f * spl / (2.0f * peak); spl = 100.0f * spl / (2.0f * peak);

View File

@ -12,7 +12,6 @@ namespace Pinetime {
float decay; float decay;
float boost; float boost;
float threshold; float threshold;
}; };
} }
} }

View File

@ -8,14 +8,24 @@ namespace Pinetime {
public: public:
void Update(int16_t x, int16_t y, int16_t z, uint32_t nbSteps); void Update(int16_t x, int16_t y, int16_t z, uint32_t nbSteps);
uint16_t X() const { return x; } uint16_t X() const {
uint16_t Y() const { return y; } return x;
uint16_t Z() const { return z; } }
uint32_t NbSteps() const { return nbSteps; } uint16_t Y() const {
return y;
}
uint16_t Z() const {
return z;
}
uint32_t NbSteps() const {
return nbSteps;
}
bool ShouldWakeUp(bool isSleeping); bool ShouldWakeUp(bool isSleeping);
void IsSensorOk(bool isOk); void IsSensorOk(bool isOk);
bool IsSensorOk() const { return isSensorOk; } bool IsSensorOk() const {
return isSensorOk;
}
private: private:
uint32_t nbSteps; uint32_t nbSteps;

View File

@ -7,7 +7,8 @@ APP_TIMER_DEF(vibTimer);
using namespace Pinetime::Controllers; using namespace Pinetime::Controllers;
MotorController::MotorController( Controllers::Settings &settingsController ) : settingsController{settingsController} {} MotorController::MotorController(Controllers::Settings& settingsController) : settingsController {settingsController} {
}
void MotorController::Init() { void MotorController::Init() {
nrf_gpio_cfg_output(pinMotor); nrf_gpio_cfg_output(pinMotor);
@ -18,13 +19,14 @@ void MotorController::Init() {
void MotorController::SetDuration(uint8_t motorDuration) { void MotorController::SetDuration(uint8_t motorDuration) {
if ( settingsController.GetVibrationStatus() == Controllers::Settings::Vibration::OFF ) return; if (settingsController.GetVibrationStatus() == Controllers::Settings::Vibration::OFF)
return;
nrf_gpio_pin_clear(pinMotor); nrf_gpio_pin_clear(pinMotor);
/* Start timer for motorDuration miliseconds and timer triggers vibrate() when it finishes*/ /* Start timer for motorDuration miliseconds and timer triggers vibrate() when it finishes*/
app_timer_start(vibTimer, APP_TIMER_TICKS(motorDuration), NULL); app_timer_start(vibTimer, APP_TIMER_TICKS(motorDuration), NULL);
} }
void MotorController::vibrate(void * p_context) { void MotorController::vibrate(void* p_context) {
nrf_gpio_pin_set(pinMotor); nrf_gpio_pin_set(pinMotor);
} }

View File

@ -10,13 +10,13 @@ namespace Pinetime {
class MotorController { class MotorController {
public: public:
MotorController( Controllers::Settings &settingsController ); MotorController(Controllers::Settings& settingsController);
void Init(); void Init();
void SetDuration(uint8_t motorDuration); void SetDuration(uint8_t motorDuration);
private: private:
Controllers::Settings& settingsController; Controllers::Settings& settingsController;
static void vibrate(void * p_context); static void vibrate(void* p_context);
}; };
} }
} }

View File

@ -2,18 +2,16 @@
using namespace Pinetime::Tools; using namespace Pinetime::Tools;
RleDecoder::RleDecoder(const uint8_t *buffer, size_t size) : buffer{buffer}, size{size} { RleDecoder::RleDecoder(const uint8_t* buffer, size_t size) : buffer {buffer}, size {size} {
} }
RleDecoder::RleDecoder(const uint8_t *buffer, size_t size, uint16_t foregroundColor, uint16_t backgroundColor) : RleDecoder{buffer, size} { RleDecoder::RleDecoder(const uint8_t* buffer, size_t size, uint16_t foregroundColor, uint16_t backgroundColor) : RleDecoder {buffer, size} {
this->foregroundColor = foregroundColor; this->foregroundColor = foregroundColor;
this->backgroundColor = backgroundColor; this->backgroundColor = backgroundColor;
} }
void RleDecoder::DecodeNext(uint8_t* output, size_t maxBytes) {
void RleDecoder::DecodeNext(uint8_t *output, size_t maxBytes) { for (; encodedBufferIndex < size; encodedBufferIndex++) {
for (;encodedBufferIndex<size; encodedBufferIndex++) {
uint8_t rl = buffer[encodedBufferIndex] - processedCount; uint8_t rl = buffer[encodedBufferIndex] - processedCount;
while (rl) { while (rl) {
output[bp] = color >> 8; output[bp] = color >> 8;
@ -36,4 +34,3 @@ void RleDecoder::DecodeNext(uint8_t *output, size_t maxBytes) {
color = backgroundColor; color = backgroundColor;
} }
} }

View File

@ -11,35 +11,33 @@ struct SettingsHeader {
#define HEADER_SIZE sizeof(SettingsHeader) #define HEADER_SIZE sizeof(SettingsHeader)
Settings::Settings(Pinetime::Drivers::SpiNorFlash& spiNorFlash) : spiNorFlash {spiNorFlash} {
Settings::Settings( Pinetime::Drivers::SpiNorFlash &spiNorFlash ) : spiNorFlash{spiNorFlash} {} }
void Settings::Init() { void Settings::Init() {
// Load default settings from Flash // Load default settings from Flash
LoadSettingsFromFlash(); LoadSettingsFromFlash();
} }
void Settings::SaveSettings() { void Settings::SaveSettings() {
// verify if is necessary to save // verify if is necessary to save
if ( settingsChanged ) { if (settingsChanged) {
SaveSettingsToFlash(); SaveSettingsToFlash();
} }
settingsChanged = false; settingsChanged = false;
} }
bool Settings::FindHeader() { bool Settings::FindHeader() {
SettingsHeader settingsHeader; SettingsHeader settingsHeader;
uint8_t bufferHead[sizeof(settingsHeader)]; uint8_t bufferHead[sizeof(settingsHeader)];
for (uint8_t block = 0; block < 10; block++) { for (uint8_t block = 0; block < 10; block++) {
spiNorFlash.Read( settingsBaseAddr + (block * 0x1000), bufferHead, sizeof(settingsHeader) ); spiNorFlash.Read(settingsBaseAddr + (block * 0x1000), bufferHead, sizeof(settingsHeader));
std::memcpy(&settingsHeader, bufferHead, sizeof(settingsHeader)); std::memcpy(&settingsHeader, bufferHead, sizeof(settingsHeader));
if ( settingsHeader.isActive == 0xF1 && settingsHeader.version == settingsVersion ) { if (settingsHeader.isActive == 0xF1 && settingsHeader.version == settingsVersion) {
settingsFlashBlock = block; settingsFlashBlock = block;
return true; return true;
} }
@ -49,7 +47,7 @@ bool Settings::FindHeader() {
void Settings::ReadSettingsData() { void Settings::ReadSettingsData() {
uint8_t bufferSettings[sizeof(settings)]; uint8_t bufferSettings[sizeof(settings)];
spiNorFlash.Read( settingsBaseAddr + (settingsFlashBlock * 0x1000) + HEADER_SIZE, bufferSettings, sizeof(settings) ); spiNorFlash.Read(settingsBaseAddr + (settingsFlashBlock * 0x1000) + HEADER_SIZE, bufferSettings, sizeof(settings));
std::memcpy(&settings, bufferSettings, sizeof(settings)); std::memcpy(&settings, bufferSettings, sizeof(settings));
} }
@ -58,7 +56,7 @@ void Settings::EraseBlock() {
spiNorFlash.SectorErase(settingsBaseAddr + (settingsFlashBlock * 0x1000)); spiNorFlash.SectorErase(settingsBaseAddr + (settingsFlashBlock * 0x1000));
} }
void Settings::SetHeader( bool state ) { void Settings::SetHeader(bool state) {
SettingsHeader settingsHeader; SettingsHeader settingsHeader;
uint8_t bufferHead[sizeof(settingsHeader)]; uint8_t bufferHead[sizeof(settingsHeader)];
settingsHeader.isActive = state ? 0xF1 : 0xF0; settingsHeader.isActive = state ? 0xF1 : 0xF0;
@ -66,7 +64,6 @@ void Settings::SetHeader( bool state ) {
std::memcpy(bufferHead, &settingsHeader, sizeof(settingsHeader)); std::memcpy(bufferHead, &settingsHeader, sizeof(settingsHeader));
spiNorFlash.Write(settingsBaseAddr + (settingsFlashBlock * 0x1000), bufferHead, sizeof(settingsHeader)); spiNorFlash.Write(settingsBaseAddr + (settingsFlashBlock * 0x1000), bufferHead, sizeof(settingsHeader));
} }
void Settings::SaveSettingsData() { void Settings::SaveSettingsData() {
@ -77,9 +74,9 @@ void Settings::SaveSettingsData() {
void Settings::LoadSettingsFromFlash() { void Settings::LoadSettingsFromFlash() {
if ( settingsFlashBlock == 99 ) { if (settingsFlashBlock == 99) {
// Find current Block, if can't find use default settings and set block to 0 ans save ! // Find current Block, if can't find use default settings and set block to 0 ans save !
if ( FindHeader() ) { if (FindHeader()) {
ReadSettingsData(); ReadSettingsData();
} else { } else {
SaveSettingsToFlash(); SaveSettingsToFlash();
@ -89,7 +86,6 @@ void Settings::LoadSettingsFromFlash() {
// never used :) // never used :)
ReadSettingsData(); ReadSettingsData();
} }
} }
void Settings::SaveSettingsToFlash() { void Settings::SaveSettingsToFlash() {
@ -101,14 +97,15 @@ void Settings::SaveSettingsToFlash() {
// if first time hever, only saves to block 0 and set settingsFlashBlock // if first time hever, only saves to block 0 and set settingsFlashBlock
if ( settingsFlashBlock != 99 ) { if (settingsFlashBlock != 99) {
SetHeader( false ); SetHeader(false);
} }
settingsFlashBlock++; settingsFlashBlock++;
if ( settingsFlashBlock > 9 ) settingsFlashBlock = 0; if (settingsFlashBlock > 9)
settingsFlashBlock = 0;
EraseBlock(); EraseBlock();
SetHeader( true ); SetHeader(true);
SaveSettingsData(); SaveSettingsData();
} }

View File

@ -9,59 +9,84 @@ namespace Pinetime {
namespace Controllers { namespace Controllers {
class Settings { class Settings {
public: public:
enum class ClockType {H24, H12}; enum class ClockType { H24, H12 };
enum class Vibration {ON, OFF}; enum class Vibration { ON, OFF };
enum class WakeUpMode {None, SingleTap, DoubleTap, RaiseWrist}; enum class WakeUpMode { None, SingleTap, DoubleTap, RaiseWrist };
Settings( Pinetime::Drivers::SpiNorFlash &spiNorFlash ); Settings(Pinetime::Drivers::SpiNorFlash& spiNorFlash);
void Init(); void Init();
void SaveSettings(); void SaveSettings();
void SetClockFace( uint8_t face ) { void SetClockFace(uint8_t face) {
if ( face != settings.clockFace ) settingsChanged = true; if (face != settings.clockFace)
settingsChanged = true;
settings.clockFace = face; settings.clockFace = face;
}; };
uint8_t GetClockFace() const { return settings.clockFace; }; uint8_t GetClockFace() const {
return settings.clockFace;
};
void SetAppMenu( uint8_t menu ) { appMenu = menu; }; void SetAppMenu(uint8_t menu) {
uint8_t GetAppMenu() { return appMenu; }; appMenu = menu;
};
uint8_t GetAppMenu() {
return appMenu;
};
void SetSettingsMenu( uint8_t menu ) { settingsMenu = menu; }; void SetSettingsMenu(uint8_t menu) {
uint8_t GetSettingsMenu() const { return settingsMenu; }; settingsMenu = menu;
};
uint8_t GetSettingsMenu() const {
return settingsMenu;
};
void SetClockType( ClockType clocktype ) { void SetClockType(ClockType clocktype) {
if ( clocktype != settings.clockType ) settingsChanged = true; if (clocktype != settings.clockType)
settingsChanged = true;
settings.clockType = clocktype; settings.clockType = clocktype;
}; };
ClockType GetClockType() const { return settings.clockType; }; ClockType GetClockType() const {
return settings.clockType;
};
void SetVibrationStatus( Vibration status ) { void SetVibrationStatus(Vibration status) {
if ( status != settings.vibrationStatus ) settingsChanged = true; if (status != settings.vibrationStatus)
settingsChanged = true;
settings.vibrationStatus = status; settings.vibrationStatus = status;
}; };
Vibration GetVibrationStatus() const { return settings.vibrationStatus; }; Vibration GetVibrationStatus() const {
return settings.vibrationStatus;
};
void SetScreenTimeOut( uint32_t timeout ) { void SetScreenTimeOut(uint32_t timeout) {
if ( timeout != settings.screenTimeOut ) settingsChanged = true; if (timeout != settings.screenTimeOut)
settingsChanged = true;
settings.screenTimeOut = timeout; settings.screenTimeOut = timeout;
}; };
uint32_t GetScreenTimeOut() const { return settings.screenTimeOut; }; uint32_t GetScreenTimeOut() const {
return settings.screenTimeOut;
};
void setWakeUpMode( WakeUpMode wakeUp ) { void setWakeUpMode(WakeUpMode wakeUp) {
if ( wakeUp != settings.wakeUpMode ) settingsChanged = true; if (wakeUp != settings.wakeUpMode)
settingsChanged = true;
settings.wakeUpMode = wakeUp; settings.wakeUpMode = wakeUp;
}; };
WakeUpMode getWakeUpMode() const { return settings.wakeUpMode; }; WakeUpMode getWakeUpMode() const {
return settings.wakeUpMode;
};
void SetBrightness( Controllers::BrightnessController::Levels level ) { void SetBrightness(Controllers::BrightnessController::Levels level) {
if ( level != settings.brightLevel ) settingsChanged = true; if (level != settings.brightLevel)
settingsChanged = true;
settings.brightLevel = level; settings.brightLevel = level;
}; };
Controllers::BrightnessController::Levels GetBrightness() const { return settings.brightLevel; }; Controllers::BrightnessController::Levels GetBrightness() const {
return settings.brightLevel;
};
private: private:
Pinetime::Drivers::SpiNorFlash& spiNorFlash; Pinetime::Drivers::SpiNorFlash& spiNorFlash;
struct SettingsData { struct SettingsData {
@ -76,7 +101,6 @@ namespace Pinetime {
WakeUpMode wakeUpMode = WakeUpMode::None; WakeUpMode wakeUpMode = WakeUpMode::None;
Controllers::BrightnessController::Levels brightLevel = Controllers::BrightnessController::Levels::Medium; Controllers::BrightnessController::Levels brightLevel = Controllers::BrightnessController::Levels::Medium;
}; };
SettingsData settings; SettingsData settings;
@ -95,11 +119,10 @@ namespace Pinetime {
bool FindHeader(); bool FindHeader();
void ReadSettingsData(); void ReadSettingsData();
void EraseBlock(); void EraseBlock();
void SetHeader( bool state ); void SetHeader(bool state);
void SaveSettingsData(); void SaveSettingsData();
void LoadSettingsFromFlash(); void LoadSettingsFromFlash();
void SaveSettingsToFlash(); void SaveSettingsToFlash();
}; };
} }
} }

View File

@ -3,9 +3,30 @@
namespace Pinetime { namespace Pinetime {
namespace Applications { namespace Applications {
enum class Apps { enum class Apps {
None, Launcher, Clock, SysInfo, FirmwareUpdate, FirmwareValidation, NotificationsPreview, Notifications, FlashLight, BatteryInfo, None,
Music, Paint, Paddle, Twos, HeartRate, Navigation, StopWatch, Motion, Launcher,
QuickSettings, Settings, SettingWatchFace, SettingTimeFormat, SettingDisplay, SettingWakeUp Clock,
SysInfo,
FirmwareUpdate,
FirmwareValidation,
NotificationsPreview,
Notifications,
FlashLight,
BatteryInfo,
Music,
Paint,
Paddle,
Twos,
HeartRate,
Navigation,
StopWatch,
Motion,
QuickSettings,
Settings,
SettingWatchFace,
SettingTimeFormat,
SettingDisplay,
SettingWakeUp
}; };
} }
} }

View File

@ -40,29 +40,33 @@
using namespace Pinetime::Applications; using namespace Pinetime::Applications;
using namespace Pinetime::Applications::Display; using namespace Pinetime::Applications::Display;
DisplayApp::DisplayApp(Drivers::St7789 &lcd, Components::LittleVgl &lvgl, Drivers::Cst816S &touchPanel, DisplayApp::DisplayApp(Drivers::St7789& lcd,
Controllers::Battery &batteryController, Controllers::Ble &bleController, Components::LittleVgl& lvgl,
Controllers::DateTime &dateTimeController, Drivers::WatchdogView &watchdog, Drivers::Cst816S& touchPanel,
System::SystemTask &systemTask, Controllers::Battery& batteryController,
Controllers::Ble& bleController,
Controllers::DateTime& dateTimeController,
Drivers::WatchdogView& watchdog,
System::SystemTask& systemTask,
Pinetime::Controllers::NotificationManager& notificationManager, Pinetime::Controllers::NotificationManager& notificationManager,
Pinetime::Controllers::HeartRateController& heartRateController, Pinetime::Controllers::HeartRateController& heartRateController,
Controllers::Settings &settingsController, Controllers::Settings& settingsController,
Pinetime::Controllers::MotionController& motionController) : Pinetime::Controllers::MotionController& motionController)
lcd{lcd}, : lcd {lcd},
lvgl{lvgl}, lvgl {lvgl},
touchPanel{touchPanel}, touchPanel {touchPanel},
batteryController{batteryController}, batteryController {batteryController},
bleController{bleController}, bleController {bleController},
dateTimeController{dateTimeController}, dateTimeController {dateTimeController},
watchdog{watchdog}, watchdog {watchdog},
systemTask{systemTask}, systemTask {systemTask},
notificationManager{notificationManager}, notificationManager {notificationManager},
heartRateController{heartRateController}, heartRateController {heartRateController},
settingsController{settingsController}, settingsController {settingsController},
motionController{motionController} { motionController {motionController} {
msgQueue = xQueueCreate(queueSize, itemSize); msgQueue = xQueueCreate(queueSize, itemSize);
// Start clock when smartwatch boots // Start clock when smartwatch boots
LoadApp( Apps::Clock, DisplayApp::FullRefreshDirections::None ); LoadApp(Apps::Clock, DisplayApp::FullRefreshDirections::None);
} }
void DisplayApp::Start() { void DisplayApp::Start() {
@ -70,8 +74,8 @@ void DisplayApp::Start() {
APP_ERROR_HANDLER(NRF_ERROR_NO_MEM); APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);
} }
void DisplayApp::Process(void *instance) { void DisplayApp::Process(void* instance) {
auto *app = static_cast<DisplayApp *>(instance); auto* app = static_cast<DisplayApp*>(instance);
NRF_LOG_INFO("displayapp task started!"); NRF_LOG_INFO("displayapp task started!");
app->InitHw(); app->InitHw();
@ -112,7 +116,7 @@ void DisplayApp::Refresh() {
switch (msg) { switch (msg) {
case Messages::GoToSleep: case Messages::GoToSleep:
brightnessController.Backup(); brightnessController.Backup();
while(brightnessController.Level() != Controllers::BrightnessController::Levels::Off) { while (brightnessController.Level() != Controllers::BrightnessController::Levels::Off) {
brightnessController.Lower(); brightnessController.Lower();
vTaskDelay(100); vTaskDelay(100);
} }
@ -129,28 +133,30 @@ void DisplayApp::Refresh() {
systemTask.PushMessage(System::SystemTask::Messages::UpdateTimeOut); systemTask.PushMessage(System::SystemTask::Messages::UpdateTimeOut);
break; break;
case Messages::UpdateBleConnection: case Messages::UpdateBleConnection:
// clockScreen.SetBleConnectionState(bleController.IsConnected() ? Screens::Clock::BleConnectionStates::Connected : Screens::Clock::BleConnectionStates::NotConnected); // clockScreen.SetBleConnectionState(bleController.IsConnected() ? Screens::Clock::BleConnectionStates::Connected :
// Screens::Clock::BleConnectionStates::NotConnected);
break; break;
case Messages::UpdateBatteryLevel: case Messages::UpdateBatteryLevel:
batteryController.Update(); batteryController.Update();
break; break;
case Messages::NewNotification: case Messages::NewNotification:
LoadApp( Apps::NotificationsPreview, DisplayApp::FullRefreshDirections::Down ); LoadApp(Apps::NotificationsPreview, DisplayApp::FullRefreshDirections::Down);
break; break;
case Messages::TouchEvent: { case Messages::TouchEvent: {
if (state != States::Running) break; if (state != States::Running)
break;
auto gesture = OnTouchEvent(); auto gesture = OnTouchEvent();
if(!currentScreen->OnTouchEvent(gesture)) { if (!currentScreen->OnTouchEvent(gesture)) {
if ( currentApp == Apps::Clock ) { if (currentApp == Apps::Clock) {
switch (gesture) { switch (gesture) {
case TouchEvents::SwipeUp: case TouchEvents::SwipeUp:
LoadApp( Apps::Launcher, DisplayApp::FullRefreshDirections::Up ); LoadApp(Apps::Launcher, DisplayApp::FullRefreshDirections::Up);
break; break;
case TouchEvents::SwipeDown: case TouchEvents::SwipeDown:
LoadApp( Apps::Notifications, DisplayApp::FullRefreshDirections::Down ); LoadApp(Apps::Notifications, DisplayApp::FullRefreshDirections::Down);
break; break;
case TouchEvents::SwipeRight: case TouchEvents::SwipeRight:
LoadApp( Apps::QuickSettings, DisplayApp::FullRefreshDirections::RightAnim ); LoadApp(Apps::QuickSettings, DisplayApp::FullRefreshDirections::RightAnim);
break; break;
case TouchEvents::DoubleTap: case TouchEvents::DoubleTap:
systemTask.PushMessage(System::SystemTask::Messages::GoToSleep); systemTask.PushMessage(System::SystemTask::Messages::GoToSleep);
@ -158,24 +164,23 @@ void DisplayApp::Refresh() {
default: default:
break; break;
} }
} else if ( returnTouchEvent == gesture ) { } else if (returnTouchEvent == gesture) {
LoadApp( returnToApp, returnDirection ); LoadApp(returnToApp, returnDirection);
} }
} }
} } break;
break;
case Messages::ButtonPushed: case Messages::ButtonPushed:
if( currentApp == Apps::Clock ) { if (currentApp == Apps::Clock) {
systemTask.PushMessage(System::SystemTask::Messages::GoToSleep); systemTask.PushMessage(System::SystemTask::Messages::GoToSleep);
} else { } else {
if ( !currentScreen->OnButtonPushed() ) { if (!currentScreen->OnButtonPushed()) {
LoadApp( returnToApp, returnDirection ); LoadApp(returnToApp, returnDirection);
} }
} }
break; break;
case Messages::BleFirmwareUpdateStarted: case Messages::BleFirmwareUpdateStarted:
LoadApp( Apps::FirmwareUpdate, DisplayApp::FullRefreshDirections::Down ); LoadApp(Apps::FirmwareUpdate, DisplayApp::FullRefreshDirections::Down);
break; break;
case Messages::UpdateDateTime: case Messages::UpdateDateTime:
// Added to remove warning // Added to remove warning
@ -184,10 +189,10 @@ void DisplayApp::Refresh() {
} }
} }
if(state != States::Idle && touchMode == TouchModes::Polling) { if (state != States::Idle && touchMode == TouchModes::Polling) {
auto info = touchPanel.GetTouchInfo(); auto info = touchPanel.GetTouchInfo();
if(info.action == 2) {// 2 = contact if (info.action == 2) { // 2 = contact
if(!currentScreen->OnTouchEvent(info.x, info.y)) { if (!currentScreen->OnTouchEvent(info.x, info.y)) {
lvgl.SetNewTapEvent(info.x, info.y); lvgl.SetNewTapEvent(info.x, info.y);
} }
} }
@ -195,14 +200,14 @@ void DisplayApp::Refresh() {
} }
void DisplayApp::RunningState() { void DisplayApp::RunningState() {
if(!currentScreen->Refresh()) { if (!currentScreen->Refresh()) {
LoadApp( returnToApp, returnDirection ); LoadApp(returnToApp, returnDirection);
} }
lv_task_handler(); lv_task_handler();
} }
void DisplayApp::StartApp(Apps app, DisplayApp::FullRefreshDirections direction) { void DisplayApp::StartApp(Apps app, DisplayApp::FullRefreshDirections direction) {
LoadApp( app, direction ); LoadApp(app, direction);
} }
void DisplayApp::returnApp(Apps app, DisplayApp::FullRefreshDirections direction, TouchEvents touchEvent) { void DisplayApp::returnApp(Apps app, DisplayApp::FullRefreshDirections direction, TouchEvents touchEvent) {
@ -213,19 +218,26 @@ void DisplayApp::returnApp(Apps app, DisplayApp::FullRefreshDirections direction
void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction) { void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction) {
currentScreen.reset(nullptr); currentScreen.reset(nullptr);
SetFullRefresh( direction ); SetFullRefresh(direction);
// default return to launcher // default return to launcher
returnApp(Apps::Launcher, FullRefreshDirections::Down, TouchEvents::SwipeDown); returnApp(Apps::Launcher, FullRefreshDirections::Down, TouchEvents::SwipeDown);
switch(app) { switch (app) {
case Apps::Launcher: case Apps::Launcher:
currentScreen = std::make_unique<Screens::ApplicationList>(this, settingsController, batteryController, dateTimeController); currentScreen = std::make_unique<Screens::ApplicationList>(this, settingsController, batteryController, dateTimeController);
returnApp(Apps::Clock, FullRefreshDirections::Down, TouchEvents::SwipeDown); returnApp(Apps::Clock, FullRefreshDirections::Down, TouchEvents::SwipeDown);
break; break;
case Apps::None: case Apps::None:
case Apps::Clock: case Apps::Clock:
currentScreen = std::make_unique<Screens::Clock>(this, dateTimeController, batteryController, bleController, notificationManager, settingsController, heartRateController, motionController); currentScreen = std::make_unique<Screens::Clock>(this,
dateTimeController,
batteryController,
bleController,
notificationManager,
settingsController,
heartRateController,
motionController);
break; break;
case Apps::FirmwareValidation: case Apps::FirmwareValidation:
@ -237,17 +249,20 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction)
break; break;
case Apps::Notifications: case Apps::Notifications:
currentScreen = std::make_unique<Screens::Notifications>(this, notificationManager, systemTask.nimble().alertService(), Screens::Notifications::Modes::Normal); currentScreen = std::make_unique<Screens::Notifications>(
this, notificationManager, systemTask.nimble().alertService(), Screens::Notifications::Modes::Normal);
returnApp(Apps::Clock, FullRefreshDirections::Up, TouchEvents::SwipeUp); returnApp(Apps::Clock, FullRefreshDirections::Up, TouchEvents::SwipeUp);
break; break;
case Apps::NotificationsPreview: case Apps::NotificationsPreview:
currentScreen = std::make_unique<Screens::Notifications>(this, notificationManager, systemTask.nimble().alertService(), Screens::Notifications::Modes::Preview); currentScreen = std::make_unique<Screens::Notifications>(
this, notificationManager, systemTask.nimble().alertService(), Screens::Notifications::Modes::Preview);
returnApp(Apps::Clock, FullRefreshDirections::Up, TouchEvents::SwipeUp); returnApp(Apps::Clock, FullRefreshDirections::Up, TouchEvents::SwipeUp);
break; break;
// Settings // Settings
case Apps::QuickSettings: case Apps::QuickSettings:
currentScreen = std::make_unique<Screens::QuickSettings>(this, batteryController, dateTimeController, brightnessController, settingsController); currentScreen =
std::make_unique<Screens::QuickSettings>(this, batteryController, dateTimeController, brightnessController, settingsController);
returnApp(Apps::Clock, FullRefreshDirections::LeftAnim, TouchEvents::SwipeLeft); returnApp(Apps::Clock, FullRefreshDirections::LeftAnim, TouchEvents::SwipeLeft);
break; break;
case Apps::Settings: case Apps::Settings:
@ -275,7 +290,8 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction)
returnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); returnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
break; break;
case Apps::SysInfo: case Apps::SysInfo:
currentScreen = std::make_unique<Screens::SystemInfo>(this, dateTimeController, batteryController, brightnessController, bleController, watchdog); currentScreen =
std::make_unique<Screens::SystemInfo>(this, dateTimeController, batteryController, brightnessController, bleController, watchdog);
returnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); returnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
break; break;
// //
@ -313,7 +329,6 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction)
} }
void DisplayApp::IdleState() { void DisplayApp::IdleState() {
} }
void DisplayApp::PushMessage(Messages msg) { void DisplayApp::PushMessage(Messages msg) {
@ -328,10 +343,10 @@ void DisplayApp::PushMessage(Messages msg) {
TouchEvents DisplayApp::OnTouchEvent() { TouchEvents DisplayApp::OnTouchEvent() {
auto info = touchPanel.GetTouchInfo(); auto info = touchPanel.GetTouchInfo();
if(info.isTouch) { if (info.isTouch) {
switch(info.gesture) { switch (info.gesture) {
case Pinetime::Drivers::Cst816S::Gestures::SingleTap: case Pinetime::Drivers::Cst816S::Gestures::SingleTap:
if(touchMode == TouchModes::Gestures) if (touchMode == TouchModes::Gestures)
lvgl.SetNewTapEvent(info.x, info.y); lvgl.SetNewTapEvent(info.x, info.y);
return TouchEvents::Tap; return TouchEvents::Tap;
case Pinetime::Drivers::Cst816S::Gestures::LongPress: case Pinetime::Drivers::Cst816S::Gestures::LongPress:
@ -355,7 +370,7 @@ TouchEvents DisplayApp::OnTouchEvent() {
} }
void DisplayApp::SetFullRefresh(DisplayApp::FullRefreshDirections direction) { void DisplayApp::SetFullRefresh(DisplayApp::FullRefreshDirections direction) {
switch(direction){ switch (direction) {
case DisplayApp::FullRefreshDirections::Down: case DisplayApp::FullRefreshDirections::Down:
lvgl.SetFullRefresh(Components::LittleVgl::FullRefreshDirections::Down); lvgl.SetFullRefresh(Components::LittleVgl::FullRefreshDirections::Down);
break; break;
@ -374,11 +389,11 @@ void DisplayApp::SetFullRefresh(DisplayApp::FullRefreshDirections direction) {
case DisplayApp::FullRefreshDirections::RightAnim: case DisplayApp::FullRefreshDirections::RightAnim:
lvgl.SetFullRefresh(Components::LittleVgl::FullRefreshDirections::RightAnim); lvgl.SetFullRefresh(Components::LittleVgl::FullRefreshDirections::RightAnim);
break; break;
default: break; default:
break;
} }
} }
void DisplayApp::SetTouchMode(DisplayApp::TouchModes mode) { void DisplayApp::SetTouchMode(DisplayApp::TouchModes mode) {
touchMode = mode; touchMode = mode;
} }

View File

@ -36,19 +36,22 @@ namespace Pinetime {
namespace Applications { namespace Applications {
class DisplayApp { class DisplayApp {
public: public:
enum class States {Idle, Running}; enum class States { Idle, Running };
enum class FullRefreshDirections { None, Up, Down, Left, Right, LeftAnim, RightAnim }; enum class FullRefreshDirections { None, Up, Down, Left, Right, LeftAnim, RightAnim };
enum class TouchModes { Gestures, Polling }; enum class TouchModes { Gestures, Polling };
DisplayApp(Drivers::St7789 &lcd, Components::LittleVgl &lvgl, Drivers::Cst816S &, DisplayApp(Drivers::St7789& lcd,
Controllers::Battery &batteryController, Controllers::Ble &bleController, Components::LittleVgl& lvgl,
Controllers::DateTime &dateTimeController, Drivers::WatchdogView &watchdog, Drivers::Cst816S&,
System::SystemTask &systemTask, Controllers::Battery& batteryController,
Controllers::Ble& bleController,
Controllers::DateTime& dateTimeController,
Drivers::WatchdogView& watchdog,
System::SystemTask& systemTask,
Pinetime::Controllers::NotificationManager& notificationManager, Pinetime::Controllers::NotificationManager& notificationManager,
Pinetime::Controllers::HeartRateController& heartRateController, Pinetime::Controllers::HeartRateController& heartRateController,
Controllers::Settings &settingsController, Controllers::Settings& settingsController,
Pinetime::Controllers::MotionController& motionController Pinetime::Controllers::MotionController& motionController);
);
void Start(); void Start();
void PushMessage(Display::Messages msg); void PushMessage(Display::Messages msg);
@ -58,12 +61,11 @@ namespace Pinetime {
void SetTouchMode(TouchModes mode); void SetTouchMode(TouchModes mode);
private: private:
Pinetime::Drivers::St7789& lcd; Pinetime::Drivers::St7789& lcd;
Pinetime::Components::LittleVgl& lvgl; Pinetime::Components::LittleVgl& lvgl;
Pinetime::Drivers::Cst816S& touchPanel; Pinetime::Drivers::Cst816S& touchPanel;
Pinetime::Controllers::Battery &batteryController; Pinetime::Controllers::Battery& batteryController;
Pinetime::Controllers::Ble &bleController; Pinetime::Controllers::Ble& bleController;
Pinetime::Controllers::DateTime& dateTimeController; Pinetime::Controllers::DateTime& dateTimeController;
Pinetime::Drivers::WatchdogView& watchdog; Pinetime::Drivers::WatchdogView& watchdog;
Pinetime::System::SystemTask& systemTask; Pinetime::System::SystemTask& systemTask;
@ -100,9 +102,6 @@ namespace Pinetime {
void Refresh(); void Refresh();
void returnApp(Apps app, DisplayApp::FullRefreshDirections direction, TouchEvents touchEvent); void returnApp(Apps app, DisplayApp::FullRefreshDirections direction, TouchEvents touchEvent);
void LoadApp(Apps app, DisplayApp::FullRefreshDirections direction); void LoadApp(Apps app, DisplayApp::FullRefreshDirections direction);
}; };
} }
} }

View File

@ -7,17 +7,20 @@
using namespace Pinetime::Applications; using namespace Pinetime::Applications;
DisplayApp::DisplayApp(Drivers::St7789 &lcd, Components::LittleVgl &lvgl, Drivers::Cst816S &touchPanel, DisplayApp::DisplayApp(Drivers::St7789& lcd,
Controllers::Battery &batteryController, Controllers::Ble &bleController, Components::LittleVgl& lvgl,
Controllers::DateTime &dateTimeController, Drivers::WatchdogView &watchdog, Drivers::Cst816S& touchPanel,
System::SystemTask &systemTask, Controllers::Battery& batteryController,
Controllers::Ble& bleController,
Controllers::DateTime& dateTimeController,
Drivers::WatchdogView& watchdog,
System::SystemTask& systemTask,
Pinetime::Controllers::NotificationManager& notificationManager, Pinetime::Controllers::NotificationManager& notificationManager,
Pinetime::Controllers::HeartRateController& heartRateController, Pinetime::Controllers::HeartRateController& heartRateController,
Pinetime::Controllers::Settings& settingsController, Pinetime::Controllers::Settings& settingsController,
Pinetime::Controllers::MotionController& motionController): Pinetime::Controllers::MotionController& motionController)
lcd{lcd}, bleController{bleController} { : lcd {lcd}, bleController {bleController} {
msgQueue = xQueueCreate(queueSize, itemSize); msgQueue = xQueueCreate(queueSize, itemSize);
} }
void DisplayApp::Start() { void DisplayApp::Start() {
@ -25,8 +28,8 @@ void DisplayApp::Start() {
APP_ERROR_HANDLER(NRF_ERROR_NO_MEM); APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);
} }
void DisplayApp::Process(void *instance) { void DisplayApp::Process(void* instance) {
auto *app = static_cast<DisplayApp *>(instance); auto* app = static_cast<DisplayApp*>(instance);
NRF_LOG_INFO("displayapp task started!"); NRF_LOG_INFO("displayapp task started!");
// Send a dummy notification to unlock the lvgl display driver for the first iteration // Send a dummy notification to unlock the lvgl display driver for the first iteration
@ -61,8 +64,9 @@ void DisplayApp::Refresh() {
} }
if (bleController.IsFirmwareUpdating()) { if (bleController.IsFirmwareUpdating()) {
uint8_t percent = (static_cast<float>(bleController.FirmwareUpdateCurrentBytes()) / uint8_t percent =
static_cast<float>(bleController.FirmwareUpdateTotalBytes())) * 100.0f; (static_cast<float>(bleController.FirmwareUpdateCurrentBytes()) / static_cast<float>(bleController.FirmwareUpdateTotalBytes())) *
100.0f;
switch (bleController.State()) { switch (bleController.State()) {
case Controllers::Ble::FirmwareUpdateStates::Running: case Controllers::Ble::FirmwareUpdateStates::Running:
DisplayOtaProgress(percent, colorWhite); DisplayOtaProgress(percent, colorWhite);
@ -81,20 +85,20 @@ void DisplayApp::Refresh() {
void DisplayApp::DisplayLogo(uint16_t color) { void DisplayApp::DisplayLogo(uint16_t color) {
Pinetime::Tools::RleDecoder rleDecoder(infinitime_nb, sizeof(infinitime_nb), color, colorBlack); Pinetime::Tools::RleDecoder rleDecoder(infinitime_nb, sizeof(infinitime_nb), color, colorBlack);
for(int i = 0; i < displayWidth; i++) { for (int i = 0; i < displayWidth; i++) {
rleDecoder.DecodeNext(displayBuffer, displayWidth * bytesPerPixel); rleDecoder.DecodeNext(displayBuffer, displayWidth * bytesPerPixel);
ulTaskNotifyTake(pdTRUE, 500); ulTaskNotifyTake(pdTRUE, 500);
lcd.DrawBuffer(0, i, displayWidth, 1, reinterpret_cast<const uint8_t *>(displayBuffer), displayWidth * bytesPerPixel); lcd.DrawBuffer(0, i, displayWidth, 1, reinterpret_cast<const uint8_t*>(displayBuffer), displayWidth * bytesPerPixel);
} }
} }
void DisplayApp::DisplayOtaProgress(uint8_t percent, uint16_t color) { void DisplayApp::DisplayOtaProgress(uint8_t percent, uint16_t color) {
const uint8_t barHeight = 20; const uint8_t barHeight = 20;
std::fill(displayBuffer, displayBuffer+(displayWidth * bytesPerPixel), color); std::fill(displayBuffer, displayBuffer + (displayWidth * bytesPerPixel), color);
for(int i = 0; i < barHeight; i++) { for (int i = 0; i < barHeight; i++) {
ulTaskNotifyTake(pdTRUE, 500); ulTaskNotifyTake(pdTRUE, 500);
uint16_t barWidth = std::min(static_cast<float>(percent) * 2.4f, static_cast<float>(displayWidth)); uint16_t barWidth = std::min(static_cast<float>(percent) * 2.4f, static_cast<float>(displayWidth));
lcd.DrawBuffer(0, displayWidth - barHeight + i, barWidth, 1, reinterpret_cast<const uint8_t *>(displayBuffer), barWidth * bytesPerPixel); lcd.DrawBuffer(0, displayWidth - barHeight + i, barWidth, 1, reinterpret_cast<const uint8_t*>(displayBuffer), barWidth * bytesPerPixel);
} }
} }

View File

@ -30,10 +30,14 @@ namespace Pinetime {
namespace Applications { namespace Applications {
class DisplayApp { class DisplayApp {
public: public:
DisplayApp(Drivers::St7789 &lcd, Components::LittleVgl &lvgl, Drivers::Cst816S &, DisplayApp(Drivers::St7789& lcd,
Controllers::Battery &batteryController, Controllers::Ble &bleController, Components::LittleVgl& lvgl,
Controllers::DateTime &dateTimeController, Drivers::WatchdogView &watchdog, Drivers::Cst816S&,
System::SystemTask &systemTask, Controllers::Battery& batteryController,
Controllers::Ble& bleController,
Controllers::DateTime& dateTimeController,
Drivers::WatchdogView& watchdog,
System::SystemTask& systemTask,
Pinetime::Controllers::NotificationManager& notificationManager, Pinetime::Controllers::NotificationManager& notificationManager,
Pinetime::Controllers::HeartRateController& heartRateController, Pinetime::Controllers::HeartRateController& heartRateController,
Pinetime::Controllers::Settings& settingsController, Pinetime::Controllers::Settings& settingsController,
@ -49,7 +53,7 @@ namespace Pinetime {
void InitHw(); void InitHw();
void Refresh(); void Refresh();
Pinetime::Drivers::St7789& lcd; Pinetime::Drivers::St7789& lcd;
Controllers::Ble &bleController; Controllers::Ble& bleController;
static constexpr uint8_t queueSize = 10; static constexpr uint8_t queueSize = 10;
static constexpr uint8_t itemSize = 1; static constexpr uint8_t itemSize = 1;
@ -66,10 +70,6 @@ namespace Pinetime {
static constexpr uint16_t colorRedSwapped = 0x00ff; static constexpr uint16_t colorRedSwapped = 0x00ff;
static constexpr uint16_t colorBlack = 0x0000; static constexpr uint16_t colorBlack = 0x0000;
uint8_t displayBuffer[displayWidth * bytesPerPixel]; uint8_t displayBuffer[displayWidth * bytesPerPixel];
}; };
} }
} }

View File

@ -11,20 +11,23 @@ namespace Pinetime {
class LittleVgl { class LittleVgl {
public: public:
enum class FullRefreshDirections { None, Up, Down }; enum class FullRefreshDirections { None, Up, Down };
LittleVgl(Pinetime::Drivers::St7789& lcd, Pinetime::Drivers::Cst816S& touchPanel) {} LittleVgl(Pinetime::Drivers::St7789& lcd, Pinetime::Drivers::Cst816S& touchPanel) {
}
LittleVgl(const LittleVgl&) = delete; LittleVgl(const LittleVgl&) = delete;
LittleVgl& operator=(const LittleVgl&) = delete; LittleVgl& operator=(const LittleVgl&) = delete;
LittleVgl(LittleVgl&&) = delete; LittleVgl(LittleVgl&&) = delete;
LittleVgl& operator=(LittleVgl&&) = delete; LittleVgl& operator=(LittleVgl&&) = delete;
void FlushDisplay(const lv_area_t * area, lv_color_t * color_p) {} void FlushDisplay(const lv_area_t* area, lv_color_t* color_p) {
bool GetTouchPadInfo(lv_indev_data_t *ptr) {return false;} }
void SetFullRefresh(FullRefreshDirections direction) {} bool GetTouchPadInfo(lv_indev_data_t* ptr) {
void SetNewTapEvent(uint16_t x, uint16_t y) {} return false;
}
void SetFullRefresh(FullRefreshDirections direction) {
}
void SetNewTapEvent(uint16_t x, uint16_t y) {
}
}; };
} }
} }

View File

@ -11,17 +11,18 @@ using namespace Pinetime::Components;
lv_style_t* LabelBigStyle = nullptr; lv_style_t* LabelBigStyle = nullptr;
static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p) { static void disp_flush(lv_disp_drv_t* disp_drv, const lv_area_t* area, lv_color_t* color_p) {
auto* lvgl = static_cast<LittleVgl*>(disp_drv->user_data); auto* lvgl = static_cast<LittleVgl*>(disp_drv->user_data);
lvgl->FlushDisplay(area, color_p); lvgl->FlushDisplay(area, color_p);
} }
bool touchpad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data) { bool touchpad_read(lv_indev_drv_t* indev_drv, lv_indev_data_t* data) {
auto* lvgl = static_cast<LittleVgl*>(indev_drv->user_data); auto* lvgl = static_cast<LittleVgl*>(indev_drv->user_data);
return lvgl->GetTouchPadInfo(data); return lvgl->GetTouchPadInfo(data);
} }
LittleVgl::LittleVgl(Pinetime::Drivers::St7789& lcd, Pinetime::Drivers::Cst816S& touchPanel) : lcd{lcd}, touchPanel{touchPanel}, previousClick{0,0} { LittleVgl::LittleVgl(Pinetime::Drivers::St7789& lcd, Pinetime::Drivers::Cst816S& touchPanel)
: lcd {lcd}, touchPanel {touchPanel}, previousClick {0, 0} {
lv_init(); lv_init();
InitTheme(); InitTheme();
InitDisplay(); InitDisplay();
@ -59,7 +60,7 @@ void LittleVgl::InitTouchpad() {
} }
void LittleVgl::SetFullRefresh(FullRefreshDirections direction) { void LittleVgl::SetFullRefresh(FullRefreshDirections direction) {
if(scrollDirection == FullRefreshDirections::None) { if (scrollDirection == FullRefreshDirections::None) {
scrollDirection = direction; scrollDirection = direction;
if (scrollDirection == FullRefreshDirections::Down) { if (scrollDirection == FullRefreshDirections::Down) {
lv_disp_set_direction(lv_disp_get_default(), 1); lv_disp_set_direction(lv_disp_get_default(), 1);
@ -75,16 +76,16 @@ void LittleVgl::SetFullRefresh(FullRefreshDirections direction) {
} }
} }
void LittleVgl::FlushDisplay(const lv_area_t *area, lv_color_t *color_p) { void LittleVgl::FlushDisplay(const lv_area_t* area, lv_color_t* color_p) {
uint16_t y1, y2, width, height = 0; uint16_t y1, y2, width, height = 0;
ulTaskNotifyTake(pdTRUE, 200); ulTaskNotifyTake(pdTRUE, 200);
// NOtification is still needed (even if there is a mutex on SPI) because of the DataCommand pin // NOtification is still needed (even if there is a mutex on SPI) because of the DataCommand pin
// which cannot be set/clear during a transfert. // which cannot be set/clear during a transfert.
if( (scrollDirection == LittleVgl::FullRefreshDirections::Down) && (area->y2 == visibleNbLines - 1)) { if ((scrollDirection == LittleVgl::FullRefreshDirections::Down) && (area->y2 == visibleNbLines - 1)) {
writeOffset = ((writeOffset + totalNbLines) - visibleNbLines) % totalNbLines; writeOffset = ((writeOffset + totalNbLines) - visibleNbLines) % totalNbLines;
} else if( (scrollDirection == FullRefreshDirections::Up) && (area->y1 == 0) ) { } else if ((scrollDirection == FullRefreshDirections::Up) && (area->y1 == 0)) {
writeOffset = (writeOffset + visibleNbLines) % totalNbLines; writeOffset = (writeOffset + visibleNbLines) % totalNbLines;
} }
@ -94,11 +95,11 @@ void LittleVgl::FlushDisplay(const lv_area_t *area, lv_color_t *color_p) {
width = (area->x2 - area->x1) + 1; width = (area->x2 - area->x1) + 1;
height = (area->y2 - area->y1) + 1; height = (area->y2 - area->y1) + 1;
if(scrollDirection == LittleVgl::FullRefreshDirections::Down) { if (scrollDirection == LittleVgl::FullRefreshDirections::Down) {
if(area->y2 < visibleNbLines - 1) { if (area->y2 < visibleNbLines - 1) {
uint16_t toScroll = 0; uint16_t toScroll = 0;
if(area->y1 == 0) { if (area->y1 == 0) {
toScroll = height * 2; toScroll = height * 2;
scrollDirection = FullRefreshDirections::None; scrollDirection = FullRefreshDirections::None;
lv_disp_set_direction(lv_disp_get_default(), 0); lv_disp_set_direction(lv_disp_get_default(), 0);
@ -106,19 +107,19 @@ void LittleVgl::FlushDisplay(const lv_area_t *area, lv_color_t *color_p) {
toScroll = height; toScroll = height;
} }
if(scrollOffset >= toScroll) if (scrollOffset >= toScroll)
scrollOffset -= toScroll; scrollOffset -= toScroll;
else { else {
toScroll -= scrollOffset; toScroll -= scrollOffset;
scrollOffset = (totalNbLines) - toScroll; scrollOffset = (totalNbLines) -toScroll;
} }
lcd.VerticalScrollStartAddress(scrollOffset); lcd.VerticalScrollStartAddress(scrollOffset);
} }
} else if(scrollDirection == FullRefreshDirections::Up) { } else if (scrollDirection == FullRefreshDirections::Up) {
if(area->y1 > 0) { if (area->y1 > 0) {
if(area->y2 == visibleNbLines - 1) { if (area->y2 == visibleNbLines - 1) {
scrollOffset += (height * 2); scrollOffset += (height * 2);
scrollDirection = FullRefreshDirections::None; scrollDirection = FullRefreshDirections::None;
lv_disp_set_direction(lv_disp_get_default(), 0); lv_disp_set_direction(lv_disp_get_default(), 0);
@ -128,13 +129,13 @@ void LittleVgl::FlushDisplay(const lv_area_t *area, lv_color_t *color_p) {
scrollOffset = scrollOffset % totalNbLines; scrollOffset = scrollOffset % totalNbLines;
lcd.VerticalScrollStartAddress(scrollOffset); lcd.VerticalScrollStartAddress(scrollOffset);
} }
} else if(scrollDirection == FullRefreshDirections::Left or scrollDirection == FullRefreshDirections::LeftAnim) { } else if (scrollDirection == FullRefreshDirections::Left or scrollDirection == FullRefreshDirections::LeftAnim) {
if(area->x2 == visibleNbLines - 1) { if (area->x2 == visibleNbLines - 1) {
scrollDirection = FullRefreshDirections::None; scrollDirection = FullRefreshDirections::None;
lv_disp_set_direction(lv_disp_get_default(), 0); lv_disp_set_direction(lv_disp_get_default(), 0);
} }
} else if(scrollDirection == FullRefreshDirections::Right or scrollDirection == FullRefreshDirections::RightAnim) { } else if (scrollDirection == FullRefreshDirections::Right or scrollDirection == FullRefreshDirections::RightAnim) {
if(area->x1 == 0) { if (area->x1 == 0) {
scrollDirection = FullRefreshDirections::None; scrollDirection = FullRefreshDirections::None;
lv_disp_set_direction(lv_disp_get_default(), 0); lv_disp_set_direction(lv_disp_get_default(), 0);
} }
@ -143,17 +144,17 @@ void LittleVgl::FlushDisplay(const lv_area_t *area, lv_color_t *color_p) {
if (y2 < y1) { if (y2 < y1) {
height = totalNbLines - y1; height = totalNbLines - y1;
if ( height > 0 ) { if (height > 0) {
lcd.DrawBuffer(area->x1, y1, width, height, reinterpret_cast<const uint8_t *>(color_p), width * height * 2); lcd.DrawBuffer(area->x1, y1, width, height, reinterpret_cast<const uint8_t*>(color_p), width * height * 2);
ulTaskNotifyTake(pdTRUE, 100); ulTaskNotifyTake(pdTRUE, 100);
} }
uint16_t pixOffset = width * height; uint16_t pixOffset = width * height;
height = y2 + 1; height = y2 + 1;
lcd.DrawBuffer(area->x1, 0, width, height, reinterpret_cast<const uint8_t *>(color_p + pixOffset), width * height * 2); lcd.DrawBuffer(area->x1, 0, width, height, reinterpret_cast<const uint8_t*>(color_p + pixOffset), width * height * 2);
} else { } else {
lcd.DrawBuffer(area->x1, y1, width, height, reinterpret_cast<const uint8_t *>(color_p), width * height * 2); lcd.DrawBuffer(area->x1, y1, width, height, reinterpret_cast<const uint8_t*>(color_p), width * height * 2);
} }
// IMPORTANT!!! // IMPORTANT!!!
@ -167,8 +168,8 @@ void LittleVgl::SetNewTapEvent(uint16_t x, uint16_t y) {
tapped = true; tapped = true;
} }
bool LittleVgl::GetTouchPadInfo(lv_indev_data_t *ptr) { bool LittleVgl::GetTouchPadInfo(lv_indev_data_t* ptr) {
if(tapped) { if (tapped) {
ptr->point.x = tap_x; ptr->point.x = tap_x;
ptr->point.y = tap_y; ptr->point.y = tap_y;
ptr->state = LV_INDEV_STATE_PR; ptr->state = LV_INDEV_STATE_PR;
@ -202,14 +203,8 @@ bool LittleVgl::GetTouchPadInfo(lv_indev_data_t *ptr) {
void LittleVgl::InitTheme() { void LittleVgl::InitTheme() {
lv_theme_t * th = lv_pinetime_theme_init( lv_theme_t* th = lv_pinetime_theme_init(
LV_COLOR_WHITE, LV_COLOR_SILVER, LV_COLOR_WHITE, LV_COLOR_SILVER, 0, &jetbrains_mono_bold_20, &jetbrains_mono_bold_20, &jetbrains_mono_bold_20, &jetbrains_mono_bold_20);
0,
&jetbrains_mono_bold_20,
&jetbrains_mono_bold_20,
&jetbrains_mono_bold_20,
&jetbrains_mono_bold_20);
lv_theme_set_act(th); lv_theme_set_act(th);
} }

View File

@ -19,8 +19,8 @@ namespace Pinetime {
LittleVgl(LittleVgl&&) = delete; LittleVgl(LittleVgl&&) = delete;
LittleVgl& operator=(LittleVgl&&) = delete; LittleVgl& operator=(LittleVgl&&) = delete;
void FlushDisplay(const lv_area_t * area, lv_color_t * color_p); void FlushDisplay(const lv_area_t* area, lv_color_t* color_p);
bool GetTouchPadInfo(lv_indev_data_t *ptr); bool GetTouchPadInfo(lv_indev_data_t* ptr);
void SetFullRefresh(FullRefreshDirections direction); void SetFullRefresh(FullRefreshDirections direction);
void SetNewTapEvent(uint16_t x, uint16_t y); void SetNewTapEvent(uint16_t x, uint16_t y);
@ -29,11 +29,9 @@ namespace Pinetime {
void InitTouchpad(); void InitTouchpad();
void InitTheme(); void InitTheme();
Pinetime::Drivers::St7789& lcd; Pinetime::Drivers::St7789& lcd;
Pinetime::Drivers::Cst816S& touchPanel; Pinetime::Drivers::Cst816S& touchPanel;
lv_disp_buf_t disp_buf_2; lv_disp_buf_t disp_buf_2;
lv_color_t buf2_1[LV_HOR_RES_MAX * 4]; lv_color_t buf2_1[LV_HOR_RES_MAX * 4];
lv_color_t buf2_2[LV_HOR_RES_MAX * 4]; lv_color_t buf2_2[LV_HOR_RES_MAX * 4];
@ -45,7 +43,9 @@ namespace Pinetime {
static constexpr uint8_t nbWriteLines = 4; static constexpr uint8_t nbWriteLines = 4;
static constexpr uint16_t totalNbLines = 320; static constexpr uint16_t totalNbLines = 320;
static constexpr uint16_t visibleNbLines = 240; static constexpr uint16_t visibleNbLines = 240;
static constexpr uint8_t MaxScrollOffset() { return LV_VER_RES_MAX - nbWriteLines; } static constexpr uint8_t MaxScrollOffset() {
return LV_VER_RES_MAX - nbWriteLines;
}
FullRefreshDirections scrollDirection = FullRefreshDirections::None; FullRefreshDirections scrollDirection = FullRefreshDirections::None;
uint16_t writeOffset = 0; uint16_t writeOffset = 0;
uint16_t scrollOffset = 0; uint16_t scrollOffset = 0;
@ -56,4 +56,3 @@ namespace Pinetime {
}; };
} }
} }

View File

@ -3,8 +3,16 @@ namespace Pinetime {
namespace Applications { namespace Applications {
namespace Display { namespace Display {
enum class Messages : uint8_t { enum class Messages : uint8_t {
GoToSleep, GoToRunning, UpdateDateTime, UpdateBleConnection, UpdateBatteryLevel, TouchEvent, ButtonPushed, GoToSleep,
NewNotification, BleFirmwareUpdateStarted, UpdateTimeOut GoToRunning,
UpdateDateTime,
UpdateBleConnection,
UpdateBatteryLevel,
TouchEvent,
ButtonPushed,
NewNotification,
BleFirmwareUpdateStarted,
UpdateTimeOut
}; };
} }
} }

View File

@ -3,6 +3,6 @@
namespace Pinetime { namespace Pinetime {
namespace Applications { namespace Applications {
enum class TouchEvents { None, Tap, SwipeLeft, SwipeRight, SwipeUp, SwipeDown, LongTap, DoubleTap}; enum class TouchEvents { None, Tap, SwipeLeft, SwipeRight, SwipeUp, SwipeDown, LongTap, DoubleTap };
} }
} }

View File

@ -0,0 +1,44 @@
# Fonts
* [Jetbrains Mono](https://www.jetbrains.com/fr-fr/lp/mono/)
* [Awesome font from LVGL](https://lvgl.io/assets/others/FontAwesome5-Solid+Brands+Regular.woff)
## Generate the fonts:
* Open the [LVGL font converter](https://lvgl.io/tools/fontconverter)
* Name : jetbrains_mono_bold_20
* Size : 20
* Bpp : 1 bit-per-pixel
* Do not enable font compression and horizontal subpixel hinting
* Load the file `JetBrainsMono-Bold.tff` and specify the following range : `0x20-0x7f, 0x410-0x44f`
* Add a 2nd font, load the file `FontAwesome5-Solid+Brands+Regular.woff` and specify the following
range : `0xf293, 0xf294, 0xf244, 0xf240, 0xf242, 0xf243, 0xf241, 0xf54b, 0xf21e, 0xf1e6, 0xf54b, 0xf017, 0xf129, 0xf03a, 0xf185, 0xf560, 0xf001, 0xf3fd, 0xf069, 0xf1fc, 0xf45d, 0xf59f, 0xf5a0, 0xf029, 0xf027, 0xf028, 0xf6a9, 0xf04b, 0xf04c, 0xf048, 0xf051, 0xf095, 0xf3dd, 0xf04d, 0xf2f2, 0xf024`
* Click on Convert, and download the file `jetbrains_mono_bold_20.c` and copy it in `src/DisplayApp/Fonts`
Add new symbols:
* Browse the [cheatsheet](https://fontawesome.com/cheatsheet/free/solid) and find your new symbols
* For each symbol, add its hex code (0xf641 for the 'Ad' icon, for example) to the *Range* list (Remember to keep this
readme updated with newest range list)
* Convert this hex value into a UTF-8 code
using [this site](http://www.ltg.ed.ac.uk/~richard/utf-8.cgi?input=f185&mode=hex)
* Define the new symbols in `src/DisplayApp/Screens/Symbols.h`:
```
static constex char* newSymbol = "\xEF\x86\x85";
```
#### Navigation font
To create the navigtion.ttf I use the web app [icomoon](https://icomoon.io/app)
this app can import the svg files from the folder *src/displayapp/icons/navigation/unique* and creat a ttf file the
project for the site is *lv_font_navi_80.json* you can import it to add or remove icons
You can also use the online LVGL tool to create the .c
ttf file : navigation.ttf name : lv_font_navi_80 size : 80px Bpp : 2 bit-per-pixel range : 0xe900-0xe929
$lv_font_conv --font navigation.ttf -r '0xe900-0xe929' --size 80 --format lvgl --bpp 2 --no-prefilter -o
lv_font_navi_80.c
#### I use the method above to create the other ttf

View File

@ -1,41 +0,0 @@
#Fonts
* [Jetbrains Mono](https://www.jetbrains.com/fr-fr/lp/mono/)
* [Awesome font from LVGL](https://lvgl.io/assets/others/FontAwesome5-Solid+Brands+Regular.woff)
## Generate the fonts:
* Open the [LVGL font converter](https://lvgl.io/tools/fontconverter)
* Name : jetbrains_mono_bold_20
* Size : 20
* Bpp : 1 bit-per-pixel
* Do not enable font compression and horizontal subpixel hinting
* Load the file `JetBrainsMono-Bold.tff` and specify the following range : `0x20-0x7f, 0x410-0x44f`
* Add a 2nd font, load the file `FontAwesome5-Solid+Brands+Regular.woff` and specify the following range : `0xf293, 0xf294, 0xf244, 0xf240, 0xf242, 0xf243, 0xf241, 0xf54b, 0xf21e, 0xf1e6, 0xf54b, 0xf017, 0xf129, 0xf03a, 0xf185, 0xf560, 0xf001, 0xf3fd, 0xf069, 0xf1fc, 0xf45d, 0xf59f, 0xf5a0, 0xf029, 0xf027, 0xf028, 0xf6a9, 0xf04b, 0xf04c, 0xf048, 0xf051, 0xf095, 0xf3dd, 0xf04d, 0xf2f2, 0xf024`
* Click on Convert, and download the file `jetbrains_mono_bold_20.c` and copy it in `src/DisplayApp/Fonts`
Add new symbols:
* Browse the [cheatsheet](https://fontawesome.com/cheatsheet/free/solid) and find your new symbols
* For each symbol, add its hex code (0xf641 for the 'Ad' icon, for example) to the *Range* list (Remember to keep this readme updated with newest range list)
* Convert this hex value into a UTF-8 code using [this site](http://www.ltg.ed.ac.uk/~richard/utf-8.cgi?input=f185&mode=hex)
* Define the new symbols in `src/DisplayApp/Screens/Symbols.h`:
```
static constex char* newSymbol = "\xEF\x86\x85";
```
#### Navigation font
To create the navigtion.ttf I use the web app [icomoon](https://icomoon.io/app)
this app can import the svg files from the folder *src/displayapp/icons/navigation/unique* and creat a ttf file
the project for the site is *lv_font_navi_80.json* you can import it to add or remove icons
You can also use the online LVGL tool to create the .c
ttf file : navigation.ttf
name : lv_font_navi_80
size : 80px
Bpp : 2 bit-per-pixel
range : 0xe900-0xe929
$lv_font_conv --font navigation.ttf -r '0xe900-0xe929' --size 80 --format lvgl --bpp 2 --no-prefilter -o lv_font_navi_80.c
#### I use the method above to create the other ttf

View File

@ -19,7 +19,7 @@
/********************** /**********************
* STATIC PROTOTYPES * STATIC PROTOTYPES
**********************/ **********************/
static void theme_apply(lv_obj_t * obj, lv_theme_style_t name); static void theme_apply(lv_obj_t* obj, lv_theme_style_t name);
/********************** /**********************
* STATIC VARIABLES * STATIC VARIABLES
@ -67,15 +67,14 @@ static bool inited;
* STATIC FUNCTIONS * STATIC FUNCTIONS
**********************/ **********************/
static void style_init_reset(lv_style_t * style) static void style_init_reset(lv_style_t* style) {
{ if (inited)
if(inited) lv_style_reset(style); lv_style_reset(style);
else lv_style_init(style); else
lv_style_init(style);
} }
static void basic_init(void) {
static void basic_init(void)
{
style_init_reset(&style_pad); style_init_reset(&style_pad);
lv_style_set_pad_top(&style_pad, LV_STATE_DEFAULT, LV_VER_RES / 30); lv_style_set_pad_top(&style_pad, LV_STATE_DEFAULT, LV_VER_RES / 30);
@ -103,7 +102,6 @@ static void basic_init(void)
lv_style_set_border_color(&style_box_border, LV_STATE_DEFAULT, LV_PINETIME_GRAY); lv_style_set_border_color(&style_box_border, LV_STATE_DEFAULT, LV_PINETIME_GRAY);
lv_style_set_text_color(&style_box, LV_STATE_DEFAULT, LV_PINETIME_BLUE); lv_style_set_text_color(&style_box, LV_STATE_DEFAULT, LV_PINETIME_BLUE);
style_init_reset(&style_title); style_init_reset(&style_title);
lv_style_set_text_color(&style_title, LV_STATE_DEFAULT, LV_PINETIME_WHITE); lv_style_set_text_color(&style_title, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
lv_style_set_text_font(&style_title, LV_STATE_DEFAULT, theme.font_subtitle); lv_style_set_text_font(&style_title, LV_STATE_DEFAULT, theme.font_subtitle);
@ -212,10 +210,10 @@ static void basic_init(void)
lv_style_set_bg_opa(&style_sw_knob, LV_STATE_DEFAULT, LV_OPA_COVER); lv_style_set_bg_opa(&style_sw_knob, LV_STATE_DEFAULT, LV_OPA_COVER);
lv_style_set_bg_color(&style_sw_knob, LV_STATE_DEFAULT, LV_PINETIME_WHITE); lv_style_set_bg_color(&style_sw_knob, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
lv_style_set_radius(&style_sw_knob, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); lv_style_set_radius(&style_sw_knob, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
lv_style_set_pad_top(&style_sw_knob, LV_STATE_DEFAULT, - 4); lv_style_set_pad_top(&style_sw_knob, LV_STATE_DEFAULT, -4);
lv_style_set_pad_bottom(&style_sw_knob, LV_STATE_DEFAULT, - 4); lv_style_set_pad_bottom(&style_sw_knob, LV_STATE_DEFAULT, -4);
lv_style_set_pad_left(&style_sw_knob, LV_STATE_DEFAULT, - 4); lv_style_set_pad_left(&style_sw_knob, LV_STATE_DEFAULT, -4);
lv_style_set_pad_right(&style_sw_knob, LV_STATE_DEFAULT, - 4); lv_style_set_pad_right(&style_sw_knob, LV_STATE_DEFAULT, -4);
style_init_reset(&style_slider_knob); style_init_reset(&style_slider_knob);
lv_style_set_bg_opa(&style_slider_knob, LV_STATE_DEFAULT, LV_OPA_COVER); lv_style_set_bg_opa(&style_slider_knob, LV_STATE_DEFAULT, LV_OPA_COVER);
@ -301,10 +299,8 @@ static void basic_init(void)
lv_style_set_pad_right(&style_cb_bullet, LV_STATE_DEFAULT, LV_DPX(8)); lv_style_set_pad_right(&style_cb_bullet, LV_STATE_DEFAULT, LV_DPX(8));
lv_style_set_pad_top(&style_cb_bullet, LV_STATE_DEFAULT, LV_DPX(8)); lv_style_set_pad_top(&style_cb_bullet, LV_STATE_DEFAULT, LV_DPX(8));
lv_style_set_pad_bottom(&style_cb_bullet, LV_STATE_DEFAULT, LV_DPX(8)); lv_style_set_pad_bottom(&style_cb_bullet, LV_STATE_DEFAULT, LV_DPX(8));
} }
/********************** /**********************
* GLOBAL FUNCTIONS * GLOBAL FUNCTIONS
**********************/ **********************/
@ -320,10 +316,13 @@ static void basic_init(void)
* @param font_title pointer to a extra large font * @param font_title pointer to a extra large font
* @return a pointer to reference this theme later * @return a pointer to reference this theme later
*/ */
lv_theme_t * lv_pinetime_theme_init(lv_color_t color_primary, lv_color_t color_secondary, uint32_t flags, lv_theme_t* lv_pinetime_theme_init(lv_color_t color_primary,
const lv_font_t * font_small, const lv_font_t * font_normal, const lv_font_t * font_subtitle, lv_color_t color_secondary,
const lv_font_t * font_title) uint32_t flags,
{ const lv_font_t* font_small,
const lv_font_t* font_normal,
const lv_font_t* font_subtitle,
const lv_font_t* font_title) {
theme.color_primary = color_primary; theme.color_primary = color_primary;
theme.color_secondary = color_secondary; theme.color_secondary = color_secondary;
theme.font_small = font_small; theme.font_small = font_small;
@ -341,14 +340,12 @@ lv_theme_t * lv_pinetime_theme_init(lv_color_t color_primary, lv_color_t color_s
return &theme; return &theme;
} }
static void theme_apply(lv_obj_t* obj, lv_theme_style_t name) {
static void theme_apply(lv_obj_t * obj, lv_theme_style_t name) lv_style_list_t* list;
{
lv_style_list_t * list;
/*To avoid warnings*/ /*To avoid warnings*/
uint32_t name_int = (uint32_t) name; uint32_t name_int = (uint32_t) name;
switch(name_int) { switch (name_int) {
case LV_THEME_NONE: case LV_THEME_NONE:
break; break;
@ -442,7 +439,6 @@ static void theme_apply(lv_obj_t * obj, lv_theme_style_t name)
_lv_style_list_add_style(list, &style_list_btn); _lv_style_list_add_style(list, &style_list_btn);
break; break;
case LV_THEME_ARC: case LV_THEME_ARC:
lv_obj_clean_style_list(obj, LV_ARC_PART_BG); lv_obj_clean_style_list(obj, LV_ARC_PART_BG);
list = lv_obj_get_style_list(obj, LV_ARC_PART_BG); list = lv_obj_get_style_list(obj, LV_ARC_PART_BG);
@ -453,7 +449,6 @@ static void theme_apply(lv_obj_t * obj, lv_theme_style_t name)
_lv_style_list_add_style(list, &style_arc_indic); _lv_style_list_add_style(list, &style_arc_indic);
break; break;
case LV_THEME_SWITCH: case LV_THEME_SWITCH:
lv_obj_clean_style_list(obj, LV_SWITCH_PART_BG); lv_obj_clean_style_list(obj, LV_SWITCH_PART_BG);
list = lv_obj_get_style_list(obj, LV_SWITCH_PART_BG); list = lv_obj_get_style_list(obj, LV_SWITCH_PART_BG);
@ -497,7 +492,7 @@ static void theme_apply(lv_obj_t * obj, lv_theme_style_t name)
start at 1 due to presence of LV_TABLE_PART_BG=0 start at 1 due to presence of LV_TABLE_PART_BG=0
in the enum (lv_table.h) */ in the enum (lv_table.h) */
/* declaring idx outside loop to work with older compilers */ /* declaring idx outside loop to work with older compilers */
for(; idx <= LV_TABLE_CELL_STYLE_CNT; idx ++) { for (; idx <= LV_TABLE_CELL_STYLE_CNT; idx++) {
list = lv_obj_get_style_list(obj, idx); list = lv_obj_get_style_list(obj, idx);
_lv_style_list_add_style(list, &style_table_cell); _lv_style_list_add_style(list, &style_table_cell);
_lv_style_list_add_style(list, &style_label_white); _lv_style_list_add_style(list, &style_label_white);
@ -526,15 +521,11 @@ static void theme_apply(lv_obj_t * obj, lv_theme_style_t name)
_lv_style_list_add_style(list, &style_cb_bullet); _lv_style_list_add_style(list, &style_cb_bullet);
break; break;
default: default:
break; break;
} }
lv_obj_refresh_style(obj, LV_OBJ_PART_ALL, LV_STYLE_PROP_ALL); lv_obj_refresh_style(obj, LV_OBJ_PART_ALL, LV_STYLE_PROP_ALL);
} }
/********************** /**********************

View File

@ -23,7 +23,7 @@ extern "C" {
#define LV_PINETIME_LIGHT lv_color_hex(0xf3f8fe) #define LV_PINETIME_LIGHT lv_color_hex(0xf3f8fe)
#define LV_PINETIME_GRAY lv_color_hex(0x8a8a8a) #define LV_PINETIME_GRAY lv_color_hex(0x8a8a8a)
#define LV_PINETIME_LIGHT_GRAY lv_color_hex(0xc4c4c4) #define LV_PINETIME_LIGHT_GRAY lv_color_hex(0xc4c4c4)
#define LV_PINETIME_BLUE lv_color_hex(0x2f3243) //006fb6 #define LV_PINETIME_BLUE lv_color_hex(0x2f3243) // 006fb6
#define LV_PINETIME_GREEN lv_color_hex(0x4cb242) #define LV_PINETIME_GREEN lv_color_hex(0x4cb242)
#define LV_PINETIME_RED lv_color_hex(0xd51732) #define LV_PINETIME_RED lv_color_hex(0xd51732)
@ -31,12 +31,10 @@ extern "C" {
* TYPEDEFS * TYPEDEFS
**********************/ **********************/
/********************** /**********************
* GLOBAL PROTOTYPES * GLOBAL PROTOTYPES
**********************/ **********************/
/** /**
* Initialize the default * Initialize the default
* @param color_primary the primary color of the theme * @param color_primary the primary color of the theme
@ -48,9 +46,13 @@ extern "C" {
* @param font_title pointer to a extra large font * @param font_title pointer to a extra large font
* @return a pointer to reference this theme later * @return a pointer to reference this theme later
*/ */
lv_theme_t * lv_pinetime_theme_init(lv_color_t color_primary, lv_color_t color_secondary, uint32_t flags, lv_theme_t* lv_pinetime_theme_init(lv_color_t color_primary,
const lv_font_t * font_small, const lv_font_t * font_normal, const lv_font_t * font_subtitle, lv_color_t color_secondary,
const lv_font_t * font_title); uint32_t flags,
const lv_font_t* font_small,
const lv_font_t* font_normal,
const lv_font_t* font_subtitle,
const lv_font_t* font_title);
/********************** /**********************
* MACROS * MACROS
**********************/ **********************/

View File

@ -8,31 +8,34 @@
using namespace Pinetime::Applications::Screens; using namespace Pinetime::Applications::Screens;
ApplicationList::ApplicationList(Pinetime::Applications::DisplayApp *app, ApplicationList::ApplicationList(Pinetime::Applications::DisplayApp* app,
Pinetime::Controllers::Settings &settingsController, Pinetime::Controllers::Settings& settingsController,
Pinetime::Controllers::Battery& batteryController, Pinetime::Controllers::Battery& batteryController,
Controllers::DateTime& dateTimeController) : Controllers::DateTime& dateTimeController)
Screen(app), : Screen(app),
settingsController{settingsController}, settingsController {settingsController},
batteryController{batteryController}, batteryController {batteryController},
dateTimeController{dateTimeController}, dateTimeController {dateTimeController},
screens{app, screens {app,
settingsController.GetAppMenu(), settingsController.GetAppMenu(),
{ {
[this]() -> std::unique_ptr<Screen> { return CreateScreen1(); }, [this]() -> std::unique_ptr<Screen> {
[this]() -> std::unique_ptr<Screen> { return CreateScreen2(); }, return CreateScreen1();
},
[this]() -> std::unique_ptr<Screen> {
return CreateScreen2();
},
//[this]() -> std::unique_ptr<Screen> { return CreateScreen3(); } //[this]() -> std::unique_ptr<Screen> { return CreateScreen3(); }
}, },
Screens::ScreenListModes::UpDown Screens::ScreenListModes::UpDown} {
} {} }
ApplicationList::~ApplicationList() { ApplicationList::~ApplicationList() {
lv_obj_clean(lv_scr_act()); lv_obj_clean(lv_scr_act());
} }
bool ApplicationList::Refresh() { bool ApplicationList::Refresh() {
if(running) if (running)
running = screens.Refresh(); running = screens.Refresh();
return running; return running;
} }
@ -42,31 +45,27 @@ bool ApplicationList::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
} }
std::unique_ptr<Screen> ApplicationList::CreateScreen1() { std::unique_ptr<Screen> ApplicationList::CreateScreen1() {
std::array<Screens::Tile::Applications, 6> applications { std::array<Screens::Tile::Applications, 6> applications {{
{
{Symbols::stopWatch, Apps::StopWatch}, {Symbols::stopWatch, Apps::StopWatch},
{Symbols::music, Apps::Music}, {Symbols::music, Apps::Music},
{Symbols::map, Apps::Navigation}, {Symbols::map, Apps::Navigation},
{Symbols::shoe, Apps::Motion}, {Symbols::shoe, Apps::Motion},
{Symbols::heartBeat, Apps::HeartRate}, {Symbols::heartBeat, Apps::HeartRate},
{"", Apps::None}, {"", Apps::None},
} }};
};
return std::make_unique<Screens::Tile>(0, 2, app, settingsController, batteryController, dateTimeController, applications); return std::make_unique<Screens::Tile>(0, 2, app, settingsController, batteryController, dateTimeController, applications);
} }
std::unique_ptr<Screen> ApplicationList::CreateScreen2() { std::unique_ptr<Screen> ApplicationList::CreateScreen2() {
std::array<Screens::Tile::Applications, 6> applications { std::array<Screens::Tile::Applications, 6> applications {{
{
{Symbols::paintbrush, Apps::Paint}, {Symbols::paintbrush, Apps::Paint},
{Symbols::paddle, Apps::Paddle}, {Symbols::paddle, Apps::Paddle},
{"2", Apps::Twos}, {"2", Apps::Twos},
{"", Apps::None}, {"", Apps::None},
{"", Apps::None}, {"", Apps::None},
{"", Apps::None}, {"", Apps::None},
} }};
};
return std::make_unique<Screens::Tile>(1, 2, app, settingsController, batteryController, dateTimeController, applications); return std::make_unique<Screens::Tile>(1, 2, app, settingsController, batteryController, dateTimeController, applications);
} }
@ -84,4 +83,3 @@ std::unique_ptr<Screen> ApplicationList::CreateScreen2() {
return std::make_unique<Screens::Tile>(2, 3, app, settingsController, batteryController, dateTimeController, applications); return std::make_unique<Screens::Tile>(2, 3, app, settingsController, batteryController, dateTimeController, applications);
}*/ }*/

View File

@ -14,14 +14,14 @@ namespace Pinetime {
class ApplicationList : public Screen { class ApplicationList : public Screen {
public: public:
explicit ApplicationList(DisplayApp* app, explicit ApplicationList(DisplayApp* app,
Pinetime::Controllers::Settings &settingsController, Pinetime::Controllers::Settings& settingsController,
Pinetime::Controllers::Battery& batteryController, Pinetime::Controllers::Battery& batteryController,
Controllers::DateTime& dateTimeController); Controllers::DateTime& dateTimeController);
~ApplicationList() override; ~ApplicationList() override;
bool Refresh() override; bool Refresh() override;
bool OnTouchEvent(TouchEvents event) override; bool OnTouchEvent(TouchEvents event) override;
private:
private:
Controllers::Settings& settingsController; Controllers::Settings& settingsController;
Pinetime::Controllers::Battery& batteryController; Pinetime::Controllers::Battery& batteryController;
Controllers::DateTime& dateTimeController; Controllers::DateTime& dateTimeController;
@ -29,7 +29,7 @@ namespace Pinetime {
ScreenList<2> screens; ScreenList<2> screens;
std::unique_ptr<Screen> CreateScreen1(); std::unique_ptr<Screen> CreateScreen1();
std::unique_ptr<Screen> CreateScreen2(); std::unique_ptr<Screen> CreateScreen2();
//std::unique_ptr<Screen> CreateScreen3(); // std::unique_ptr<Screen> CreateScreen3();
}; };
} }
} }

View File

@ -4,10 +4,14 @@
using namespace Pinetime::Applications::Screens; using namespace Pinetime::Applications::Screens;
const char* BatteryIcon::GetBatteryIcon(int batteryPercent) { const char* BatteryIcon::GetBatteryIcon(int batteryPercent) {
if(batteryPercent > 90) return Symbols::batteryFull; if (batteryPercent > 90)
if(batteryPercent > 75) return Symbols::batteryThreeQuarter; return Symbols::batteryFull;
if(batteryPercent > 50) return Symbols::batteryHalf; if (batteryPercent > 75)
if(batteryPercent > 25) return Symbols::batteryOneQuarter; return Symbols::batteryThreeQuarter;
if (batteryPercent > 50)
return Symbols::batteryHalf;
if (batteryPercent > 25)
return Symbols::batteryOneQuarter;
return Symbols::batteryEmpty; return Symbols::batteryEmpty;
} }
@ -15,8 +19,9 @@ const char* BatteryIcon::GetUnknownIcon() {
return Symbols::batteryEmpty; return Symbols::batteryEmpty;
} }
const char *BatteryIcon::GetPlugIcon(bool isCharging) { const char* BatteryIcon::GetPlugIcon(bool isCharging) {
if(isCharging) if (isCharging)
return Symbols::plug; return Symbols::plug;
else return ""; else
return "";
} }

View File

@ -4,22 +4,18 @@
using namespace Pinetime::Applications::Screens; using namespace Pinetime::Applications::Screens;
static void lv_update_task(struct _lv_task_t *task) { static void lv_update_task(struct _lv_task_t* task) {
auto user_data = static_cast<BatteryInfo *>(task->user_data); auto user_data = static_cast<BatteryInfo*>(task->user_data);
user_data->UpdateScreen(); user_data->UpdateScreen();
} }
static void lv_anim_task(struct _lv_task_t *task) { static void lv_anim_task(struct _lv_task_t* task) {
auto user_data = static_cast<BatteryInfo *>(task->user_data); auto user_data = static_cast<BatteryInfo*>(task->user_data);
user_data->UpdateAnim(); user_data->UpdateAnim();
} }
BatteryInfo::BatteryInfo( BatteryInfo::BatteryInfo(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Battery& batteryController)
Pinetime::Applications::DisplayApp *app, : Screen(app), batteryController {batteryController} {
Pinetime::Controllers::Battery& batteryController) :
Screen(app),
batteryController{batteryController}
{
batteryPercent = batteryController.PercentRemaining(); batteryPercent = batteryController.PercentRemaining();
batteryVoltage = batteryController.Voltage(); batteryVoltage = batteryController.Voltage();
@ -32,37 +28,38 @@ BatteryInfo::BatteryInfo(
lv_obj_set_style_local_radius(charging_bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); lv_obj_set_style_local_radius(charging_bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, lv_color_hex(0x222222)); lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, lv_color_hex(0x222222));
lv_obj_set_style_local_bg_opa(charging_bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, LV_OPA_100); lv_obj_set_style_local_bg_opa(charging_bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, LV_OPA_100);
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC , LV_STATE_DEFAULT, lv_color_hex(0xFF0000)); lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, lv_color_hex(0xFF0000));
lv_bar_set_value(charging_bar, batteryPercent, LV_ANIM_OFF); lv_bar_set_value(charging_bar, batteryPercent, LV_ANIM_OFF);
status = lv_label_create(lv_scr_act(), nullptr); status = lv_label_create(lv_scr_act(), nullptr);
lv_label_set_text_static(status,"Reading Battery status"); lv_label_set_text_static(status, "Reading Battery status");
lv_label_set_align(status, LV_LABEL_ALIGN_CENTER); lv_label_set_align(status, LV_LABEL_ALIGN_CENTER);
lv_obj_align(status, charging_bar, LV_ALIGN_OUT_BOTTOM_MID, 0, 20); lv_obj_align(status, charging_bar, LV_ALIGN_OUT_BOTTOM_MID, 0, 20);
percent = lv_label_create(lv_scr_act(), nullptr); percent = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_font(percent, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76); lv_obj_set_style_local_text_font(percent, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76);
if ( batteryPercent >= 0) { if (batteryPercent >= 0) {
lv_label_set_text_fmt(percent,"%02i%%", batteryPercent); lv_label_set_text_fmt(percent, "%02i%%", batteryPercent);
} else { } else {
lv_label_set_text(percent,"--%"); lv_label_set_text(percent, "--%");
} }
lv_label_set_align(percent, LV_LABEL_ALIGN_LEFT); lv_label_set_align(percent, LV_LABEL_ALIGN_LEFT);
lv_obj_align(percent, nullptr, LV_ALIGN_CENTER, 0, -60); lv_obj_align(percent, nullptr, LV_ALIGN_CENTER, 0, -60);
// hack to not use the flot functions from printf // hack to not use the flot functions from printf
uint8_t batteryVoltageBytes[2]; uint8_t batteryVoltageBytes[2];
batteryVoltageBytes[1] = static_cast<uint8_t>(batteryVoltage); //truncate whole numbers batteryVoltageBytes[1] = static_cast<uint8_t>(batteryVoltage); // truncate whole numbers
batteryVoltageBytes[0] = static_cast<uint8_t>((batteryVoltage - batteryVoltageBytes[1]) * 100); //remove whole part of flt and shift 2 places over batteryVoltageBytes[0] =
static_cast<uint8_t>((batteryVoltage - batteryVoltageBytes[1]) * 100); // remove whole part of flt and shift 2 places over
// //
voltage = lv_label_create(lv_scr_act(), nullptr); voltage = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(voltage, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xC6A600)); lv_obj_set_style_local_text_color(voltage, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xC6A600));
lv_label_set_text_fmt(voltage,"%1i.%02i volts", batteryVoltageBytes[1], batteryVoltageBytes[0]); lv_label_set_text_fmt(voltage, "%1i.%02i volts", batteryVoltageBytes[1], batteryVoltageBytes[0]);
lv_label_set_align(voltage, LV_LABEL_ALIGN_CENTER); lv_label_set_align(voltage, LV_LABEL_ALIGN_CENTER);
lv_obj_align(voltage, nullptr, LV_ALIGN_CENTER, 0, 95); lv_obj_align(voltage, nullptr, LV_ALIGN_CENTER, 0, 95);
lv_obj_t * backgroundLabel = lv_label_create(lv_scr_act(), nullptr); lv_obj_t* backgroundLabel = lv_label_create(lv_scr_act(), nullptr);
lv_label_set_long_mode(backgroundLabel, LV_LABEL_LONG_CROP); lv_label_set_long_mode(backgroundLabel, LV_LABEL_LONG_CROP);
lv_obj_set_size(backgroundLabel, 240, 240); lv_obj_set_size(backgroundLabel, 240, 240);
lv_obj_set_pos(backgroundLabel, 0, 0); lv_obj_set_pos(backgroundLabel, 0, 0);
@ -73,7 +70,6 @@ BatteryInfo::BatteryInfo(
UpdateScreen(); UpdateScreen();
} }
BatteryInfo::~BatteryInfo() { BatteryInfo::~BatteryInfo() {
lv_task_del(taskUpdate); lv_task_del(taskUpdate);
lv_task_del(taskAnim); lv_task_del(taskAnim);
@ -83,9 +79,9 @@ BatteryInfo::~BatteryInfo() {
void BatteryInfo::UpdateAnim() { void BatteryInfo::UpdateAnim() {
batteryPercent = batteryController.PercentRemaining(); batteryPercent = batteryController.PercentRemaining();
if ( batteryPercent >= 0 ) { if (batteryPercent >= 0) {
if ( batteryController.IsCharging() and batteryPercent < 100 ) { if (batteryController.IsCharging() and batteryPercent < 100) {
animation +=1; animation += 1;
if (animation >= 100) { if (animation >= 100) {
animation = 0; animation = 0;
} }
@ -110,40 +106,39 @@ void BatteryInfo::UpdateScreen() {
batteryPercent = batteryController.PercentRemaining(); batteryPercent = batteryController.PercentRemaining();
batteryVoltage = batteryController.Voltage(); batteryVoltage = batteryController.Voltage();
if ( batteryPercent >= 0 ) { if (batteryPercent >= 0) {
if ( batteryController.IsCharging() and batteryPercent < 100 ) { if (batteryController.IsCharging() and batteryPercent < 100) {
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC , LV_STATE_DEFAULT, LV_COLOR_RED); 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,"Battery charging"); lv_label_set_text_static(status, "Battery charging");
} else if ( batteryPercent == 100 ) { } else if (batteryPercent == 100) {
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC , LV_STATE_DEFAULT, LV_COLOR_BLUE); lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_BLUE);
lv_label_set_text_static(status,"Battery is fully charged"); lv_label_set_text_static(status, "Battery is fully charged");
} else if ( batteryPercent < 10 ) { } else if (batteryPercent < 10) {
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC , LV_STATE_DEFAULT, LV_COLOR_YELLOW); lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_YELLOW);
lv_label_set_text_static(status,"Battery is low"); lv_label_set_text_static(status, "Battery is low");
} else { } else {
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC , LV_STATE_DEFAULT, LV_COLOR_GREEN); lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_GREEN);
lv_label_set_text_static(status,"Battery discharging"); lv_label_set_text_static(status, "Battery discharging");
} }
lv_label_set_text_fmt(percent,"%02i%%", batteryPercent); lv_label_set_text_fmt(percent, "%02i%%", batteryPercent);
} else { } else {
lv_label_set_text_static(status,"Reading Battery status"); lv_label_set_text_static(status, "Reading Battery status");
lv_label_set_text(percent,"--%"); lv_label_set_text(percent, "--%");
} }
lv_obj_align(status, charging_bar, LV_ALIGN_OUT_BOTTOM_MID, 0, 20); lv_obj_align(status, charging_bar, LV_ALIGN_OUT_BOTTOM_MID, 0, 20);
// hack to not use the flot functions from printf // hack to not use the flot functions from printf
uint8_t batteryVoltageBytes[2]; uint8_t batteryVoltageBytes[2];
batteryVoltageBytes[1] = static_cast<uint8_t>(batteryVoltage); //truncate whole numbers batteryVoltageBytes[1] = static_cast<uint8_t>(batteryVoltage); // truncate whole numbers
batteryVoltageBytes[0] = static_cast<uint8_t>((batteryVoltage - batteryVoltageBytes[1]) * 100); //remove whole part of flt and shift 2 places over batteryVoltageBytes[0] =
static_cast<uint8_t>((batteryVoltage - batteryVoltageBytes[1]) * 100); // remove whole part of flt and shift 2 places over
// //
lv_label_set_text_fmt(voltage,"%1i.%02i volts", batteryVoltageBytes[1], batteryVoltageBytes[0]); lv_label_set_text_fmt(voltage, "%1i.%02i volts", batteryVoltageBytes[1], batteryVoltageBytes[0]);
} }
bool BatteryInfo::Refresh() { bool BatteryInfo::Refresh() {
return running; return running;
} }

View File

@ -6,7 +6,6 @@
#include "Screen.h" #include "Screen.h"
#include <lvgl/lvgl.h> #include <lvgl/lvgl.h>
namespace Pinetime { namespace Pinetime {
namespace Controllers { namespace Controllers {
class Battery; class Battery;
@ -15,20 +14,17 @@ namespace Pinetime {
namespace Applications { namespace Applications {
namespace Screens { namespace Screens {
class BatteryInfo : public Screen{ class BatteryInfo : public Screen {
public: public:
BatteryInfo(DisplayApp* app, BatteryInfo(DisplayApp* app, Pinetime::Controllers::Battery& batteryController);
Pinetime::Controllers::Battery& batteryController);
~BatteryInfo() override; ~BatteryInfo() override;
bool Refresh() override; bool Refresh() override;
void UpdateScreen(); void UpdateScreen();
void UpdateAnim(); void UpdateAnim();
private: private:
Pinetime::Controllers::Battery& batteryController; Pinetime::Controllers::Battery& batteryController;
lv_obj_t* voltage; lv_obj_t* voltage;
@ -42,7 +38,6 @@ namespace Pinetime {
int8_t animation = 0; int8_t animation = 0;
int8_t batteryPercent = -1; int8_t batteryPercent = -1;
float batteryVoltage = 0.0f; float batteryVoltage = 0.0f;
}; };
} }
} }

View File

@ -3,6 +3,8 @@
using namespace Pinetime::Applications::Screens; using namespace Pinetime::Applications::Screens;
const char* BleIcon::GetIcon(bool isConnected) { const char* BleIcon::GetIcon(bool isConnected) {
if(isConnected) return Symbols::bluetooth; if (isConnected)
else return ""; return Symbols::bluetooth;
else
return "";
} }

View File

@ -3,14 +3,15 @@
using namespace Pinetime::Applications::Screens; using namespace Pinetime::Applications::Screens;
void slider_event_cb(lv_obj_t * slider, lv_event_t event) { void slider_event_cb(lv_obj_t* slider, lv_event_t event) {
if(event == LV_EVENT_VALUE_CHANGED) { if (event == LV_EVENT_VALUE_CHANGED) {
auto* brightnessSlider = static_cast<Brightness*>(slider->user_data); auto* brightnessSlider = static_cast<Brightness*>(slider->user_data);
brightnessSlider->OnValueChanged(); brightnessSlider->OnValueChanged();
} }
} }
Brightness::Brightness(Pinetime::Applications::DisplayApp *app, Controllers::BrightnessController& brightness) : Screen(app), brightness{brightness} { Brightness::Brightness(Pinetime::Applications::DisplayApp* app, Controllers::BrightnessController& brightness)
: Screen(app), brightness {brightness} {
slider = lv_slider_create(lv_scr_act(), nullptr); slider = lv_slider_create(lv_scr_act(), nullptr);
lv_obj_set_user_data(slider, this); lv_obj_set_user_data(slider, this);
lv_obj_set_width(slider, LV_DPI * 2); lv_obj_set_width(slider, LV_DPI * 2);
@ -33,13 +34,18 @@ bool Brightness::Refresh() {
return running; return running;
} }
const char *Brightness::LevelToString(Pinetime::Controllers::BrightnessController::Levels level) { const char* Brightness::LevelToString(Pinetime::Controllers::BrightnessController::Levels level) {
switch(level) { switch (level) {
case Pinetime::Controllers::BrightnessController::Levels::Off: return "Off"; case Pinetime::Controllers::BrightnessController::Levels::Off:
case Pinetime::Controllers::BrightnessController::Levels::Low: return "Low"; return "Off";
case Pinetime::Controllers::BrightnessController::Levels::Medium: return "Medium"; case Pinetime::Controllers::BrightnessController::Levels::Low:
case Pinetime::Controllers::BrightnessController::Levels::High: return "High"; return "Low";
default : return "???"; case Pinetime::Controllers::BrightnessController::Levels::Medium:
return "Medium";
case Pinetime::Controllers::BrightnessController::Levels::High:
return "High";
default:
return "???";
} }
} }
@ -48,29 +54,40 @@ void Brightness::OnValueChanged() {
} }
void Brightness::SetValue(uint8_t value) { void Brightness::SetValue(uint8_t value) {
switch(value) { switch (value) {
case 0: brightness.Set(Controllers::BrightnessController::Levels::Low); break; case 0:
case 1: brightness.Set(Controllers::BrightnessController::Levels::Medium); break; brightness.Set(Controllers::BrightnessController::Levels::Low);
case 2: brightness.Set(Controllers::BrightnessController::Levels::High); break; break;
case 1:
brightness.Set(Controllers::BrightnessController::Levels::Medium);
break;
case 2:
brightness.Set(Controllers::BrightnessController::Levels::High);
break;
} }
lv_label_set_text(slider_label, LevelToString(brightness.Level())); lv_label_set_text(slider_label, LevelToString(brightness.Level()));
} }
uint8_t Brightness::LevelToInt(Pinetime::Controllers::BrightnessController::Levels level) { uint8_t Brightness::LevelToInt(Pinetime::Controllers::BrightnessController::Levels level) {
switch(level) { switch (level) {
case Pinetime::Controllers::BrightnessController::Levels::Off: return 0; case Pinetime::Controllers::BrightnessController::Levels::Off:
case Pinetime::Controllers::BrightnessController::Levels::Low: return 0; return 0;
case Pinetime::Controllers::BrightnessController::Levels::Medium: return 1; case Pinetime::Controllers::BrightnessController::Levels::Low:
case Pinetime::Controllers::BrightnessController::Levels::High: return 2; return 0;
default : return 0; case Pinetime::Controllers::BrightnessController::Levels::Medium:
return 1;
case Pinetime::Controllers::BrightnessController::Levels::High:
return 2;
default:
return 0;
} }
} }
bool Brightness::OnTouchEvent(Pinetime::Applications::TouchEvents event) { bool Brightness::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
switch(event) { switch (event) {
case TouchEvents::SwipeLeft: case TouchEvents::SwipeLeft:
brightness.Lower(); brightness.Lower();
if ( brightness.Level() == Pinetime::Controllers::BrightnessController::Levels::Off) { if (brightness.Level() == Pinetime::Controllers::BrightnessController::Levels::Off) {
brightness.Set(Controllers::BrightnessController::Levels::Low); brightness.Set(Controllers::BrightnessController::Levels::Low);
} }
SetValue(); SetValue();

View File

@ -17,12 +17,12 @@ namespace Pinetime {
bool OnTouchEvent(TouchEvents event) override; bool OnTouchEvent(TouchEvents event) override;
void OnValueChanged(); void OnValueChanged();
private:
private:
Controllers::BrightnessController& brightness; Controllers::BrightnessController& brightness;
lv_obj_t * slider_label; lv_obj_t* slider_label;
lv_obj_t * slider; lv_obj_t* slider;
const char* LevelToString(Controllers::BrightnessController::Levels level); const char* LevelToString(Controllers::BrightnessController::Levels level);
uint8_t LevelToInt(Controllers::BrightnessController::Levels level); uint8_t LevelToInt(Controllers::BrightnessController::Levels level);

View File

@ -15,7 +15,6 @@
#include "WatchFaceDigital.h" #include "WatchFaceDigital.h"
#include "WatchFaceAnalog.h" #include "WatchFaceAnalog.h"
using namespace Pinetime::Applications::Screens; using namespace Pinetime::Applications::Screens;
Clock::Clock(DisplayApp* app, Clock::Clock(DisplayApp* app,
@ -23,35 +22,39 @@ Clock::Clock(DisplayApp* app,
Controllers::Battery& batteryController, Controllers::Battery& batteryController,
Controllers::Ble& bleController, Controllers::Ble& bleController,
Controllers::NotificationManager& notificatioManager, Controllers::NotificationManager& notificatioManager,
Controllers::Settings &settingsController, Controllers::Settings& settingsController,
Controllers::HeartRateController& heartRateController, Controllers::HeartRateController& heartRateController,
Controllers::MotionController& motionController) : Screen(app), Controllers::MotionController& motionController)
dateTimeController{dateTimeController}, batteryController{batteryController}, : Screen(app),
bleController{bleController}, notificatioManager{notificatioManager}, dateTimeController {dateTimeController},
settingsController{settingsController}, batteryController {batteryController},
heartRateController{heartRateController}, bleController {bleController},
motionController{motionController}, notificatioManager {notificatioManager},
screens{app, settingsController {settingsController},
heartRateController {heartRateController},
motionController {motionController},
screens {app,
settingsController.GetClockFace(), settingsController.GetClockFace(),
{ {
[this]() -> std::unique_ptr<Screen> { return WatchFaceDigitalScreen(); }, [this]() -> std::unique_ptr<Screen> {
[this]() -> std::unique_ptr<Screen> { return WatchFaceAnalogScreen(); }, return WatchFaceDigitalScreen();
},
[this]() -> std::unique_ptr<Screen> {
return WatchFaceAnalogScreen();
},
// Examples for more watch faces // Examples for more watch faces
//[this]() -> std::unique_ptr<Screen> { return WatchFaceMinimalScreen(); }, //[this]() -> std::unique_ptr<Screen> { return WatchFaceMinimalScreen(); },
//[this]() -> std::unique_ptr<Screen> { return WatchFaceCustomScreen(); } //[this]() -> std::unique_ptr<Screen> { return WatchFaceCustomScreen(); }
}, },
Screens::ScreenListModes::LongPress Screens::ScreenListModes::LongPress} {
} {
settingsController.SetAppMenu(0); settingsController.SetAppMenu(0);
}
}
Clock::~Clock() { Clock::~Clock() {
lv_obj_clean(lv_scr_act()); lv_obj_clean(lv_scr_act());
} }
bool Clock::Refresh() { bool Clock::Refresh() {
screens.Refresh(); screens.Refresh();
return running; return running;
@ -62,20 +65,30 @@ bool Clock::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
} }
std::unique_ptr<Screen> Clock::WatchFaceDigitalScreen() { std::unique_ptr<Screen> Clock::WatchFaceDigitalScreen() {
return std::make_unique<Screens::WatchFaceDigital>(app, dateTimeController, batteryController, bleController, notificatioManager, settingsController, heartRateController, motionController); return std::make_unique<Screens::WatchFaceDigital>(app,
dateTimeController,
batteryController,
bleController,
notificatioManager,
settingsController,
heartRateController,
motionController);
} }
std::unique_ptr<Screen> Clock::WatchFaceAnalogScreen() { std::unique_ptr<Screen> Clock::WatchFaceAnalogScreen() {
return std::make_unique<Screens::WatchFaceAnalog>(app, dateTimeController, batteryController, bleController, notificatioManager, settingsController); return std::make_unique<Screens::WatchFaceAnalog>(
app, dateTimeController, batteryController, bleController, notificatioManager, settingsController);
} }
/* /*
// Examples for more watch faces // Examples for more watch faces
std::unique_ptr<Screen> Clock::WatchFaceMinimalScreen() { std::unique_ptr<Screen> Clock::WatchFaceMinimalScreen() {
return std::make_unique<Screens::WatchFaceMinimal>(app, dateTimeController, batteryController, bleController, notificatioManager, settingsController); return std::make_unique<Screens::WatchFaceMinimal>(app, dateTimeController, batteryController, bleController, notificatioManager,
settingsController);
} }
std::unique_ptr<Screen> Clock::WatchFaceCustomScreen() { std::unique_ptr<Screen> Clock::WatchFaceCustomScreen() {
return std::make_unique<Screens::WatchFaceCustom>(app, dateTimeController, batteryController, bleController, notificatioManager, settingsController); return std::make_unique<Screens::WatchFaceCustom>(app, dateTimeController, batteryController, bleController, notificatioManager,
settingsController);
} }
*/ */

View File

@ -29,7 +29,7 @@ namespace Pinetime {
Controllers::Battery& batteryController, Controllers::Battery& batteryController,
Controllers::Ble& bleController, Controllers::Ble& bleController,
Controllers::NotificationManager& notificatioManager, Controllers::NotificationManager& notificatioManager,
Controllers::Settings &settingsController, Controllers::Settings& settingsController,
Controllers::HeartRateController& heartRateController, Controllers::HeartRateController& heartRateController,
Controllers::MotionController& motionController); Controllers::MotionController& motionController);
~Clock() override; ~Clock() override;
@ -39,7 +39,6 @@ namespace Pinetime {
bool OnTouchEvent(TouchEvents event) override; bool OnTouchEvent(TouchEvents event) override;
private: private:
Controllers::DateTime& dateTimeController; Controllers::DateTime& dateTimeController;
Controllers::Battery& batteryController; Controllers::Battery& batteryController;
Controllers::Ble& bleController; Controllers::Ble& bleController;
@ -48,17 +47,13 @@ namespace Pinetime {
Controllers::HeartRateController& heartRateController; Controllers::HeartRateController& heartRateController;
Controllers::MotionController& motionController; Controllers::MotionController& motionController;
ScreenList<2> screens; ScreenList<2> screens;
std::unique_ptr<Screen> WatchFaceDigitalScreen(); std::unique_ptr<Screen> WatchFaceDigitalScreen();
std::unique_ptr<Screen> WatchFaceAnalogScreen(); std::unique_ptr<Screen> WatchFaceAnalogScreen();
// Examples for more watch faces // Examples for more watch faces
//std::unique_ptr<Screen> WatchFaceMinimalScreen(); // std::unique_ptr<Screen> WatchFaceMinimalScreen();
//std::unique_ptr<Screen> WatchFaceCustomScreen(); // std::unique_ptr<Screen> WatchFaceCustomScreen();
}; };
} }
} }

View File

@ -5,10 +5,11 @@
using namespace Pinetime::Applications::Screens; using namespace Pinetime::Applications::Screens;
DropDownDemo::DropDownDemo(Pinetime::Applications::DisplayApp *app) : Screen(app) { DropDownDemo::DropDownDemo(Pinetime::Applications::DisplayApp* app) : Screen(app) {
// Create the dropdown object, with many item, and fix its height // Create the dropdown object, with many item, and fix its height
ddlist = lv_ddlist_create(lv_scr_act(), nullptr); ddlist = lv_ddlist_create(lv_scr_act(), nullptr);
lv_ddlist_set_options(ddlist, "Apple\n" lv_ddlist_set_options(ddlist,
"Apple\n"
"Banana\n" "Banana\n"
"Orange\n" "Orange\n"
"Melon\n" "Melon\n"
@ -32,12 +33,12 @@ DropDownDemo::~DropDownDemo() {
} }
bool DropDownDemo::Refresh() { bool DropDownDemo::Refresh() {
auto* list = static_cast<lv_ddlist_ext_t *>(ddlist->ext_attr); auto* list = static_cast<lv_ddlist_ext_t*>(ddlist->ext_attr);
// Switch touchmode to Polling if the dropdown is opened. This will allow to scroll inside the // Switch touchmode to Polling if the dropdown is opened. This will allow to scroll inside the
// dropdown while it is opened. // dropdown while it is opened.
// Disable the polling mode when the dropdown is closed to be able to handle the gestures. // Disable the polling mode when the dropdown is closed to be able to handle the gestures.
if(list->opened) if (list->opened)
app->SetTouchMode(DisplayApp::TouchModes::Polling); app->SetTouchMode(DisplayApp::TouchModes::Polling);
else else
app->SetTouchMode(DisplayApp::TouchModes::Gestures); app->SetTouchMode(DisplayApp::TouchModes::Gestures);
@ -47,11 +48,10 @@ bool DropDownDemo::Refresh() {
bool DropDownDemo::OnTouchEvent(Pinetime::Applications::TouchEvents event) { bool DropDownDemo::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
// If the dropdown is opened, notify Display app that it doesn't need to handle the event // If the dropdown is opened, notify Display app that it doesn't need to handle the event
// (this will prevent displayApp from going back to the menu or clock scree). // (this will prevent displayApp from going back to the menu or clock scree).
auto* list = static_cast<lv_ddlist_ext_t *>(ddlist->ext_attr); auto* list = static_cast<lv_ddlist_ext_t*>(ddlist->ext_attr);
if(list->opened) { if (list->opened) {
return true; return true;
} else { } else {
return false; return false;
} }
} }

View File

@ -18,7 +18,7 @@ namespace Pinetime {
bool OnTouchEvent(TouchEvents event) override; bool OnTouchEvent(TouchEvents event) override;
private: private:
lv_obj_t * ddlist; lv_obj_t* ddlist;
bool isDropDownOpened = false; bool isDropDownOpened = false;
}; };

View File

@ -5,9 +5,8 @@
using namespace Pinetime::Applications::Screens; using namespace Pinetime::Applications::Screens;
FirmwareUpdate::FirmwareUpdate(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Ble& bleController)
FirmwareUpdate::FirmwareUpdate(Pinetime::Applications::DisplayApp *app, Pinetime::Controllers::Ble& bleController) : : Screen(app), bleController {bleController} {
Screen(app), bleController{bleController} {
lv_obj_t * backgroundLabel = lv_label_create(lv_scr_act(), nullptr); lv_obj_t * backgroundLabel = lv_label_create(lv_scr_act(), nullptr);
lv_label_set_long_mode(backgroundLabel, LV_LABEL_LONG_CROP); lv_label_set_long_mode(backgroundLabel, LV_LABEL_LONG_CROP);
@ -38,21 +37,21 @@ FirmwareUpdate::~FirmwareUpdate() {
} }
bool FirmwareUpdate::Refresh() { bool FirmwareUpdate::Refresh() {
switch(bleController.State()) { switch (bleController.State()) {
default: default:
case Pinetime::Controllers::Ble::FirmwareUpdateStates::Idle: case Pinetime::Controllers::Ble::FirmwareUpdateStates::Idle:
case Pinetime::Controllers::Ble::FirmwareUpdateStates::Running: case Pinetime::Controllers::Ble::FirmwareUpdateStates::Running:
if(state != States::Running) if (state != States::Running)
state = States::Running; state = States::Running;
return DisplayProgression(); return DisplayProgression();
case Pinetime::Controllers::Ble::FirmwareUpdateStates::Validated: case Pinetime::Controllers::Ble::FirmwareUpdateStates::Validated:
if(state != States::Validated) { if (state != States::Validated) {
UpdateValidated(); UpdateValidated();
state = States::Validated; state = States::Validated;
} }
return running; return running;
case Pinetime::Controllers::Ble::FirmwareUpdateStates::Error: case Pinetime::Controllers::Ble::FirmwareUpdateStates::Error:
if(state != States::Error) { if (state != States::Error) {
UpdateError(); UpdateError();
state = States::Error; state = States::Error;
} }

View File

@ -10,14 +10,13 @@ namespace Pinetime {
namespace Applications { namespace Applications {
namespace Screens { namespace Screens {
class FirmwareUpdate : public Screen{ class FirmwareUpdate : public Screen {
public: public:
FirmwareUpdate(DisplayApp* app, Pinetime::Controllers::Ble& bleController); FirmwareUpdate(DisplayApp* app, Pinetime::Controllers::Ble& bleController);
~FirmwareUpdate() override; ~FirmwareUpdate() override;
bool Refresh() override; bool Refresh() override;
private: private:
enum class States { Idle, Running, Validated, Error }; enum class States { Idle, Running, Validated, Error };
Pinetime::Controllers::Ble& bleController; Pinetime::Controllers::Ble& bleController;

View File

@ -7,23 +7,20 @@
using namespace Pinetime::Applications::Screens; using namespace Pinetime::Applications::Screens;
namespace { namespace {
static void ButtonEventHandler(lv_obj_t * obj, lv_event_t event) static void ButtonEventHandler(lv_obj_t* obj, lv_event_t event) {
{ FirmwareValidation* screen = static_cast<FirmwareValidation*>(obj->user_data);
FirmwareValidation* screen = static_cast<FirmwareValidation *>(obj->user_data);
screen->OnButtonEvent(obj, event); screen->OnButtonEvent(obj, event);
} }
} }
FirmwareValidation::FirmwareValidation(Pinetime::Applications::DisplayApp *app, FirmwareValidation::FirmwareValidation(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::FirmwareValidator& validator)
Pinetime::Controllers::FirmwareValidator &validator) : Screen {app}, validator {validator} {
: Screen{app}, validator{validator} {
labelVersionInfo = lv_label_create(lv_scr_act(), nullptr); labelVersionInfo = lv_label_create(lv_scr_act(), nullptr);
lv_obj_align(labelVersionInfo, nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0); lv_obj_align(labelVersionInfo, nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0);
lv_label_set_text(labelVersionInfo, "Version : "); lv_label_set_text(labelVersionInfo, "Version : ");
lv_label_set_align(labelVersionInfo, LV_LABEL_ALIGN_LEFT); lv_label_set_align(labelVersionInfo, LV_LABEL_ALIGN_LEFT);
labelVersionValue = lv_label_create(lv_scr_act(), nullptr); labelVersionValue = lv_label_create(lv_scr_act(), nullptr);
lv_obj_align(labelVersionValue, labelVersionInfo, LV_ALIGN_OUT_RIGHT_MID, 0, 0); lv_obj_align(labelVersionValue, labelVersionInfo, LV_ALIGN_OUT_RIGHT_MID, 0, 0);
lv_label_set_recolor(labelVersionValue, true); lv_label_set_recolor(labelVersionValue, true);
@ -36,11 +33,10 @@ FirmwareValidation::FirmwareValidation(Pinetime::Applications::DisplayApp *app,
lv_label_set_long_mode(labelIsValidated, LV_LABEL_LONG_BREAK); lv_label_set_long_mode(labelIsValidated, LV_LABEL_LONG_BREAK);
lv_obj_set_width(labelIsValidated, 240); lv_obj_set_width(labelIsValidated, 240);
if(validator.IsValidated()) if (validator.IsValidated())
lv_label_set_text(labelIsValidated, "You have already\n#00ff00 validated# this firmware#"); lv_label_set_text(labelIsValidated, "You have already\n#00ff00 validated# this firmware#");
else { else {
lv_label_set_text(labelIsValidated, lv_label_set_text(labelIsValidated, "Please #00ff00 Validate# this version or\n#ff0000 Reset# to rollback to the previous version.");
"Please #00ff00 Validate# this version or\n#ff0000 Reset# to rollback to the previous version.");
buttonValidate = lv_btn_create(lv_scr_act(), nullptr); buttonValidate = lv_btn_create(lv_scr_act(), nullptr);
lv_obj_align(buttonValidate, NULL, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0); lv_obj_align(buttonValidate, NULL, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0);
@ -62,7 +58,6 @@ FirmwareValidation::FirmwareValidation(Pinetime::Applications::DisplayApp *app,
} }
} }
FirmwareValidation::~FirmwareValidation() { FirmwareValidation::~FirmwareValidation() {
lv_obj_clean(lv_scr_act()); lv_obj_clean(lv_scr_act());
} }
@ -71,12 +66,11 @@ bool FirmwareValidation::Refresh() {
return running; return running;
} }
void FirmwareValidation::OnButtonEvent(lv_obj_t *object, lv_event_t event) { void FirmwareValidation::OnButtonEvent(lv_obj_t* object, lv_event_t event) {
if(object == buttonValidate && event == LV_EVENT_PRESSED) { if (object == buttonValidate && event == LV_EVENT_PRESSED) {
validator.Validate(); validator.Validate();
running = false; running = false;
} else if(object == buttonReset && event == LV_EVENT_PRESSED) { } else if (object == buttonReset && event == LV_EVENT_PRESSED) {
validator.Reset(); validator.Reset();
} }
} }

View File

@ -11,15 +11,14 @@ namespace Pinetime {
namespace Applications { namespace Applications {
namespace Screens { namespace Screens {
class FirmwareValidation : public Screen{ class FirmwareValidation : public Screen {
public: public:
FirmwareValidation(DisplayApp* app, Pinetime::Controllers::FirmwareValidator& validator); FirmwareValidation(DisplayApp* app, Pinetime::Controllers::FirmwareValidator& validator);
~FirmwareValidation() override; ~FirmwareValidation() override;
bool Refresh() override; bool Refresh() override;
void OnButtonEvent(lv_obj_t* object, lv_event_t event);
void OnButtonEvent(lv_obj_t *object, lv_event_t event);
private: private:
Pinetime::Controllers::FirmwareValidator& validator; Pinetime::Controllers::FirmwareValidator& validator;
@ -32,7 +31,6 @@ namespace Pinetime {
lv_obj_t* labelButtonValidate; lv_obj_t* labelButtonValidate;
lv_obj_t* buttonReset; lv_obj_t* buttonReset;
lv_obj_t* labelButtonReset; lv_obj_t* labelButtonReset;
}; };
} }
} }

View File

@ -5,19 +5,18 @@
using namespace Pinetime::Applications::Screens; using namespace Pinetime::Applications::Screens;
namespace { namespace {
static void event_handler(lv_obj_t * obj, lv_event_t event) { static void event_handler(lv_obj_t* obj, lv_event_t event) {
FlashLight* screen = static_cast<FlashLight *>(obj->user_data); FlashLight* screen = static_cast<FlashLight*>(obj->user_data);
screen->OnClickEvent(obj, event); screen->OnClickEvent(obj, event);
} }
} }
FlashLight::FlashLight( FlashLight::FlashLight(Pinetime::Applications::DisplayApp* app,
Pinetime::Applications::DisplayApp *app, System::SystemTask& systemTask,
System::SystemTask &systemTask, Controllers::BrightnessController& brightness)
Controllers::BrightnessController& brightness) : : Screen(app),
Screen(app), systemTask {systemTask},
systemTask{systemTask}, brightness {brightness}
brightness{brightness}
{ {
brightness.Backup(); brightness.Backup();
@ -41,10 +40,8 @@ FlashLight::FlashLight(
lv_obj_set_event_cb(backgroundAction, event_handler); lv_obj_set_event_cb(backgroundAction, event_handler);
systemTask.PushMessage(Pinetime::System::SystemTask::Messages::DisableSleeping); systemTask.PushMessage(Pinetime::System::SystemTask::Messages::DisableSleeping);
} }
FlashLight::~FlashLight() { FlashLight::~FlashLight() {
lv_obj_clean(lv_scr_act()); 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)); lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
@ -52,19 +49,18 @@ FlashLight::~FlashLight() {
systemTask.PushMessage(Pinetime::System::SystemTask::Messages::EnableSleeping); systemTask.PushMessage(Pinetime::System::SystemTask::Messages::EnableSleeping);
} }
void FlashLight::OnClickEvent(lv_obj_t *obj, lv_event_t event) { void FlashLight::OnClickEvent(lv_obj_t* obj, lv_event_t event) {
if(obj == backgroundAction) { if (obj == backgroundAction) {
if (event == LV_EVENT_CLICKED) { if (event == LV_EVENT_CLICKED) {
isOn = !isOn; isOn = !isOn;
if ( 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_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)); lv_obj_set_style_local_text_color(flashLight, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
} else { } 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_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)); lv_obj_set_style_local_text_color(flashLight, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xFFFFFF));
} }
} }
} }
} }
@ -76,4 +72,3 @@ bool FlashLight::Refresh() {
bool FlashLight::OnTouchEvent(Pinetime::Applications::TouchEvents event) { bool FlashLight::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
return true; return true;
} }

View File

@ -6,21 +6,20 @@
#include "systemtask/SystemTask.h" #include "systemtask/SystemTask.h"
#include "components/brightness/BrightnessController.h" #include "components/brightness/BrightnessController.h"
namespace Pinetime { namespace Pinetime {
namespace Applications { namespace Applications {
namespace Screens { namespace Screens {
class FlashLight : public Screen{ class FlashLight : public Screen {
public: public:
FlashLight(DisplayApp* app, System::SystemTask &systemTask, Controllers::BrightnessController& brightness); FlashLight(DisplayApp* app, System::SystemTask& systemTask, Controllers::BrightnessController& brightness);
~FlashLight() override; ~FlashLight() override;
bool Refresh() override; bool Refresh() override;
bool OnTouchEvent(Pinetime::Applications::TouchEvents event) override; bool OnTouchEvent(Pinetime::Applications::TouchEvents event) override;
void OnClickEvent(lv_obj_t *obj, lv_event_t event); void OnClickEvent(lv_obj_t* obj, lv_event_t event);
private: private:
Pinetime::System::SystemTask& systemTask; Pinetime::System::SystemTask& systemTask;
@ -29,7 +28,6 @@ namespace Pinetime {
lv_obj_t* flashLight; lv_obj_t* flashLight;
lv_obj_t* backgroundAction; lv_obj_t* backgroundAction;
bool isOn = true; bool isOn = true;
}; };
} }
} }

View File

@ -7,7 +7,7 @@
using namespace Pinetime::Applications::Screens; using namespace Pinetime::Applications::Screens;
namespace { namespace {
const char *ToString(Pinetime::Controllers::HeartRateController::States s) { const char* ToString(Pinetime::Controllers::HeartRateController::States s) {
switch (s) { switch (s) {
case Pinetime::Controllers::HeartRateController::States::NotEnoughData: case Pinetime::Controllers::HeartRateController::States::NotEnoughData:
return "Not enough data,\nplease wait..."; return "Not enough data,\nplease wait...";
@ -21,20 +21,22 @@ namespace {
return ""; return "";
} }
static void btnStartStopEventHandler(lv_obj_t *obj, lv_event_t event) { static void btnStartStopEventHandler(lv_obj_t* obj, lv_event_t event) {
HeartRate *screen = static_cast<HeartRate *>(obj->user_data); HeartRate* screen = static_cast<HeartRate*>(obj->user_data);
screen->OnStartStopEvent(event); screen->OnStartStopEvent(event);
} }
} }
HeartRate::HeartRate(Pinetime::Applications::DisplayApp *app, Controllers::HeartRateController& heartRateController, System::SystemTask &systemTask) : HeartRate::HeartRate(Pinetime::Applications::DisplayApp* app,
Screen(app), heartRateController{heartRateController}, systemTask{systemTask} { Controllers::HeartRateController& heartRateController,
System::SystemTask& systemTask)
: Screen(app), heartRateController {heartRateController}, systemTask {systemTask} {
bool isHrRunning = heartRateController.State() != Controllers::HeartRateController::States::Stopped; bool isHrRunning = heartRateController.State() != Controllers::HeartRateController::States::Stopped;
label_hr = lv_label_create(lv_scr_act(), nullptr); label_hr = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_font(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76); lv_obj_set_style_local_text_font(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76);
if(isHrRunning) if (isHrRunning)
lv_obj_set_style_local_text_color(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GREEN); lv_obj_set_style_local_text_color(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GREEN);
else else
lv_obj_set_style_local_text_color(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY); lv_obj_set_style_local_text_color(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
@ -60,7 +62,7 @@ HeartRate::HeartRate(Pinetime::Applications::DisplayApp *app, Controllers::Heart
label_startStop = lv_label_create(btn_startStop, nullptr); label_startStop = lv_label_create(btn_startStop, nullptr);
UpdateStartStopButton(isHrRunning); UpdateStartStopButton(isHrRunning);
if(isHrRunning) if (isHrRunning)
systemTask.PushMessage(Pinetime::System::SystemTask::Messages::DisableSleeping); systemTask.PushMessage(Pinetime::System::SystemTask::Messages::DisableSleeping);
} }
@ -72,10 +74,10 @@ HeartRate::~HeartRate() {
bool HeartRate::Refresh() { bool HeartRate::Refresh() {
auto state = heartRateController.State(); auto state = heartRateController.State();
switch(state) { switch (state) {
case Controllers::HeartRateController::States::NoTouch: case Controllers::HeartRateController::States::NoTouch:
case Controllers::HeartRateController::States::NotEnoughData: case Controllers::HeartRateController::States::NotEnoughData:
//case Controllers::HeartRateController::States::Stopped: // case Controllers::HeartRateController::States::Stopped:
lv_label_set_text(label_hr, "000"); lv_label_set_text(label_hr, "000");
break; break;
default: default:
@ -90,13 +92,12 @@ bool HeartRate::Refresh() {
void HeartRate::OnStartStopEvent(lv_event_t event) { void HeartRate::OnStartStopEvent(lv_event_t event) {
if (event == LV_EVENT_CLICKED) { if (event == LV_EVENT_CLICKED) {
if(heartRateController.State() == Controllers::HeartRateController::States::Stopped) { if (heartRateController.State() == Controllers::HeartRateController::States::Stopped) {
heartRateController.Start(); heartRateController.Start();
UpdateStartStopButton(heartRateController.State() != Controllers::HeartRateController::States::Stopped); UpdateStartStopButton(heartRateController.State() != Controllers::HeartRateController::States::Stopped);
systemTask.PushMessage(Pinetime::System::SystemTask::Messages::DisableSleeping); systemTask.PushMessage(Pinetime::System::SystemTask::Messages::DisableSleeping);
lv_obj_set_style_local_text_color(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GREEN); lv_obj_set_style_local_text_color(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GREEN);
} } else {
else {
heartRateController.Stop(); heartRateController.Stop();
UpdateStartStopButton(heartRateController.State() != Controllers::HeartRateController::States::Stopped); UpdateStartStopButton(heartRateController.State() != Controllers::HeartRateController::States::Stopped);
systemTask.PushMessage(Pinetime::System::SystemTask::Messages::EnableSleeping); systemTask.PushMessage(Pinetime::System::SystemTask::Messages::EnableSleeping);
@ -106,7 +107,7 @@ void HeartRate::OnStartStopEvent(lv_event_t event) {
} }
void HeartRate::UpdateStartStopButton(bool isRunning) { void HeartRate::UpdateStartStopButton(bool isRunning) {
if(isRunning) if (isRunning)
lv_label_set_text(label_startStop, "Stop"); lv_label_set_text(label_startStop, "Stop");
else else
lv_label_set_text(label_startStop, "Start"); lv_label_set_text(label_startStop, "Start");

View File

@ -15,9 +15,9 @@ namespace Pinetime {
namespace Applications { namespace Applications {
namespace Screens { namespace Screens {
class HeartRate : public Screen{ class HeartRate : public Screen {
public: public:
HeartRate(DisplayApp* app, Controllers::HeartRateController& HeartRateController, System::SystemTask &systemTask); HeartRate(DisplayApp* app, Controllers::HeartRateController& HeartRateController, System::SystemTask& systemTask);
~HeartRate() override; ~HeartRate() override;
bool Refresh() override; bool Refresh() override;
@ -33,9 +33,6 @@ namespace Pinetime {
lv_obj_t* label_status; lv_obj_t* label_status;
lv_obj_t* btn_startStop; lv_obj_t* btn_startStop;
lv_obj_t* label_startStop; lv_obj_t* label_startStop;
}; };
} }
} }

View File

@ -4,7 +4,7 @@
using namespace Pinetime::Applications::Screens; using namespace Pinetime::Applications::Screens;
InfiniPaint::InfiniPaint(Pinetime::Applications::DisplayApp* app, Pinetime::Components::LittleVgl& lvgl) : Screen(app), lvgl{lvgl} { InfiniPaint::InfiniPaint(Pinetime::Applications::DisplayApp* app, Pinetime::Components::LittleVgl& lvgl) : Screen(app), lvgl {lvgl} {
app->SetTouchMode(DisplayApp::TouchModes::Polling); app->SetTouchMode(DisplayApp::TouchModes::Polling);
std::fill(b, b + bufferSize, selectColor); std::fill(b, b + bufferSize, selectColor);
} }
@ -20,7 +20,7 @@ bool InfiniPaint::Refresh() {
} }
bool InfiniPaint::OnTouchEvent(Pinetime::Applications::TouchEvents event) { bool InfiniPaint::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
switch(event) { switch (event) {
case Pinetime::Applications::TouchEvents::LongTap: case Pinetime::Applications::TouchEvents::LongTap:
switch (color) { switch (color) {
case 0: case 0:
@ -72,4 +72,3 @@ bool InfiniPaint::OnTouchEvent(uint16_t x, uint16_t y) {
lvgl.FlushDisplay(&area, b); lvgl.FlushDisplay(&area, b);
return true; return true;
} }

View File

@ -31,7 +31,6 @@ namespace Pinetime {
lv_color_t b[bufferSize]; lv_color_t b[bufferSize];
lv_color_t selectColor = LV_COLOR_WHITE; lv_color_t selectColor = LV_COLOR_WHITE;
uint8_t color = 2; uint8_t color = 2;
}; };
} }
} }

View File

@ -2,12 +2,10 @@
using namespace Pinetime::Applications::Screens; using namespace Pinetime::Applications::Screens;
Label::Label(uint8_t screenID, uint8_t numScreens, Label::Label(uint8_t screenID, uint8_t numScreens, Pinetime::Applications::DisplayApp* app, lv_obj_t* labelText)
Pinetime::Applications::DisplayApp *app, lv_obj_t* labelText) : : Screen(app), labelText {labelText} {
Screen(app),
labelText{labelText} {
if ( numScreens > 1 ) { if (numScreens > 1) {
pageIndicatorBasePoints[0].x = 240 - 1; pageIndicatorBasePoints[0].x = 240 - 1;
pageIndicatorBasePoints[0].y = 6; pageIndicatorBasePoints[0].y = 6;
pageIndicatorBasePoints[1].x = 240 - 1; pageIndicatorBasePoints[1].x = 240 - 1;
@ -19,7 +17,6 @@ Label::Label(uint8_t screenID, uint8_t numScreens,
lv_obj_set_style_local_line_rounded(pageIndicatorBase, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, true); lv_obj_set_style_local_line_rounded(pageIndicatorBase, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, true);
lv_line_set_points(pageIndicatorBase, pageIndicatorBasePoints, 2); lv_line_set_points(pageIndicatorBase, pageIndicatorBasePoints, 2);
uint16_t indicatorSize = 228 / numScreens; uint16_t indicatorSize = 228 / numScreens;
uint16_t indicatorPos = indicatorSize * screenID; uint16_t indicatorPos = indicatorSize * screenID;
@ -34,7 +31,6 @@ Label::Label(uint8_t screenID, uint8_t numScreens,
lv_obj_set_style_local_line_rounded(pageIndicator, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, true); lv_obj_set_style_local_line_rounded(pageIndicator, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, true);
lv_line_set_points(pageIndicator, pageIndicatorPoints, 2); lv_line_set_points(pageIndicator, pageIndicatorPoints, 2);
} }
} }
Label::~Label() { Label::~Label() {

View File

@ -9,18 +9,15 @@ namespace Pinetime {
class Label : public Screen { class Label : public Screen {
public: public:
Label( uint8_t screenID, uint8_t numScreens, Label(uint8_t screenID, uint8_t numScreens, DisplayApp* app, lv_obj_t* labelText);
DisplayApp* app, lv_obj_t* labelText );
~Label() override; ~Label() override;
bool Refresh() override; bool Refresh() override;
private: private:
bool running = true; bool running = true;
lv_obj_t * labelText = nullptr; lv_obj_t* labelText = nullptr;
lv_point_t pageIndicatorBasePoints[2]; lv_point_t pageIndicatorBasePoints[2];
lv_point_t pageIndicatorPoints[2]; lv_point_t pageIndicatorPoints[2];
lv_obj_t* pageIndicatorBase; lv_obj_t* pageIndicatorBase;

View File

@ -5,27 +5,26 @@
using namespace Pinetime::Applications::Screens; using namespace Pinetime::Applications::Screens;
namespace { namespace {
static void ButtonEventHandler(lv_obj_t * obj, lv_event_t event) { static void ButtonEventHandler(lv_obj_t* obj, lv_event_t event) {
List* screen = static_cast<List *>(obj->user_data); List* screen = static_cast<List*>(obj->user_data);
screen->OnButtonEvent(obj, event); screen->OnButtonEvent(obj, event);
} }
} }
List::List(uint8_t screenID, uint8_t numScreens, List::List(uint8_t screenID,
uint8_t numScreens,
DisplayApp* app, DisplayApp* app,
Controllers::Settings &settingsController, Controllers::Settings& settingsController,
std::array<Applications, MAXLISTITEMS>& applications) : std::array<Applications, MAXLISTITEMS>& applications)
Screen(app), : Screen(app), settingsController {settingsController} {
settingsController{settingsController}
{
// Set the background to Black // Set the background to Black
lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, lv_color_make(0, 0, 0)); lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, lv_color_make(0, 0, 0));
settingsController.SetSettingsMenu(screenID); settingsController.SetSettingsMenu(screenID);
if ( numScreens > 1 ) { if (numScreens > 1) {
pageIndicatorBasePoints[0].x = 240 - 1; pageIndicatorBasePoints[0].x = 240 - 1;
pageIndicatorBasePoints[0].y = 6; pageIndicatorBasePoints[0].y = 6;
pageIndicatorBasePoints[1].x = 240 - 1; pageIndicatorBasePoints[1].x = 240 - 1;
@ -37,7 +36,6 @@ List::List(uint8_t screenID, uint8_t numScreens,
lv_obj_set_style_local_line_rounded(pageIndicatorBase, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, true); lv_obj_set_style_local_line_rounded(pageIndicatorBase, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, true);
lv_line_set_points(pageIndicatorBase, pageIndicatorBasePoints, 2); lv_line_set_points(pageIndicatorBase, pageIndicatorBasePoints, 2);
uint16_t indicatorSize = 228 / numScreens; uint16_t indicatorSize = 228 / numScreens;
uint16_t indicatorPos = indicatorSize * screenID; uint16_t indicatorPos = indicatorSize * screenID;
@ -53,10 +51,9 @@ List::List(uint8_t screenID, uint8_t numScreens,
lv_line_set_points(pageIndicator, pageIndicatorPoints, 2); lv_line_set_points(pageIndicator, pageIndicatorPoints, 2);
} }
lv_obj_t* container1 = lv_cont_create(lv_scr_act(), nullptr); lv_obj_t* container1 = lv_cont_create(lv_scr_act(), nullptr);
//lv_obj_set_style_local_bg_color(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x111111)); // lv_obj_set_style_local_bg_color(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x111111));
lv_obj_set_style_local_bg_opa(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP); lv_obj_set_style_local_bg_opa(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP);
lv_obj_set_style_local_pad_all(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 10); lv_obj_set_style_local_pad_all(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 10);
lv_obj_set_style_local_pad_inner(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 5); lv_obj_set_style_local_pad_inner(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 5);
@ -67,12 +64,12 @@ List::List(uint8_t screenID, uint8_t numScreens,
lv_obj_set_height(container1, LV_VER_RES); lv_obj_set_height(container1, LV_VER_RES);
lv_cont_set_layout(container1, LV_LAYOUT_COLUMN_LEFT); lv_cont_set_layout(container1, LV_LAYOUT_COLUMN_LEFT);
lv_obj_t * labelBt; lv_obj_t* labelBt;
lv_obj_t * labelBtIco; lv_obj_t* labelBtIco;
for(int i = 0; i < MAXLISTITEMS; i++) { for (int i = 0; i < MAXLISTITEMS; i++) {
apps[i] = applications[i].application; apps[i] = applications[i].application;
if ( applications[i].application != Apps::None) { if (applications[i].application != Apps::None) {
itemApps[i] = lv_btn_create(container1, nullptr); itemApps[i] = lv_btn_create(container1, nullptr);
lv_obj_set_style_local_bg_opa(itemApps[i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_20); lv_obj_set_style_local_bg_opa(itemApps[i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_20);
@ -91,16 +88,14 @@ List::List(uint8_t screenID, uint8_t numScreens,
labelBt = lv_label_create(itemApps[i], nullptr); labelBt = lv_label_create(itemApps[i], nullptr);
lv_label_set_text_fmt(labelBt, " %s", applications[i].name); lv_label_set_text_fmt(labelBt, " %s", applications[i].name);
} }
} }
lv_obj_t * backgroundLabel = lv_label_create(lv_scr_act(), nullptr); lv_obj_t* backgroundLabel = lv_label_create(lv_scr_act(), nullptr);
lv_label_set_long_mode(backgroundLabel, LV_LABEL_LONG_CROP); lv_label_set_long_mode(backgroundLabel, LV_LABEL_LONG_CROP);
lv_obj_set_size(backgroundLabel, LV_HOR_RES, LV_VER_RES); lv_obj_set_size(backgroundLabel, LV_HOR_RES, LV_VER_RES);
lv_obj_set_pos(backgroundLabel, 0, 0); lv_obj_set_pos(backgroundLabel, 0, 0);
lv_label_set_text_static(backgroundLabel, ""); lv_label_set_text_static(backgroundLabel, "");
} }
List::~List() { List::~List() {
@ -112,10 +107,10 @@ bool List::Refresh() {
return running; return running;
} }
void List::OnButtonEvent(lv_obj_t * object, lv_event_t event) { void List::OnButtonEvent(lv_obj_t* object, lv_event_t event) {
if ( event == LV_EVENT_RELEASED ) { if (event == LV_EVENT_RELEASED) {
for(int i = 0; i < MAXLISTITEMS; i++) { for (int i = 0; i < MAXLISTITEMS; i++) {
if ( apps[i] != Apps::None && object == itemApps[i] ) { if (apps[i] != Apps::None && object == itemApps[i]) {
app->StartApp(apps[i], DisplayApp::FullRefreshDirections::Up); app->StartApp(apps[i], DisplayApp::FullRefreshDirections::Up);
running = false; running = false;
return; return;
@ -123,4 +118,3 @@ void List::OnButtonEvent(lv_obj_t * object, lv_event_t event) {
} }
} }
} }

View File

@ -20,7 +20,8 @@ namespace Pinetime {
Pinetime::Applications::Apps application; Pinetime::Applications::Apps application;
}; };
explicit List(uint8_t screenID, uint8_t numScreens, explicit List(uint8_t screenID,
uint8_t numScreens,
DisplayApp* app, DisplayApp* app,
Controllers::Settings& settingsController, Controllers::Settings& settingsController,
std::array<Applications, MAXLISTITEMS>& applications); std::array<Applications, MAXLISTITEMS>& applications);
@ -28,21 +29,18 @@ namespace Pinetime {
bool Refresh() override; bool Refresh() override;
void OnButtonEvent(lv_obj_t* object, lv_event_t event);
void OnButtonEvent(lv_obj_t *object, lv_event_t event);
private: private:
Controllers::Settings& settingsController; Controllers::Settings& settingsController;
Pinetime::Applications::Apps apps[MAXLISTITEMS]; Pinetime::Applications::Apps apps[MAXLISTITEMS];
lv_obj_t * itemApps[MAXLISTITEMS]; lv_obj_t* itemApps[MAXLISTITEMS];
lv_point_t pageIndicatorBasePoints[2]; lv_point_t pageIndicatorBasePoints[2];
lv_point_t pageIndicatorPoints[2]; lv_point_t pageIndicatorPoints[2];
lv_obj_t* pageIndicatorBase; lv_obj_t* pageIndicatorBase;
lv_obj_t* pageIndicator; lv_obj_t* pageIndicator;
}; };
} }
} }

View File

@ -4,8 +4,7 @@
using namespace Pinetime::Applications::Screens; using namespace Pinetime::Applications::Screens;
Meter::Meter(Pinetime::Applications::DisplayApp* app) : Screen(app) {
Meter::Meter(Pinetime::Applications::DisplayApp *app) : Screen(app) {
/*Create a line meter */ /*Create a line meter */
lmeter = lv_linemeter_create(lv_scr_act(), nullptr); lmeter = lv_linemeter_create(lv_scr_act(), nullptr);
@ -14,25 +13,24 @@ Meter::Meter(Pinetime::Applications::DisplayApp *app) : Screen(app) {
lv_linemeter_set_angle_offset(lmeter, 180); lv_linemeter_set_angle_offset(lmeter, 180);
lv_linemeter_set_scale(lmeter, 360, 60); /*Set the angle and number of lines*/ lv_linemeter_set_scale(lmeter, 360, 60); /*Set the angle and number of lines*/
lv_obj_set_style_local_scale_end_color(lmeter, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, lv_color_make(255,0,0)); lv_obj_set_style_local_scale_end_color(lmeter, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, lv_color_make(255, 0, 0));
lv_obj_set_style_local_scale_grad_color(lmeter, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, lv_color_make(160,0,0)); lv_obj_set_style_local_scale_grad_color(lmeter, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, lv_color_make(160, 0, 0));
lv_obj_set_style_local_line_width(lmeter, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, 2); lv_obj_set_style_local_line_width(lmeter, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, 2);
lv_obj_set_style_local_line_color(lmeter, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_SILVER); lv_obj_set_style_local_line_color(lmeter, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_SILVER);
lv_obj_set_size(lmeter, 200, 200); lv_obj_set_size(lmeter, 200, 200);
lv_obj_align(lmeter, nullptr, LV_ALIGN_CENTER, 0, 0); lv_obj_align(lmeter, nullptr, LV_ALIGN_CENTER, 0, 0);
} }
Meter::~Meter() { Meter::~Meter() {
lv_obj_clean(lv_scr_act()); lv_obj_clean(lv_scr_act());
} }
bool Meter::Refresh() { bool Meter::Refresh() {
lv_linemeter_set_value(lmeter, value++); /*Set the current value*/ lv_linemeter_set_value(lmeter, value++); /*Set the current value*/
if(value>=60) value = 0; if (value >= 60)
value = 0;
return running; return running;
} }

View File

@ -9,7 +9,7 @@ namespace Pinetime {
namespace Applications { namespace Applications {
namespace Screens { namespace Screens {
class Meter : public Screen{ class Meter : public Screen {
public: public:
Meter(DisplayApp* app); Meter(DisplayApp* app);
~Meter() override; ~Meter() override;
@ -18,11 +18,9 @@ namespace Pinetime {
private: private:
lv_style_t style_lmeter; lv_style_t style_lmeter;
lv_obj_t * lmeter; lv_obj_t* lmeter;
uint32_t value=0;
uint32_t value = 0;
}; };
} }
} }

Some files were not shown because too many files have changed in this diff Show More