Merge branch 'develop' of

https://github.com/JF002/InfiniTime into StepsApp
This commit is contained in:
Joaquim 2021-04-26 21:29:48 +01:00
commit cd0d85dff9
177 changed files with 10107 additions and 10659 deletions

View file

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

3
.gitignore vendored
View file

@ -1,4 +1,7 @@
.idea/
# Python virtual environment for DFU images
.venv/
# CMake
cmake-build-*
cmake-*

View file

@ -24,8 +24,7 @@ The goal of this project is to design an open-source firmware for the Pinetime s
## Overview
![Pinetime screens](images/0.14.0/collage1.png "PinetimeScreens")
![Pinetime screens](images/0.14.0/collage2.png "PinetimeScreens")
![Pinetime screens](images/1.0.0/collage.png "PinetimeScreens")
As of now, here is the list of achievements of this project:
@ -37,10 +36,15 @@ As of now, here is the list of achievements of this project:
- Heart rate measurements
- Step counting
- Wake-up on wrist rotation
- Quick actions
* Disable vibration on notification
* Brightness settings
* Flashlight
* Settings
- 2 watch faces:
* Digital
* Analog
- Multiple 'apps' :
* Clock (displays the date, time, battery level, ble connection status, heart rate)
* System info (displays various info : BLE MAC, build date/time, uptime, version,...)
* Brightess (allows the user to configure the brightness of the display)
* Music (control the playback of the music on your phone)
* Heart rate (controls the heart rate sensor and display current heartbeat)
* Navigation (displays navigation instructions coming from the companion app)
@ -48,13 +52,22 @@ As of now, here is the list of achievements of this project:
* Paddle (single player pong-like game)
* Two (2048 clone game)
* Stopwatch (with all the necessary functions such as play, pause, lap, stop)
* Motion sensor and step counter (displays the number of steps and the state of the motion sensor in real-time)
- User settings:
* Display timeout
* Wake-up condition
* Time format (12/24h)
* Default watch face
* Battery status
* Firmware validation
* System information
- Supported by 3 companion apps (development is in progress):
* [Gadgetbridge](https://codeberg.org/Freeyourgadget/Gadgetbridge/) (on Android)
* [Amazfish](https://openrepos.net/content/piggz/amazfish) (on SailfishOS and Linux)
* [Siglo](https://github.com/alexr4535/siglo) (on Linux)
* **[Experimental]** [WebBLEWatch](https://hubmartin.github.io/WebBLEWatch/) Synchronize time directly from your web browser. [video](https://youtu.be/IakiuhVDdrY)
- **[Experimental]** OTA (Over-the-air) update via BLE
- **[Experimental]** Bootloader based on [MCUBoot](https://juullabs-oss.github.io/mcuboot/)
- OTA (Over-the-air) update via BLE
- [Bootloader](https://github.com/JF002/pinetime-mcuboot-bootloader) based on [MCUBoot](https://juullabs-oss.github.io/mcuboot/)
## Documentation
@ -62,7 +75,7 @@ As of now, here is the list of achievements of this project:
- [Flash, upgrade (OTA), time synchronization,...](doc/gettingStarted/gettingStarted.md)
### 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)
### Build, flash and debug

BIN
images/1.0.0/collage.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

View file

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

View file

@ -2,11 +2,11 @@
namespace Pinetime {
class BootloaderVersion {
public:
static uint32_t Major();
static uint32_t Minor();
static uint32_t Patch();
static const char* VersionString();
static bool IsValid();
public:
static uint32_t Major();
static uint32_t Minor();
static uint32_t Patch();
static const char* VersionString();
static bool IsValid();
};
}

View file

@ -26,20 +26,19 @@
* 1 tab == 4 spaces!
*/
#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H
#ifdef SOFTDEVICE_PRESENT
#include "nrf_soc.h"
#include "nrf_soc.h"
#endif
#include "app_util_platform.h"
/*-----------------------------------------------------------
* Possible configurations for system timer
*/
#define FREERTOS_USE_RTC 0 /**< Use real time clock for the system */
#define FREERTOS_USE_SYSTICK 1 /**< Use SysTick timer for system */
#define FREERTOS_USE_RTC 0 /**< Use real time clock for the system */
#define FREERTOS_USE_SYSTICK 1 /**< Use SysTick timer for system */
/*-----------------------------------------------------------
* Application specific definitions.
@ -55,153 +54,150 @@
#define configTICK_SOURCE FREERTOS_USE_RTC
#define configUSE_PREEMPTION 1
#define configUSE_PREEMPTION 1
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
#define configUSE_TICKLESS_IDLE 1
#define configUSE_TICKLESS_IDLE_SIMPLE_DEBUG 0 /* See into vPortSuppressTicksAndSleep source code for explanation */
#define configCPU_CLOCK_HZ ( SystemCoreClock )
#define configTICK_RATE_HZ 1024
#define configMAX_PRIORITIES ( 3 )
#define configMINIMAL_STACK_SIZE ( 120 )
#define configTOTAL_HEAP_SIZE ( 1024*16 )
#define configMAX_TASK_NAME_LEN ( 4 )
#define configUSE_16_BIT_TICKS 0
#define configIDLE_SHOULD_YIELD 1
#define configUSE_MUTEXES 1
#define configUSE_RECURSIVE_MUTEXES 1
#define configUSE_COUNTING_SEMAPHORES 1
#define configUSE_ALTERNATIVE_API 0 /* Deprecated! */
#define configQUEUE_REGISTRY_SIZE 2
#define configUSE_QUEUE_SETS 0
#define configUSE_TIME_SLICING 0
#define configUSE_NEWLIB_REENTRANT 0
#define configENABLE_BACKWARD_COMPATIBILITY 1
#define configUSE_TICKLESS_IDLE 1
#define configUSE_TICKLESS_IDLE_SIMPLE_DEBUG 0 /* See into vPortSuppressTicksAndSleep source code for explanation */
#define configCPU_CLOCK_HZ (SystemCoreClock)
#define configTICK_RATE_HZ 1024
#define configMAX_PRIORITIES (3)
#define configMINIMAL_STACK_SIZE (120)
#define configTOTAL_HEAP_SIZE (1024 * 16)
#define configMAX_TASK_NAME_LEN (4)
#define configUSE_16_BIT_TICKS 0
#define configIDLE_SHOULD_YIELD 1
#define configUSE_MUTEXES 1
#define configUSE_RECURSIVE_MUTEXES 1
#define configUSE_COUNTING_SEMAPHORES 1
#define configUSE_ALTERNATIVE_API 0 /* Deprecated! */
#define configQUEUE_REGISTRY_SIZE 2
#define configUSE_QUEUE_SETS 0
#define configUSE_TIME_SLICING 0
#define configUSE_NEWLIB_REENTRANT 0
#define configENABLE_BACKWARD_COMPATIBILITY 1
/* Hook function related definitions. */
#define configUSE_IDLE_HOOK 1
#define configUSE_TICK_HOOK 0
#define configCHECK_FOR_STACK_OVERFLOW 0
#define configUSE_MALLOC_FAILED_HOOK 0
#define configUSE_IDLE_HOOK 1
#define configUSE_TICK_HOOK 0
#define configCHECK_FOR_STACK_OVERFLOW 0
#define configUSE_MALLOC_FAILED_HOOK 0
/* Run time and task stats gathering related definitions. */
#define configGENERATE_RUN_TIME_STATS 0
#define configUSE_TRACE_FACILITY 1
#define configUSE_STATS_FORMATTING_FUNCTIONS 0
#define configGENERATE_RUN_TIME_STATS 0
#define configUSE_TRACE_FACILITY 1
#define configUSE_STATS_FORMATTING_FUNCTIONS 0
/* Co-routine definitions. */
#define configUSE_CO_ROUTINES 0
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
#define configUSE_CO_ROUTINES 0
#define configMAX_CO_ROUTINE_PRIORITIES (2)
/* Software timer definitions. */
#define configUSE_TIMERS 1
#define configTIMER_TASK_PRIORITY ( 0 )
#define configTIMER_QUEUE_LENGTH 32
#define configTIMER_TASK_STACK_DEPTH ( 300 )
#define configUSE_TIMERS 1
#define configTIMER_TASK_PRIORITY (0)
#define configTIMER_QUEUE_LENGTH 32
#define configTIMER_TASK_STACK_DEPTH (300)
/* Tickless Idle configuration. */
#define configEXPECTED_IDLE_TIME_BEFORE_SLEEP 2
#define configEXPECTED_IDLE_TIME_BEFORE_SLEEP 2
/* Tickless idle/low power functionality. */
/* Define to trap errors during development. */
#if defined(DEBUG_NRF) || defined(DEBUG_NRF_USER)
#define configASSERT( x ) ASSERT(x)
#define configASSERT(x) ASSERT(x)
#endif
/* FreeRTOS MPU specific definitions. */
#define configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS 1
#define configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS 1
/* Optional functions - most linkers will remove unused functions anyway. */
#define INCLUDE_vTaskPrioritySet 1
#define INCLUDE_uxTaskPriorityGet 1
#define INCLUDE_vTaskDelete 1
#define INCLUDE_vTaskSuspend 1
#define INCLUDE_xResumeFromISR 1
#define INCLUDE_vTaskDelayUntil 1
#define INCLUDE_vTaskDelay 1
#define INCLUDE_xTaskGetSchedulerState 1
#define INCLUDE_xTaskGetCurrentTaskHandle 1
#define INCLUDE_uxTaskGetStackHighWaterMark 1
#define INCLUDE_xTaskGetIdleTaskHandle 1
#define INCLUDE_xTimerGetTimerDaemonTaskHandle 1
#define INCLUDE_pcTaskGetTaskName 1
#define INCLUDE_eTaskGetState 1
#define INCLUDE_xEventGroupSetBitFromISR 1
#define INCLUDE_xTimerPendFunctionCall 1
#define INCLUDE_vTaskPrioritySet 1
#define INCLUDE_uxTaskPriorityGet 1
#define INCLUDE_vTaskDelete 1
#define INCLUDE_vTaskSuspend 1
#define INCLUDE_xResumeFromISR 1
#define INCLUDE_vTaskDelayUntil 1
#define INCLUDE_vTaskDelay 1
#define INCLUDE_xTaskGetSchedulerState 1
#define INCLUDE_xTaskGetCurrentTaskHandle 1
#define INCLUDE_uxTaskGetStackHighWaterMark 1
#define INCLUDE_xTaskGetIdleTaskHandle 1
#define INCLUDE_xTimerGetTimerDaemonTaskHandle 1
#define INCLUDE_pcTaskGetTaskName 1
#define INCLUDE_eTaskGetState 1
#define INCLUDE_xEventGroupSetBitFromISR 1
#define INCLUDE_xTimerPendFunctionCall 1
/* The lowest interrupt priority that can be used in a call to a "set priority"
function. */
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 0xf
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 0xf
/* The highest interrupt priority that can be used by any interrupt service
routine that makes calls to interrupt safe FreeRTOS API functions. DO NOT CALL
INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
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
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
/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
#define configMAX_SYSCALL_INTERRUPT_PRIORITY configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY
#define configMAX_SYSCALL_INTERRUPT_PRIORITY configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY
/* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS
standard names - or at least those used in the unmodified vector table. */
#define vPortSVCHandler SVC_Handler
#define xPortPendSVHandler PendSV_Handler
#define vPortSVCHandler SVC_Handler
#define xPortPendSVHandler PendSV_Handler
/*-----------------------------------------------------------
* Settings that are generated automatically
* basing on the settings above
*/
#if (configTICK_SOURCE == FREERTOS_USE_SYSTICK)
// do not define configSYSTICK_CLOCK_HZ for SysTick to be configured automatically
// to CPU clock source
#define xPortSysTickHandler SysTick_Handler
// do not define configSYSTICK_CLOCK_HZ for SysTick to be configured automatically
// to CPU clock source
#define xPortSysTickHandler SysTick_Handler
#elif (configTICK_SOURCE == FREERTOS_USE_RTC)
#define configSYSTICK_CLOCK_HZ ( 32768UL )
#define xPortSysTickHandler RTC1_IRQHandler
#define configSYSTICK_CLOCK_HZ (32768UL)
#define xPortSysTickHandler RTC1_IRQHandler
#else
#error Unsupported configTICK_SOURCE value
#error Unsupported configTICK_SOURCE value
#endif
/* Code below should be only used by the compiler, and not the assembler. */
#if !(defined(__ASSEMBLY__) || defined(__ASSEMBLER__))
#include "nrf.h"
#include "nrf_assert.h"
#include "nrf.h"
#include "nrf_assert.h"
/* This part of definitions may be problematic in assembly - it uses definitions from files that are not assembly compatible. */
/* Cortex-M specific definitions. */
#ifdef __NVIC_PRIO_BITS
/* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */
#define configPRIO_BITS __NVIC_PRIO_BITS
#else
#error "This port requires __NVIC_PRIO_BITS to be defined"
#endif
/* This part of definitions may be problematic in assembly - it uses definitions from files that are not assembly compatible. */
/* Cortex-M specific definitions. */
#ifdef __NVIC_PRIO_BITS
/* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */
#define configPRIO_BITS __NVIC_PRIO_BITS
#else
#error "This port requires __NVIC_PRIO_BITS to be defined"
#endif
/* Access to current system core clock is required only if we are ticking the system by systimer */
#if (configTICK_SOURCE == FREERTOS_USE_SYSTICK)
#include <stdint.h>
extern uint32_t SystemCoreClock;
#endif
/* Access to current system core clock is required only if we are ticking the system by systimer */
#if (configTICK_SOURCE == FREERTOS_USE_SYSTICK)
#include <stdint.h>
extern uint32_t SystemCoreClock;
#endif
#endif /* !assembler */
/** Implementation note: Use this with caution and set this to 1 ONLY for debugging
* ----------------------------------------------------------
* Set the value of configUSE_DISABLE_TICK_AUTO_CORRECTION_DEBUG to below for enabling or disabling RTOS tick auto correction:
* 0. This is default. If the RTC tick interrupt is masked for more than 1 tick by higher priority interrupts, then most likely
* 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.
* 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
* 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
* convenient for debugging.
*/
#define configUSE_DISABLE_TICK_AUTO_CORRECTION_DEBUG 0
* Set the value of configUSE_DISABLE_TICK_AUTO_CORRECTION_DEBUG to below for enabling or disabling RTOS tick auto correction:
* 0. This is default. If the RTC tick interrupt is masked for more than 1 tick by higher priority interrupts, then most likely
* 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.
* 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 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 convenient for debugging.
*/
#define configUSE_DISABLE_TICK_AUTO_CORRECTION_DEBUG 0
#endif /* FREERTOS_CONFIG_H */

View file

@ -7,15 +7,15 @@
using namespace Pinetime::Controllers;
Battery *Battery::instance = nullptr;
Battery* Battery::instance = nullptr;
Battery::Battery() {
instance = this;
}
void Battery::Init() {
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(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);
}
void Battery::Update() {
@ -23,17 +23,17 @@ void Battery::Update() {
isCharging = !nrf_gpio_pin_read(chargingPin);
isPowerPresent = !nrf_gpio_pin_read(powerPresentPin);
if ( isReading ) return;
if (isReading)
return;
// Non blocking read
samples = 0;
isReading = true;
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);
}
@ -41,48 +41,44 @@ void Battery::SaadcInit() {
nrfx_saadc_config_t adcConfig = NRFX_SAADC_DEFAULT_CONFIG;
APP_ERROR_CHECK(nrfx_saadc_init(&adcConfig, adcCallbackStatic));
nrf_saadc_channel_config_t adcChannelConfig = {
.resistor_p = NRF_SAADC_RESISTOR_DISABLED,
.resistor_n = NRF_SAADC_RESISTOR_DISABLED,
.gain = NRF_SAADC_GAIN1_5,
.reference = NRF_SAADC_REFERENCE_INTERNAL,
.acq_time = NRF_SAADC_ACQTIME_3US,
.mode = NRF_SAADC_MODE_SINGLE_ENDED,
.burst = NRF_SAADC_BURST_ENABLED,
.pin_p = batteryVoltageAdcInput,
.pin_n = NRF_SAADC_INPUT_DISABLED
};
nrf_saadc_channel_config_t adcChannelConfig = {.resistor_p = NRF_SAADC_RESISTOR_DISABLED,
.resistor_n = NRF_SAADC_RESISTOR_DISABLED,
.gain = NRF_SAADC_GAIN1_5,
.reference = NRF_SAADC_REFERENCE_INTERNAL,
.acq_time = NRF_SAADC_ACQTIME_3US,
.mode = NRF_SAADC_MODE_SINGLE_ENDED,
.burst = NRF_SAADC_BURST_ENABLED,
.pin_p = batteryVoltageAdcInput,
.pin_n = NRF_SAADC_INPUT_DISABLED};
APP_ERROR_CHECK(nrfx_saadc_channel_init(0, &adcChannelConfig));
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_min = 3.20; // minimum voltage of battery before shutdown ( depends on the battery )
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 )
if (p_event->type == NRFX_SAADC_EVT_DONE) {
if (p_event->type == NRFX_SAADC_EVT_DONE) {
APP_ERROR_CHECK(nrfx_saadc_buffer_convert(&saadc_value, 1));
APP_ERROR_CHECK(nrfx_saadc_buffer_convert(&saadc_value, 1));
voltage = (static_cast<float>(p_event->data.done.p_buffer[0]) * 2.04f) / (1024 / 3.0f);
voltage = roundf(voltage * 100) / 100;
voltage = (static_cast<float>(p_event->data.done.p_buffer[0]) * 2.04f) / (1024 / 3.0f);
voltage = roundf(voltage * 100) / 100;
percentRemaining = static_cast<int>(((voltage - battery_min) / (battery_max - battery_min)) * 100);
percentRemaining = static_cast<int>(((voltage - battery_min) / (battery_max - battery_min)) * 100);
percentRemaining = std::max(percentRemaining, 0);
percentRemaining = std::min(percentRemaining, 100);
percentRemaining = std::max(percentRemaining, 0);
percentRemaining = std::min(percentRemaining, 100);
percentRemainingBuffer.insert(percentRemaining);
percentRemainingBuffer.insert(percentRemaining);
samples++;
if ( samples > percentRemainingSamples ) {
nrfx_saadc_uninit();
isReading = false;
} else {
nrfx_saadc_sample();
}
samples++;
if (samples > percentRemainingSamples) {
nrfx_saadc_uninit();
isReading = false;
} else {
nrfx_saadc_sample();
}
}
}

View file

@ -11,10 +11,10 @@ namespace Pinetime {
out the sensor values. The total capacity of the CircBuffer
is given as the template parameter N.
*/
template <int N>
class CircBuffer {
template <int N> class CircBuffer {
public:
CircBuffer() : arr{}, sz{}, cap{N}, head{} {}
CircBuffer() : arr {}, sz {}, cap {N}, head {} {
}
/**
insert member function overwrites the next data to the current
HEAD and moves the HEAD to the newly inserted value.
@ -34,49 +34,56 @@ namespace Pinetime {
private:
std::array<int, N> arr; /**< internal array used to store the values*/
uint8_t sz; /**< The current size of the array.*/
uint8_t cap; /**< Total capacity of the CircBuffer.*/
uint8_t head; /**< The current head of the CircBuffer*/
uint8_t sz; /**< The current size of the array.*/
uint8_t cap; /**< Total capacity of the CircBuffer.*/
uint8_t head; /**< The current head of the CircBuffer*/
};
class Battery {
public:
public:
Battery();
Battery();
void Init();
void Update();
void Init();
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 IsPowerPresent() const {
return isPowerPresent;
}
bool IsCharging() const { return isCharging; }
bool IsPowerPresent() const { return isPowerPresent; }
private:
static Battery* instance;
nrf_saadc_value_t saadc_value;
private:
static Battery *instance;
nrf_saadc_value_t saadc_value;
static constexpr uint8_t percentRemainingSamples = 5;
CircBuffer<percentRemainingSamples> percentRemainingBuffer {};
static constexpr uint8_t percentRemainingSamples = 5;
CircBuffer<percentRemainingSamples> percentRemainingBuffer {};
static constexpr uint32_t chargingPin = 12;
static constexpr uint32_t powerPresentPin = 19;
static constexpr nrf_saadc_input_t batteryVoltageAdcInput = NRF_SAADC_INPUT_AIN7;
float voltage = 0.0f;
int percentRemaining = -1;
static constexpr uint32_t chargingPin = 12;
static constexpr uint32_t powerPresentPin = 19;
static constexpr nrf_saadc_input_t batteryVoltageAdcInput = NRF_SAADC_INPUT_AIN7;
float voltage = 0.0f;
int percentRemaining = -1;
bool isCharging = false;
bool isPowerPresent = false;
bool isCharging = false;
bool isPowerPresent = false;
void SaadcInit();
void SaadcInit();
void SaadcEventHandler(nrfx_saadc_evt_t const* p_event);
static void adcCallbackStatic(nrfx_saadc_evt_t const* event);
void SaadcEventHandler(nrfx_saadc_evt_t const * p_event);
static void adcCallbackStatic(nrfx_saadc_evt_t const *event);
bool isReading = false;
uint8_t samples = 0;
bool isReading = false;
uint8_t samples = 0;
};
}
}

View file

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

View file

@ -19,68 +19,52 @@ namespace Pinetime {
class NotificationManager;
class AlertNotificationClient : public BleClient {
public:
explicit AlertNotificationClient(Pinetime::System::SystemTask &systemTask,
Pinetime::Controllers::NotificationManager &notificationManager);
public:
explicit AlertNotificationClient(Pinetime::System::SystemTask& systemTask,
Pinetime::Controllers::NotificationManager& notificationManager);
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,
const ble_gatt_chr *characteristic);
int OnNewAlertSubcribe(uint16_t connectionHandle, const ble_gatt_error *error, ble_gatt_attr *attribute);
int OnDescriptorDiscoveryEventCallback(uint16_t connectionHandle, const ble_gatt_error *error,
uint16_t characteristicValueHandle, const ble_gatt_dsc *descriptor);
void OnNotification(ble_gap_event *event);
void Reset();
void Discover(uint16_t connectionHandle, std::function<void(uint16_t)> lambda) override;
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, const ble_gatt_chr* characteristic);
int OnNewAlertSubcribe(uint16_t connectionHandle, const ble_gatt_error* error, ble_gatt_attr* attribute);
int OnDescriptorDiscoveryEventCallback(uint16_t connectionHandle,
const ble_gatt_error* error,
uint16_t characteristicValueHandle,
const ble_gatt_dsc* descriptor);
void OnNotification(ble_gap_event* event);
void Reset();
void Discover(uint16_t connectionHandle, std::function<void(uint16_t)> lambda) override;
private:
static constexpr uint16_t ansServiceId{0x1811};
static constexpr uint16_t supportedNewAlertCategoryId = 0x2a47;
static constexpr uint16_t supportedUnreadAlertCategoryId = 0x2a48;
static constexpr uint16_t newAlertId = 0x2a46;
static constexpr uint16_t unreadAlertStatusId = 0x2a45;
static constexpr uint16_t controlPointId = 0x2a44;
private:
static constexpr uint16_t ansServiceId {0x1811};
static constexpr uint16_t supportedNewAlertCategoryId = 0x2a47;
static constexpr uint16_t supportedUnreadAlertCategoryId = 0x2a48;
static constexpr uint16_t newAlertId = 0x2a46;
static constexpr uint16_t unreadAlertStatusId = 0x2a45;
static constexpr uint16_t controlPointId = 0x2a44;
static constexpr ble_uuid16_t ansServiceUuid{
.u {.type = BLE_UUID_TYPE_16},
.value = ansServiceId
};
static constexpr ble_uuid16_t supportedNewAlertCategoryUuid{
.u {.type = BLE_UUID_TYPE_16},
.value = supportedNewAlertCategoryId
};
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
};
static constexpr ble_uuid16_t ansServiceUuid {.u {.type = BLE_UUID_TYPE_16}, .value = ansServiceId};
static constexpr ble_uuid16_t supportedNewAlertCategoryUuid {.u {.type = BLE_UUID_TYPE_16}, .value = supportedNewAlertCategoryId};
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 ansEndHandle = 0;
uint16_t supportedNewAlertCategoryHandle = 0;
uint16_t supportedUnreadAlertCategoryHandle = 0;
uint16_t newAlertHandle = 0;
uint16_t newAlertDescriptorHandle = 0;
uint16_t newAlertDefHandle = 0;
uint16_t unreadAlertStatusHandle = 0;
uint16_t controlPointHandle = 0;
bool isDiscovered = false;
Pinetime::System::SystemTask &systemTask;
Pinetime::Controllers::NotificationManager &notificationManager;
std::function<void(uint16_t)> onServiceDiscovered;
bool isCharacteristicDiscovered = false;
bool isDescriptorFound = false;
uint16_t ansStartHandle = 0;
uint16_t ansEndHandle = 0;
uint16_t supportedNewAlertCategoryHandle = 0;
uint16_t supportedUnreadAlertCategoryHandle = 0;
uint16_t newAlertHandle = 0;
uint16_t newAlertDescriptorHandle = 0;
uint16_t newAlertDefHandle = 0;
uint16_t unreadAlertStatusHandle = 0;
uint16_t controlPointHandle = 0;
bool isDiscovered = false;
Pinetime::System::SystemTask& systemTask;
Pinetime::Controllers::NotificationManager& notificationManager;
std::function<void(uint16_t)> onServiceDiscovered;
bool isCharacteristicDiscovered = false;
bool isDescriptorFound = false;
};
}
}

View file

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

View file

@ -7,8 +7,9 @@
#undef max
#undef min
//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}
// 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 }
namespace Pinetime {
@ -19,64 +20,49 @@ namespace Pinetime {
class NotificationManager;
class AlertNotificationService {
public:
AlertNotificationService(Pinetime::System::SystemTask &systemTask,
Pinetime::Controllers::NotificationManager &notificationManager);
void Init();
public:
AlertNotificationService(Pinetime::System::SystemTask& systemTask, Pinetime::Controllers::NotificationManager& notificationManager);
void Init();
int OnAlert(uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt);
int OnAlert(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt);
void AcceptIncomingCall();
void RejectIncomingCall();
void MuteIncomingCall();
void AcceptIncomingCall();
void RejectIncomingCall();
void MuteIncomingCall();
enum class IncomingCallResponses : uint8_t {
Reject = 0x00,
Answer = 0x01,
Mute = 0x02
};
enum class IncomingCallResponses : uint8_t { Reject = 0x00, Answer = 0x01, Mute = 0x02 };
private:
enum class Categories : uint8_t {
SimpleAlert = 0x00,
Email = 0x01,
News = 0x02,
Call = 0x03,
MissedCall = 0x04,
MmsSms = 0x05,
VoiceMail = 0x06,
Schedule = 0x07,
HighPrioritizedAlert = 0x08,
InstantMessage = 0x09,
All = 0xff
};
private:
enum class Categories : uint8_t {
SimpleAlert = 0x00,
Email = 0x01,
News = 0x02,
Call = 0x03,
MissedCall = 0x04,
MmsSms = 0x05,
VoiceMail = 0x06,
Schedule = 0x07,
HighPrioritizedAlert = 0x08,
InstantMessage = 0x09,
All = 0xff
};
static constexpr uint16_t ansId {0x1811};
static constexpr uint16_t ansCharId {0x2a46};
static constexpr uint16_t ansId {0x1811};
static constexpr uint16_t ansCharId {0x2a46};
static constexpr ble_uuid16_t ansUuid {
.u { .type = BLE_UUID_TYPE_16 },
.value = ansId
};
static constexpr ble_uuid16_t ansUuid {.u {.type = BLE_UUID_TYPE_16}, .value = ansId};
static constexpr ble_uuid16_t ansCharUuid {
.u { .type = BLE_UUID_TYPE_16 },
.value = ansCharId
};
static constexpr ble_uuid16_t ansCharUuid {.u {.type = BLE_UUID_TYPE_16}, .value = ansCharId};
static constexpr ble_uuid128_t notificationEventUuid {
.u { .type = BLE_UUID_TYPE_128 },
.value = NOTIFICATION_EVENT_SERVICE_UUID_BASE
};
static constexpr ble_uuid128_t notificationEventUuid {.u {.type = BLE_UUID_TYPE_128}, .value = NOTIFICATION_EVENT_SERVICE_UUID_BASE};
struct ble_gatt_chr_def characteristicDefinition[3];
struct ble_gatt_svc_def serviceDefinition[2];
struct ble_gatt_chr_def characteristicDefinition[3];
struct ble_gatt_svc_def serviceDefinition[2];
Pinetime::System::SystemTask &systemTask;
NotificationManager &notificationManager;
Pinetime::System::SystemTask& systemTask;
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::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);
return batteryInformationService->OnBatteryServiceRequested(conn_handle, attr_handle, ctxt);
}
BatteryInformationService::BatteryInformationService(Controllers::Battery& batteryController) :
batteryController{batteryController},
characteristicDefinition{
{
.uuid = (ble_uuid_t *) &batteryLevelUuid,
.access_cb = BatteryInformationServiceCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_READ,
.val_handle = &batteryLevelHandle
},
{
0
}
},
serviceDefinition{
{
/* Device Information Service */
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = (ble_uuid_t *) &batteryInformationServiceUuid,
.characteristics = characteristicDefinition
},
{
0
},
}{
BatteryInformationService::BatteryInformationService(Controllers::Battery& batteryController)
: batteryController {batteryController},
characteristicDefinition {{.uuid = (ble_uuid_t*) &batteryLevelUuid,
.access_cb = BatteryInformationServiceCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_READ,
.val_handle = &batteryLevelHandle},
{0}},
serviceDefinition {
{/* Device Information Service */
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = (ble_uuid_t*) &batteryInformationServiceUuid,
.characteristics = characteristicDefinition},
{0},
} {
}
void BatteryInformationService::Init() {
@ -51,9 +38,10 @@ void BatteryInformationService::Init() {
ASSERT(res == 0);
}
int BatteryInformationService::OnBatteryServiceRequested(uint16_t connectionHandle, uint16_t attributeHandle,
ble_gatt_access_ctxt *context) {
if(attributeHandle == batteryLevelHandle) {
int BatteryInformationService::OnBatteryServiceRequested(uint16_t connectionHandle,
uint16_t attributeHandle,
ble_gatt_access_ctxt* context) {
if (attributeHandle == batteryLevelHandle) {
NRF_LOG_INFO("BATTERY : handle = %d", batteryLevelHandle);
static uint8_t batteryValue = batteryController.PercentRemaining();
int res = os_mbuf_append(context->om, &batteryValue, 1);

View file

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

View file

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

View file

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

View file

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

View file

@ -8,54 +8,51 @@
#include "BleClient.h"
namespace Pinetime {
namespace Controllers {
class DateTime;
namespace Controllers {
class DateTime;
class CurrentTimeClient : public BleClient {
public:
explicit CurrentTimeClient(DateTime& dateTimeController);
void Init();
void Reset();
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,
const ble_gatt_chr *characteristic);
int OnCurrentTimeReadResult(uint16_t conn_handle, const ble_gatt_error *error, const ble_gatt_attr *attribute);
static constexpr const ble_uuid16_t* Uuid() { return &CurrentTimeClient::ctsServiceUuid; }
static constexpr const ble_uuid16_t* CurrentTimeCharacteristicUuid() { return &CurrentTimeClient::currentTimeCharacteristicUuid; }
void Discover(uint16_t connectionHandle, std::function<void(uint16_t)> lambda) override;
class CurrentTimeClient : public BleClient {
public:
explicit CurrentTimeClient(DateTime& dateTimeController);
void Init();
void Reset();
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, const ble_gatt_chr* characteristic);
int OnCurrentTimeReadResult(uint16_t conn_handle, const ble_gatt_error* error, const ble_gatt_attr* attribute);
static constexpr const ble_uuid16_t* Uuid() {
return &CurrentTimeClient::ctsServiceUuid;
}
static constexpr const ble_uuid16_t* CurrentTimeCharacteristicUuid() {
return &CurrentTimeClient::currentTimeCharacteristicUuid;
}
void Discover(uint16_t connectionHandle, std::function<void(uint16_t)> lambda) override;
private:
typedef struct __attribute__((packed)) {
uint16_t year;
uint8_t month;
uint8_t dayofmonth;
uint8_t hour;
uint8_t minute;
uint8_t second;
uint8_t millis;
uint8_t reason;
} CtsData;
private:
typedef struct __attribute__((packed)) {
uint16_t year;
uint8_t month;
uint8_t dayofmonth;
uint8_t hour;
uint8_t minute;
uint8_t second;
uint8_t millis;
uint8_t reason;
} CtsData;
static constexpr uint16_t ctsServiceId {0x1805};
static constexpr uint16_t currentTimeCharacteristicId {0x2a2b};
static constexpr uint16_t ctsServiceId {0x1805};
static constexpr uint16_t currentTimeCharacteristicId {0x2a2b};
static constexpr ble_uuid16_t ctsServiceUuid {
.u { .type = BLE_UUID_TYPE_16 },
.value = ctsServiceId
};
static constexpr ble_uuid16_t currentTimeCharacteristicUuid {
.u { .type = BLE_UUID_TYPE_16 },
.value = currentTimeCharacteristicId
};
static constexpr ble_uuid16_t ctsServiceUuid {.u {.type = BLE_UUID_TYPE_16}, .value = ctsServiceId};
static constexpr ble_uuid16_t currentTimeCharacteristicUuid {.u {.type = BLE_UUID_TYPE_16}, .value = currentTimeCharacteristicId};
DateTime& dateTimeController;
bool isDiscovered = false;
uint16_t ctsStartHandle;
uint16_t ctsEndHandle;
DateTime& dateTimeController;
bool isDiscovered = false;
uint16_t ctsStartHandle;
uint16_t ctsEndHandle;
bool isCharacteristicDiscovered = false;
uint16_t currentTimeHandle;
std::function<void(uint16_t)> onServiceDiscovered;
};
}
bool isCharacteristicDiscovered = false;
uint16_t currentTimeHandle;
std::function<void(uint16_t)> onServiceDiscovered;
};
}
}

View file

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

View file

@ -12,42 +12,35 @@
namespace Pinetime {
namespace Controllers {
class CurrentTimeService {
public:
CurrentTimeService(DateTime &dateTimeController);
void Init();
public:
CurrentTimeService(DateTime& dateTimeController);
void Init();
int OnTimeAccessed(uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt);
int OnTimeAccessed(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt);
private:
static constexpr uint16_t ctsId {0x1805};
static constexpr uint16_t ctsCharId {0x2a2b};
private:
static constexpr uint16_t ctsId {0x1805};
static constexpr uint16_t ctsCharId {0x2a2b};
static constexpr ble_uuid16_t ctsUuid {
.u { .type = BLE_UUID_TYPE_16 },
.value = ctsId
};
static constexpr ble_uuid16_t ctsUuid {.u {.type = BLE_UUID_TYPE_16}, .value = ctsId};
static constexpr ble_uuid16_t ctChrUuid {
.u { .type = BLE_UUID_TYPE_16 },
.value = ctsCharId
};
static constexpr ble_uuid16_t ctChrUuid {.u {.type = BLE_UUID_TYPE_16}, .value = ctsCharId};
struct ble_gatt_chr_def characteristicDefinition[2];
struct ble_gatt_svc_def serviceDefinition[2];
struct ble_gatt_chr_def characteristicDefinition[2];
struct ble_gatt_svc_def serviceDefinition[2];
typedef struct __attribute__((packed)) {
uint16_t year;
uint8_t month;
uint8_t dayofmonth;
uint8_t hour;
uint8_t minute;
uint8_t second;
uint8_t millis;
uint8_t reason;
} CtsData;
typedef struct __attribute__((packed)) {
uint16_t year;
uint8_t month;
uint8_t dayofmonth;
uint8_t hour;
uint8_t minute;
uint8_t second;
uint8_t millis;
uint8_t reason;
} 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::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);
return deviceInformationService->OnDeviceInfoRequested(conn_handle, attr_handle, ctxt);
}
@ -25,10 +24,8 @@ void DeviceInformationService::Init() {
ASSERT(res == 0);
}
int DeviceInformationService::OnDeviceInfoRequested(uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt) {
const char *str;
int DeviceInformationService::OnDeviceInfoRequested(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) {
const char* str;
switch (ble_uuid_u16(ctxt->chr->uuid)) {
case manufacturerNameId:
@ -57,60 +54,49 @@ int DeviceInformationService::OnDeviceInfoRequested(uint16_t conn_handle, uint16
return (res == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
}
DeviceInformationService::DeviceInformationService() :
characteristicDefinition{
{
.uuid = (ble_uuid_t *) &manufacturerNameUuid,
.access_cb = DeviceInformationCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_READ,
},
{
.uuid = (ble_uuid_t *) &modelNumberUuid,
.access_cb = DeviceInformationCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_READ,
},
{
.uuid = (ble_uuid_t *) &serialNumberUuid,
.access_cb = DeviceInformationCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_READ,
},
{
.uuid = (ble_uuid_t *) &fwRevisionUuid,
.access_cb = DeviceInformationCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_READ,
},
{
.uuid = (ble_uuid_t *) &hwRevisionUuid,
.access_cb = DeviceInformationCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_READ,
},
{
.uuid = (ble_uuid_t *) &swRevisionUuid,
.access_cb = DeviceInformationCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_READ,
},
{
0
}
},
serviceDefinition{
{
/* Device Information Service */
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = (ble_uuid_t *) &deviceInfoUuid,
.characteristics = characteristicDefinition
},
{
0
},
}
{
DeviceInformationService::DeviceInformationService()
: characteristicDefinition {{
.uuid = (ble_uuid_t*) &manufacturerNameUuid,
.access_cb = DeviceInformationCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_READ,
},
{
.uuid = (ble_uuid_t*) &modelNumberUuid,
.access_cb = DeviceInformationCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_READ,
},
{
.uuid = (ble_uuid_t*) &serialNumberUuid,
.access_cb = DeviceInformationCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_READ,
},
{
.uuid = (ble_uuid_t*) &fwRevisionUuid,
.access_cb = DeviceInformationCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_READ,
},
{
.uuid = (ble_uuid_t*) &hwRevisionUuid,
.access_cb = DeviceInformationCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_READ,
},
{
.uuid = (ble_uuid_t*) &swRevisionUuid,
.access_cb = DeviceInformationCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_READ,
},
{0}},
serviceDefinition {
{/* Device Information Service */
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = (ble_uuid_t*) &deviceInfoUuid,
.characteristics = characteristicDefinition},
{0},
} {
}

View file

@ -9,69 +9,44 @@
namespace Pinetime {
namespace Controllers {
class DeviceInformationService {
public:
DeviceInformationService();
void Init();
public:
DeviceInformationService();
void Init();
int OnDeviceInfoRequested(uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt);
int OnDeviceInfoRequested(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt);
private:
static constexpr uint16_t deviceInfoId {0x180a};
static constexpr uint16_t manufacturerNameId {0x2a29};
static constexpr uint16_t modelNumberId {0x2a24};
static constexpr uint16_t serialNumberId {0x2a25};
static constexpr uint16_t fwRevisionId {0x2a26};
static constexpr uint16_t hwRevisionId {0x2a27};
static constexpr uint16_t swRevisionId {0x2a28};
private:
static constexpr uint16_t deviceInfoId {0x180a};
static constexpr uint16_t manufacturerNameId {0x2a29};
static constexpr uint16_t modelNumberId {0x2a24};
static constexpr uint16_t serialNumberId {0x2a25};
static constexpr uint16_t fwRevisionId {0x2a26};
static constexpr uint16_t hwRevisionId {0x2a27};
static constexpr uint16_t swRevisionId {0x2a28};
static constexpr const char* manufacturerName = "PINE64";
static constexpr const char* modelNumber = "PineTime";
static constexpr const char* hwRevision = "1.0.0";
static constexpr const char* serialNumber = "0";
static constexpr const char* fwRevision = Version::VersionString();
static constexpr const char* swRevision = "InfiniTime";
static constexpr const char* manufacturerName = "PINE64";
static constexpr const char* modelNumber = "PineTime";
static constexpr const char* hwRevision = "1.0.0";
static constexpr const char* serialNumber = "0";
static constexpr const char* fwRevision = Version::VersionString();
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 {
.u { .type = BLE_UUID_TYPE_16 },
.value = deviceInfoId
};
static constexpr ble_uuid16_t manufacturerNameUuid {.u {.type = BLE_UUID_TYPE_16}, .value = manufacturerNameId};
static constexpr ble_uuid16_t manufacturerNameUuid {
.u { .type = BLE_UUID_TYPE_16 },
.value = manufacturerNameId
};
static constexpr ble_uuid16_t modelNumberUuid {.u {.type = BLE_UUID_TYPE_16}, .value = modelNumberId};
static constexpr ble_uuid16_t modelNumberUuid {
.u { .type = BLE_UUID_TYPE_16 },
.value = modelNumberId
};
static constexpr ble_uuid16_t serialNumberUuid {.u {.type = BLE_UUID_TYPE_16}, .value = serialNumberId};
static constexpr ble_uuid16_t serialNumberUuid {
.u { .type = BLE_UUID_TYPE_16 },
.value = serialNumberId
};
static constexpr ble_uuid16_t fwRevisionUuid {.u {.type = BLE_UUID_TYPE_16}, .value = fwRevisionId};
static constexpr ble_uuid16_t fwRevisionUuid {
.u { .type = BLE_UUID_TYPE_16 },
.value = fwRevisionId
};
static constexpr ble_uuid16_t hwRevisionUuid {
.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_svc_def serviceDefinition[2];
static constexpr ble_uuid16_t hwRevisionUuid {.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_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::packetCharacteristicUuid;
int DfuServiceCallback(uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg) {
auto dfuService = static_cast<DfuService *>(arg);
int DfuServiceCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
auto dfuService = static_cast<DfuService*>(arg);
return dfuService->OnServiceData(conn_handle, attr_handle, ctxt);
}
void NotificationTimerCallback(TimerHandle_t xTimer) {
auto notificationManager = static_cast<DfuService::NotificationManager *>(pvTimerGetTimerID(xTimer));
auto notificationManager = static_cast<DfuService::NotificationManager*>(pvTimerGetTimerID(xTimer));
notificationManager->OnNotificationTimer();
}
void TimeoutTimerCallback(TimerHandle_t xTimer) {
auto dfuService = static_cast<DfuService *>(pvTimerGetTimerID(xTimer));
auto dfuService = static_cast<DfuService*>(pvTimerGetTimerID(xTimer));
dfuService->OnTimeout();
}
DfuService::DfuService(Pinetime::System::SystemTask &systemTask, Pinetime::Controllers::Ble &bleController,
Pinetime::Drivers::SpiNorFlash &spiNorFlash) :
systemTask{systemTask},
bleController{bleController},
dfuImage{spiNorFlash},
characteristicDefinition{
{
.uuid = (ble_uuid_t *) &packetCharacteristicUuid,
.access_cb = DfuServiceCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_WRITE_NO_RSP,
.val_handle = nullptr,
},
{
.uuid = (ble_uuid_t *) &controlPointCharacteristicUuid,
.access_cb = DfuServiceCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_NOTIFY,
.val_handle = nullptr,
},
{
.uuid = (ble_uuid_t *) &revisionCharacteristicUuid,
.access_cb = DfuServiceCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_READ,
.val_handle = &revision,
DfuService::DfuService(Pinetime::System::SystemTask& systemTask,
Pinetime::Controllers::Ble& bleController,
Pinetime::Drivers::SpiNorFlash& spiNorFlash)
: systemTask {systemTask},
bleController {bleController},
dfuImage {spiNorFlash},
characteristicDefinition {{
.uuid = (ble_uuid_t*) &packetCharacteristicUuid,
.access_cb = DfuServiceCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_WRITE_NO_RSP,
.val_handle = nullptr,
},
{
.uuid = (ble_uuid_t*) &controlPointCharacteristicUuid,
.access_cb = DfuServiceCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_NOTIFY,
.val_handle = nullptr,
},
{
.uuid = (ble_uuid_t*) &revisionCharacteristicUuid,
.access_cb = DfuServiceCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_READ,
.val_handle = &revision,
},
{
0
}
},
{0}
},
serviceDefinition{
{
/* Device Information Service */
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = (ble_uuid_t *) &serviceUuid,
.characteristics = characteristicDefinition
},
{
0
},
} {
timeoutTimer = xTimerCreate ("notificationTimer", 10000, pdFALSE, this, TimeoutTimerCallback);
},
serviceDefinition {
{/* Device Information Service */
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = (ble_uuid_t*) &serviceUuid,
.characteristics = characteristicDefinition},
{0},
} {
timeoutTimer = xTimerCreate("notificationTimer", 10000, pdFALSE, this, TimeoutTimerCallback);
}
void DfuService::Init() {
@ -83,55 +76,54 @@ void DfuService::Init() {
ASSERT(res == 0);
}
int DfuService::OnServiceData(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt *context) {
if(bleController.IsFirmwareUpdating()){
int DfuService::OnServiceData(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context) {
if (bleController.IsFirmwareUpdating()) {
xTimerStart(timeoutTimer, 0);
}
ble_gatts_find_chr((ble_uuid_t *) &serviceUuid, (ble_uuid_t *) &packetCharacteristicUuid, nullptr,
&packetCharacteristicHandle);
ble_gatts_find_chr((ble_uuid_t *) &serviceUuid, (ble_uuid_t *) &controlPointCharacteristicUuid, nullptr,
&controlPointCharacteristicHandle);
ble_gatts_find_chr((ble_uuid_t *) &serviceUuid, (ble_uuid_t *) &revisionCharacteristicUuid, nullptr,
&revisionCharacteristicHandle);
ble_gatts_find_chr((ble_uuid_t*) &serviceUuid, (ble_uuid_t*) &packetCharacteristicUuid, nullptr, &packetCharacteristicHandle);
ble_gatts_find_chr((ble_uuid_t*) &serviceUuid, (ble_uuid_t*) &controlPointCharacteristicUuid, nullptr, &controlPointCharacteristicHandle);
ble_gatts_find_chr((ble_uuid_t*) &serviceUuid, (ble_uuid_t*) &revisionCharacteristicUuid, nullptr, &revisionCharacteristicHandle);
if (attributeHandle == packetCharacteristicHandle) {
if (context->op == BLE_GATT_ACCESS_OP_WRITE_CHR)
return WritePacketHandler(connectionHandle, context->om);
else return 0;
else
return 0;
} else if (attributeHandle == controlPointCharacteristicHandle) {
if (context->op == BLE_GATT_ACCESS_OP_WRITE_CHR)
return ControlPointHandler(connectionHandle, context->om);
else return 0;
else
return 0;
} else if (attributeHandle == revisionCharacteristicHandle) {
if (context->op == BLE_GATT_ACCESS_OP_READ_CHR)
return SendDfuRevision(context->om);
else return 0;
else
return 0;
} else {
NRF_LOG_INFO("[DFU] Unknown Characteristic : %d", attributeHandle);
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));
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) {
case States::Start: {
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);
applicationSize = om->om_data[8] + (om->om_data[9] << 8) + (om->om_data[10] << 16) + (om->om_data[11] << 24);
bleController.FirmwareUpdateTotalBytes(applicationSize);
NRF_LOG_INFO("[DFU] -> Start data received : SD size : %d, BT size : %d, app size : %d", softdeviceSize,
bootloaderSize, applicationSize);
NRF_LOG_INFO(
"[DFU] -> Start data received : SD size : %d, BT size : %d, app size : %d", softdeviceSize, bootloaderSize, applicationSize);
dfuImage.Erase();
uint8_t data[]{16, 1, 1};
uint8_t data[] {16, 1, 1};
notificationManager.Send(connectionHandle, controlPointCharacteristicHandle, data, 3);
state = States::Init;
}
@ -139,19 +131,22 @@ int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf *om) {
case States::Init: {
uint16_t deviceType = om->om_data[0] + (om->om_data[1] << 8);
uint16_t deviceRevision = om->om_data[2] + (om->om_data[3] << 8);
uint32_t applicationVersion =
om->om_data[4] + (om->om_data[5] << 8) + (om->om_data[6] << 16) + (om->om_data[7] << 24);
uint32_t applicationVersion = 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 sd[softdeviceArrayLength];
for (int i = 0; i < softdeviceArrayLength; i++) {
sd[i] = om->om_data[10 + (i * 2)] + (om->om_data[10 + (i * 2) + 1] << 8);
}
expectedCrc =
om->om_data[10 + (softdeviceArrayLength * 2)] + (om->om_data[10 + (softdeviceArrayLength * 2) + 1] << 8);
expectedCrc = om->om_data[10 + (softdeviceArrayLength * 2)] + (om->om_data[10 + (softdeviceArrayLength * 2) + 1] << 8);
NRF_LOG_INFO(
"[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);
"[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);
return 0;
}
@ -163,16 +158,18 @@ int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf *om) {
bleController.FirmwareUpdateCurrentBytes(bytesReceived);
if ((nbPacketReceived % nbPacketsToNotify) == 0 && bytesReceived != applicationSize) {
uint8_t data[5]{static_cast<uint8_t>(Opcodes::PacketReceiptNotification),
(uint8_t) (bytesReceived & 0x000000FFu), (uint8_t) (bytesReceived >> 8u),
(uint8_t) (bytesReceived >> 16u), (uint8_t) (bytesReceived >> 24u)};
uint8_t data[5] {static_cast<uint8_t>(Opcodes::PacketReceiptNotification),
(uint8_t) (bytesReceived & 0x000000FFu),
(uint8_t) (bytesReceived >> 8u),
(uint8_t) (bytesReceived >> 16u),
(uint8_t) (bytesReceived >> 24u)};
NRF_LOG_INFO("[DFU] -> Send packet notification: %d bytes received", bytesReceived);
notificationManager.Send(connectionHandle, controlPointCharacteristicHandle, data, 5);
}
if (dfuImage.IsComplete()) {
uint8_t data[3]{static_cast<uint8_t>(Opcodes::Response),
static_cast<uint8_t>(Opcodes::ReceiveFirmwareImage),
static_cast<uint8_t>(ErrorCodes::NoError)};
uint8_t data[3] {static_cast<uint8_t>(Opcodes::Response),
static_cast<uint8_t>(Opcodes::ReceiveFirmwareImage),
static_cast<uint8_t>(ErrorCodes::NoError)};
NRF_LOG_INFO("[DFU] -> Send packet notification : all bytes received!");
notificationManager.Send(connectionHandle, controlPointCharacteristicHandle, data, 3);
state = States::Validate;
@ -186,7 +183,7 @@ int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf *om) {
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]);
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);
return 0;
}
}
break;
} break;
case Opcodes::InitDFUParameters: {
if (state != States::Init) {
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");
if (isInitComplete) {
uint8_t data[3] {
static_cast<uint8_t>(Opcodes::Response),
static_cast<uint8_t>(Opcodes::InitDFUParameters),
(isInitComplete ? uint8_t{1} : uint8_t{0})
};
uint8_t data[3] {static_cast<uint8_t>(Opcodes::Response),
static_cast<uint8_t>(Opcodes::InitDFUParameters),
(isInitComplete ? uint8_t {1} : uint8_t {0})};
notificationManager.AsyncSend(connectionHandle, controlPointCharacteristicHandle, data, 3);
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);
if(dfuImage.Validate()){
if (dfuImage.Validate()) {
state = States::Validated;
bleController.State(Pinetime::Controllers::Ble::FirmwareUpdateStates::Validated);
NRF_LOG_INFO("Image OK");
uint8_t data[3] {
static_cast<uint8_t>(Opcodes::Response),
static_cast<uint8_t>(Opcodes::ValidateFirmware),
static_cast<uint8_t>(ErrorCodes::NoError)
};
uint8_t data[3] {static_cast<uint8_t>(Opcodes::Response),
static_cast<uint8_t>(Opcodes::ValidateFirmware),
static_cast<uint8_t>(ErrorCodes::NoError)};
notificationManager.AsyncSend(connectionHandle, controlPointCharacteristicHandle, data, 3);
} else {
bleController.State(Pinetime::Controllers::Ble::FirmwareUpdateStates::Error);
NRF_LOG_INFO("Image Error : bad CRC");
uint8_t data[3] {
static_cast<uint8_t>(Opcodes::Response),
static_cast<uint8_t>(Opcodes::ValidateFirmware),
static_cast<uint8_t>(ErrorCodes::CrcError)
};
uint8_t data[3] {static_cast<uint8_t>(Opcodes::Response),
static_cast<uint8_t>(Opcodes::ValidateFirmware),
static_cast<uint8_t>(ErrorCodes::CrcError)};
notificationManager.AsyncSend(connectionHandle, controlPointCharacteristicHandle, data, 3);
}
@ -318,11 +308,11 @@ void DfuService::Reset() {
}
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) {
if(size != 0 || s > 10)
bool DfuService::NotificationManager::AsyncSend(uint16_t connection, uint16_t charactHandle, uint8_t* data, size_t s) {
if (size != 0 || s > 10)
return false;
connectionHandle = connection;
@ -334,14 +324,14 @@ bool DfuService::NotificationManager::AsyncSend(uint16_t connection, uint16_t ch
}
void DfuService::NotificationManager::OnNotificationTimer() {
if(size > 0) {
if (size > 0) {
Send(connectionHandle, characteristicHandle, buffer, size);
size = 0;
}
}
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);
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 ret = ble_gattc_notify_custom(connection, charactHandle, om);
ASSERT(ret == 0);
}
@ -354,27 +344,29 @@ void DfuService::NotificationManager::Reset() {
}
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->totalSize = totalSize;
this->expectedCrc = expectedCrc;
this->ready = true;
}
void DfuService::DfuImage::Append(uint8_t *data, size_t size) {
if(!ready) return;
void DfuService::DfuImage::Append(uint8_t* data, size_t size) {
if (!ready)
return;
ASSERT(size <= 20);
std::memcpy(tempBuffer + bufferWriteIndex, data, size);
bufferWriteIndex += size;
if(bufferWriteIndex == bufferSize) {
if (bufferWriteIndex == bufferSize) {
spiNorFlash.Write(writeOffset + totalWriteIndex, tempBuffer, bufferWriteIndex);
totalWriteIndex += bufferWriteIndex;
bufferWriteIndex = 0;
}
if(bufferWriteIndex > 0 && totalWriteIndex + bufferWriteIndex == totalSize) {
if (bufferWriteIndex > 0 && totalWriteIndex + bufferWriteIndex == totalSize) {
spiNorFlash.Write(writeOffset + totalWriteIndex, tempBuffer, bufferWriteIndex);
totalWriteIndex += bufferWriteIndex;
if (totalSize < maxSize)
@ -383,15 +375,16 @@ void DfuService::DfuImage::Append(uint8_t *data, size_t size) {
}
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?
0xf395c277,
0x7fefd260,
0x0f505235,
0x8079b62c,
uint32_t magic[4] = {
// TODO When this variable is a static constexpr, the values written to the memory are not correct. Why?
0xf395c277,
0x7fefd260,
0x0f505235,
0x8079b62c,
};
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() {
@ -421,7 +414,7 @@ bool DfuService::DfuImage::Validate() {
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;
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() {
if(!ready) return false;
if (!ready)
return false;
return totalWriteIndex == totalSize;
}

View file

@ -20,146 +20,139 @@ namespace Pinetime {
class Ble;
class DfuService {
public:
DfuService(Pinetime::System::SystemTask& systemTask,
Pinetime::Controllers::Ble& bleController,
Pinetime::Drivers::SpiNorFlash& spiNorFlash);
void Init();
int OnServiceData(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context);
void OnTimeout();
void Reset();
class NotificationManager {
public:
DfuService(Pinetime::System::SystemTask &systemTask, Pinetime::Controllers::Ble &bleController,
Pinetime::Drivers::SpiNorFlash &spiNorFlash);
void Init();
int OnServiceData(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt *context);
void OnTimeout();
void Reset();
class NotificationManager {
public:
NotificationManager();
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);
private:
TimerHandle_t timer;
uint16_t connectionHandle = 0;
uint16_t characteristicHandle = 0;
size_t size = 0;
uint8_t buffer[10];
public:
void OnNotificationTimer();
void Reset();
};
class DfuImage {
public:
DfuImage(Pinetime::Drivers::SpiNorFlash& spiNorFlash) : spiNorFlash{spiNorFlash} {}
void Init(size_t chunkSize, size_t totalSize, uint16_t expectedCrc);
void Erase();
void Append(uint8_t* data, size_t size);
bool Validate();
bool IsComplete();
private:
Pinetime::Drivers::SpiNorFlash& spiNorFlash;
static constexpr size_t bufferSize = 200;
bool ready = false;
size_t chunkSize = 0;
size_t totalSize = 0;
size_t maxSize = 475136;
size_t bufferWriteIndex = 0;
size_t totalWriteIndex = 0;
static constexpr size_t writeOffset = 0x40000;
uint8_t tempBuffer[bufferSize];
uint16_t expectedCrc = 0;
void WriteMagicNumber();
uint16_t ComputeCrc(uint8_t const *p_data, uint32_t size, uint16_t const *p_crc);
};
NotificationManager();
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);
private:
Pinetime::System::SystemTask &systemTask;
Pinetime::Controllers::Ble &bleController;
DfuImage dfuImage;
NotificationManager notificationManager;
TimerHandle_t timer;
uint16_t connectionHandle = 0;
uint16_t characteristicHandle = 0;
size_t size = 0;
uint8_t buffer[10];
static constexpr uint16_t dfuServiceId{0x1530};
static constexpr uint16_t packetCharacteristicId{0x1532};
static constexpr uint16_t controlPointCharacteristicId{0x1531};
static constexpr uint16_t revisionCharacteristicId{0x1534};
public:
void OnNotificationTimer();
void Reset();
};
class DfuImage {
public:
DfuImage(Pinetime::Drivers::SpiNorFlash& spiNorFlash) : spiNorFlash {spiNorFlash} {
}
void Init(size_t chunkSize, size_t totalSize, uint16_t expectedCrc);
void Erase();
void Append(uint8_t* data, size_t size);
bool Validate();
bool IsComplete();
uint16_t revision{0x0008};
static constexpr ble_uuid128_t serviceUuid{
.u {.type = BLE_UUID_TYPE_128},
.value = {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15,
0xDE, 0xEF, 0x12, 0x12, 0x30, 0x15, 0x00, 0x00}
};
static constexpr ble_uuid128_t packetCharacteristicUuid{
.u {.type = BLE_UUID_TYPE_128},
.value = {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15,
0xDE, 0xEF, 0x12, 0x12, 0x32, 0x15, 0x00, 0x00}
};
static constexpr ble_uuid128_t controlPointCharacteristicUuid{
.u {.type = BLE_UUID_TYPE_128},
.value = {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15,
0xDE, 0xEF, 0x12, 0x12, 0x31, 0x15, 0x00, 0x00}
};
static constexpr ble_uuid128_t revisionCharacteristicUuid{
.u {.type = BLE_UUID_TYPE_128},
.value = {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15,
0xDE, 0xEF, 0x12, 0x12, 0x34, 0x15, 0x00, 0x00}
};
struct ble_gatt_chr_def characteristicDefinition[4];
struct ble_gatt_svc_def serviceDefinition[2];
uint16_t packetCharacteristicHandle;
uint16_t controlPointCharacteristicHandle;
uint16_t revisionCharacteristicHandle;
enum class States : uint8_t {
Idle, Init, Start, Data, Validate, Validated
};
States state = States::Idle;
enum class ImageTypes : uint8_t {
NoImage = 0x00,
SoftDevice = 0x01,
Bootloader = 0x02,
SoftDeviceAndBootloader = 0x03,
Application = 0x04
};
enum class Opcodes : uint8_t {
StartDFU = 0x01,
InitDFUParameters = 0x02,
ReceiveFirmwareImage = 0x03,
ValidateFirmware = 0x04,
ActivateImageAndReset = 0x05,
PacketReceiptNotificationRequest = 0x08,
Response = 0x10,
PacketReceiptNotification = 0x11
};
enum class ErrorCodes {
NoError = 0x01,
InvalidState = 0x02,
NotSupported = 0x03,
DataSizeExceedsLimits = 0x04,
CrcError = 0x05,
OperationFailed = 0x06
};
uint8_t nbPacketsToNotify = 0;
uint32_t nbPacketReceived = 0;
uint32_t bytesReceived = 0;
uint32_t softdeviceSize = 0;
uint32_t bootloaderSize = 0;
uint32_t applicationSize = 0;
private:
Pinetime::Drivers::SpiNorFlash& spiNorFlash;
static constexpr size_t bufferSize = 200;
bool ready = false;
size_t chunkSize = 0;
size_t totalSize = 0;
size_t maxSize = 475136;
size_t bufferWriteIndex = 0;
size_t totalWriteIndex = 0;
static constexpr size_t writeOffset = 0x40000;
uint8_t tempBuffer[bufferSize];
uint16_t expectedCrc = 0;
int SendDfuRevision(os_mbuf *om) const;
int WritePacketHandler(uint16_t connectionHandle, os_mbuf *om);
int ControlPointHandler(uint16_t connectionHandle, os_mbuf *om);
void WriteMagicNumber();
uint16_t ComputeCrc(uint8_t const* p_data, uint32_t size, uint16_t const* p_crc);
};
TimerHandle_t timeoutTimer;
private:
Pinetime::System::SystemTask& systemTask;
Pinetime::Controllers::Ble& bleController;
DfuImage dfuImage;
NotificationManager notificationManager;
static constexpr uint16_t dfuServiceId {0x1530};
static constexpr uint16_t packetCharacteristicId {0x1532};
static constexpr uint16_t controlPointCharacteristicId {0x1531};
static constexpr uint16_t revisionCharacteristicId {0x1534};
uint16_t revision {0x0008};
static constexpr ble_uuid128_t serviceUuid {
.u {.type = BLE_UUID_TYPE_128},
.value = {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15, 0xDE, 0xEF, 0x12, 0x12, 0x30, 0x15, 0x00, 0x00}};
static constexpr ble_uuid128_t packetCharacteristicUuid {
.u {.type = BLE_UUID_TYPE_128},
.value = {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15, 0xDE, 0xEF, 0x12, 0x12, 0x32, 0x15, 0x00, 0x00}};
static constexpr ble_uuid128_t controlPointCharacteristicUuid {
.u {.type = BLE_UUID_TYPE_128},
.value = {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15, 0xDE, 0xEF, 0x12, 0x12, 0x31, 0x15, 0x00, 0x00}};
static constexpr ble_uuid128_t revisionCharacteristicUuid {
.u {.type = BLE_UUID_TYPE_128},
.value = {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15, 0xDE, 0xEF, 0x12, 0x12, 0x34, 0x15, 0x00, 0x00}};
struct ble_gatt_chr_def characteristicDefinition[4];
struct ble_gatt_svc_def serviceDefinition[2];
uint16_t packetCharacteristicHandle;
uint16_t controlPointCharacteristicHandle;
uint16_t revisionCharacteristicHandle;
enum class States : uint8_t { Idle, Init, Start, Data, Validate, Validated };
States state = States::Idle;
enum class ImageTypes : uint8_t {
NoImage = 0x00,
SoftDevice = 0x01,
Bootloader = 0x02,
SoftDeviceAndBootloader = 0x03,
Application = 0x04
};
enum class Opcodes : uint8_t {
StartDFU = 0x01,
InitDFUParameters = 0x02,
ReceiveFirmwareImage = 0x03,
ValidateFirmware = 0x04,
ActivateImageAndReset = 0x05,
PacketReceiptNotificationRequest = 0x08,
Response = 0x10,
PacketReceiptNotification = 0x11
};
enum class ErrorCodes {
NoError = 0x01,
InvalidState = 0x02,
NotSupported = 0x03,
DataSizeExceedsLimits = 0x04,
CrcError = 0x05,
OperationFailed = 0x06
};
uint8_t nbPacketsToNotify = 0;
uint32_t nbPacketReceived = 0;
uint32_t bytesReceived = 0;
uint32_t softdeviceSize = 0;
uint32_t bootloaderSize = 0;
uint32_t applicationSize = 0;
uint16_t expectedCrc = 0;
int SendDfuRevision(os_mbuf* om) const;
int WritePacketHandler(uint16_t connectionHandle, os_mbuf* om);
int ControlPointHandler(uint16_t connectionHandle, os_mbuf* om);
TimerHandle_t timeoutTimer;
};
}
}

View file

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

View file

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

View file

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

View file

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

View file

@ -18,12 +18,12 @@
#include "MusicService.h"
#include "systemtask/SystemTask.h"
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);
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);
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[15] = msId[1];
@ -87,79 +87,48 @@ Pinetime::Controllers::MusicService::MusicService(Pinetime::System::SystemTask &
msShuffleCharUuid.value[14] = msId[0];
msShuffleCharUuid.value[15] = msId[1];
characteristicDefinition[0] = {.uuid = (ble_uuid_t *) (&msEventCharUuid),
.access_cb = MSCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_NOTIFY,
.val_handle = &eventHandle
};
characteristicDefinition[1] = {.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,
.arg = this,
.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[0] = {.uuid = (ble_uuid_t*) (&msEventCharUuid),
.access_cb = MSCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_NOTIFY,
.val_handle = &eventHandle};
characteristicDefinition[1] = {
.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,
.arg = this,
.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};
serviceDefinition[0] = {
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = (ble_uuid_t *) &msUuid,
.characteristics = characteristicDefinition
};
serviceDefinition[0] = {.type = BLE_GATT_SVC_TYPE_PRIMARY, .uuid = (ble_uuid_t*) &msUuid, .characteristics = characteristicDefinition};
serviceDefinition[1] = {0};
artistName = "Waiting for";
@ -182,36 +151,35 @@ void Pinetime::Controllers::MusicService::Init() {
ASSERT(res == 0);
}
int Pinetime::Controllers::MusicService::OnCommand(uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt) {
int Pinetime::Controllers::MusicService::OnCommand(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) {
if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
size_t notifSize = OS_MBUF_PKTLEN(ctxt->om);
uint8_t data[notifSize + 1];
data[notifSize] = '\0';
os_mbuf_copydata(ctxt->om, 0, notifSize, data);
char *s = (char *) &data[0];
if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msArtistCharUuid) == 0) {
char* s = (char*) &data[0];
if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msArtistCharUuid) == 0) {
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;
} 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;
} 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];
} 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];
} 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];
} 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];
} 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];
} 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];
} 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];
} 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;
}
}
@ -239,7 +207,7 @@ float Pinetime::Controllers::MusicService::getPlaybackSpeed() {
}
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();
@ -257,4 +225,3 @@ int Pinetime::Controllers::MusicService::getProgress() {
int Pinetime::Controllers::MusicService::getTrackLength() {
return trackLength;
}

View file

@ -26,8 +26,9 @@
#undef max
#undef min
//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}
// 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 }
namespace Pinetime {
namespace System {
@ -37,12 +38,11 @@ namespace Pinetime {
class MusicService {
public:
explicit MusicService(Pinetime::System::SystemTask &system);
explicit MusicService(Pinetime::System::SystemTask& system);
void Init();
int OnCommand(uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt);
int OnCommand(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt);
void event(char event);
@ -68,10 +68,8 @@ namespace Pinetime {
static const char EVENT_MUSIC_VOLUP = 0x05;
static const char EVENT_MUSIC_VOLDOWN = 0x06;
enum MusicStatus {
NotPlaying = 0x00,
Playing = 0x01
};
enum MusicStatus { NotPlaying = 0x00, Playing = 0x01 };
private:
static constexpr uint8_t msId[2] = {0x00, 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 msShuffleCharId[2] = {0x0c, 0x00};
ble_uuid128_t msUuid{
.u = {.type = BLE_UUID_TYPE_128},
.value = MUSIC_SERVICE_UUID_BASE
};
ble_uuid128_t msUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
ble_uuid128_t msEventCharUuid{
.u = {.type = BLE_UUID_TYPE_128},
.value = MUSIC_SERVICE_UUID_BASE
};
ble_uuid128_t msStatusCharUuid{
.u = {.type = BLE_UUID_TYPE_128},
.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 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
};
ble_uuid128_t msEventCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
ble_uuid128_t msStatusCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .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 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_svc_def serviceDefinition[2];
@ -162,8 +121,7 @@ namespace Pinetime {
bool repeat;
bool shuffle;
Pinetime::System::SystemTask &m_system;
Pinetime::System::SystemTask& m_system;
};
}
}

View file

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

View file

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

View file

@ -19,36 +19,37 @@ using namespace Pinetime::Controllers;
NimbleController::NimbleController(Pinetime::System::SystemTask& systemTask,
Pinetime::Controllers::Ble& bleController,
DateTime& dateTimeController,
Pinetime::Controllers::NotificationManager& notificationManager,
Controllers::Battery& batteryController,
Pinetime::Drivers::SpiNorFlash& spiNorFlash,
Controllers::HeartRateController& heartRateController) :
systemTask{systemTask},
bleController{bleController},
dateTimeController{dateTimeController},
notificationManager{notificationManager},
spiNorFlash{spiNorFlash},
dfuService{systemTask, bleController, spiNorFlash},
currentTimeClient{dateTimeController},
anService{systemTask, notificationManager},
alertNotificationClient{systemTask, notificationManager},
currentTimeService{dateTimeController},
musicService{systemTask},
navService{systemTask},
batteryInformationService{batteryController},
immediateAlertService{systemTask, notificationManager},
heartRateService{systemTask, heartRateController},
serviceDiscovery({&currentTimeClient, &alertNotificationClient}) {
DateTime& dateTimeController,
Pinetime::Controllers::NotificationManager& notificationManager,
Controllers::Battery& batteryController,
Pinetime::Drivers::SpiNorFlash& spiNorFlash,
Controllers::HeartRateController& heartRateController)
: systemTask {systemTask},
bleController {bleController},
dateTimeController {dateTimeController},
notificationManager {notificationManager},
spiNorFlash {spiNorFlash},
dfuService {systemTask, bleController, spiNorFlash},
currentTimeClient {dateTimeController},
anService {systemTask, notificationManager},
alertNotificationClient {systemTask, notificationManager},
currentTimeService {dateTimeController},
musicService {systemTask},
navService {systemTask},
batteryInformationService {batteryController},
immediateAlertService {systemTask, notificationManager},
heartRateService {systemTask, heartRateController},
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);
return nimbleController->OnGAPEvent(event);
}
void NimbleController::Init() {
while (!ble_hs_synced()) {}
while (!ble_hs_synced()) {
}
ble_svc_gap_init();
ble_svc_gatt_init();
@ -81,7 +82,8 @@ void NimbleController::Init() {
}
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);
@ -101,29 +103,27 @@ void NimbleController::StartAdvertising() {
adv_params.conn_mode = BLE_GAP_CONN_MODE_UND;
adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN;
fields.flags = BLE_HS_ADV_F_DISC_GEN |
BLE_HS_ADV_F_BREDR_UNSUP;
// fields.uuids128 = BLE_UUID128(BLE_UUID128_DECLARE(
// 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
// 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff));
fields.flags = BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP;
// fields.uuids128 = BLE_UUID128(BLE_UUID128_DECLARE(
// 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
// 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff));
fields.uuids128 = &dfuServiceUuid;
fields.num_uuids128 = 1;
fields.uuids128_is_complete = 1;
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_is_complete = 1;
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);
// ASSERT(res == 0);
// ASSERT(res == 0);
ble_gap_adv_start(addrType, NULL, 180000,
&adv_params, GAPEventCallback, this);
// ASSERT(res == 0);// TODO I've disabled these ASSERT as they sometime asserts and reset the mcu.
ble_gap_adv_start(addrType, NULL, 180000, &adv_params, GAPEventCallback, this);
// ASSERT(res == 0);// TODO I've disabled these ASSERT as they sometime asserts and reset the mcu.
// For now, the advertising is restarted as soon as it ends. There may be a race condition
// that prevent the advertising from restarting reliably.
// I remove the assert to prevent this uncesseray crash, but in the long term, the management of
@ -131,7 +131,7 @@ void NimbleController::StartAdvertising() {
// 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) {
case 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");
/* A new connection was established or a connection attempt failed. */
NRF_LOG_INFO("connection %s; status=%d ", event->connect.status == 0 ? "established" : "failed",
event->connect.status);
NRF_LOG_INFO("connection %s; status=%d ", event->connect.status == 0 ? "established" : "failed", event->connect.status);
if (event->connect.status != 0) {
/* Connection failed; resume advertising. */
@ -154,8 +153,7 @@ int NimbleController::OnGAPEvent(ble_gap_event *event) {
connectionHandle = event->connect.conn_handle;
// Service discovery is deffered via systemtask
}
}
break;
} break;
case BLE_GAP_EVENT_DISCONNECT:
NRF_LOG_INFO("Advertising event : BLE_GAP_EVENT_DISCONNECT");
NRF_LOG_INFO("disconnect; reason=%d", event->disconnect.reason);
@ -178,19 +176,16 @@ int NimbleController::OnGAPEvent(ble_gap_event *event) {
return 0;
case BLE_GAP_EVENT_SUBSCRIBE:
NRF_LOG_INFO("subscribe event; conn_handle=%d attr_handle=%d "
"reason=%d prevn=%d curn=%d previ=%d curi=???\n",
event->subscribe.conn_handle,
event->subscribe.attr_handle,
event->subscribe.reason,
event->subscribe.prev_notify,
event->subscribe.cur_notify,
event->subscribe.prev_indicate);
"reason=%d prevn=%d curn=%d previ=%d curi=???\n",
event->subscribe.conn_handle,
event->subscribe.attr_handle,
event->subscribe.reason,
event->subscribe.prev_notify,
event->subscribe.cur_notify,
event->subscribe.prev_indicate);
return 0;
case BLE_GAP_EVENT_MTU:
NRF_LOG_INFO("mtu update event; conn_handle=%d cid=%d mtu=%d\n",
event->mtu.conn_handle,
event->mtu.channel_id,
event->mtu.value);
NRF_LOG_INFO("mtu update event; conn_handle=%d cid=%d mtu=%d\n", event->mtu.conn_handle, event->mtu.channel_id, event->mtu.value);
return 0;
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 "
"attr_len=%d",
event->notify_rx.indication ?
"indication" :
"notification",
event->notify_rx.indication ? "indication" : "notification",
event->notify_rx.conn_handle,
event->notify_rx.attr_handle,
notifSize);
@ -229,7 +222,7 @@ int NimbleController::OnGAPEvent(ble_gap_event *event) {
/* Attribute data is contained in event->notify_rx.attr_data. */
default:
// NRF_LOG_INFO("Advertising event : %d", event->type);
// NRF_LOG_INFO("Advertising event : %d", event->type);
break;
}
return 0;
@ -239,8 +232,6 @@ void NimbleController::StartDiscovery() {
serviceDiscovery.StartDiscovery(connectionHandle);
}
uint16_t NimbleController::connHandle() {
return connectionHandle;
return connectionHandle;
}

View file

@ -36,62 +36,69 @@ namespace Pinetime {
class NimbleController {
public:
NimbleController(Pinetime::System::SystemTask& systemTask, Pinetime::Controllers::Ble& bleController,
DateTime& dateTimeController, Pinetime::Controllers::NotificationManager& notificationManager,
Controllers::Battery& batteryController, Pinetime::Drivers::SpiNorFlash& spiNorFlash,
Controllers::HeartRateController& heartRateController);
void Init();
void StartAdvertising();
int OnGAPEvent(ble_gap_event *event);
public:
NimbleController(Pinetime::System::SystemTask& systemTask,
Pinetime::Controllers::Ble& bleController,
DateTime& dateTimeController,
Pinetime::Controllers::NotificationManager& notificationManager,
Controllers::Battery& batteryController,
Pinetime::Drivers::SpiNorFlash& spiNorFlash,
Controllers::HeartRateController& heartRateController);
void Init();
void StartAdvertising();
int OnGAPEvent(ble_gap_event* event);
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,
const ble_gatt_chr *characteristic);
int OnANSCharacteristicDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error *error,
const ble_gatt_chr *characteristic);
int OnCurrentTimeReadResult(uint16_t connectionHandle, const ble_gatt_error *error, ble_gatt_attr *attribute);
int OnANSDescriptorDiscoveryEventCallback(uint16_t connectionHandle, const ble_gatt_error *error,
uint16_t characteristicValueHandle, const ble_gatt_dsc *descriptor);
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, const ble_gatt_chr* characteristic);
int OnANSCharacteristicDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error* error, const ble_gatt_chr* characteristic);
int OnCurrentTimeReadResult(uint16_t connectionHandle, const ble_gatt_error* error, ble_gatt_attr* attribute);
int OnANSDescriptorDiscoveryEventCallback(uint16_t connectionHandle,
const ble_gatt_error* error,
uint16_t characteristicValueHandle,
const ble_gatt_dsc* descriptor);
void StartDiscovery();
void StartDiscovery();
Pinetime::Controllers::MusicService& music() {return musicService;};
Pinetime::Controllers::NavigationService& navigation() {return navService;};
Pinetime::Controllers::AlertNotificationService& alertService() {return anService;};
Pinetime::Controllers::MusicService& music() {
return musicService;
};
Pinetime::Controllers::NavigationService& navigation() {
return navService;
};
Pinetime::Controllers::AlertNotificationService& alertService() {
return anService;
};
uint16_t connHandle();
uint16_t connHandle();
private:
static constexpr const char* deviceName = "InfiniTime";
Pinetime::System::SystemTask& systemTask;
Pinetime::Controllers::Ble& bleController;
DateTime& dateTimeController;
Pinetime::Controllers::NotificationManager& notificationManager;
Pinetime::Drivers::SpiNorFlash& spiNorFlash;
Pinetime::Controllers::DfuService dfuService;
private:
static constexpr const char* deviceName = "InfiniTime";
Pinetime::System::SystemTask& systemTask;
Pinetime::Controllers::Ble& bleController;
DateTime& dateTimeController;
Pinetime::Controllers::NotificationManager& notificationManager;
Pinetime::Drivers::SpiNorFlash& spiNorFlash;
Pinetime::Controllers::DfuService dfuService;
DeviceInformationService deviceInformationService;
CurrentTimeClient currentTimeClient;
AlertNotificationService anService;
AlertNotificationClient alertNotificationClient;
CurrentTimeService currentTimeService;
MusicService musicService;
NavigationService navService;
BatteryInformationService batteryInformationService;
ImmediateAlertService immediateAlertService;
HeartRateService heartRateService;
DeviceInformationService deviceInformationService;
CurrentTimeClient currentTimeClient;
AlertNotificationService anService;
AlertNotificationClient alertNotificationClient;
CurrentTimeService currentTimeService;
MusicService musicService;
NavigationService navService;
BatteryInformationService batteryInformationService;
ImmediateAlertService immediateAlertService;
HeartRateService heartRateService;
uint8_t addrType; // 1 = Random, 0 = PUBLIC
uint16_t connectionHandle = 0;
uint8_t addrType; // 1 = Random, 0 = PUBLIC
uint16_t connectionHandle = 0;
ble_uuid128_t dfuServiceUuid {
.u { .type = BLE_UUID_TYPE_128},
.value = {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15,
0xDE, 0xEF, 0x12, 0x12, 0x30, 0x15, 0x00, 0x00}
};
ble_uuid128_t dfuServiceUuid {
.u {.type = BLE_UUID_TYPE_128},
.value = {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15, 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;
void NotificationManager::Push(NotificationManager::Notification &&notif) {
void NotificationManager::Push(NotificationManager::Notification&& notif) {
notif.id = GetNextId();
notif.valid = true;
notifications[writeIndex] = std::move(notif);
writeIndex = (writeIndex + 1 < TotalNbNotifications) ? writeIndex + 1 : 0;
if(!empty)
if (!empty)
readIndex = (readIndex + 1 < TotalNbNotifications) ? readIndex + 1 : 0;
else empty = false;
else
empty = false;
newNotification = true;
}
@ -30,40 +30,48 @@ NotificationManager::Notification::Id NotificationManager::GetNextId() {
}
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;});
if(currentIterator == notifications.end() || currentIterator->id != id) return Notification{};
auto currentIterator = std::find_if(notifications.begin(), notifications.end(), [id](const Notification& n) {
return n.valid && n.id == id;
});
if (currentIterator == notifications.end() || currentIterator->id != id)
return Notification {};
auto& lastNotification = notifications[readIndex];
NotificationManager::Notification result;
if(currentIterator == (notifications.end()-1))
if (currentIterator == (notifications.end() - 1))
result = *(notifications.begin());
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;
}
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;});
if(currentIterator == notifications.end() || currentIterator->id != id) return Notification{};
auto currentIterator = std::find_if(notifications.begin(), notifications.end(), [id](const Notification& n) {
return n.valid && n.id == id;
});
if (currentIterator == notifications.end() || currentIterator->id != id)
return Notification {};
auto& lastNotification = notifications[readIndex];
NotificationManager::Notification result;
if(currentIterator == notifications.begin())
result = *(notifications.end()-1);
if (currentIterator == notifications.begin())
result = *(notifications.end() - 1);
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;
}
@ -84,21 +92,23 @@ bool NotificationManager::ClearNewNotificationFlag() {
}
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* itField = std::find(message.begin(), message.begin()+size-1, '\0');
if(itField != message.begin()+size-1) {
const char* ptr = (itField)+1;
const char* itField = std::find(message.begin(), message.begin() + size - 1, '\0');
if (itField != message.begin() + size - 1) {
const char* ptr = (itField) + 1;
return ptr;
}
return const_cast<char*>(message.data());
}
const char* NotificationManager::Notification::Title() const {
const char * itField = std::find(message.begin(), message.begin()+size-1, '\0');
if(itField != message.begin()+size-1) {
const char* itField = std::find(message.begin(), message.begin() + size - 1, '\0');
if (itField != message.begin() + size - 1) {
return message.data();
}
return {};

View file

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

View file

@ -4,8 +4,7 @@
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) {
@ -16,7 +15,7 @@ void ServiceDiscovery::StartDiscovery(uint16_t connectionHandle) {
void ServiceDiscovery::OnServiceDiscovered(uint16_t connectionHandle) {
clientIterator++;
if(clientIterator != clients.end()) {
if (clientIterator != clients.end()) {
DiscoverNextService(connectionHandle);
} else {
NRF_LOG_INFO("End of service discovery");
@ -26,7 +25,7 @@ void ServiceDiscovery::OnServiceDiscovered(uint16_t connectionHandle) {
void ServiceDiscovery::DiscoverNextService(uint16_t connectionHandle) {
NRF_LOG_INFO("[Discovery] Discover next service");
auto discoverNextService = [this](uint16_t connectionHandle){
auto discoverNextService = [this](uint16_t connectionHandle) {
this->OnServiceDiscovered(connectionHandle);
};
(*clientIterator)->Discover(connectionHandle, discoverNextService);

View file

@ -8,17 +8,16 @@ namespace Pinetime {
class BleClient;
class ServiceDiscovery {
public:
ServiceDiscovery(std::array<BleClient*, 2>&& bleClients);
public:
ServiceDiscovery(std::array<BleClient*, 2>&& bleClients);
void StartDiscovery(uint16_t connectionHandle);
void StartDiscovery(uint16_t connectionHandle);
private:
BleClient** clientIterator;
std::array<BleClient*, 2> clients;
void OnServiceDiscovered(uint16_t connectionHandle);
void DiscoverNextService(uint16_t connectionHandle);
private:
BleClient** clientIterator;
std::array<BleClient*, 2> clients;
void OnServiceDiscovered(uint16_t connectionHandle);
void DiscoverNextService(uint16_t connectionHandle);
};
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -5,14 +5,15 @@
namespace Pinetime {
namespace Controllers {
class FirmwareValidator {
public:
void Validate();
bool IsValidated() const;
public:
void Validate();
bool IsValidated() const;
void Reset();
private:
static constexpr uint32_t validBitAdress {0x7BFE8};
static constexpr uint32_t validBitValue {1};
void Reset();
private:
static constexpr uint32_t validBitAdress {0x7BFE8};
static constexpr uint32_t validBitValue {1};
};
}
}

View file

@ -2,11 +2,10 @@
#include "drivers/St7789.h"
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::ClearScreen() {
@ -18,9 +17,8 @@ void Gfx::ClearScreen() {
state.action = Action::FillRectangle;
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();
}
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.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();
}
@ -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.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();
}
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)) {
// Not enough space to write even single char.
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;
uint16_t bytes_in_line = CEIL_DIV(font->charInfo[char_idx].widthBits, 8);
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 (uint8_t k = 0; k < 8; k++) {
if ((1 << (7 - k)) & font->data[font->charInfo[char_idx].offset + j]) {
buffer[(j*8)+k] = color;
}
else {
buffer[(j*8)+k] = bg;
buffer[(j * 8) + k] = color;
} else {
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.busy = true;
state.action = Action::DrawChar;
state.font = const_cast<FONT_INFO *>(font);
state.font = const_cast<FONT_INFO*>(font);
state.character = c;
state.color = color;
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();
*x += font->charInfo[char_idx].widthBits + font->spacePixels;
@ -136,13 +133,14 @@ void Gfx::Wakeup() {
}
void Gfx::SetBackgroundColor(uint16_t color) {
for(int i = 0; i < width; i++) {
for (int i = 0; i < width; i++) {
buffer[i] = color;
}
}
bool Gfx::GetNextBuffer(uint8_t **data, size_t &size) {
if(!state.busy) return false;
bool Gfx::GetNextBuffer(uint8_t** data, size_t& size) {
if (!state.busy)
return false;
state.remainingIterations--;
if (state.remainingIterations == 0) {
state.busy = false;
@ -150,27 +148,26 @@ bool Gfx::GetNextBuffer(uint8_t **data, size_t &size) {
return false;
}
if(state.action == Action::FillRectangle) {
*data = reinterpret_cast<uint8_t *>(buffer);
if (state.action == Action::FillRectangle) {
*data = reinterpret_cast<uint8_t*>(buffer);
size = width * 2;
} else if(state.action == Action::DrawChar) {
} else if (state.action == Action::DrawChar) {
uint16_t bg = 0x0000;
uint8_t char_idx = state.character - state.font->startChar;
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 (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]) {
buffer[(j*8)+k] = state.color;
}
else {
buffer[(j*8)+k] = bg;
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;
} else {
buffer[(j * 8) + k] = bg;
}
}
}
*data = reinterpret_cast<uint8_t *>(buffer);
size = bytes_in_line*8*2;
*data = reinterpret_cast<uint8_t*>(buffer);
size = bytes_in_line * 8 * 2;
}
state.currentIteration++;
@ -179,7 +176,7 @@ bool Gfx::GetNextBuffer(uint8_t **data, size_t &size) {
}
void Gfx::NotifyEndOfTransfer(TaskHandle_t task) {
if(task != nullptr) {
if (task != nullptr) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
vTaskNotifyGiveFromISR(task, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);

View file

@ -12,49 +12,48 @@ namespace Pinetime {
}
namespace Components {
class Gfx : public Pinetime::Drivers::BufferProvider {
public:
explicit Gfx(Drivers::St7789& lcd);
void Init();
void ClearScreen();
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 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 SetScrollArea(uint16_t topFixedLines, uint16_t scrollLines, uint16_t bottomFixedLines);
void SetScrollStartLine(uint16_t line);
public:
explicit Gfx(Drivers::St7789& lcd);
void Init();
void ClearScreen();
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 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 SetScrollArea(uint16_t topFixedLines, uint16_t scrollLines, uint16_t bottomFixedLines);
void SetScrollStartLine(uint16_t line);
void Sleep();
void Wakeup();
bool GetNextBuffer(uint8_t** buffer, size_t& size) override;
void pixel_draw(uint8_t x, uint8_t y, uint16_t color);
void Sleep();
void Wakeup();
bool GetNextBuffer(uint8_t **buffer, size_t &size) override;
void pixel_draw(uint8_t x, uint8_t y, uint16_t color);
private:
static constexpr uint8_t width = 240;
static constexpr uint8_t height = 240;
enum class Action { None, FillRectangle, DrawChar };
struct State {
State() : busy {false}, action {Action::None}, remainingIterations {0}, currentIteration {0} {
}
volatile bool busy;
volatile Action action;
volatile uint16_t remainingIterations;
volatile uint16_t currentIteration;
volatile FONT_INFO* font;
volatile uint16_t color;
volatile uint8_t character;
volatile TaskHandle_t taskToNotify = nullptr;
};
private:
static constexpr uint8_t width = 240;
static constexpr uint8_t height = 240;
volatile State state;
enum class Action { None, FillRectangle, DrawChar};
struct State {
State() : busy{false}, action{Action::None}, remainingIterations{0}, currentIteration{0} {}
volatile bool busy;
volatile Action action;
volatile uint16_t remainingIterations;
volatile uint16_t currentIteration;
volatile FONT_INFO *font;
volatile uint16_t color;
volatile uint8_t character;
volatile TaskHandle_t taskToNotify = nullptr;
};
uint16_t buffer[width]; // 1 line buffer
Drivers::St7789& lcd;
volatile State state;
uint16_t buffer[width]; // 1 line buffer
Drivers::St7789& lcd;
void SetBackgroundColor(uint16_t color);
void WaitTransferFinished() const;
void NotifyEndOfTransfer(TaskHandle_t task);
void SetBackgroundColor(uint16_t color);
void WaitTransferFinished() const;
void NotifyEndOfTransfer(TaskHandle_t task);
};
}
}

View file

@ -9,8 +9,7 @@
using namespace Pinetime::Controllers;
/** 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) {

View file

@ -5,7 +5,7 @@ namespace Pinetime {
/// Direct Form II Biquad Filter
class Biquad {
public:
Biquad(float b0, float b1, float b2, float a1, float a2);
Biquad(float b0, float b1, float b2, float a1, float a2);
float Step(float x);
private:

View file

@ -4,38 +4,35 @@
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) {
this->state = newState;
if(this->heartRate != heartRate) {
if (this->heartRate != heartRate) {
this->heartRate = heartRate;
service->OnNewHeartRateValue(heartRate);
}
}
void HeartRateController::Start() {
if(task != nullptr) {
if (task != nullptr) {
state = States::NotEnoughData;
task->PushMessage(Pinetime::Applications::HeartRateTask::Messages::StartMeasurement);
}
}
void HeartRateController::Stop() {
if(task != nullptr) {
if (task != nullptr) {
state = States::Stopped;
task->PushMessage(Pinetime::Applications::HeartRateTask::Messages::StopMeasurement);
}
}
void HeartRateController::SetHeartRateTask(Pinetime::Applications::HeartRateTask *task) {
void HeartRateController::SetHeartRateTask(Pinetime::Applications::HeartRateTask* task) {
this->task = task;
}
void HeartRateController::SetService(Pinetime::Controllers::HeartRateService *service) {
void HeartRateController::SetService(Pinetime::Controllers::HeartRateService* service) {
this->service = service;
}

View file

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

View file

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

View file

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

View file

@ -10,17 +10,16 @@
using namespace Pinetime::Controllers;
/** 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) {
if(std::abs(spl) > peak)
if (std::abs(spl) > peak)
peak *= boost;
else
peak *= decay;
if((spl > (peak * threshold)) || (spl < (peak * -threshold)))
if ((spl > (peak * threshold)) || (spl < (peak * -threshold)))
return 0.0f;
spl = 100.0f * spl / (2.0f * peak);

View file

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

View file

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

View file

@ -7,24 +7,26 @@ APP_TIMER_DEF(vibTimer);
using namespace Pinetime::Controllers;
MotorController::MotorController( Controllers::Settings &settingsController ) : settingsController{settingsController} {}
MotorController::MotorController(Controllers::Settings& settingsController) : settingsController {settingsController} {
}
void MotorController::Init() {
nrf_gpio_cfg_output(pinMotor);
nrf_gpio_pin_set(pinMotor);
app_timer_init();
app_timer_create(&vibTimer, APP_TIMER_MODE_SINGLE_SHOT, vibrate);
nrf_gpio_cfg_output(pinMotor);
nrf_gpio_pin_set(pinMotor);
app_timer_init();
app_timer_create(&vibTimer, APP_TIMER_MODE_SINGLE_SHOT, vibrate);
}
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);
/* Start timer for motorDuration miliseconds and timer triggers vibrate() when it finishes*/
app_timer_start(vibTimer, APP_TIMER_TICKS(motorDuration), NULL);
nrf_gpio_pin_clear(pinMotor);
/* Start timer for motorDuration miliseconds and timer triggers vibrate() when it finishes*/
app_timer_start(vibTimer, APP_TIMER_TICKS(motorDuration), NULL);
}
void MotorController::vibrate(void * p_context) {
nrf_gpio_pin_set(pinMotor);
void MotorController::vibrate(void* p_context) {
nrf_gpio_pin_set(pinMotor);
}

View file

@ -9,14 +9,14 @@ namespace Pinetime {
static constexpr uint8_t pinMotor = 16;
class MotorController {
public:
MotorController( Controllers::Settings &settingsController );
void Init();
void SetDuration(uint8_t motorDuration);
public:
MotorController(Controllers::Settings& settingsController);
void Init();
void SetDuration(uint8_t motorDuration);
private:
Controllers::Settings& settingsController;
static void vibrate(void * p_context);
private:
Controllers::Settings& settingsController;
static void vibrate(void* p_context);
};
}
}

View file

@ -2,18 +2,16 @@
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->backgroundColor = backgroundColor;
}
void RleDecoder::DecodeNext(uint8_t *output, size_t maxBytes) {
for (;encodedBufferIndex<size; encodedBufferIndex++) {
void RleDecoder::DecodeNext(uint8_t* output, size_t maxBytes) {
for (; encodedBufferIndex < size; encodedBufferIndex++) {
uint8_t rl = buffer[encodedBufferIndex] - processedCount;
while (rl) {
output[bp] = color >> 8;
@ -36,4 +34,3 @@ void RleDecoder::DecodeNext(uint8_t *output, size_t maxBytes) {
color = backgroundColor;
}
}

View file

@ -5,110 +5,107 @@
using namespace Pinetime::Controllers;
struct SettingsHeader {
uint8_t isActive; // 0xF1 = Block is active, 0xF0 = Block is inactive
uint16_t version; // Current version, to verify if the saved data is for the current Version
uint8_t isActive; // 0xF1 = Block is active, 0xF0 = Block is inactive
uint16_t version; // Current version, to verify if the saved data is for the current Version
};
#define HEADER_SIZE sizeof(SettingsHeader)
Settings::Settings( Pinetime::Drivers::SpiNorFlash &spiNorFlash ) : spiNorFlash{spiNorFlash} {}
Settings::Settings(Pinetime::Drivers::SpiNorFlash& spiNorFlash) : spiNorFlash {spiNorFlash} {
}
void Settings::Init() {
// Load default settings from Flash
LoadSettingsFromFlash();
// Load default settings from Flash
LoadSettingsFromFlash();
}
void Settings::SaveSettings() {
// verify if is necessary to save
if ( settingsChanged ) {
SaveSettingsToFlash();
}
settingsChanged = false;
// verify if is necessary to save
if (settingsChanged) {
SaveSettingsToFlash();
}
settingsChanged = false;
}
bool Settings::FindHeader() {
SettingsHeader settingsHeader;
uint8_t bufferHead[sizeof(settingsHeader)];
SettingsHeader 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) );
std::memcpy(&settingsHeader, bufferHead, sizeof(settingsHeader));
if ( settingsHeader.isActive == 0xF1 && settingsHeader.version == settingsVersion ) {
settingsFlashBlock = block;
return true;
}
spiNorFlash.Read(settingsBaseAddr + (block * 0x1000), bufferHead, sizeof(settingsHeader));
std::memcpy(&settingsHeader, bufferHead, sizeof(settingsHeader));
if (settingsHeader.isActive == 0xF1 && settingsHeader.version == settingsVersion) {
settingsFlashBlock = block;
return true;
}
return false;
}
return false;
}
void Settings::ReadSettingsData() {
uint8_t bufferSettings[sizeof(settings)];
spiNorFlash.Read( settingsBaseAddr + (settingsFlashBlock * 0x1000) + HEADER_SIZE, bufferSettings, sizeof(settings) );
std::memcpy(&settings, bufferSettings, sizeof(settings));
uint8_t bufferSettings[sizeof(settings)];
spiNorFlash.Read(settingsBaseAddr + (settingsFlashBlock * 0x1000) + HEADER_SIZE, bufferSettings, sizeof(settings));
std::memcpy(&settings, bufferSettings, sizeof(settings));
}
void Settings::EraseBlock() {
spiNorFlash.SectorErase(settingsBaseAddr + (settingsFlashBlock * 0x1000));
spiNorFlash.SectorErase(settingsBaseAddr + (settingsFlashBlock * 0x1000));
}
void Settings::SetHeader( bool state ) {
SettingsHeader settingsHeader;
uint8_t bufferHead[sizeof(settingsHeader)];
settingsHeader.isActive = state ? 0xF1 : 0xF0;
settingsHeader.version = settingsVersion;
std::memcpy(bufferHead, &settingsHeader, sizeof(settingsHeader));
spiNorFlash.Write(settingsBaseAddr + (settingsFlashBlock * 0x1000), bufferHead, sizeof(settingsHeader));
void Settings::SetHeader(bool state) {
SettingsHeader settingsHeader;
uint8_t bufferHead[sizeof(settingsHeader)];
settingsHeader.isActive = state ? 0xF1 : 0xF0;
settingsHeader.version = settingsVersion;
std::memcpy(bufferHead, &settingsHeader, sizeof(settingsHeader));
spiNorFlash.Write(settingsBaseAddr + (settingsFlashBlock * 0x1000), bufferHead, sizeof(settingsHeader));
}
void Settings::SaveSettingsData() {
uint8_t bufferSettings[sizeof(settings)];
std::memcpy(bufferSettings, &settings, sizeof(settings));
spiNorFlash.Write(settingsBaseAddr + (settingsFlashBlock * 0x1000) + HEADER_SIZE, bufferSettings, sizeof(settings));
uint8_t bufferSettings[sizeof(settings)];
std::memcpy(bufferSettings, &settings, sizeof(settings));
spiNorFlash.Write(settingsBaseAddr + (settingsFlashBlock * 0x1000) + HEADER_SIZE, bufferSettings, sizeof(settings));
}
void Settings::LoadSettingsFromFlash() {
if ( settingsFlashBlock == 99 ) {
// Find current Block, if can't find use default settings and set block to 0 ans save !
if ( FindHeader() ) {
ReadSettingsData();
} else {
SaveSettingsToFlash();
}
if (settingsFlashBlock == 99) {
// Find current Block, if can't find use default settings and set block to 0 ans save !
if (FindHeader()) {
ReadSettingsData();
} else {
// Read Settings from flash...
// never used :)
ReadSettingsData();
SaveSettingsToFlash();
}
} else {
// Read Settings from flash...
// never used :)
ReadSettingsData();
}
}
void Settings::SaveSettingsToFlash() {
// calculate where to save...
// mark current to inactive
// erase the new location and save
// set settingsFlashBlock
// calculate where to save...
// mark current to inactive
// erase the new location and save
// set settingsFlashBlock
// 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 ) {
SetHeader( false );
}
if (settingsFlashBlock != 99) {
SetHeader(false);
}
settingsFlashBlock++;
if ( settingsFlashBlock > 9 ) settingsFlashBlock = 0;
settingsFlashBlock++;
if (settingsFlashBlock > 9)
settingsFlashBlock = 0;
EraseBlock();
SetHeader( true );
SaveSettingsData();
EraseBlock();
SetHeader(true);
SaveSettingsData();
}

View file

@ -8,104 +8,129 @@
namespace Pinetime {
namespace Controllers {
class Settings {
public:
enum class ClockType {H24, H12};
enum class Vibration {ON, OFF};
enum class WakeUpMode {None, SingleTap, DoubleTap, RaiseWrist};
public:
enum class ClockType { H24, H12 };
enum class Vibration { ON, OFF };
enum class WakeUpMode { None, SingleTap, DoubleTap, RaiseWrist };
Settings( Pinetime::Drivers::SpiNorFlash &spiNorFlash );
Settings(Pinetime::Drivers::SpiNorFlash& spiNorFlash);
void Init();
void SaveSettings();
void Init();
void SaveSettings();
void SetClockFace( uint8_t face ) {
if ( face != settings.clockFace ) settingsChanged = true;
settings.clockFace = face;
};
uint8_t GetClockFace() const { return settings.clockFace; };
void SetClockFace(uint8_t face) {
if (face != settings.clockFace)
settingsChanged = true;
settings.clockFace = face;
};
uint8_t GetClockFace() const {
return settings.clockFace;
};
void SetAppMenu( uint8_t menu ) { appMenu = menu; };
uint8_t GetAppMenu() { return appMenu; };
void SetAppMenu(uint8_t menu) {
appMenu = menu;
};
uint8_t GetAppMenu() {
return appMenu;
};
void SetSettingsMenu( uint8_t menu ) { settingsMenu = menu; };
uint8_t GetSettingsMenu() const { return settingsMenu; };
void SetSettingsMenu(uint8_t menu) {
settingsMenu = menu;
};
uint8_t GetSettingsMenu() const {
return settingsMenu;
};
void SetClockType( ClockType clocktype ) {
if ( clocktype != settings.clockType ) settingsChanged = true;
settings.clockType = clocktype;
};
ClockType GetClockType() const { return settings.clockType; };
void SetClockType(ClockType clocktype) {
if (clocktype != settings.clockType)
settingsChanged = true;
settings.clockType = clocktype;
};
ClockType GetClockType() const {
return settings.clockType;
};
void SetVibrationStatus( Vibration status ) {
if ( status != settings.vibrationStatus ) settingsChanged = true;
settings.vibrationStatus = status;
};
Vibration GetVibrationStatus() const { return settings.vibrationStatus; };
void SetVibrationStatus(Vibration status) {
if (status != settings.vibrationStatus)
settingsChanged = true;
settings.vibrationStatus = status;
};
Vibration GetVibrationStatus() const {
return settings.vibrationStatus;
};
void SetScreenTimeOut( uint32_t timeout ) {
if ( timeout != settings.screenTimeOut ) settingsChanged = true;
settings.screenTimeOut = timeout;
};
uint32_t GetScreenTimeOut() const { return settings.screenTimeOut; };
void SetScreenTimeOut(uint32_t timeout) {
if (timeout != settings.screenTimeOut)
settingsChanged = true;
settings.screenTimeOut = timeout;
};
uint32_t GetScreenTimeOut() const {
return settings.screenTimeOut;
};
void setWakeUpMode( WakeUpMode wakeUp ) {
if ( wakeUp != settings.wakeUpMode ) settingsChanged = true;
settings.wakeUpMode = wakeUp;
};
WakeUpMode getWakeUpMode() const { return settings.wakeUpMode; };
void setWakeUpMode(WakeUpMode wakeUp) {
if (wakeUp != settings.wakeUpMode)
settingsChanged = true;
settings.wakeUpMode = wakeUp;
};
WakeUpMode getWakeUpMode() const {
return settings.wakeUpMode;
};
void SetBrightness( Controllers::BrightnessController::Levels level ) {
if ( level != settings.brightLevel ) settingsChanged = true;
settings.brightLevel = level;
};
Controllers::BrightnessController::Levels GetBrightness() const { return settings.brightLevel; };
void SetBrightness(Controllers::BrightnessController::Levels level) {
if (level != settings.brightLevel)
settingsChanged = true;
settings.brightLevel = level;
};
Controllers::BrightnessController::Levels GetBrightness() const {
return settings.brightLevel;
};
void SetStepsGoal( uint32_t goal ) {
if ( goal != settings.stepsGoal ) settingsChanged = true;
settings.stepsGoal = goal;
};
uint32_t GetStepsGoal() const { return settings.stepsGoal; };
void SetStepsGoal( uint32_t goal ) {
if ( goal != settings.stepsGoal )
settingsChanged = true;
settings.stepsGoal = goal;
};
private:
uint32_t GetStepsGoal() const { return settings.stepsGoal; };
Pinetime::Drivers::SpiNorFlash& spiNorFlash;
struct SettingsData {
private:
Pinetime::Drivers::SpiNorFlash& spiNorFlash;
struct SettingsData {
ClockType clockType = ClockType::H24;
Vibration vibrationStatus = Vibration::ON;
ClockType clockType = ClockType::H24;
Vibration vibrationStatus = Vibration::ON;
uint8_t clockFace = 0;
uint8_t clockFace = 0;
uint32_t stepsGoal = 10000;
uint32_t screenTimeOut = 15000;
uint32_t stepsGoal = 10000;
uint32_t screenTimeOut = 15000;
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;
bool settingsChanged = false;
SettingsData settings;
bool settingsChanged = false;
uint8_t appMenu = 0;
uint8_t settingsMenu = 0;
uint8_t appMenu = 0;
uint8_t settingsMenu = 0;
// There are 10 blocks of reserved flash to save settings
// to minimize wear, the recording is done in a rotating way by the 10 blocks
uint8_t settingsFlashBlock = 99; // default to indicate it needs to find the active block
// There are 10 blocks of reserved flash to save settings
// to minimize wear, the recording is done in a rotating way by the 10 blocks
uint8_t settingsFlashBlock = 99; // default to indicate it needs to find the active block
static constexpr uint32_t settingsBaseAddr = 0x3F6000; // Flash Settings Location
static constexpr uint16_t settingsVersion = 0x0100; // Flash Settings Version
bool FindHeader();
void ReadSettingsData();
void EraseBlock();
void SetHeader( bool state );
void SaveSettingsData();
void LoadSettingsFromFlash();
void SaveSettingsToFlash();
static constexpr uint32_t settingsBaseAddr = 0x3F6000; // Flash Settings Location
static constexpr uint16_t settingsVersion = 0x0100; // Flash Settings Version
bool FindHeader();
void ReadSettingsData();
void EraseBlock();
void SetHeader(bool state);
void SaveSettingsData();
void LoadSettingsFromFlash();
void SaveSettingsToFlash();
};
}
}

View file

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

View file

@ -42,29 +42,33 @@
using namespace Pinetime::Applications;
using namespace Pinetime::Applications::Display;
DisplayApp::DisplayApp(Drivers::St7789 &lcd, Components::LittleVgl &lvgl, Drivers::Cst816S &touchPanel,
Controllers::Battery &batteryController, Controllers::Ble &bleController,
Controllers::DateTime &dateTimeController, Drivers::WatchdogView &watchdog,
System::SystemTask &systemTask,
DisplayApp::DisplayApp(Drivers::St7789& lcd,
Components::LittleVgl& lvgl,
Drivers::Cst816S& touchPanel,
Controllers::Battery& batteryController,
Controllers::Ble& bleController,
Controllers::DateTime& dateTimeController,
Drivers::WatchdogView& watchdog,
System::SystemTask& systemTask,
Pinetime::Controllers::NotificationManager& notificationManager,
Pinetime::Controllers::HeartRateController& heartRateController,
Controllers::Settings &settingsController,
Pinetime::Controllers::MotionController& motionController) :
lcd{lcd},
lvgl{lvgl},
touchPanel{touchPanel},
batteryController{batteryController},
bleController{bleController},
dateTimeController{dateTimeController},
watchdog{watchdog},
systemTask{systemTask},
notificationManager{notificationManager},
heartRateController{heartRateController},
settingsController{settingsController},
motionController{motionController} {
Controllers::Settings& settingsController,
Pinetime::Controllers::MotionController& motionController)
: lcd {lcd},
lvgl {lvgl},
touchPanel {touchPanel},
batteryController {batteryController},
bleController {bleController},
dateTimeController {dateTimeController},
watchdog {watchdog},
systemTask {systemTask},
notificationManager {notificationManager},
heartRateController {heartRateController},
settingsController {settingsController},
motionController {motionController} {
msgQueue = xQueueCreate(queueSize, itemSize);
// Start clock when smartwatch boots
LoadApp( Apps::Clock, DisplayApp::FullRefreshDirections::None );
LoadApp(Apps::Clock, DisplayApp::FullRefreshDirections::None);
}
void DisplayApp::Start() {
@ -72,8 +76,8 @@ void DisplayApp::Start() {
APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);
}
void DisplayApp::Process(void *instance) {
auto *app = static_cast<DisplayApp *>(instance);
void DisplayApp::Process(void* instance) {
auto* app = static_cast<DisplayApp*>(instance);
NRF_LOG_INFO("displayapp task started!");
app->InitHw();
@ -114,7 +118,7 @@ void DisplayApp::Refresh() {
switch (msg) {
case Messages::GoToSleep:
brightnessController.Backup();
while(brightnessController.Level() != Controllers::BrightnessController::Levels::Off) {
while (brightnessController.Level() != Controllers::BrightnessController::Levels::Off) {
brightnessController.Lower();
vTaskDelay(100);
}
@ -129,30 +133,32 @@ void DisplayApp::Refresh() {
break;
case Messages::UpdateTimeOut:
systemTask.PushMessage(System::SystemTask::Messages::UpdateTimeOut);
break;
break;
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;
case Messages::UpdateBatteryLevel:
batteryController.Update();
break;
case Messages::NewNotification:
LoadApp( Apps::NotificationsPreview, DisplayApp::FullRefreshDirections::Down );
LoadApp(Apps::NotificationsPreview, DisplayApp::FullRefreshDirections::Down);
break;
case Messages::TouchEvent: {
if (state != States::Running) break;
if (state != States::Running)
break;
auto gesture = OnTouchEvent();
if(!currentScreen->OnTouchEvent(gesture)) {
if ( currentApp == Apps::Clock ) {
if (!currentScreen->OnTouchEvent(gesture)) {
if (currentApp == Apps::Clock) {
switch (gesture) {
case TouchEvents::SwipeUp:
LoadApp( Apps::Launcher, DisplayApp::FullRefreshDirections::Up );
LoadApp(Apps::Launcher, DisplayApp::FullRefreshDirections::Up);
break;
case TouchEvents::SwipeDown:
LoadApp( Apps::Notifications, DisplayApp::FullRefreshDirections::Down );
LoadApp(Apps::Notifications, DisplayApp::FullRefreshDirections::Down);
break;
case TouchEvents::SwipeRight:
LoadApp( Apps::QuickSettings, DisplayApp::FullRefreshDirections::RightAnim );
LoadApp(Apps::QuickSettings, DisplayApp::FullRefreshDirections::RightAnim);
break;
case TouchEvents::DoubleTap:
systemTask.PushMessage(System::SystemTask::Messages::GoToSleep);
@ -160,36 +166,35 @@ void DisplayApp::Refresh() {
default:
break;
}
} else if ( returnTouchEvent == gesture ) {
LoadApp( returnToApp, returnDirection );
} else if (returnTouchEvent == gesture) {
LoadApp(returnToApp, returnDirection);
}
}
}
break;
} break;
case Messages::ButtonPushed:
if( currentApp == Apps::Clock ) {
if (currentApp == Apps::Clock) {
systemTask.PushMessage(System::SystemTask::Messages::GoToSleep);
} else {
if ( !currentScreen->OnButtonPushed() ) {
LoadApp( returnToApp, returnDirection );
if (!currentScreen->OnButtonPushed()) {
LoadApp(returnToApp, returnDirection);
}
}
break;
case Messages::BleFirmwareUpdateStarted:
LoadApp( Apps::FirmwareUpdate, DisplayApp::FullRefreshDirections::Down );
LoadApp(Apps::FirmwareUpdate, DisplayApp::FullRefreshDirections::Down);
break;
case Messages::UpdateDateTime:
// Added to remove warning
// What should happen here?
break;
case Messages::UpdateDateTime:
// Added to remove warning
// What should happen here?
break;
}
}
if(state != States::Idle && touchMode == TouchModes::Polling) {
if (state != States::Idle && touchMode == TouchModes::Polling) {
auto info = touchPanel.GetTouchInfo();
if(info.action == 2) {// 2 = contact
if(!currentScreen->OnTouchEvent(info.x, info.y)) {
if (info.action == 2) { // 2 = contact
if (!currentScreen->OnTouchEvent(info.x, info.y)) {
lvgl.SetNewTapEvent(info.x, info.y);
}
}
@ -197,14 +202,14 @@ void DisplayApp::Refresh() {
}
void DisplayApp::RunningState() {
if(!currentScreen->Refresh()) {
LoadApp( returnToApp, returnDirection );
if (!currentScreen->Refresh()) {
LoadApp(returnToApp, returnDirection);
}
lv_task_handler();
}
void DisplayApp::StartApp(Apps app, DisplayApp::FullRefreshDirections direction) {
LoadApp( app, direction );
LoadApp(app, direction);
}
void DisplayApp::returnApp(Apps app, DisplayApp::FullRefreshDirections direction, TouchEvents touchEvent) {
@ -215,19 +220,26 @@ void DisplayApp::returnApp(Apps app, DisplayApp::FullRefreshDirections direction
void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction) {
currentScreen.reset(nullptr);
SetFullRefresh( direction );
SetFullRefresh(direction);
// default return to launcher
returnApp(Apps::Launcher, FullRefreshDirections::Down, TouchEvents::SwipeDown);
switch(app) {
switch (app) {
case Apps::Launcher:
currentScreen = std::make_unique<Screens::ApplicationList>(this, settingsController, batteryController, dateTimeController);
returnApp(Apps::Clock, FullRefreshDirections::Down, TouchEvents::SwipeDown);
break;
case Apps::None:
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;
case Apps::FirmwareValidation:
@ -239,17 +251,20 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction)
break;
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);
break;
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);
break;
// Settings
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);
break;
case Apps::Settings:
@ -281,10 +296,11 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction)
returnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
break;
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);
break;
//
//
case Apps::FlashLight:
currentScreen = std::make_unique<Screens::FlashLight>(this, systemTask, brightnessController);
@ -322,7 +338,6 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction)
}
void DisplayApp::IdleState() {
}
void DisplayApp::PushMessage(Messages msg) {
@ -337,10 +352,10 @@ void DisplayApp::PushMessage(Messages msg) {
TouchEvents DisplayApp::OnTouchEvent() {
auto info = touchPanel.GetTouchInfo();
if(info.isTouch) {
switch(info.gesture) {
if (info.isTouch) {
switch (info.gesture) {
case Pinetime::Drivers::Cst816S::Gestures::SingleTap:
if(touchMode == TouchModes::Gestures)
if (touchMode == TouchModes::Gestures)
lvgl.SetNewTapEvent(info.x, info.y);
return TouchEvents::Tap;
case Pinetime::Drivers::Cst816S::Gestures::LongPress:
@ -364,7 +379,7 @@ TouchEvents DisplayApp::OnTouchEvent() {
}
void DisplayApp::SetFullRefresh(DisplayApp::FullRefreshDirections direction) {
switch(direction){
switch (direction) {
case DisplayApp::FullRefreshDirections::Down:
lvgl.SetFullRefresh(Components::LittleVgl::FullRefreshDirections::Down);
break;
@ -383,11 +398,11 @@ void DisplayApp::SetFullRefresh(DisplayApp::FullRefreshDirections direction) {
case DisplayApp::FullRefreshDirections::RightAnim:
lvgl.SetFullRefresh(Components::LittleVgl::FullRefreshDirections::RightAnim);
break;
default: break;
default:
break;
}
}
void DisplayApp::SetTouchMode(DisplayApp::TouchModes mode) {
touchMode = mode;
}

View file

@ -35,74 +35,73 @@ namespace Pinetime {
};
namespace Applications {
class DisplayApp {
public:
enum class States {Idle, Running};
enum class FullRefreshDirections { None, Up, Down, Left, Right, LeftAnim, RightAnim };
enum class TouchModes { Gestures, Polling };
public:
enum class States { Idle, Running };
enum class FullRefreshDirections { None, Up, Down, Left, Right, LeftAnim, RightAnim };
enum class TouchModes { Gestures, Polling };
DisplayApp(Drivers::St7789 &lcd, Components::LittleVgl &lvgl, Drivers::Cst816S &,
Controllers::Battery &batteryController, Controllers::Ble &bleController,
Controllers::DateTime &dateTimeController, Drivers::WatchdogView &watchdog,
System::SystemTask &systemTask,
Pinetime::Controllers::NotificationManager& notificationManager,
Pinetime::Controllers::HeartRateController& heartRateController,
Controllers::Settings &settingsController,
Pinetime::Controllers::MotionController& motionController
);
void Start();
void PushMessage(Display::Messages msg);
DisplayApp(Drivers::St7789& lcd,
Components::LittleVgl& lvgl,
Drivers::Cst816S&,
Controllers::Battery& batteryController,
Controllers::Ble& bleController,
Controllers::DateTime& dateTimeController,
Drivers::WatchdogView& watchdog,
System::SystemTask& systemTask,
Pinetime::Controllers::NotificationManager& notificationManager,
Pinetime::Controllers::HeartRateController& heartRateController,
Controllers::Settings& settingsController,
Pinetime::Controllers::MotionController& motionController);
void Start();
void PushMessage(Display::Messages msg);
void StartApp(Apps app, DisplayApp::FullRefreshDirections direction);
void StartApp(Apps app, DisplayApp::FullRefreshDirections direction);
void SetFullRefresh(FullRefreshDirections direction);
void SetTouchMode(TouchModes mode);
void SetFullRefresh(FullRefreshDirections direction);
void SetTouchMode(TouchModes mode);
private:
private:
Pinetime::Drivers::St7789& lcd;
Pinetime::Components::LittleVgl& lvgl;
Pinetime::Drivers::Cst816S& touchPanel;
Pinetime::Controllers::Battery& batteryController;
Pinetime::Controllers::Ble& bleController;
Pinetime::Controllers::DateTime& dateTimeController;
Pinetime::Drivers::WatchdogView& watchdog;
Pinetime::System::SystemTask& systemTask;
Pinetime::Controllers::NotificationManager& notificationManager;
Pinetime::Controllers::HeartRateController& heartRateController;
Pinetime::Controllers::Settings& settingsController;
Pinetime::Controllers::MotionController& motionController;
Pinetime::Drivers::St7789& lcd;
Pinetime::Components::LittleVgl& lvgl;
Pinetime::Drivers::Cst816S& touchPanel;
Pinetime::Controllers::Battery &batteryController;
Pinetime::Controllers::Ble &bleController;
Pinetime::Controllers::DateTime& dateTimeController;
Pinetime::Drivers::WatchdogView& watchdog;
Pinetime::System::SystemTask& systemTask;
Pinetime::Controllers::NotificationManager& notificationManager;
Pinetime::Controllers::HeartRateController& heartRateController;
Pinetime::Controllers::Settings& settingsController;
Pinetime::Controllers::MotionController& motionController;
Pinetime::Controllers::FirmwareValidator validator;
Controllers::BrightnessController brightnessController;
Pinetime::Controllers::FirmwareValidator validator;
Controllers::BrightnessController brightnessController;
TaskHandle_t taskHandle;
TaskHandle_t taskHandle;
States state = States::Running;
QueueHandle_t msgQueue;
States state = States::Running;
QueueHandle_t msgQueue;
static constexpr uint8_t queueSize = 10;
static constexpr uint8_t itemSize = 1;
static constexpr uint8_t queueSize = 10;
static constexpr uint8_t itemSize = 1;
std::unique_ptr<Screens::Screen> currentScreen;
std::unique_ptr<Screens::Screen> currentScreen;
Apps currentApp = Apps::None;
Apps returnToApp = Apps::None;
FullRefreshDirections returnDirection = FullRefreshDirections::None;
TouchEvents returnTouchEvent = TouchEvents::None;
Apps currentApp = Apps::None;
Apps returnToApp = Apps::None;
FullRefreshDirections returnDirection = FullRefreshDirections::None;
TouchEvents returnTouchEvent = TouchEvents::None;
TouchModes touchMode = TouchModes::Gestures;
TouchEvents OnTouchEvent();
void RunningState();
void IdleState();
static void Process(void* instance);
void InitHw();
void Refresh();
void returnApp(Apps app, DisplayApp::FullRefreshDirections direction, TouchEvents touchEvent);
void LoadApp(Apps app, DisplayApp::FullRefreshDirections direction);
TouchModes touchMode = TouchModes::Gestures;
TouchEvents OnTouchEvent();
void RunningState();
void IdleState();
static void Process(void* instance);
void InitHw();
void Refresh();
void returnApp(Apps app, DisplayApp::FullRefreshDirections direction, TouchEvents touchEvent);
void LoadApp(Apps app, DisplayApp::FullRefreshDirections direction);
};
}
}

View file

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

View file

@ -9,22 +9,25 @@
namespace Pinetime {
namespace Components {
class LittleVgl {
public:
enum class FullRefreshDirections { None, Up, Down };
LittleVgl(Pinetime::Drivers::St7789& lcd, Pinetime::Drivers::Cst816S& touchPanel) {}
LittleVgl(const LittleVgl&) = delete;
LittleVgl& operator=(const LittleVgl&) = delete;
LittleVgl(LittleVgl&&) = delete;
LittleVgl& operator=(LittleVgl&&) = delete;
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) {}
void SetNewTapEvent(uint16_t x, uint16_t y) {}
public:
enum class FullRefreshDirections { None, Up, Down };
LittleVgl(Pinetime::Drivers::St7789& lcd, Pinetime::Drivers::Cst816S& touchPanel) {
}
LittleVgl(const LittleVgl&) = delete;
LittleVgl& operator=(const LittleVgl&) = delete;
LittleVgl(LittleVgl&&) = delete;
LittleVgl& operator=(LittleVgl&&) = delete;
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) {
}
void SetNewTapEvent(uint16_t x, uint16_t y) {
}
};
}
}

View file

@ -11,17 +11,18 @@ using namespace Pinetime::Components;
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);
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);
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();
InitTheme();
InitDisplay();
@ -29,8 +30,8 @@ LittleVgl::LittleVgl(Pinetime::Drivers::St7789& lcd, Pinetime::Drivers::Cst816S&
}
void LittleVgl::InitDisplay() {
lv_disp_buf_init(&disp_buf_2, buf2_1, buf2_2, LV_HOR_RES_MAX * 4); /*Initialize the display buffer*/
lv_disp_drv_init(&disp_drv); /*Basic initialization*/
lv_disp_buf_init(&disp_buf_2, buf2_1, buf2_2, LV_HOR_RES_MAX * 4); /*Initialize the display buffer*/
lv_disp_drv_init(&disp_drv); /*Basic initialization*/
/*Set up the functions to access to your display*/
@ -59,7 +60,7 @@ void LittleVgl::InitTouchpad() {
}
void LittleVgl::SetFullRefresh(FullRefreshDirections direction) {
if(scrollDirection == FullRefreshDirections::None) {
if (scrollDirection == FullRefreshDirections::None) {
scrollDirection = direction;
if (scrollDirection == FullRefreshDirections::Down) {
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;
ulTaskNotifyTake(pdTRUE, 200);
// 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.
if( (scrollDirection == LittleVgl::FullRefreshDirections::Down) && (area->y2 == visibleNbLines - 1)) {
if ((scrollDirection == LittleVgl::FullRefreshDirections::Down) && (area->y2 == visibleNbLines - 1)) {
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;
}
@ -94,11 +95,11 @@ void LittleVgl::FlushDisplay(const lv_area_t *area, lv_color_t *color_p) {
width = (area->x2 - area->x1) + 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;
if(area->y1 == 0) {
if (area->y1 == 0) {
toScroll = height * 2;
scrollDirection = FullRefreshDirections::None;
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;
}
if(scrollOffset >= toScroll)
if (scrollOffset >= toScroll)
scrollOffset -= toScroll;
else {
toScroll -= scrollOffset;
scrollOffset = (totalNbLines) - toScroll;
scrollOffset = (totalNbLines) -toScroll;
}
lcd.VerticalScrollStartAddress(scrollOffset);
}
} else if(scrollDirection == FullRefreshDirections::Up) {
} else if (scrollDirection == FullRefreshDirections::Up) {
if(area->y1 > 0) {
if(area->y2 == visibleNbLines - 1) {
if (area->y1 > 0) {
if (area->y2 == visibleNbLines - 1) {
scrollOffset += (height * 2);
scrollDirection = FullRefreshDirections::None;
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;
lcd.VerticalScrollStartAddress(scrollOffset);
}
} else if(scrollDirection == FullRefreshDirections::Left or scrollDirection == FullRefreshDirections::LeftAnim) {
if(area->x2 == visibleNbLines - 1) {
} else if (scrollDirection == FullRefreshDirections::Left or scrollDirection == FullRefreshDirections::LeftAnim) {
if (area->x2 == visibleNbLines - 1) {
scrollDirection = FullRefreshDirections::None;
lv_disp_set_direction(lv_disp_get_default(), 0);
}
} else if(scrollDirection == FullRefreshDirections::Right or scrollDirection == FullRefreshDirections::RightAnim) {
if(area->x1 == 0) {
} else if (scrollDirection == FullRefreshDirections::Right or scrollDirection == FullRefreshDirections::RightAnim) {
if (area->x1 == 0) {
scrollDirection = FullRefreshDirections::None;
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) {
height = totalNbLines - y1;
if ( height > 0 ) {
lcd.DrawBuffer(area->x1, y1, width, height, reinterpret_cast<const uint8_t *>(color_p), width * height * 2);
if (height > 0) {
lcd.DrawBuffer(area->x1, y1, width, height, reinterpret_cast<const uint8_t*>(color_p), width * height * 2);
ulTaskNotifyTake(pdTRUE, 100);
}
uint16_t pixOffset = width * height;
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 {
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!!!
@ -167,8 +168,8 @@ void LittleVgl::SetNewTapEvent(uint16_t x, uint16_t y) {
tapped = true;
}
bool LittleVgl::GetTouchPadInfo(lv_indev_data_t *ptr) {
if(tapped) {
bool LittleVgl::GetTouchPadInfo(lv_indev_data_t* ptr) {
if (tapped) {
ptr->point.x = tap_x;
ptr->point.y = tap_y;
ptr->state = LV_INDEV_STATE_PR;
@ -202,14 +203,8 @@ bool LittleVgl::GetTouchPadInfo(lv_indev_data_t *ptr) {
void LittleVgl::InitTheme() {
lv_theme_t * th = lv_pinetime_theme_init(
LV_COLOR_WHITE, LV_COLOR_SILVER,
0,
&jetbrains_mono_bold_20,
&jetbrains_mono_bold_20,
&jetbrains_mono_bold_20,
&jetbrains_mono_bold_20);
lv_theme_t* th = lv_pinetime_theme_init(
LV_COLOR_WHITE, LV_COLOR_SILVER, 0, &jetbrains_mono_bold_20, &jetbrains_mono_bold_20, &jetbrains_mono_bold_20, &jetbrains_mono_bold_20);
lv_theme_set_act(th);
}

View file

@ -10,50 +10,49 @@ namespace Pinetime {
namespace Components {
class LittleVgl {
public:
enum class FullRefreshDirections { None, Up, Down, Left, Right, LeftAnim, RightAnim };
LittleVgl(Pinetime::Drivers::St7789& lcd, Pinetime::Drivers::Cst816S& touchPanel);
public:
enum class FullRefreshDirections { None, Up, Down, Left, Right, LeftAnim, RightAnim };
LittleVgl(Pinetime::Drivers::St7789& lcd, Pinetime::Drivers::Cst816S& touchPanel);
LittleVgl(const LittleVgl&) = delete;
LittleVgl& operator=(const LittleVgl&) = delete;
LittleVgl(LittleVgl&&) = delete;
LittleVgl& operator=(LittleVgl&&) = delete;
LittleVgl(const LittleVgl&) = delete;
LittleVgl& operator=(const LittleVgl&) = delete;
LittleVgl(LittleVgl&&) = delete;
LittleVgl& operator=(LittleVgl&&) = delete;
void FlushDisplay(const lv_area_t * area, lv_color_t * color_p);
bool GetTouchPadInfo(lv_indev_data_t *ptr);
void SetFullRefresh(FullRefreshDirections direction);
void SetNewTapEvent(uint16_t x, uint16_t y);
void FlushDisplay(const lv_area_t* area, lv_color_t* color_p);
bool GetTouchPadInfo(lv_indev_data_t* ptr);
void SetFullRefresh(FullRefreshDirections direction);
void SetNewTapEvent(uint16_t x, uint16_t y);
private:
void InitDisplay();
void InitTouchpad();
void InitTheme();
private:
void InitDisplay();
void InitTouchpad();
void InitTheme();
Pinetime::Drivers::St7789& lcd;
Pinetime::Drivers::Cst816S& touchPanel;
Pinetime::Drivers::St7789& lcd;
Pinetime::Drivers::Cst816S& touchPanel;
lv_disp_buf_t disp_buf_2;
lv_color_t buf2_1[LV_HOR_RES_MAX * 4];
lv_color_t buf2_2[LV_HOR_RES_MAX * 4];
lv_disp_drv_t disp_drv;
lv_point_t previousClick;
lv_disp_buf_t disp_buf_2;
lv_color_t buf2_1[LV_HOR_RES_MAX * 4];
lv_color_t buf2_2[LV_HOR_RES_MAX * 4];
bool firstTouch = true;
static constexpr uint8_t nbWriteLines = 4;
static constexpr uint16_t totalNbLines = 320;
static constexpr uint16_t visibleNbLines = 240;
static constexpr uint8_t MaxScrollOffset() {
return LV_VER_RES_MAX - nbWriteLines;
}
FullRefreshDirections scrollDirection = FullRefreshDirections::None;
uint16_t writeOffset = 0;
uint16_t scrollOffset = 0;
lv_disp_drv_t disp_drv;
lv_point_t previousClick;
bool firstTouch = true;
static constexpr uint8_t nbWriteLines = 4;
static constexpr uint16_t totalNbLines = 320;
static constexpr uint16_t visibleNbLines = 240;
static constexpr uint8_t MaxScrollOffset() { return LV_VER_RES_MAX - nbWriteLines; }
FullRefreshDirections scrollDirection = FullRefreshDirections::None;
uint16_t writeOffset = 0;
uint16_t scrollOffset = 0;
uint16_t tap_x = 0;
uint16_t tap_y = 0;
bool tapped = false;
uint16_t tap_x = 0;
uint16_t tap_y = 0;
bool tapped = false;
};
}
}

View file

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

View file

@ -3,6 +3,6 @@
namespace Pinetime {
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 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
@ -67,244 +67,240 @@ static bool inited;
* STATIC FUNCTIONS
**********************/
static void style_init_reset(lv_style_t * style)
{
if(inited) lv_style_reset(style);
else lv_style_init(style);
static void style_init_reset(lv_style_t* style) {
if (inited)
lv_style_reset(style);
else
lv_style_init(style);
}
static void basic_init(void) {
static void basic_init(void)
{
style_init_reset(&style_pad);
lv_style_set_pad_top(&style_pad, LV_STATE_DEFAULT, LV_VER_RES / 30);
lv_style_set_pad_bottom(&style_pad, LV_STATE_DEFAULT, LV_VER_RES / 30);
lv_style_set_pad_left(&style_pad, LV_STATE_DEFAULT, LV_VER_RES / 40);
lv_style_set_pad_right(&style_pad, LV_STATE_DEFAULT, LV_VER_RES / 40);
style_init_reset(&style_pad);
lv_style_set_pad_top(&style_pad, LV_STATE_DEFAULT, LV_VER_RES / 30);
lv_style_set_pad_bottom(&style_pad, LV_STATE_DEFAULT, LV_VER_RES / 30);
lv_style_set_pad_left(&style_pad, LV_STATE_DEFAULT, LV_VER_RES / 40);
lv_style_set_pad_right(&style_pad, LV_STATE_DEFAULT, LV_VER_RES / 40);
style_init_reset(&style_circle);
lv_style_set_radius(&style_circle, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
style_init_reset(&style_circle);
lv_style_set_radius(&style_circle, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
style_init_reset(&style_bg);
lv_style_set_bg_opa(&style_bg, LV_STATE_DEFAULT, LV_OPA_COVER);
lv_style_set_bg_color(&style_bg, LV_STATE_DEFAULT, LV_COLOR_BLACK);
lv_style_set_text_font(&style_bg, LV_STATE_DEFAULT, theme.font_normal);
style_init_reset(&style_bg);
lv_style_set_bg_opa(&style_bg, LV_STATE_DEFAULT, LV_OPA_COVER);
lv_style_set_bg_color(&style_bg, LV_STATE_DEFAULT, LV_COLOR_BLACK);
lv_style_set_text_font(&style_bg, LV_STATE_DEFAULT, theme.font_normal);
style_init_reset(&style_box);
lv_style_set_bg_opa(&style_box, LV_STATE_DEFAULT, LV_OPA_COVER);
lv_style_set_radius(&style_box, LV_STATE_DEFAULT, 10);
lv_style_set_value_color(&style_box, LV_STATE_DEFAULT, LV_PINETIME_BLUE);
lv_style_set_value_font(&style_box, LV_STATE_DEFAULT, theme.font_normal);
style_init_reset(&style_box);
lv_style_set_bg_opa(&style_box, LV_STATE_DEFAULT, LV_OPA_COVER);
lv_style_set_radius(&style_box, LV_STATE_DEFAULT, 10);
lv_style_set_value_color(&style_box, LV_STATE_DEFAULT, LV_PINETIME_BLUE);
lv_style_set_value_font(&style_box, LV_STATE_DEFAULT, theme.font_normal);
style_init_reset(&style_box_border);
lv_style_set_bg_opa(&style_box_border, LV_STATE_DEFAULT, LV_OPA_TRANSP);
lv_style_set_border_width(&style_box_border, LV_STATE_DEFAULT, 2);
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);
style_init_reset(&style_box_border);
lv_style_set_bg_opa(&style_box_border, LV_STATE_DEFAULT, LV_OPA_TRANSP);
lv_style_set_border_width(&style_box_border, LV_STATE_DEFAULT, 2);
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);
style_init_reset(&style_title);
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);
style_init_reset(&style_label_white);
lv_style_set_text_color(&style_label_white, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
style_init_reset(&style_title);
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);
style_init_reset(&style_btn);
lv_style_set_radius(&style_btn, LV_STATE_DEFAULT, 10);
lv_style_set_bg_opa(&style_btn, LV_STATE_DEFAULT, LV_OPA_COVER);
lv_style_set_bg_color(&style_btn, LV_STATE_DEFAULT, lv_color_hex(0x2F3540));
lv_style_set_bg_color(&style_btn, LV_STATE_CHECKED, LV_COLOR_GREEN);
lv_style_set_bg_color(&style_btn, LV_STATE_DISABLED, lv_color_hex(0x2F3540));
lv_style_set_bg_color(&style_btn, LV_STATE_DISABLED | LV_STATE_CHECKED, lv_color_hex3(0x888));
lv_style_set_border_color(&style_btn, LV_STATE_DEFAULT, theme.color_primary);
lv_style_set_border_width(&style_btn, LV_STATE_DEFAULT, 0);
lv_style_set_border_opa(&style_btn, LV_STATE_CHECKED, LV_OPA_TRANSP);
style_init_reset(&style_label_white);
lv_style_set_text_color(&style_label_white, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
lv_style_set_text_color(&style_btn, LV_STATE_DEFAULT, lv_color_hex(0xffffff));
lv_style_set_text_color(&style_btn, LV_STATE_CHECKED, lv_color_hex(0xffffff));
lv_style_set_text_color(&style_btn, LV_STATE_CHECKED, lv_color_hex(0xffffff));
lv_style_set_text_color(&style_btn, LV_STATE_DISABLED, lv_color_hex(0x888888));
style_init_reset(&style_btn);
lv_style_set_radius(&style_btn, LV_STATE_DEFAULT, 10);
lv_style_set_bg_opa(&style_btn, LV_STATE_DEFAULT, LV_OPA_COVER);
lv_style_set_bg_color(&style_btn, LV_STATE_DEFAULT, lv_color_hex(0x2F3540));
lv_style_set_bg_color(&style_btn, LV_STATE_CHECKED, LV_COLOR_GREEN);
lv_style_set_bg_color(&style_btn, LV_STATE_DISABLED, lv_color_hex(0x2F3540));
lv_style_set_bg_color(&style_btn, LV_STATE_DISABLED | LV_STATE_CHECKED, lv_color_hex3(0x888));
lv_style_set_border_color(&style_btn, LV_STATE_DEFAULT, theme.color_primary);
lv_style_set_border_width(&style_btn, LV_STATE_DEFAULT, 0);
lv_style_set_border_opa(&style_btn, LV_STATE_CHECKED, LV_OPA_TRANSP);
lv_style_set_value_color(&style_btn, LV_STATE_DEFAULT, lv_color_hex(0xffffff));
lv_style_set_value_color(&style_btn, LV_STATE_CHECKED, lv_color_hex(0xffffff));
lv_style_set_value_color(&style_btn, LV_STATE_CHECKED, lv_color_hex(0xffffff));
lv_style_set_value_color(&style_btn, LV_STATE_DISABLED, lv_color_hex(0x888888));
lv_style_set_text_color(&style_btn, LV_STATE_DEFAULT, lv_color_hex(0xffffff));
lv_style_set_text_color(&style_btn, LV_STATE_CHECKED, lv_color_hex(0xffffff));
lv_style_set_text_color(&style_btn, LV_STATE_CHECKED, lv_color_hex(0xffffff));
lv_style_set_text_color(&style_btn, LV_STATE_DISABLED, lv_color_hex(0x888888));
lv_style_set_pad_left(&style_btn, LV_STATE_DEFAULT, LV_DPX(20));
lv_style_set_pad_right(&style_btn, LV_STATE_DEFAULT, LV_DPX(20));
lv_style_set_pad_top(&style_btn, LV_STATE_DEFAULT, LV_DPX(20));
lv_style_set_pad_bottom(&style_btn, LV_STATE_DEFAULT, LV_DPX(20));
lv_style_set_pad_inner(&style_btn, LV_STATE_DEFAULT, LV_DPX(15));
lv_style_set_outline_width(&style_btn, LV_STATE_DEFAULT, LV_DPX(2));
lv_style_set_outline_opa(&style_btn, LV_STATE_DEFAULT, LV_OPA_0);
lv_style_set_outline_color(&style_btn, LV_STATE_DEFAULT, theme.color_primary);
lv_style_set_transition_time(&style_btn, LV_STATE_DEFAULT, 0);
lv_style_set_transition_delay(&style_btn, LV_STATE_DEFAULT, 0);
lv_style_set_value_color(&style_btn, LV_STATE_DEFAULT, lv_color_hex(0xffffff));
lv_style_set_value_color(&style_btn, LV_STATE_CHECKED, lv_color_hex(0xffffff));
lv_style_set_value_color(&style_btn, LV_STATE_CHECKED, lv_color_hex(0xffffff));
lv_style_set_value_color(&style_btn, LV_STATE_DISABLED, lv_color_hex(0x888888));
style_init_reset(&style_btn_border);
lv_style_set_radius(&style_btn_border, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
lv_style_set_border_color(&style_btn_border, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
lv_style_set_border_width(&style_btn_border, LV_STATE_DEFAULT, 2);
lv_style_set_bg_opa(&style_btn_border, LV_STATE_DEFAULT, LV_OPA_TRANSP);
lv_style_set_bg_color(&style_btn_border, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
lv_style_set_text_color(&style_btn_border, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
lv_style_set_value_color(&style_btn_border, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
lv_style_set_transition_prop_3(&style_btn_border, LV_STATE_DEFAULT, LV_STYLE_BG_OPA);
lv_style_set_pad_left(&style_btn, LV_STATE_DEFAULT, LV_DPX(20));
lv_style_set_pad_right(&style_btn, LV_STATE_DEFAULT, LV_DPX(20));
lv_style_set_pad_top(&style_btn, LV_STATE_DEFAULT, LV_DPX(20));
lv_style_set_pad_bottom(&style_btn, LV_STATE_DEFAULT, LV_DPX(20));
lv_style_set_pad_inner(&style_btn, LV_STATE_DEFAULT, LV_DPX(15));
lv_style_set_outline_width(&style_btn, LV_STATE_DEFAULT, LV_DPX(2));
lv_style_set_outline_opa(&style_btn, LV_STATE_DEFAULT, LV_OPA_0);
lv_style_set_outline_color(&style_btn, LV_STATE_DEFAULT, theme.color_primary);
lv_style_set_transition_time(&style_btn, LV_STATE_DEFAULT, 0);
lv_style_set_transition_delay(&style_btn, LV_STATE_DEFAULT, 0);
style_init_reset(&style_icon);
lv_style_set_text_color(&style_icon, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
style_init_reset(&style_btn_border);
lv_style_set_radius(&style_btn_border, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
lv_style_set_border_color(&style_btn_border, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
lv_style_set_border_width(&style_btn_border, LV_STATE_DEFAULT, 2);
lv_style_set_bg_opa(&style_btn_border, LV_STATE_DEFAULT, LV_OPA_TRANSP);
lv_style_set_bg_color(&style_btn_border, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
lv_style_set_text_color(&style_btn_border, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
lv_style_set_value_color(&style_btn_border, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
lv_style_set_transition_prop_3(&style_btn_border, LV_STATE_DEFAULT, LV_STYLE_BG_OPA);
style_init_reset(&style_back);
lv_style_set_value_color(&style_back, LV_STATE_DEFAULT, LV_PINETIME_GRAY);
lv_style_set_value_str(&style_back, LV_STATE_DEFAULT, LV_SYMBOL_LEFT);
lv_style_set_value_font(&style_back, LV_STATE_DEFAULT, theme.font_subtitle);
style_init_reset(&style_icon);
lv_style_set_text_color(&style_icon, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
style_init_reset(&style_bar_indic);
lv_style_set_bg_opa(&style_bar_indic, LV_STATE_DEFAULT, LV_OPA_COVER);
lv_style_set_radius(&style_bar_indic, LV_STATE_DEFAULT, 10);
style_init_reset(&style_back);
lv_style_set_value_color(&style_back, LV_STATE_DEFAULT, LV_PINETIME_GRAY);
lv_style_set_value_str(&style_back, LV_STATE_DEFAULT, LV_SYMBOL_LEFT);
lv_style_set_value_font(&style_back, LV_STATE_DEFAULT, theme.font_subtitle);
style_init_reset(&style_scrollbar);
lv_style_set_bg_opa(&style_scrollbar, LV_STATE_DEFAULT, LV_OPA_COVER);
lv_style_set_radius(&style_scrollbar, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
lv_style_set_bg_color(&style_scrollbar, LV_STATE_DEFAULT, LV_PINETIME_LIGHT_GRAY);
lv_style_set_size(&style_scrollbar, LV_STATE_DEFAULT, LV_HOR_RES / 80);
lv_style_set_pad_right(&style_scrollbar, LV_STATE_DEFAULT, LV_HOR_RES / 60);
style_init_reset(&style_bar_indic);
lv_style_set_bg_opa(&style_bar_indic, LV_STATE_DEFAULT, LV_OPA_COVER);
lv_style_set_radius(&style_bar_indic, LV_STATE_DEFAULT, 10);
style_init_reset(&style_list_btn);
lv_style_set_bg_opa(&style_list_btn, LV_STATE_DEFAULT, LV_OPA_COVER);
lv_style_set_bg_color(&style_list_btn, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
lv_style_set_bg_color(&style_list_btn, LV_STATE_CHECKED, LV_PINETIME_GRAY);
lv_style_set_bg_color(&style_list_btn, LV_STATE_CHECKED | LV_STATE_PRESSED, lv_color_darken(LV_PINETIME_GRAY, LV_OPA_20));
lv_style_set_text_color(&style_list_btn, LV_STATE_DEFAULT, LV_PINETIME_BLUE);
lv_style_set_text_color(&style_list_btn, LV_STATE_CHECKED, LV_PINETIME_WHITE);
lv_style_set_text_color(&style_list_btn, LV_STATE_CHECKED | LV_STATE_PRESSED, LV_PINETIME_WHITE);
lv_style_set_image_recolor(&style_list_btn, LV_STATE_DEFAULT, LV_PINETIME_BLUE);
lv_style_set_image_recolor(&style_list_btn, LV_STATE_CHECKED, LV_PINETIME_WHITE);
lv_style_set_image_recolor(&style_list_btn, LV_STATE_CHECKED | LV_STATE_PRESSED, LV_PINETIME_WHITE);
lv_style_set_pad_left(&style_list_btn, LV_STATE_DEFAULT, LV_HOR_RES / 25);
lv_style_set_pad_right(&style_list_btn, LV_STATE_DEFAULT, LV_HOR_RES / 25);
lv_style_set_pad_top(&style_list_btn, LV_STATE_DEFAULT, LV_HOR_RES / 100);
lv_style_set_pad_bottom(&style_list_btn, LV_STATE_DEFAULT, LV_HOR_RES / 100);
lv_style_set_pad_inner(&style_list_btn, LV_STATE_DEFAULT, LV_HOR_RES / 50);
style_init_reset(&style_scrollbar);
lv_style_set_bg_opa(&style_scrollbar, LV_STATE_DEFAULT, LV_OPA_COVER);
lv_style_set_radius(&style_scrollbar, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
lv_style_set_bg_color(&style_scrollbar, LV_STATE_DEFAULT, LV_PINETIME_LIGHT_GRAY);
lv_style_set_size(&style_scrollbar, LV_STATE_DEFAULT, LV_HOR_RES / 80);
lv_style_set_pad_right(&style_scrollbar, LV_STATE_DEFAULT, LV_HOR_RES / 60);
style_init_reset(&style_ddlist_list);
lv_style_set_text_line_space(&style_ddlist_list, LV_STATE_DEFAULT, LV_VER_RES / 25);
lv_style_set_shadow_width(&style_ddlist_list, LV_STATE_DEFAULT, LV_VER_RES / 20);
lv_style_set_shadow_color(&style_ddlist_list, LV_STATE_DEFAULT, LV_PINETIME_GRAY);
style_init_reset(&style_list_btn);
lv_style_set_bg_opa(&style_list_btn, LV_STATE_DEFAULT, LV_OPA_COVER);
lv_style_set_bg_color(&style_list_btn, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
lv_style_set_bg_color(&style_list_btn, LV_STATE_CHECKED, LV_PINETIME_GRAY);
lv_style_set_bg_color(&style_list_btn, LV_STATE_CHECKED | LV_STATE_PRESSED, lv_color_darken(LV_PINETIME_GRAY, LV_OPA_20));
lv_style_set_text_color(&style_list_btn, LV_STATE_DEFAULT, LV_PINETIME_BLUE);
lv_style_set_text_color(&style_list_btn, LV_STATE_CHECKED, LV_PINETIME_WHITE);
lv_style_set_text_color(&style_list_btn, LV_STATE_CHECKED | LV_STATE_PRESSED, LV_PINETIME_WHITE);
lv_style_set_image_recolor(&style_list_btn, LV_STATE_DEFAULT, LV_PINETIME_BLUE);
lv_style_set_image_recolor(&style_list_btn, LV_STATE_CHECKED, LV_PINETIME_WHITE);
lv_style_set_image_recolor(&style_list_btn, LV_STATE_CHECKED | LV_STATE_PRESSED, LV_PINETIME_WHITE);
lv_style_set_pad_left(&style_list_btn, LV_STATE_DEFAULT, LV_HOR_RES / 25);
lv_style_set_pad_right(&style_list_btn, LV_STATE_DEFAULT, LV_HOR_RES / 25);
lv_style_set_pad_top(&style_list_btn, LV_STATE_DEFAULT, LV_HOR_RES / 100);
lv_style_set_pad_bottom(&style_list_btn, LV_STATE_DEFAULT, LV_HOR_RES / 100);
lv_style_set_pad_inner(&style_list_btn, LV_STATE_DEFAULT, LV_HOR_RES / 50);
style_init_reset(&style_ddlist_selected);
lv_style_set_bg_opa(&style_ddlist_selected, LV_STATE_DEFAULT, LV_OPA_COVER);
lv_style_set_bg_color(&style_ddlist_selected, LV_STATE_DEFAULT, LV_PINETIME_BLUE);
style_init_reset(&style_ddlist_list);
lv_style_set_text_line_space(&style_ddlist_list, LV_STATE_DEFAULT, LV_VER_RES / 25);
lv_style_set_shadow_width(&style_ddlist_list, LV_STATE_DEFAULT, LV_VER_RES / 20);
lv_style_set_shadow_color(&style_ddlist_list, LV_STATE_DEFAULT, LV_PINETIME_GRAY);
style_init_reset(&style_sw_bg);
lv_style_set_bg_opa(&style_sw_bg, LV_STATE_DEFAULT, LV_OPA_COVER);
lv_style_set_bg_color(&style_sw_bg, LV_STATE_DEFAULT, LV_PINETIME_LIGHT_GRAY);
lv_style_set_radius(&style_sw_bg, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
lv_style_set_value_color(&style_sw_bg, LV_STATE_DEFAULT, LV_PINETIME_BLUE);
style_init_reset(&style_ddlist_selected);
lv_style_set_bg_opa(&style_ddlist_selected, LV_STATE_DEFAULT, LV_OPA_COVER);
lv_style_set_bg_color(&style_ddlist_selected, LV_STATE_DEFAULT, LV_PINETIME_BLUE);
style_init_reset(&style_sw_indic);
lv_style_set_bg_opa(&style_sw_indic, LV_STATE_DEFAULT, LV_OPA_COVER);
lv_style_set_bg_color(&style_sw_indic, LV_STATE_DEFAULT, LV_PINETIME_GREEN);
style_init_reset(&style_sw_bg);
lv_style_set_bg_opa(&style_sw_bg, LV_STATE_DEFAULT, LV_OPA_COVER);
lv_style_set_bg_color(&style_sw_bg, LV_STATE_DEFAULT, LV_PINETIME_LIGHT_GRAY);
lv_style_set_radius(&style_sw_bg, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
lv_style_set_value_color(&style_sw_bg, LV_STATE_DEFAULT, LV_PINETIME_BLUE);
style_init_reset(&style_sw_knob);
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_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_bottom(&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);
style_init_reset(&style_sw_indic);
lv_style_set_bg_opa(&style_sw_indic, LV_STATE_DEFAULT, LV_OPA_COVER);
lv_style_set_bg_color(&style_sw_indic, LV_STATE_DEFAULT, LV_PINETIME_GREEN);
style_init_reset(&style_slider_knob);
lv_style_set_bg_opa(&style_slider_knob, LV_STATE_DEFAULT, LV_OPA_COVER);
lv_style_set_bg_color(&style_slider_knob, LV_STATE_DEFAULT, LV_COLOR_RED);
lv_style_set_border_color(&style_slider_knob, LV_STATE_DEFAULT, LV_COLOR_WHITE);
lv_style_set_border_width(&style_slider_knob, LV_STATE_DEFAULT, 6);
lv_style_set_radius(&style_slider_knob, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
lv_style_set_pad_top(&style_slider_knob, LV_STATE_DEFAULT, 10);
lv_style_set_pad_bottom(&style_slider_knob, LV_STATE_DEFAULT, 10);
lv_style_set_pad_left(&style_slider_knob, LV_STATE_DEFAULT, 10);
lv_style_set_pad_right(&style_slider_knob, LV_STATE_DEFAULT, 10);
lv_style_set_pad_top(&style_slider_knob, LV_STATE_PRESSED, 14);
lv_style_set_pad_bottom(&style_slider_knob, LV_STATE_PRESSED, 14);
lv_style_set_pad_left(&style_slider_knob, LV_STATE_PRESSED, 14);
lv_style_set_pad_right(&style_slider_knob, LV_STATE_PRESSED, 14);
style_init_reset(&style_sw_knob);
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_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_bottom(&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);
style_init_reset(&style_arc_indic);
lv_style_set_line_color(&style_arc_indic, LV_STATE_DEFAULT, LV_PINETIME_BLUE);
lv_style_set_line_width(&style_arc_indic, LV_STATE_DEFAULT, LV_DPX(25));
lv_style_set_line_rounded(&style_arc_indic, LV_STATE_DEFAULT, true);
style_init_reset(&style_slider_knob);
lv_style_set_bg_opa(&style_slider_knob, LV_STATE_DEFAULT, LV_OPA_COVER);
lv_style_set_bg_color(&style_slider_knob, LV_STATE_DEFAULT, LV_COLOR_RED);
lv_style_set_border_color(&style_slider_knob, LV_STATE_DEFAULT, LV_COLOR_WHITE);
lv_style_set_border_width(&style_slider_knob, LV_STATE_DEFAULT, 6);
lv_style_set_radius(&style_slider_knob, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
lv_style_set_pad_top(&style_slider_knob, LV_STATE_DEFAULT, 10);
lv_style_set_pad_bottom(&style_slider_knob, LV_STATE_DEFAULT, 10);
lv_style_set_pad_left(&style_slider_knob, LV_STATE_DEFAULT, 10);
lv_style_set_pad_right(&style_slider_knob, LV_STATE_DEFAULT, 10);
lv_style_set_pad_top(&style_slider_knob, LV_STATE_PRESSED, 14);
lv_style_set_pad_bottom(&style_slider_knob, LV_STATE_PRESSED, 14);
lv_style_set_pad_left(&style_slider_knob, LV_STATE_PRESSED, 14);
lv_style_set_pad_right(&style_slider_knob, LV_STATE_PRESSED, 14);
style_init_reset(&style_arc_bg);
lv_style_set_line_color(&style_arc_bg, LV_STATE_DEFAULT, LV_PINETIME_GRAY);
lv_style_set_line_width(&style_arc_bg, LV_STATE_DEFAULT, LV_DPX(25));
lv_style_set_line_rounded(&style_arc_bg, LV_STATE_DEFAULT, true);
style_init_reset(&style_arc_indic);
lv_style_set_line_color(&style_arc_indic, LV_STATE_DEFAULT, LV_PINETIME_BLUE);
lv_style_set_line_width(&style_arc_indic, LV_STATE_DEFAULT, LV_DPX(25));
lv_style_set_line_rounded(&style_arc_indic, LV_STATE_DEFAULT, true);
style_init_reset(&style_table_cell);
lv_style_set_border_color(&style_table_cell, LV_STATE_DEFAULT, LV_PINETIME_GRAY);
lv_style_set_border_width(&style_table_cell, LV_STATE_DEFAULT, 1);
lv_style_set_border_side(&style_table_cell, LV_STATE_DEFAULT, LV_BORDER_SIDE_FULL);
lv_style_set_pad_left(&style_table_cell, LV_STATE_DEFAULT, 5);
lv_style_set_pad_right(&style_table_cell, LV_STATE_DEFAULT, 5);
lv_style_set_pad_top(&style_table_cell, LV_STATE_DEFAULT, 2);
lv_style_set_pad_bottom(&style_table_cell, LV_STATE_DEFAULT, 2);
style_init_reset(&style_arc_bg);
lv_style_set_line_color(&style_arc_bg, LV_STATE_DEFAULT, LV_PINETIME_GRAY);
lv_style_set_line_width(&style_arc_bg, LV_STATE_DEFAULT, LV_DPX(25));
lv_style_set_line_rounded(&style_arc_bg, LV_STATE_DEFAULT, true);
style_init_reset(&style_pad_small);
lv_style_int_t pad_small_value = 10;
lv_style_set_pad_left(&style_pad_small, LV_STATE_DEFAULT, pad_small_value);
lv_style_set_pad_right(&style_pad_small, LV_STATE_DEFAULT, pad_small_value);
lv_style_set_pad_top(&style_pad_small, LV_STATE_DEFAULT, pad_small_value);
lv_style_set_pad_bottom(&style_pad_small, LV_STATE_DEFAULT, pad_small_value);
lv_style_set_pad_inner(&style_pad_small, LV_STATE_DEFAULT, pad_small_value);
style_init_reset(&style_table_cell);
lv_style_set_border_color(&style_table_cell, LV_STATE_DEFAULT, LV_PINETIME_GRAY);
lv_style_set_border_width(&style_table_cell, LV_STATE_DEFAULT, 1);
lv_style_set_border_side(&style_table_cell, LV_STATE_DEFAULT, LV_BORDER_SIDE_FULL);
lv_style_set_pad_left(&style_table_cell, LV_STATE_DEFAULT, 5);
lv_style_set_pad_right(&style_table_cell, LV_STATE_DEFAULT, 5);
lv_style_set_pad_top(&style_table_cell, LV_STATE_DEFAULT, 2);
lv_style_set_pad_bottom(&style_table_cell, LV_STATE_DEFAULT, 2);
style_init_reset(&style_bg_grad);
lv_style_set_bg_color(&style_bg_grad, LV_STATE_DEFAULT, lv_color_hsv_to_rgb(10, 10, 40));
lv_style_set_bg_grad_color(&style_bg_grad, LV_STATE_DEFAULT, lv_color_hsv_to_rgb(10, 10, 20));
lv_style_set_bg_grad_dir(&style_bg_grad, LV_STATE_DEFAULT, LV_GRAD_DIR_VER);
style_init_reset(&style_pad_small);
lv_style_int_t pad_small_value = 10;
lv_style_set_pad_left(&style_pad_small, LV_STATE_DEFAULT, pad_small_value);
lv_style_set_pad_right(&style_pad_small, LV_STATE_DEFAULT, pad_small_value);
lv_style_set_pad_top(&style_pad_small, LV_STATE_DEFAULT, pad_small_value);
lv_style_set_pad_bottom(&style_pad_small, LV_STATE_DEFAULT, pad_small_value);
lv_style_set_pad_inner(&style_pad_small, LV_STATE_DEFAULT, pad_small_value);
style_init_reset(&style_lmeter);
lv_style_set_radius(&style_lmeter, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
lv_style_set_pad_left(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(20));
lv_style_set_pad_right(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(20));
lv_style_set_pad_top(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(20));
lv_style_set_pad_inner(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(30));
lv_style_set_scale_width(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(25));
style_init_reset(&style_bg_grad);
lv_style_set_bg_color(&style_bg_grad, LV_STATE_DEFAULT, lv_color_hsv_to_rgb(10, 10, 40));
lv_style_set_bg_grad_color(&style_bg_grad, LV_STATE_DEFAULT, lv_color_hsv_to_rgb(10, 10, 20));
lv_style_set_bg_grad_dir(&style_bg_grad, LV_STATE_DEFAULT, LV_GRAD_DIR_VER);
lv_style_set_line_color(&style_lmeter, LV_STATE_DEFAULT, theme.color_primary);
lv_style_set_scale_grad_color(&style_lmeter, LV_STATE_DEFAULT, theme.color_primary);
lv_style_set_scale_end_color(&style_lmeter, LV_STATE_DEFAULT, lv_color_hex3(0x888));
lv_style_set_line_width(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(10));
lv_style_set_scale_end_line_width(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(7));
style_init_reset(&style_lmeter);
lv_style_set_radius(&style_lmeter, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
lv_style_set_pad_left(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(20));
lv_style_set_pad_right(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(20));
lv_style_set_pad_top(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(20));
lv_style_set_pad_inner(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(30));
lv_style_set_scale_width(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(25));
style_init_reset(&style_chart_serie);
lv_style_set_line_color(&style_chart_serie, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
lv_style_set_line_width(&style_chart_serie, LV_STATE_DEFAULT, 4);
lv_style_set_size(&style_chart_serie, LV_STATE_DEFAULT, 4);
lv_style_set_bg_opa(&style_chart_serie, LV_STATE_DEFAULT, 0);
lv_style_set_line_color(&style_lmeter, LV_STATE_DEFAULT, theme.color_primary);
lv_style_set_scale_grad_color(&style_lmeter, LV_STATE_DEFAULT, theme.color_primary);
lv_style_set_scale_end_color(&style_lmeter, LV_STATE_DEFAULT, lv_color_hex3(0x888));
lv_style_set_line_width(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(10));
lv_style_set_scale_end_line_width(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(7));
style_init_reset(&style_chart_serie);
lv_style_set_line_color(&style_chart_serie, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
lv_style_set_line_width(&style_chart_serie, LV_STATE_DEFAULT, 4);
lv_style_set_size(&style_chart_serie, LV_STATE_DEFAULT, 4);
lv_style_set_bg_opa(&style_chart_serie, LV_STATE_DEFAULT, 0);
lv_style_reset(&style_cb_bg);
lv_style_set_radius(&style_cb_bg, LV_STATE_DEFAULT, LV_DPX(4));
lv_style_set_pad_inner(&style_cb_bg, LV_STATE_DEFAULT, LV_DPX(10));
lv_style_set_outline_color(&style_cb_bg, LV_STATE_DEFAULT, theme.color_primary);
lv_style_set_outline_width(&style_cb_bg, LV_STATE_DEFAULT, LV_DPX(2));
lv_style_set_outline_pad(&style_cb_bg, LV_STATE_DEFAULT, LV_DPX(20));
lv_style_set_transition_time(&style_cb_bg, LV_STATE_DEFAULT, 0);
lv_style_set_transition_prop_6(&style_cb_bg, LV_STATE_DEFAULT, LV_STYLE_OUTLINE_OPA);
lv_style_reset(&style_cb_bullet);
lv_style_set_outline_opa(&style_cb_bullet, LV_STATE_FOCUSED, LV_OPA_TRANSP);
lv_style_set_radius(&style_cb_bullet, LV_STATE_DEFAULT, LV_DPX(4));
lv_style_set_pattern_recolor(&style_cb_bullet, LV_STATE_CHECKED, LV_COLOR_WHITE);
lv_style_set_pad_left(&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_bottom(&style_cb_bullet, LV_STATE_DEFAULT, LV_DPX(8));
lv_style_reset(&style_cb_bg);
lv_style_set_radius(&style_cb_bg, LV_STATE_DEFAULT, LV_DPX(4));
lv_style_set_pad_inner(&style_cb_bg, LV_STATE_DEFAULT, LV_DPX(10));
lv_style_set_outline_color(&style_cb_bg, LV_STATE_DEFAULT, theme.color_primary);
lv_style_set_outline_width(&style_cb_bg, LV_STATE_DEFAULT, LV_DPX(2));
lv_style_set_outline_pad(&style_cb_bg, LV_STATE_DEFAULT, LV_DPX(20));
lv_style_set_transition_time(&style_cb_bg, LV_STATE_DEFAULT, 0);
lv_style_set_transition_prop_6(&style_cb_bg, LV_STATE_DEFAULT, LV_STYLE_OUTLINE_OPA);
lv_style_reset(&style_cb_bullet);
lv_style_set_outline_opa(&style_cb_bullet, LV_STATE_FOCUSED, LV_OPA_TRANSP);
lv_style_set_radius(&style_cb_bullet, LV_STATE_DEFAULT, LV_DPX(4));
lv_style_set_pattern_recolor(&style_cb_bullet, LV_STATE_CHECKED, LV_COLOR_WHITE);
lv_style_set_pad_left(&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_bottom(&style_cb_bullet, LV_STATE_DEFAULT, LV_DPX(8));
}
/**********************
* GLOBAL FUNCTIONS
**********************/
@ -320,221 +316,216 @@ static void basic_init(void)
* @param font_title pointer to a extra large font
* @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,
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_secondary = color_secondary;
theme.font_small = font_small;
theme.font_normal = font_normal;
theme.font_subtitle = font_subtitle;
theme.font_title = font_title;
theme.flags = flags;
lv_theme_t* lv_pinetime_theme_init(lv_color_t color_primary,
lv_color_t color_secondary,
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_secondary = color_secondary;
theme.font_small = font_small;
theme.font_normal = font_normal;
theme.font_subtitle = font_subtitle;
theme.font_title = font_title;
theme.flags = flags;
basic_init();
basic_init();
theme.apply_xcb = theme_apply;
theme.apply_xcb = theme_apply;
inited = true;
inited = true;
return &theme;
return &theme;
}
static void theme_apply(lv_obj_t* obj, lv_theme_style_t name) {
lv_style_list_t* list;
static void theme_apply(lv_obj_t * obj, lv_theme_style_t name)
{
lv_style_list_t * list;
/*To avoid warnings*/
uint32_t name_int = (uint32_t) name;
switch (name_int) {
case LV_THEME_NONE:
break;
/*To avoid warnings*/
uint32_t name_int = (uint32_t) name;
switch(name_int) {
case LV_THEME_NONE:
break;
case LV_THEME_SCR:
lv_obj_clean_style_list(obj, LV_OBJ_PART_MAIN);
list = lv_obj_get_style_list(obj, LV_OBJ_PART_MAIN);
_lv_style_list_add_style(list, &style_bg);
_lv_style_list_add_style(list, &style_label_white);
break;
case LV_THEME_SCR:
lv_obj_clean_style_list(obj, LV_OBJ_PART_MAIN);
list = lv_obj_get_style_list(obj, LV_OBJ_PART_MAIN);
_lv_style_list_add_style(list, &style_bg);
_lv_style_list_add_style(list, &style_label_white);
break;
case LV_THEME_OBJ:
lv_obj_clean_style_list(obj, LV_OBJ_PART_MAIN);
list = lv_obj_get_style_list(obj, LV_OBJ_PART_MAIN);
_lv_style_list_add_style(list, &style_box);
break;
case LV_THEME_OBJ:
lv_obj_clean_style_list(obj, LV_OBJ_PART_MAIN);
list = lv_obj_get_style_list(obj, LV_OBJ_PART_MAIN);
_lv_style_list_add_style(list, &style_box);
break;
case LV_THEME_CONT:
lv_obj_clean_style_list(obj, LV_OBJ_PART_MAIN);
list = lv_obj_get_style_list(obj, LV_CONT_PART_MAIN);
_lv_style_list_add_style(list, &style_box);
break;
case LV_THEME_CONT:
lv_obj_clean_style_list(obj, LV_OBJ_PART_MAIN);
list = lv_obj_get_style_list(obj, LV_CONT_PART_MAIN);
_lv_style_list_add_style(list, &style_box);
break;
case LV_THEME_BTN:
lv_obj_clean_style_list(obj, LV_BTN_PART_MAIN);
list = lv_obj_get_style_list(obj, LV_BTN_PART_MAIN);
_lv_style_list_add_style(list, &style_btn);
//_lv_style_list_add_style(list, &style_bg_grad);
break;
case LV_THEME_BTN:
lv_obj_clean_style_list(obj, LV_BTN_PART_MAIN);
list = lv_obj_get_style_list(obj, LV_BTN_PART_MAIN);
_lv_style_list_add_style(list, &style_btn);
//_lv_style_list_add_style(list, &style_bg_grad);
break;
case LV_THEME_BTNMATRIX:
list = lv_obj_get_style_list(obj, LV_BTNMATRIX_PART_BG);
_lv_style_list_add_style(list, &style_bg);
_lv_style_list_add_style(list, &style_pad_small);
case LV_THEME_BTNMATRIX:
list = lv_obj_get_style_list(obj, LV_BTNMATRIX_PART_BG);
_lv_style_list_add_style(list, &style_bg);
_lv_style_list_add_style(list, &style_pad_small);
list = lv_obj_get_style_list(obj, LV_BTNMATRIX_PART_BTN);
_lv_style_list_add_style(list, &style_btn);
//_lv_style_list_add_style(list, &style_bg_grad);
//_lv_style_list_add_style(list, &style_bg_click);
break;
list = lv_obj_get_style_list(obj, LV_BTNMATRIX_PART_BTN);
_lv_style_list_add_style(list, &style_btn);
//_lv_style_list_add_style(list, &style_bg_grad);
//_lv_style_list_add_style(list, &style_bg_click);
break;
case LV_THEME_BAR:
lv_obj_clean_style_list(obj, LV_BAR_PART_BG);
list = lv_obj_get_style_list(obj, LV_BAR_PART_BG);
case LV_THEME_BAR:
lv_obj_clean_style_list(obj, LV_BAR_PART_BG);
list = lv_obj_get_style_list(obj, LV_BAR_PART_BG);
lv_obj_clean_style_list(obj, LV_BAR_PART_INDIC);
list = lv_obj_get_style_list(obj, LV_BAR_PART_INDIC);
_lv_style_list_add_style(list, &style_bar_indic);
break;
lv_obj_clean_style_list(obj, LV_BAR_PART_INDIC);
list = lv_obj_get_style_list(obj, LV_BAR_PART_INDIC);
_lv_style_list_add_style(list, &style_bar_indic);
break;
case LV_THEME_IMAGE:
lv_obj_clean_style_list(obj, LV_IMG_PART_MAIN);
list = lv_obj_get_style_list(obj, LV_IMG_PART_MAIN);
_lv_style_list_add_style(list, &style_icon);
break;
case LV_THEME_IMAGE:
lv_obj_clean_style_list(obj, LV_IMG_PART_MAIN);
list = lv_obj_get_style_list(obj, LV_IMG_PART_MAIN);
_lv_style_list_add_style(list, &style_icon);
break;
case LV_THEME_LABEL:
lv_obj_clean_style_list(obj, LV_LABEL_PART_MAIN);
list = lv_obj_get_style_list(obj, LV_LABEL_PART_MAIN);
_lv_style_list_add_style(list, &style_label_white);
break;
case LV_THEME_LABEL:
lv_obj_clean_style_list(obj, LV_LABEL_PART_MAIN);
list = lv_obj_get_style_list(obj, LV_LABEL_PART_MAIN);
_lv_style_list_add_style(list, &style_label_white);
break;
case LV_THEME_SLIDER:
lv_obj_clean_style_list(obj, LV_SLIDER_PART_BG);
list = lv_obj_get_style_list(obj, LV_SLIDER_PART_BG);
_lv_style_list_add_style(list, &style_sw_bg);
case LV_THEME_SLIDER:
lv_obj_clean_style_list(obj, LV_SLIDER_PART_BG);
list = lv_obj_get_style_list(obj, LV_SLIDER_PART_BG);
_lv_style_list_add_style(list, &style_sw_bg);
lv_obj_clean_style_list(obj, LV_SLIDER_PART_INDIC);
list = lv_obj_get_style_list(obj, LV_SLIDER_PART_INDIC);
lv_obj_clean_style_list(obj, LV_SLIDER_PART_INDIC);
list = lv_obj_get_style_list(obj, LV_SLIDER_PART_INDIC);
lv_obj_clean_style_list(obj, LV_SLIDER_PART_KNOB);
list = lv_obj_get_style_list(obj, LV_SLIDER_PART_KNOB);
_lv_style_list_add_style(list, &style_slider_knob);
break;
lv_obj_clean_style_list(obj, LV_SLIDER_PART_KNOB);
list = lv_obj_get_style_list(obj, LV_SLIDER_PART_KNOB);
_lv_style_list_add_style(list, &style_slider_knob);
break;
case LV_THEME_LIST:
lv_obj_clean_style_list(obj, LV_LIST_PART_BG);
list = lv_obj_get_style_list(obj, LV_LIST_PART_BG);
_lv_style_list_add_style(list, &style_box);
case LV_THEME_LIST:
lv_obj_clean_style_list(obj, LV_LIST_PART_BG);
list = lv_obj_get_style_list(obj, LV_LIST_PART_BG);
_lv_style_list_add_style(list, &style_box);
lv_obj_clean_style_list(obj, LV_LIST_PART_SCROLLABLE);
list = lv_obj_get_style_list(obj, LV_LIST_PART_SCROLLABLE);
lv_obj_clean_style_list(obj, LV_LIST_PART_SCROLLABLE);
list = lv_obj_get_style_list(obj, LV_LIST_PART_SCROLLABLE);
lv_obj_clean_style_list(obj, LV_LIST_PART_SCROLLBAR);
list = lv_obj_get_style_list(obj, LV_LIST_PART_SCROLLBAR);
_lv_style_list_add_style(list, &style_scrollbar);
break;
lv_obj_clean_style_list(obj, LV_LIST_PART_SCROLLBAR);
list = lv_obj_get_style_list(obj, LV_LIST_PART_SCROLLBAR);
_lv_style_list_add_style(list, &style_scrollbar);
break;
case LV_THEME_LIST_BTN:
lv_obj_clean_style_list(obj, LV_BTN_PART_MAIN);
list = lv_obj_get_style_list(obj, LV_BTN_PART_MAIN);
_lv_style_list_add_style(list, &style_list_btn);
break;
case LV_THEME_LIST_BTN:
lv_obj_clean_style_list(obj, LV_BTN_PART_MAIN);
list = lv_obj_get_style_list(obj, LV_BTN_PART_MAIN);
_lv_style_list_add_style(list, &style_list_btn);
break;
case LV_THEME_ARC:
lv_obj_clean_style_list(obj, LV_ARC_PART_BG);
list = lv_obj_get_style_list(obj, LV_ARC_PART_BG);
_lv_style_list_add_style(list, &style_arc_bg);
lv_obj_clean_style_list(obj, LV_ARC_PART_INDIC);
list = lv_obj_get_style_list(obj, LV_ARC_PART_INDIC);
_lv_style_list_add_style(list, &style_arc_indic);
break;
case LV_THEME_ARC:
lv_obj_clean_style_list(obj, LV_ARC_PART_BG);
list = lv_obj_get_style_list(obj, LV_ARC_PART_BG);
_lv_style_list_add_style(list, &style_arc_bg);
case LV_THEME_SWITCH:
lv_obj_clean_style_list(obj, LV_SWITCH_PART_BG);
list = lv_obj_get_style_list(obj, LV_SWITCH_PART_BG);
_lv_style_list_add_style(list, &style_sw_bg);
lv_obj_clean_style_list(obj, LV_ARC_PART_INDIC);
list = lv_obj_get_style_list(obj, LV_ARC_PART_INDIC);
_lv_style_list_add_style(list, &style_arc_indic);
break;
lv_obj_clean_style_list(obj, LV_SWITCH_PART_INDIC);
list = lv_obj_get_style_list(obj, LV_SWITCH_PART_INDIC);
_lv_style_list_add_style(list, &style_sw_indic);
lv_obj_clean_style_list(obj, LV_SWITCH_PART_KNOB);
list = lv_obj_get_style_list(obj, LV_SWITCH_PART_KNOB);
_lv_style_list_add_style(list, &style_sw_knob);
break;
case LV_THEME_SWITCH:
lv_obj_clean_style_list(obj, LV_SWITCH_PART_BG);
list = lv_obj_get_style_list(obj, LV_SWITCH_PART_BG);
_lv_style_list_add_style(list, &style_sw_bg);
case LV_THEME_DROPDOWN:
lv_obj_clean_style_list(obj, LV_DROPDOWN_PART_MAIN);
list = lv_obj_get_style_list(obj, LV_DROPDOWN_PART_MAIN);
_lv_style_list_add_style(list, &style_btn);
_lv_style_list_add_style(list, &style_pad);
lv_obj_clean_style_list(obj, LV_SWITCH_PART_INDIC);
list = lv_obj_get_style_list(obj, LV_SWITCH_PART_INDIC);
_lv_style_list_add_style(list, &style_sw_indic);
lv_obj_clean_style_list(obj, LV_DROPDOWN_PART_LIST);
list = lv_obj_get_style_list(obj, LV_DROPDOWN_PART_LIST);
_lv_style_list_add_style(list, &style_box);
_lv_style_list_add_style(list, &style_ddlist_list);
_lv_style_list_add_style(list, &style_pad);
lv_obj_clean_style_list(obj, LV_SWITCH_PART_KNOB);
list = lv_obj_get_style_list(obj, LV_SWITCH_PART_KNOB);
_lv_style_list_add_style(list, &style_sw_knob);
break;
lv_obj_clean_style_list(obj, LV_DROPDOWN_PART_SELECTED);
list = lv_obj_get_style_list(obj, LV_DROPDOWN_PART_SELECTED);
_lv_style_list_add_style(list, &style_ddlist_selected);
case LV_THEME_DROPDOWN:
lv_obj_clean_style_list(obj, LV_DROPDOWN_PART_MAIN);
list = lv_obj_get_style_list(obj, LV_DROPDOWN_PART_MAIN);
_lv_style_list_add_style(list, &style_btn);
_lv_style_list_add_style(list, &style_pad);
lv_obj_clean_style_list(obj, LV_DROPDOWN_PART_SCROLLBAR);
list = lv_obj_get_style_list(obj, LV_DROPDOWN_PART_SCROLLBAR);
_lv_style_list_add_style(list, &style_scrollbar);
break;
lv_obj_clean_style_list(obj, LV_DROPDOWN_PART_LIST);
list = lv_obj_get_style_list(obj, LV_DROPDOWN_PART_LIST);
_lv_style_list_add_style(list, &style_box);
_lv_style_list_add_style(list, &style_ddlist_list);
_lv_style_list_add_style(list, &style_pad);
case LV_THEME_TABLE:
list = lv_obj_get_style_list(obj, LV_TABLE_PART_BG);
_lv_style_list_add_style(list, &style_bg);
lv_obj_clean_style_list(obj, LV_DROPDOWN_PART_SELECTED);
list = lv_obj_get_style_list(obj, LV_DROPDOWN_PART_SELECTED);
_lv_style_list_add_style(list, &style_ddlist_selected);
int idx = 1; /* start value should be 1, not zero, since cell styles
start at 1 due to presence of LV_TABLE_PART_BG=0
in the enum (lv_table.h) */
/* declaring idx outside loop to work with older compilers */
for (; idx <= LV_TABLE_CELL_STYLE_CNT; 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_label_white);
}
break;
lv_obj_clean_style_list(obj, LV_DROPDOWN_PART_SCROLLBAR);
list = lv_obj_get_style_list(obj, LV_DROPDOWN_PART_SCROLLBAR);
_lv_style_list_add_style(list, &style_scrollbar);
break;
case LV_THEME_LINEMETER:
list = lv_obj_get_style_list(obj, LV_LINEMETER_PART_MAIN);
_lv_style_list_add_style(list, &style_bg);
_lv_style_list_add_style(list, &style_lmeter);
break;
case LV_THEME_TABLE:
list = lv_obj_get_style_list(obj, LV_TABLE_PART_BG);
_lv_style_list_add_style(list, &style_bg);
case LV_THEME_CHART:
lv_obj_clean_style_list(obj, LV_CHART_PART_SERIES);
list = lv_obj_get_style_list(obj, LV_CHART_PART_SERIES);
_lv_style_list_add_style(list, &style_btn);
_lv_style_list_add_style(list, &style_chart_serie);
break;
int idx = 1; /* start value should be 1, not zero, since cell styles
start at 1 due to presence of LV_TABLE_PART_BG=0
in the enum (lv_table.h) */
/* declaring idx outside loop to work with older compilers */
for(; idx <= LV_TABLE_CELL_STYLE_CNT; 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_label_white);
}
break;
case LV_THEME_CHECKBOX:
list = lv_obj_get_style_list(obj, LV_CHECKBOX_PART_BG);
_lv_style_list_add_style(list, &style_cb_bg);
case LV_THEME_LINEMETER:
list = lv_obj_get_style_list(obj, LV_LINEMETER_PART_MAIN);
_lv_style_list_add_style(list, &style_bg);
_lv_style_list_add_style(list, &style_lmeter);
break;
case LV_THEME_CHART:
lv_obj_clean_style_list(obj, LV_CHART_PART_SERIES);
list = lv_obj_get_style_list(obj, LV_CHART_PART_SERIES);
_lv_style_list_add_style(list, &style_btn);
_lv_style_list_add_style(list, &style_chart_serie);
break;
case LV_THEME_CHECKBOX:
list = lv_obj_get_style_list(obj, LV_CHECKBOX_PART_BG);
_lv_style_list_add_style(list, &style_cb_bg);
list = lv_obj_get_style_list(obj, LV_CHECKBOX_PART_BULLET);
_lv_style_list_add_style(list, &style_btn);
_lv_style_list_add_style(list, &style_cb_bullet);
break;
default:
break;
}
lv_obj_refresh_style(obj, LV_OBJ_PART_ALL, LV_STYLE_PROP_ALL);
list = lv_obj_get_style_list(obj, LV_CHECKBOX_PART_BULLET);
_lv_style_list_add_style(list, &style_btn);
_lv_style_list_add_style(list, &style_cb_bullet);
break;
default:
break;
}
lv_obj_refresh_style(obj, LV_OBJ_PART_ALL, LV_STYLE_PROP_ALL);
}
/**********************

View file

@ -19,24 +19,22 @@ extern "C" {
* DEFINES
*********************/
/*Colors*/
#define LV_PINETIME_WHITE lv_color_hex(0xffffff)
#define LV_PINETIME_LIGHT lv_color_hex(0xf3f8fe)
#define LV_PINETIME_GRAY lv_color_hex(0x8a8a8a)
#define LV_PINETIME_LIGHT_GRAY lv_color_hex(0xc4c4c4)
#define LV_PINETIME_BLUE lv_color_hex(0x2f3243) //006fb6
#define LV_PINETIME_GREEN lv_color_hex(0x4cb242)
#define LV_PINETIME_RED lv_color_hex(0xd51732)
#define LV_PINETIME_WHITE lv_color_hex(0xffffff)
#define LV_PINETIME_LIGHT lv_color_hex(0xf3f8fe)
#define LV_PINETIME_GRAY lv_color_hex(0x8a8a8a)
#define LV_PINETIME_LIGHT_GRAY lv_color_hex(0xc4c4c4)
#define LV_PINETIME_BLUE lv_color_hex(0x2f3243) // 006fb6
#define LV_PINETIME_GREEN lv_color_hex(0x4cb242)
#define LV_PINETIME_RED lv_color_hex(0xd51732)
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Initialize the default
* @param color_primary the primary color of the theme
@ -48,9 +46,13 @@ extern "C" {
* @param font_title pointer to a extra large font
* @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,
const lv_font_t * font_small, const lv_font_t * font_normal, const lv_font_t * font_subtitle,
const lv_font_t * font_title);
lv_theme_t* lv_pinetime_theme_init(lv_color_t color_primary,
lv_color_t color_secondary,
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
**********************/

View file

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

View file

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

View file

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

View file

@ -6,8 +6,8 @@ namespace Pinetime {
class BatteryIcon {
public:
static const char* GetUnknownIcon();
static const char* GetBatteryIcon(int batteryPercent);
static const char* GetPlugIcon(bool isCharging);
static const char* GetBatteryIcon(int batteryPercent);
static const char* GetPlugIcon(bool isCharging);
};
}
}

View file

@ -4,22 +4,18 @@
using namespace Pinetime::Applications::Screens;
static void lv_update_task(struct _lv_task_t *task) {
auto user_data = static_cast<BatteryInfo *>(task->user_data);
static void lv_update_task(struct _lv_task_t* task) {
auto user_data = static_cast<BatteryInfo*>(task->user_data);
user_data->UpdateScreen();
}
static void lv_anim_task(struct _lv_task_t *task) {
auto user_data = static_cast<BatteryInfo *>(task->user_data);
static void lv_anim_task(struct _lv_task_t* task) {
auto user_data = static_cast<BatteryInfo*>(task->user_data);
user_data->UpdateAnim();
}
BatteryInfo::BatteryInfo(
Pinetime::Applications::DisplayApp *app,
Pinetime::Controllers::Battery& batteryController) :
Screen(app),
batteryController{batteryController}
{
BatteryInfo::BatteryInfo(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Battery& batteryController)
: Screen(app), batteryController {batteryController} {
batteryPercent = batteryController.PercentRemaining();
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_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_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);
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_obj_align(status, charging_bar, LV_ALIGN_OUT_BOTTOM_MID, 0, 20);
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);
if ( batteryPercent >= 0) {
lv_label_set_text_fmt(percent,"%02i%%", batteryPercent);
if (batteryPercent >= 0) {
lv_label_set_text_fmt(percent, "%02i%%", batteryPercent);
} else {
lv_label_set_text(percent,"--%");
lv_label_set_text(percent, "--%");
}
lv_label_set_align(percent, LV_LABEL_ALIGN_LEFT);
lv_obj_align(percent, nullptr, LV_ALIGN_CENTER, 0, -60);
// hack to not use the flot functions from printf
uint8_t batteryVoltageBytes[2];
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[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
//
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_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_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_obj_set_size(backgroundLabel, 240, 240);
lv_obj_set_pos(backgroundLabel, 0, 0);
@ -73,7 +70,6 @@ BatteryInfo::BatteryInfo(
UpdateScreen();
}
BatteryInfo::~BatteryInfo() {
lv_task_del(taskUpdate);
lv_task_del(taskAnim);
@ -83,9 +79,9 @@ BatteryInfo::~BatteryInfo() {
void BatteryInfo::UpdateAnim() {
batteryPercent = batteryController.PercentRemaining();
if ( batteryPercent >= 0 ) {
if ( batteryController.IsCharging() and batteryPercent < 100 ) {
animation +=1;
if (batteryPercent >= 0) {
if (batteryController.IsCharging() and batteryPercent < 100) {
animation += 1;
if (animation >= 100) {
animation = 0;
}
@ -110,40 +106,39 @@ void BatteryInfo::UpdateScreen() {
batteryPercent = batteryController.PercentRemaining();
batteryVoltage = batteryController.Voltage();
if ( batteryPercent >= 0 ) {
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_label_set_text_static(status,"Battery charging");
} else if ( batteryPercent == 100 ) {
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");
} else if ( batteryPercent < 10 ) {
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");
if (batteryPercent >= 0) {
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_label_set_text_static(status, "Battery charging");
} else if (batteryPercent == 100) {
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");
} else if (batteryPercent < 10) {
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");
} else {
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_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_fmt(percent,"%02i%%", batteryPercent);
lv_label_set_text_fmt(percent, "%02i%%", batteryPercent);
} else {
lv_label_set_text_static(status,"Reading Battery status");
lv_label_set_text(percent,"--%");
lv_label_set_text_static(status, "Reading Battery status");
lv_label_set_text(percent, "--%");
}
lv_obj_align(status, charging_bar, LV_ALIGN_OUT_BOTTOM_MID, 0, 20);
// hack to not use the flot functions from printf
uint8_t batteryVoltageBytes[2];
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[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
//
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() {
return running;
}

View file

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

View file

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

View file

@ -3,14 +3,15 @@
using namespace Pinetime::Applications::Screens;
void slider_event_cb(lv_obj_t * slider, lv_event_t event) {
if(event == LV_EVENT_VALUE_CHANGED) {
void slider_event_cb(lv_obj_t* slider, lv_event_t event) {
if (event == LV_EVENT_VALUE_CHANGED) {
auto* brightnessSlider = static_cast<Brightness*>(slider->user_data);
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);
lv_obj_set_user_data(slider, this);
lv_obj_set_width(slider, LV_DPI * 2);
@ -33,13 +34,18 @@ bool Brightness::Refresh() {
return running;
}
const char *Brightness::LevelToString(Pinetime::Controllers::BrightnessController::Levels level) {
switch(level) {
case Pinetime::Controllers::BrightnessController::Levels::Off: return "Off";
case Pinetime::Controllers::BrightnessController::Levels::Low: return "Low";
case Pinetime::Controllers::BrightnessController::Levels::Medium: return "Medium";
case Pinetime::Controllers::BrightnessController::Levels::High: return "High";
default : return "???";
const char* Brightness::LevelToString(Pinetime::Controllers::BrightnessController::Levels level) {
switch (level) {
case Pinetime::Controllers::BrightnessController::Levels::Off:
return "Off";
case Pinetime::Controllers::BrightnessController::Levels::Low:
return "Low";
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) {
switch(value) {
case 0: brightness.Set(Controllers::BrightnessController::Levels::Low); break;
case 1: brightness.Set(Controllers::BrightnessController::Levels::Medium); break;
case 2: brightness.Set(Controllers::BrightnessController::Levels::High); break;
switch (value) {
case 0:
brightness.Set(Controllers::BrightnessController::Levels::Low);
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()));
}
uint8_t Brightness::LevelToInt(Pinetime::Controllers::BrightnessController::Levels level) {
switch(level) {
case Pinetime::Controllers::BrightnessController::Levels::Off: return 0;
case Pinetime::Controllers::BrightnessController::Levels::Low: return 0;
case Pinetime::Controllers::BrightnessController::Levels::Medium: return 1;
case Pinetime::Controllers::BrightnessController::Levels::High: return 2;
default : return 0;
switch (level) {
case Pinetime::Controllers::BrightnessController::Levels::Off:
return 0;
case Pinetime::Controllers::BrightnessController::Levels::Low:
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) {
switch(event) {
switch (event) {
case TouchEvents::SwipeLeft:
brightness.Lower();
if ( brightness.Level() == Pinetime::Controllers::BrightnessController::Levels::Off) {
if (brightness.Level() == Pinetime::Controllers::BrightnessController::Levels::Off) {
brightness.Set(Controllers::BrightnessController::Levels::Low);
}
SetValue();

View file

@ -9,25 +9,25 @@ namespace Pinetime {
namespace Applications {
namespace Screens {
class Brightness : public Screen {
public:
Brightness(DisplayApp* app, Controllers::BrightnessController& brightness);
~Brightness() override;
bool Refresh() override;
public:
Brightness(DisplayApp* app, Controllers::BrightnessController& brightness);
~Brightness() override;
bool Refresh() override;
bool OnTouchEvent(TouchEvents event) override;
bool OnTouchEvent(TouchEvents event) override;
void OnValueChanged();
private:
void OnValueChanged();
Controllers::BrightnessController& brightness;
private:
Controllers::BrightnessController& brightness;
lv_obj_t * slider_label;
lv_obj_t * slider;
lv_obj_t* slider_label;
lv_obj_t* slider;
const char* LevelToString(Controllers::BrightnessController::Levels level);
uint8_t LevelToInt(Controllers::BrightnessController::Levels level);
void SetValue(uint8_t value);
void SetValue();
const char* LevelToString(Controllers::BrightnessController::Levels level);
uint8_t LevelToInt(Controllers::BrightnessController::Levels level);
void SetValue(uint8_t value);
void SetValue();
};
}
}

View file

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

@ -23,42 +23,37 @@ namespace Pinetime {
namespace Applications {
namespace Screens {
class Clock : public Screen {
public:
Clock(DisplayApp* app,
Controllers::DateTime& dateTimeController,
Controllers::Battery& batteryController,
Controllers::Ble& bleController,
Controllers::NotificationManager& notificatioManager,
Controllers::Settings &settingsController,
Controllers::HeartRateController& heartRateController,
Controllers::MotionController& motionController);
~Clock() override;
public:
Clock(DisplayApp* app,
Controllers::DateTime& dateTimeController,
Controllers::Battery& batteryController,
Controllers::Ble& bleController,
Controllers::NotificationManager& notificatioManager,
Controllers::Settings& settingsController,
Controllers::HeartRateController& heartRateController,
Controllers::MotionController& motionController);
~Clock() override;
bool Refresh() override;
bool Refresh() override;
bool OnTouchEvent(TouchEvents event) override;
private:
Controllers::DateTime& dateTimeController;
Controllers::Battery& batteryController;
Controllers::Ble& bleController;
Controllers::NotificationManager& notificatioManager;
Controllers::Settings& settingsController;
Controllers::HeartRateController& heartRateController;
Controllers::MotionController& motionController;
ScreenList<2> screens;
std::unique_ptr<Screen> WatchFaceDigitalScreen();
std::unique_ptr<Screen> WatchFaceAnalogScreen();
// Examples for more watch faces
//std::unique_ptr<Screen> WatchFaceMinimalScreen();
//std::unique_ptr<Screen> WatchFaceCustomScreen();
bool OnTouchEvent(TouchEvents event) override;
private:
Controllers::DateTime& dateTimeController;
Controllers::Battery& batteryController;
Controllers::Ble& bleController;
Controllers::NotificationManager& notificatioManager;
Controllers::Settings& settingsController;
Controllers::HeartRateController& heartRateController;
Controllers::MotionController& motionController;
ScreenList<2> screens;
std::unique_ptr<Screen> WatchFaceDigitalScreen();
std::unique_ptr<Screen> WatchFaceAnalogScreen();
// Examples for more watch faces
// std::unique_ptr<Screen> WatchFaceMinimalScreen();
// std::unique_ptr<Screen> WatchFaceCustomScreen();
};
}
}

View file

@ -5,20 +5,21 @@
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
ddlist = lv_ddlist_create(lv_scr_act(), nullptr);
lv_ddlist_set_options(ddlist, "Apple\n"
"Banana\n"
"Orange\n"
"Melon\n"
"Grape\n"
"Raspberry\n"
"A\n"
"B\n"
"C\n"
"D\n"
"E");
lv_ddlist_set_options(ddlist,
"Apple\n"
"Banana\n"
"Orange\n"
"Melon\n"
"Grape\n"
"Raspberry\n"
"A\n"
"B\n"
"C\n"
"D\n"
"E");
lv_ddlist_set_fix_width(ddlist, 150);
lv_ddlist_set_draw_arrow(ddlist, true);
lv_ddlist_set_fix_height(ddlist, 150);
@ -32,12 +33,12 @@ DropDownDemo::~DropDownDemo() {
}
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
// dropdown while it is opened.
// 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);
else
app->SetTouchMode(DisplayApp::TouchModes::Gestures);
@ -47,11 +48,10 @@ bool DropDownDemo::Refresh() {
bool DropDownDemo::OnTouchEvent(Pinetime::Applications::TouchEvents 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).
auto* list = static_cast<lv_ddlist_ext_t *>(ddlist->ext_attr);
if(list->opened) {
auto* list = static_cast<lv_ddlist_ext_t*>(ddlist->ext_attr);
if (list->opened) {
return true;
} else {
return false;
}
}

View file

@ -9,18 +9,18 @@ namespace Pinetime {
namespace Screens {
class DropDownDemo : public Screen {
public:
DropDownDemo(DisplayApp* app);
~DropDownDemo() override;
public:
DropDownDemo(DisplayApp* app);
~DropDownDemo() override;
bool Refresh() override;
bool Refresh() override;
bool OnTouchEvent(TouchEvents event) override;
bool OnTouchEvent(TouchEvents event) override;
private:
lv_obj_t * ddlist;
private:
lv_obj_t* ddlist;
bool isDropDownOpened = false;
bool isDropDownOpened = false;
};
}
}

View file

@ -5,11 +5,10 @@
using namespace Pinetime::Applications::Screens;
FirmwareUpdate::FirmwareUpdate(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Ble& bleController)
: Screen(app), bleController {bleController} {
FirmwareUpdate::FirmwareUpdate(Pinetime::Applications::DisplayApp *app, Pinetime::Controllers::Ble& 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_obj_set_size(backgroundLabel, 240, 240);
lv_obj_set_pos(backgroundLabel, 0, 0);
@ -38,21 +37,21 @@ FirmwareUpdate::~FirmwareUpdate() {
}
bool FirmwareUpdate::Refresh() {
switch(bleController.State()) {
switch (bleController.State()) {
default:
case Pinetime::Controllers::Ble::FirmwareUpdateStates::Idle:
case Pinetime::Controllers::Ble::FirmwareUpdateStates::Running:
if(state != States::Running)
if (state != States::Running)
state = States::Running;
return DisplayProgression();
case Pinetime::Controllers::Ble::FirmwareUpdateStates::Validated:
if(state != States::Validated) {
if (state != States::Validated) {
UpdateValidated();
state = States::Validated;
}
return running;
case Pinetime::Controllers::Ble::FirmwareUpdateStates::Error:
if(state != States::Error) {
if (state != States::Error) {
UpdateError();
state = States::Error;
}

View file

@ -10,29 +10,28 @@ namespace Pinetime {
namespace Applications {
namespace Screens {
class FirmwareUpdate : public Screen{
public:
FirmwareUpdate(DisplayApp* app, Pinetime::Controllers::Ble& bleController);
~FirmwareUpdate() override;
class FirmwareUpdate : public Screen {
public:
FirmwareUpdate(DisplayApp* app, Pinetime::Controllers::Ble& bleController);
~FirmwareUpdate() override;
bool Refresh() override;
bool Refresh() override;
private:
enum class States { Idle, Running, Validated, Error };
Pinetime::Controllers::Ble& bleController;
lv_obj_t* bar1;
lv_obj_t* percentLabel;
lv_obj_t* titleLabel;
mutable char percentStr[10];
private:
enum class States { Idle, Running, Validated, Error };
Pinetime::Controllers::Ble& bleController;
lv_obj_t* bar1;
lv_obj_t* percentLabel;
lv_obj_t* titleLabel;
mutable char percentStr[10];
States state;
States state;
bool DisplayProgression() const;
bool DisplayProgression() const;
void UpdateValidated();
void UpdateValidated();
void UpdateError();
void UpdateError();
};
}
}

View file

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

View file

@ -11,28 +11,26 @@ namespace Pinetime {
namespace Applications {
namespace Screens {
class FirmwareValidation : public Screen{
public:
FirmwareValidation(DisplayApp* app, Pinetime::Controllers::FirmwareValidator& validator);
~FirmwareValidation() override;
class FirmwareValidation : public Screen {
public:
FirmwareValidation(DisplayApp* app, Pinetime::Controllers::FirmwareValidator& validator);
~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:
Pinetime::Controllers::FirmwareValidator& validator;
lv_obj_t* labelVersionInfo;
lv_obj_t* labelVersionValue;
char version[9];
lv_obj_t* labelIsValidated;
lv_obj_t* buttonValidate;
lv_obj_t* labelButtonValidate;
lv_obj_t* buttonReset;
lv_obj_t* labelButtonReset;
private:
Pinetime::Controllers::FirmwareValidator& validator;
lv_obj_t* labelVersionInfo;
lv_obj_t* labelVersionValue;
char version[9];
lv_obj_t* labelIsValidated;
lv_obj_t* buttonValidate;
lv_obj_t* labelButtonValidate;
lv_obj_t* buttonReset;
lv_obj_t* labelButtonReset;
};
}
}

View file

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

View file

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

View file

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

View file

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

View file

@ -4,7 +4,7 @@
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);
std::fill(b, b + bufferSize, selectColor);
}
@ -20,7 +20,7 @@ bool InfiniPaint::Refresh() {
}
bool InfiniPaint::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
switch(event) {
switch (event) {
case Pinetime::Applications::TouchEvents::LongTap:
switch (color) {
case 0:
@ -72,4 +72,3 @@ bool InfiniPaint::OnTouchEvent(uint16_t x, uint16_t y) {
lvgl.FlushDisplay(&area, b);
return true;
}

View file

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

View file

@ -2,12 +2,10 @@
using namespace Pinetime::Applications::Screens;
Label::Label(uint8_t screenID, uint8_t numScreens,
Pinetime::Applications::DisplayApp *app, lv_obj_t* labelText) :
Screen(app),
labelText{labelText} {
Label::Label(uint8_t screenID, uint8_t numScreens, Pinetime::Applications::DisplayApp* app, lv_obj_t* labelText)
: Screen(app), labelText {labelText} {
if ( numScreens > 1 ) {
if (numScreens > 1) {
pageIndicatorBasePoints[0].x = 240 - 1;
pageIndicatorBasePoints[0].y = 6;
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_line_set_points(pageIndicatorBase, pageIndicatorBasePoints, 2);
uint16_t indicatorSize = 228 / numScreens;
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_line_set_points(pageIndicator, pageIndicatorPoints, 2);
}
}
Label::~Label() {

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