Merge branch 'develop' of
https://github.com/JF002/InfiniTime into StepsApp
This commit is contained in:
commit
cd0d85dff9
|
@ -21,8 +21,8 @@ AlwaysBreakAfterDefinitionReturnType: None
|
||||||
AlwaysBreakAfterReturnType: None
|
AlwaysBreakAfterReturnType: None
|
||||||
AlwaysBreakBeforeMultilineStrings: false
|
AlwaysBreakBeforeMultilineStrings: false
|
||||||
AlwaysBreakTemplateDeclarations: MultiLine
|
AlwaysBreakTemplateDeclarations: MultiLine
|
||||||
BinPackArguments: true
|
BinPackArguments: false
|
||||||
BinPackParameters: true
|
BinPackParameters: false
|
||||||
BraceWrapping:
|
BraceWrapping:
|
||||||
AfterCaseLabel: false
|
AfterCaseLabel: false
|
||||||
AfterClass: false
|
AfterClass: false
|
||||||
|
@ -52,14 +52,14 @@ BreakStringLiterals: true
|
||||||
ColumnLimit: 140
|
ColumnLimit: 140
|
||||||
CommentPragmas: '^ IWYU pragma:'
|
CommentPragmas: '^ IWYU pragma:'
|
||||||
CompactNamespaces: false
|
CompactNamespaces: false
|
||||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||||
ConstructorInitializerIndentWidth: 2
|
ConstructorInitializerIndentWidth: 2
|
||||||
ContinuationIndentWidth: 2
|
ContinuationIndentWidth: 2
|
||||||
Cpp11BracedListStyle: true
|
Cpp11BracedListStyle: true
|
||||||
DeriveLineEnding: false
|
DeriveLineEnding: false
|
||||||
DerivePointerAlignment: false
|
DerivePointerAlignment: false
|
||||||
DisableFormat: false
|
DisableFormat: false
|
||||||
ExperimentalAutoDetectBinPacking: false
|
ExperimentalAutoDetectBinPacking: true
|
||||||
FixNamespaceComments: false
|
FixNamespaceComments: false
|
||||||
ForEachMacros:
|
ForEachMacros:
|
||||||
- foreach
|
- foreach
|
||||||
|
@ -90,10 +90,6 @@ MacroBlockBegin: ''
|
||||||
MacroBlockEnd: ''
|
MacroBlockEnd: ''
|
||||||
MaxEmptyLinesToKeep: 1
|
MaxEmptyLinesToKeep: 1
|
||||||
NamespaceIndentation: All
|
NamespaceIndentation: All
|
||||||
ObjCBinPackProtocolList: Auto
|
|
||||||
ObjCBlockIndentWidth: 2
|
|
||||||
ObjCSpaceAfterProperty: false
|
|
||||||
ObjCSpaceBeforeProtocolList: true
|
|
||||||
PenaltyBreakAssignment: 2
|
PenaltyBreakAssignment: 2
|
||||||
PenaltyBreakBeforeFirstCallParameter: 19
|
PenaltyBreakBeforeFirstCallParameter: 19
|
||||||
PenaltyBreakComment: 300
|
PenaltyBreakComment: 300
|
||||||
|
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,4 +1,7 @@
|
||||||
.idea/
|
.idea/
|
||||||
|
# Python virtual environment for DFU images
|
||||||
|
.venv/
|
||||||
|
|
||||||
# CMake
|
# CMake
|
||||||
cmake-build-*
|
cmake-build-*
|
||||||
cmake-*
|
cmake-*
|
||||||
|
|
29
README.md
29
README.md
|
@ -24,8 +24,7 @@ The goal of this project is to design an open-source firmware for the Pinetime s
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
![Pinetime screens](images/0.14.0/collage1.png "PinetimeScreens")
|
![Pinetime screens](images/1.0.0/collage.png "PinetimeScreens")
|
||||||
![Pinetime screens](images/0.14.0/collage2.png "PinetimeScreens")
|
|
||||||
|
|
||||||
As of now, here is the list of achievements of this project:
|
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
|
- Heart rate measurements
|
||||||
- Step counting
|
- Step counting
|
||||||
- Wake-up on wrist rotation
|
- Wake-up on wrist rotation
|
||||||
|
- Quick actions
|
||||||
|
* Disable vibration on notification
|
||||||
|
* Brightness settings
|
||||||
|
* Flashlight
|
||||||
|
* Settings
|
||||||
|
- 2 watch faces:
|
||||||
|
* Digital
|
||||||
|
* Analog
|
||||||
- Multiple 'apps' :
|
- 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)
|
* Music (control the playback of the music on your phone)
|
||||||
* Heart rate (controls the heart rate sensor and display current heartbeat)
|
* Heart rate (controls the heart rate sensor and display current heartbeat)
|
||||||
* Navigation (displays navigation instructions coming from the companion app)
|
* 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)
|
* Paddle (single player pong-like game)
|
||||||
* Two (2048 clone game)
|
* Two (2048 clone game)
|
||||||
* Stopwatch (with all the necessary functions such as play, pause, lap, stop)
|
* 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):
|
- Supported by 3 companion apps (development is in progress):
|
||||||
* [Gadgetbridge](https://codeberg.org/Freeyourgadget/Gadgetbridge/) (on Android)
|
* [Gadgetbridge](https://codeberg.org/Freeyourgadget/Gadgetbridge/) (on Android)
|
||||||
* [Amazfish](https://openrepos.net/content/piggz/amazfish) (on SailfishOS and Linux)
|
* [Amazfish](https://openrepos.net/content/piggz/amazfish) (on SailfishOS and Linux)
|
||||||
* [Siglo](https://github.com/alexr4535/siglo) (on 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]** [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
|
- OTA (Over-the-air) update via BLE
|
||||||
- **[Experimental]** Bootloader based on [MCUBoot](https://juullabs-oss.github.io/mcuboot/)
|
- [Bootloader](https://github.com/JF002/pinetime-mcuboot-bootloader) based on [MCUBoot](https://juullabs-oss.github.io/mcuboot/)
|
||||||
|
|
||||||
## Documentation
|
## 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)
|
- [Flash, upgrade (OTA), time synchronization,...](doc/gettingStarted/gettingStarted.md)
|
||||||
|
|
||||||
### Develop
|
### Develop
|
||||||
- [Generate the fonts and symbols](src/displayapp/fonts/Readme.md)
|
- [Generate the fonts and symbols](src/displayapp/fonts/README.md)
|
||||||
- [Creating a stopwatch in Pinetime(article)](https://pankajraghav.com/2021/04/03/PINETIME-STOPCLOCK.html)
|
- [Creating a stopwatch in Pinetime(article)](https://pankajraghav.com/2021/04/03/PINETIME-STOPCLOCK.html)
|
||||||
|
|
||||||
### Build, flash and debug
|
### Build, flash and debug
|
||||||
|
|
BIN
images/1.0.0/collage.png
Normal file
BIN
images/1.0.0/collage.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 MiB |
|
@ -17,7 +17,7 @@ uint32_t BootloaderVersion::Patch() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *BootloaderVersion::VersionString() {
|
const char* BootloaderVersion::VersionString() {
|
||||||
return "0.0.0";
|
return "0.0.0";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,11 +2,11 @@
|
||||||
|
|
||||||
namespace Pinetime {
|
namespace Pinetime {
|
||||||
class BootloaderVersion {
|
class BootloaderVersion {
|
||||||
public:
|
public:
|
||||||
static uint32_t Major();
|
static uint32_t Major();
|
||||||
static uint32_t Minor();
|
static uint32_t Minor();
|
||||||
static uint32_t Patch();
|
static uint32_t Patch();
|
||||||
static const char* VersionString();
|
static const char* VersionString();
|
||||||
static bool IsValid();
|
static bool IsValid();
|
||||||
};
|
};
|
||||||
}
|
}
|
|
@ -26,20 +26,19 @@
|
||||||
* 1 tab == 4 spaces!
|
* 1 tab == 4 spaces!
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#ifndef FREERTOS_CONFIG_H
|
#ifndef FREERTOS_CONFIG_H
|
||||||
#define FREERTOS_CONFIG_H
|
#define FREERTOS_CONFIG_H
|
||||||
|
|
||||||
#ifdef SOFTDEVICE_PRESENT
|
#ifdef SOFTDEVICE_PRESENT
|
||||||
#include "nrf_soc.h"
|
#include "nrf_soc.h"
|
||||||
#endif
|
#endif
|
||||||
#include "app_util_platform.h"
|
#include "app_util_platform.h"
|
||||||
|
|
||||||
/*-----------------------------------------------------------
|
/*-----------------------------------------------------------
|
||||||
* Possible configurations for system timer
|
* Possible configurations for system timer
|
||||||
*/
|
*/
|
||||||
#define FREERTOS_USE_RTC 0 /**< Use real time clock for the system */
|
#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_SYSTICK 1 /**< Use SysTick timer for system */
|
||||||
|
|
||||||
/*-----------------------------------------------------------
|
/*-----------------------------------------------------------
|
||||||
* Application specific definitions.
|
* Application specific definitions.
|
||||||
|
@ -55,153 +54,150 @@
|
||||||
|
|
||||||
#define configTICK_SOURCE FREERTOS_USE_RTC
|
#define configTICK_SOURCE FREERTOS_USE_RTC
|
||||||
|
|
||||||
#define configUSE_PREEMPTION 1
|
#define configUSE_PREEMPTION 1
|
||||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
||||||
#define configUSE_TICKLESS_IDLE 1
|
#define configUSE_TICKLESS_IDLE 1
|
||||||
#define configUSE_TICKLESS_IDLE_SIMPLE_DEBUG 0 /* See into vPortSuppressTicksAndSleep source code for explanation */
|
#define configUSE_TICKLESS_IDLE_SIMPLE_DEBUG 0 /* See into vPortSuppressTicksAndSleep source code for explanation */
|
||||||
#define configCPU_CLOCK_HZ ( SystemCoreClock )
|
#define configCPU_CLOCK_HZ (SystemCoreClock)
|
||||||
#define configTICK_RATE_HZ 1024
|
#define configTICK_RATE_HZ 1024
|
||||||
#define configMAX_PRIORITIES ( 3 )
|
#define configMAX_PRIORITIES (3)
|
||||||
#define configMINIMAL_STACK_SIZE ( 120 )
|
#define configMINIMAL_STACK_SIZE (120)
|
||||||
#define configTOTAL_HEAP_SIZE ( 1024*16 )
|
#define configTOTAL_HEAP_SIZE (1024 * 16)
|
||||||
#define configMAX_TASK_NAME_LEN ( 4 )
|
#define configMAX_TASK_NAME_LEN (4)
|
||||||
#define configUSE_16_BIT_TICKS 0
|
#define configUSE_16_BIT_TICKS 0
|
||||||
#define configIDLE_SHOULD_YIELD 1
|
#define configIDLE_SHOULD_YIELD 1
|
||||||
#define configUSE_MUTEXES 1
|
#define configUSE_MUTEXES 1
|
||||||
#define configUSE_RECURSIVE_MUTEXES 1
|
#define configUSE_RECURSIVE_MUTEXES 1
|
||||||
#define configUSE_COUNTING_SEMAPHORES 1
|
#define configUSE_COUNTING_SEMAPHORES 1
|
||||||
#define configUSE_ALTERNATIVE_API 0 /* Deprecated! */
|
#define configUSE_ALTERNATIVE_API 0 /* Deprecated! */
|
||||||
#define configQUEUE_REGISTRY_SIZE 2
|
#define configQUEUE_REGISTRY_SIZE 2
|
||||||
#define configUSE_QUEUE_SETS 0
|
#define configUSE_QUEUE_SETS 0
|
||||||
#define configUSE_TIME_SLICING 0
|
#define configUSE_TIME_SLICING 0
|
||||||
#define configUSE_NEWLIB_REENTRANT 0
|
#define configUSE_NEWLIB_REENTRANT 0
|
||||||
#define configENABLE_BACKWARD_COMPATIBILITY 1
|
#define configENABLE_BACKWARD_COMPATIBILITY 1
|
||||||
|
|
||||||
/* Hook function related definitions. */
|
/* Hook function related definitions. */
|
||||||
#define configUSE_IDLE_HOOK 1
|
#define configUSE_IDLE_HOOK 1
|
||||||
#define configUSE_TICK_HOOK 0
|
#define configUSE_TICK_HOOK 0
|
||||||
#define configCHECK_FOR_STACK_OVERFLOW 0
|
#define configCHECK_FOR_STACK_OVERFLOW 0
|
||||||
#define configUSE_MALLOC_FAILED_HOOK 0
|
#define configUSE_MALLOC_FAILED_HOOK 0
|
||||||
|
|
||||||
/* Run time and task stats gathering related definitions. */
|
/* Run time and task stats gathering related definitions. */
|
||||||
#define configGENERATE_RUN_TIME_STATS 0
|
#define configGENERATE_RUN_TIME_STATS 0
|
||||||
#define configUSE_TRACE_FACILITY 1
|
#define configUSE_TRACE_FACILITY 1
|
||||||
#define configUSE_STATS_FORMATTING_FUNCTIONS 0
|
#define configUSE_STATS_FORMATTING_FUNCTIONS 0
|
||||||
|
|
||||||
/* Co-routine definitions. */
|
/* Co-routine definitions. */
|
||||||
#define configUSE_CO_ROUTINES 0
|
#define configUSE_CO_ROUTINES 0
|
||||||
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
|
#define configMAX_CO_ROUTINE_PRIORITIES (2)
|
||||||
|
|
||||||
/* Software timer definitions. */
|
/* Software timer definitions. */
|
||||||
#define configUSE_TIMERS 1
|
#define configUSE_TIMERS 1
|
||||||
#define configTIMER_TASK_PRIORITY ( 0 )
|
#define configTIMER_TASK_PRIORITY (0)
|
||||||
#define configTIMER_QUEUE_LENGTH 32
|
#define configTIMER_QUEUE_LENGTH 32
|
||||||
#define configTIMER_TASK_STACK_DEPTH ( 300 )
|
#define configTIMER_TASK_STACK_DEPTH (300)
|
||||||
|
|
||||||
/* Tickless Idle configuration. */
|
/* Tickless Idle configuration. */
|
||||||
#define configEXPECTED_IDLE_TIME_BEFORE_SLEEP 2
|
#define configEXPECTED_IDLE_TIME_BEFORE_SLEEP 2
|
||||||
|
|
||||||
/* Tickless idle/low power functionality. */
|
/* Tickless idle/low power functionality. */
|
||||||
|
|
||||||
|
|
||||||
/* Define to trap errors during development. */
|
/* Define to trap errors during development. */
|
||||||
#if defined(DEBUG_NRF) || defined(DEBUG_NRF_USER)
|
#if defined(DEBUG_NRF) || defined(DEBUG_NRF_USER)
|
||||||
#define configASSERT( x ) ASSERT(x)
|
#define configASSERT(x) ASSERT(x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* FreeRTOS MPU specific definitions. */
|
/* FreeRTOS MPU specific definitions. */
|
||||||
#define configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS 1
|
#define configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS 1
|
||||||
|
|
||||||
/* Optional functions - most linkers will remove unused functions anyway. */
|
/* Optional functions - most linkers will remove unused functions anyway. */
|
||||||
#define INCLUDE_vTaskPrioritySet 1
|
#define INCLUDE_vTaskPrioritySet 1
|
||||||
#define INCLUDE_uxTaskPriorityGet 1
|
#define INCLUDE_uxTaskPriorityGet 1
|
||||||
#define INCLUDE_vTaskDelete 1
|
#define INCLUDE_vTaskDelete 1
|
||||||
#define INCLUDE_vTaskSuspend 1
|
#define INCLUDE_vTaskSuspend 1
|
||||||
#define INCLUDE_xResumeFromISR 1
|
#define INCLUDE_xResumeFromISR 1
|
||||||
#define INCLUDE_vTaskDelayUntil 1
|
#define INCLUDE_vTaskDelayUntil 1
|
||||||
#define INCLUDE_vTaskDelay 1
|
#define INCLUDE_vTaskDelay 1
|
||||||
#define INCLUDE_xTaskGetSchedulerState 1
|
#define INCLUDE_xTaskGetSchedulerState 1
|
||||||
#define INCLUDE_xTaskGetCurrentTaskHandle 1
|
#define INCLUDE_xTaskGetCurrentTaskHandle 1
|
||||||
#define INCLUDE_uxTaskGetStackHighWaterMark 1
|
#define INCLUDE_uxTaskGetStackHighWaterMark 1
|
||||||
#define INCLUDE_xTaskGetIdleTaskHandle 1
|
#define INCLUDE_xTaskGetIdleTaskHandle 1
|
||||||
#define INCLUDE_xTimerGetTimerDaemonTaskHandle 1
|
#define INCLUDE_xTimerGetTimerDaemonTaskHandle 1
|
||||||
#define INCLUDE_pcTaskGetTaskName 1
|
#define INCLUDE_pcTaskGetTaskName 1
|
||||||
#define INCLUDE_eTaskGetState 1
|
#define INCLUDE_eTaskGetState 1
|
||||||
#define INCLUDE_xEventGroupSetBitFromISR 1
|
#define INCLUDE_xEventGroupSetBitFromISR 1
|
||||||
#define INCLUDE_xTimerPendFunctionCall 1
|
#define INCLUDE_xTimerPendFunctionCall 1
|
||||||
|
|
||||||
/* The lowest interrupt priority that can be used in a call to a "set priority"
|
/* The lowest interrupt priority that can be used in a call to a "set priority"
|
||||||
function. */
|
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
|
/* 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
|
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
|
INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
|
||||||
PRIORITY THAN THIS! (higher priorities are lower numeric values. */
|
PRIORITY THAN THIS! (higher priorities are lower numeric values. */
|
||||||
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY _PRIO_APP_HIGH
|
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY _PRIO_APP_HIGH
|
||||||
|
|
||||||
|
|
||||||
/* Interrupt priorities used by the kernel port layer itself. These are generic
|
/* Interrupt priorities used by the kernel port layer itself. These are generic
|
||||||
to all Cortex-M ports, and do not rely on any particular library functions. */
|
to all Cortex-M ports, and do not rely on any particular library functions. */
|
||||||
#define configKERNEL_INTERRUPT_PRIORITY configLIBRARY_LOWEST_INTERRUPT_PRIORITY
|
#define configKERNEL_INTERRUPT_PRIORITY configLIBRARY_LOWEST_INTERRUPT_PRIORITY
|
||||||
/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
|
/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
|
||||||
See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
|
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
|
/* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS
|
||||||
standard names - or at least those used in the unmodified vector table. */
|
standard names - or at least those used in the unmodified vector table. */
|
||||||
|
|
||||||
#define vPortSVCHandler SVC_Handler
|
#define vPortSVCHandler SVC_Handler
|
||||||
#define xPortPendSVHandler PendSV_Handler
|
#define xPortPendSVHandler PendSV_Handler
|
||||||
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------
|
/*-----------------------------------------------------------
|
||||||
* Settings that are generated automatically
|
* Settings that are generated automatically
|
||||||
* basing on the settings above
|
* basing on the settings above
|
||||||
*/
|
*/
|
||||||
#if (configTICK_SOURCE == FREERTOS_USE_SYSTICK)
|
#if (configTICK_SOURCE == FREERTOS_USE_SYSTICK)
|
||||||
// do not define configSYSTICK_CLOCK_HZ for SysTick to be configured automatically
|
// do not define configSYSTICK_CLOCK_HZ for SysTick to be configured automatically
|
||||||
// to CPU clock source
|
// to CPU clock source
|
||||||
#define xPortSysTickHandler SysTick_Handler
|
#define xPortSysTickHandler SysTick_Handler
|
||||||
#elif (configTICK_SOURCE == FREERTOS_USE_RTC)
|
#elif (configTICK_SOURCE == FREERTOS_USE_RTC)
|
||||||
#define configSYSTICK_CLOCK_HZ ( 32768UL )
|
#define configSYSTICK_CLOCK_HZ (32768UL)
|
||||||
#define xPortSysTickHandler RTC1_IRQHandler
|
#define xPortSysTickHandler RTC1_IRQHandler
|
||||||
#else
|
#else
|
||||||
#error Unsupported configTICK_SOURCE value
|
#error Unsupported configTICK_SOURCE value
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Code below should be only used by the compiler, and not the assembler. */
|
/* Code below should be only used by the compiler, and not the assembler. */
|
||||||
#if !(defined(__ASSEMBLY__) || defined(__ASSEMBLER__))
|
#if !(defined(__ASSEMBLY__) || defined(__ASSEMBLER__))
|
||||||
#include "nrf.h"
|
#include "nrf.h"
|
||||||
#include "nrf_assert.h"
|
#include "nrf_assert.h"
|
||||||
|
|
||||||
/* This part of definitions may be problematic in assembly - it uses definitions from files that are not assembly compatible. */
|
/* This part of definitions may be problematic in assembly - it uses definitions from files that are not assembly compatible. */
|
||||||
/* Cortex-M specific definitions. */
|
/* Cortex-M specific definitions. */
|
||||||
#ifdef __NVIC_PRIO_BITS
|
#ifdef __NVIC_PRIO_BITS
|
||||||
/* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */
|
/* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */
|
||||||
#define configPRIO_BITS __NVIC_PRIO_BITS
|
#define configPRIO_BITS __NVIC_PRIO_BITS
|
||||||
#else
|
#else
|
||||||
#error "This port requires __NVIC_PRIO_BITS to be defined"
|
#error "This port requires __NVIC_PRIO_BITS to be defined"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Access to current system core clock is required only if we are ticking the system by systimer */
|
/* Access to current system core clock is required only if we are ticking the system by systimer */
|
||||||
#if (configTICK_SOURCE == FREERTOS_USE_SYSTICK)
|
#if (configTICK_SOURCE == FREERTOS_USE_SYSTICK)
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
extern uint32_t SystemCoreClock;
|
extern uint32_t SystemCoreClock;
|
||||||
#endif
|
#endif
|
||||||
#endif /* !assembler */
|
#endif /* !assembler */
|
||||||
|
|
||||||
/** Implementation note: Use this with caution and set this to 1 ONLY for debugging
|
/** 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:
|
* 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
|
* 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
|
* one or more RTC ticks are lost. The tick interrupt inside RTOS will detect this and make a correction needed. This is needed
|
||||||
* for the RTOS internal timers to be more accurate.
|
* for the RTOS internal timers to be more accurate.
|
||||||
* 1. The auto correction for RTOS tick is disabled even though few RTC tick interrupts were lost. This feature is desirable when debugging
|
* 1. The auto correction for RTOS tick is disabled even though few RTC tick interrupts were lost. This feature is desirable when debugging
|
||||||
* the RTOS application and stepping though the code. After stepping when the application is continued in debug mode, the auto-corrections of
|
* the RTOS application and stepping though the code. After stepping when the application is continued in debug mode, the
|
||||||
* RTOS tick might cause asserts. Setting configUSE_DISABLE_TICK_AUTO_CORRECTION_DEBUG to 1 will make RTC and RTOS go out of sync but could be
|
* auto-corrections of RTOS tick might cause asserts. Setting configUSE_DISABLE_TICK_AUTO_CORRECTION_DEBUG to 1 will make RTC and RTOS go
|
||||||
* convenient for debugging.
|
* out of sync but could be convenient for debugging.
|
||||||
*/
|
*/
|
||||||
#define configUSE_DISABLE_TICK_AUTO_CORRECTION_DEBUG 0
|
#define configUSE_DISABLE_TICK_AUTO_CORRECTION_DEBUG 0
|
||||||
|
|
||||||
#endif /* FREERTOS_CONFIG_H */
|
#endif /* FREERTOS_CONFIG_H */
|
||||||
|
|
|
@ -7,15 +7,15 @@
|
||||||
|
|
||||||
using namespace Pinetime::Controllers;
|
using namespace Pinetime::Controllers;
|
||||||
|
|
||||||
Battery *Battery::instance = nullptr;
|
Battery* Battery::instance = nullptr;
|
||||||
|
|
||||||
Battery::Battery() {
|
Battery::Battery() {
|
||||||
instance = this;
|
instance = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Battery::Init() {
|
void Battery::Init() {
|
||||||
nrf_gpio_cfg_input(chargingPin, (nrf_gpio_pin_pull_t)GPIO_PIN_CNF_PULL_Pullup);
|
nrf_gpio_cfg_input(chargingPin, (nrf_gpio_pin_pull_t) GPIO_PIN_CNF_PULL_Pullup);
|
||||||
nrf_gpio_cfg_input(powerPresentPin, (nrf_gpio_pin_pull_t)GPIO_PIN_CNF_PULL_Pullup);
|
nrf_gpio_cfg_input(powerPresentPin, (nrf_gpio_pin_pull_t) GPIO_PIN_CNF_PULL_Pullup);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Battery::Update() {
|
void Battery::Update() {
|
||||||
|
@ -23,17 +23,17 @@ void Battery::Update() {
|
||||||
isCharging = !nrf_gpio_pin_read(chargingPin);
|
isCharging = !nrf_gpio_pin_read(chargingPin);
|
||||||
isPowerPresent = !nrf_gpio_pin_read(powerPresentPin);
|
isPowerPresent = !nrf_gpio_pin_read(powerPresentPin);
|
||||||
|
|
||||||
if ( isReading ) return;
|
if (isReading)
|
||||||
|
return;
|
||||||
// Non blocking read
|
// Non blocking read
|
||||||
samples = 0;
|
samples = 0;
|
||||||
isReading = true;
|
isReading = true;
|
||||||
SaadcInit();
|
SaadcInit();
|
||||||
|
|
||||||
nrfx_saadc_sample();
|
nrfx_saadc_sample();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Battery::adcCallbackStatic(nrfx_saadc_evt_t const *event) {
|
void Battery::adcCallbackStatic(nrfx_saadc_evt_t const* event) {
|
||||||
instance->SaadcEventHandler(event);
|
instance->SaadcEventHandler(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,48 +41,44 @@ void Battery::SaadcInit() {
|
||||||
nrfx_saadc_config_t adcConfig = NRFX_SAADC_DEFAULT_CONFIG;
|
nrfx_saadc_config_t adcConfig = NRFX_SAADC_DEFAULT_CONFIG;
|
||||||
APP_ERROR_CHECK(nrfx_saadc_init(&adcConfig, adcCallbackStatic));
|
APP_ERROR_CHECK(nrfx_saadc_init(&adcConfig, adcCallbackStatic));
|
||||||
|
|
||||||
nrf_saadc_channel_config_t adcChannelConfig = {
|
nrf_saadc_channel_config_t adcChannelConfig = {.resistor_p = NRF_SAADC_RESISTOR_DISABLED,
|
||||||
.resistor_p = NRF_SAADC_RESISTOR_DISABLED,
|
.resistor_n = NRF_SAADC_RESISTOR_DISABLED,
|
||||||
.resistor_n = NRF_SAADC_RESISTOR_DISABLED,
|
.gain = NRF_SAADC_GAIN1_5,
|
||||||
.gain = NRF_SAADC_GAIN1_5,
|
.reference = NRF_SAADC_REFERENCE_INTERNAL,
|
||||||
.reference = NRF_SAADC_REFERENCE_INTERNAL,
|
.acq_time = NRF_SAADC_ACQTIME_3US,
|
||||||
.acq_time = NRF_SAADC_ACQTIME_3US,
|
.mode = NRF_SAADC_MODE_SINGLE_ENDED,
|
||||||
.mode = NRF_SAADC_MODE_SINGLE_ENDED,
|
.burst = NRF_SAADC_BURST_ENABLED,
|
||||||
.burst = NRF_SAADC_BURST_ENABLED,
|
.pin_p = batteryVoltageAdcInput,
|
||||||
.pin_p = batteryVoltageAdcInput,
|
.pin_n = NRF_SAADC_INPUT_DISABLED};
|
||||||
.pin_n = NRF_SAADC_INPUT_DISABLED
|
|
||||||
};
|
|
||||||
APP_ERROR_CHECK(nrfx_saadc_channel_init(0, &adcChannelConfig));
|
APP_ERROR_CHECK(nrfx_saadc_channel_init(0, &adcChannelConfig));
|
||||||
APP_ERROR_CHECK(nrfx_saadc_buffer_convert(&saadc_value, 1));
|
APP_ERROR_CHECK(nrfx_saadc_buffer_convert(&saadc_value, 1));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Battery::SaadcEventHandler(nrfx_saadc_evt_t const * p_event) {
|
void Battery::SaadcEventHandler(nrfx_saadc_evt_t const* p_event) {
|
||||||
|
|
||||||
const float battery_max = 4.18; // maximum voltage of battery ( max charging voltage is 4.21 )
|
const float battery_max = 4.18; // maximum voltage of battery ( max charging voltage is 4.21 )
|
||||||
const float battery_min = 3.20; // minimum voltage of battery before shutdown ( depends on the battery )
|
const float battery_min = 3.20; // minimum voltage of battery before shutdown ( depends on the battery )
|
||||||
|
|
||||||
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 = (static_cast<float>(p_event->data.done.p_buffer[0]) * 2.04f) / (1024 / 3.0f);
|
||||||
voltage = roundf(voltage * 100) / 100;
|
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::max(percentRemaining, 0);
|
||||||
percentRemaining = std::min(percentRemaining, 100);
|
percentRemaining = std::min(percentRemaining, 100);
|
||||||
|
|
||||||
percentRemainingBuffer.insert(percentRemaining);
|
percentRemainingBuffer.insert(percentRemaining);
|
||||||
|
|
||||||
samples++;
|
samples++;
|
||||||
if ( samples > percentRemainingSamples ) {
|
if (samples > percentRemainingSamples) {
|
||||||
nrfx_saadc_uninit();
|
nrfx_saadc_uninit();
|
||||||
isReading = false;
|
isReading = false;
|
||||||
} else {
|
} else {
|
||||||
nrfx_saadc_sample();
|
nrfx_saadc_sample();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -11,10 +11,10 @@ namespace Pinetime {
|
||||||
out the sensor values. The total capacity of the CircBuffer
|
out the sensor values. The total capacity of the CircBuffer
|
||||||
is given as the template parameter N.
|
is given as the template parameter N.
|
||||||
*/
|
*/
|
||||||
template <int N>
|
template <int N> class CircBuffer {
|
||||||
class CircBuffer {
|
|
||||||
public:
|
public:
|
||||||
CircBuffer() : arr{}, sz{}, cap{N}, head{} {}
|
CircBuffer() : arr {}, sz {}, cap {N}, head {} {
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
insert member function overwrites the next data to the current
|
insert member function overwrites the next data to the current
|
||||||
HEAD and moves the HEAD to the newly inserted value.
|
HEAD and moves the HEAD to the newly inserted value.
|
||||||
|
@ -34,49 +34,56 @@ namespace Pinetime {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::array<int, N> arr; /**< internal array used to store the values*/
|
std::array<int, N> arr; /**< internal array used to store the values*/
|
||||||
uint8_t sz; /**< The current size of the array.*/
|
uint8_t sz; /**< The current size of the array.*/
|
||||||
uint8_t cap; /**< Total capacity of the CircBuffer.*/
|
uint8_t cap; /**< Total capacity of the CircBuffer.*/
|
||||||
uint8_t head; /**< The current head of the CircBuffer*/
|
uint8_t head; /**< The current head of the CircBuffer*/
|
||||||
};
|
};
|
||||||
|
|
||||||
class Battery {
|
class Battery {
|
||||||
public:
|
public:
|
||||||
|
Battery();
|
||||||
|
|
||||||
Battery();
|
void Init();
|
||||||
|
void Update();
|
||||||
|
|
||||||
void Init();
|
int PercentRemaining() const {
|
||||||
void Update();
|
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; }
|
private:
|
||||||
bool IsPowerPresent() const { return isPowerPresent; }
|
static Battery* instance;
|
||||||
|
nrf_saadc_value_t saadc_value;
|
||||||
|
|
||||||
private:
|
static constexpr uint8_t percentRemainingSamples = 5;
|
||||||
static Battery *instance;
|
CircBuffer<percentRemainingSamples> percentRemainingBuffer {};
|
||||||
nrf_saadc_value_t saadc_value;
|
|
||||||
|
|
||||||
static constexpr uint8_t percentRemainingSamples = 5;
|
static constexpr uint32_t chargingPin = 12;
|
||||||
CircBuffer<percentRemainingSamples> percentRemainingBuffer {};
|
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;
|
bool isCharging = false;
|
||||||
static constexpr uint32_t powerPresentPin = 19;
|
bool isPowerPresent = false;
|
||||||
static constexpr nrf_saadc_input_t batteryVoltageAdcInput = NRF_SAADC_INPUT_AIN7;
|
|
||||||
float voltage = 0.0f;
|
|
||||||
int percentRemaining = -1;
|
|
||||||
|
|
||||||
bool isCharging = false;
|
void SaadcInit();
|
||||||
bool isPowerPresent = false;
|
|
||||||
|
|
||||||
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);
|
bool isReading = false;
|
||||||
static void adcCallbackStatic(nrfx_saadc_evt_t const *event);
|
uint8_t samples = 0;
|
||||||
|
|
||||||
bool isReading = false;
|
|
||||||
uint8_t samples = 0;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -12,50 +12,42 @@ constexpr ble_uuid16_t AlertNotificationClient::unreadAlertStatusUuid;
|
||||||
constexpr ble_uuid16_t AlertNotificationClient::controlPointUuid;
|
constexpr ble_uuid16_t AlertNotificationClient::controlPointUuid;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
int
|
int OnDiscoveryEventCallback(uint16_t conn_handle, const struct ble_gatt_error* error, const struct ble_gatt_svc* service, void* arg) {
|
||||||
OnDiscoveryEventCallback(uint16_t conn_handle, const struct ble_gatt_error *error, const struct ble_gatt_svc *service,
|
auto client = static_cast<AlertNotificationClient*>(arg);
|
||||||
void *arg) {
|
|
||||||
auto client = static_cast<AlertNotificationClient *>(arg);
|
|
||||||
return client->OnDiscoveryEvent(conn_handle, error, service);
|
return client->OnDiscoveryEvent(conn_handle, error, service);
|
||||||
}
|
}
|
||||||
|
|
||||||
int OnAlertNotificationCharacteristicDiscoveredCallback(uint16_t conn_handle, const struct ble_gatt_error *error,
|
int OnAlertNotificationCharacteristicDiscoveredCallback(uint16_t conn_handle,
|
||||||
const struct ble_gatt_chr *chr, void *arg) {
|
const struct ble_gatt_error* error,
|
||||||
auto client = static_cast<AlertNotificationClient *>(arg);
|
const struct ble_gatt_chr* chr,
|
||||||
|
void* arg) {
|
||||||
|
auto client = static_cast<AlertNotificationClient*>(arg);
|
||||||
return client->OnCharacteristicsDiscoveryEvent(conn_handle, error, chr);
|
return client->OnCharacteristicsDiscoveryEvent(conn_handle, error, chr);
|
||||||
}
|
}
|
||||||
|
|
||||||
int OnAlertNotificationDescriptorDiscoveryEventCallback(uint16_t conn_handle,
|
int OnAlertNotificationDescriptorDiscoveryEventCallback(
|
||||||
const struct ble_gatt_error *error,
|
uint16_t conn_handle, const struct ble_gatt_error* error, uint16_t chr_val_handle, const struct ble_gatt_dsc* dsc, void* arg) {
|
||||||
uint16_t chr_val_handle,
|
auto client = static_cast<AlertNotificationClient*>(arg);
|
||||||
const struct ble_gatt_dsc *dsc,
|
|
||||||
void *arg) {
|
|
||||||
auto client = static_cast<AlertNotificationClient *>(arg);
|
|
||||||
return client->OnDescriptorDiscoveryEventCallback(conn_handle, error, chr_val_handle, dsc);
|
return client->OnDescriptorDiscoveryEventCallback(conn_handle, error, chr_val_handle, dsc);
|
||||||
}
|
}
|
||||||
|
|
||||||
int NewAlertSubcribeCallback(uint16_t conn_handle,
|
int NewAlertSubcribeCallback(uint16_t conn_handle, const struct ble_gatt_error* error, struct ble_gatt_attr* attr, void* arg) {
|
||||||
const struct ble_gatt_error *error,
|
auto client = static_cast<AlertNotificationClient*>(arg);
|
||||||
struct ble_gatt_attr *attr,
|
|
||||||
void *arg) {
|
|
||||||
auto client = static_cast<AlertNotificationClient *>(arg);
|
|
||||||
return client->OnNewAlertSubcribe(conn_handle, error, attr);
|
return client->OnNewAlertSubcribe(conn_handle, error, attr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AlertNotificationClient::AlertNotificationClient(Pinetime::System::SystemTask &systemTask,
|
AlertNotificationClient::AlertNotificationClient(Pinetime::System::SystemTask& systemTask,
|
||||||
Pinetime::Controllers::NotificationManager ¬ificationManager) :
|
Pinetime::Controllers::NotificationManager& notificationManager)
|
||||||
systemTask{systemTask}, notificationManager{notificationManager} {
|
: systemTask {systemTask}, notificationManager {notificationManager} {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AlertNotificationClient::OnDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error *error,
|
bool AlertNotificationClient::OnDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error* error, const ble_gatt_svc* service) {
|
||||||
const ble_gatt_svc *service) {
|
|
||||||
if (service == nullptr && error->status == BLE_HS_EDONE) {
|
if (service == nullptr && error->status == BLE_HS_EDONE) {
|
||||||
if (isDiscovered) {
|
if (isDiscovered) {
|
||||||
NRF_LOG_INFO("ANS Discovery found, starting characteristics discovery");
|
NRF_LOG_INFO("ANS Discovery found, starting characteristics discovery");
|
||||||
|
|
||||||
ble_gattc_disc_all_chrs(connectionHandle, ansStartHandle, ansEndHandle,
|
ble_gattc_disc_all_chrs(connectionHandle, ansStartHandle, ansEndHandle, OnAlertNotificationCharacteristicDiscoveredCallback, this);
|
||||||
OnAlertNotificationCharacteristicDiscoveredCallback, this);
|
|
||||||
} else {
|
} else {
|
||||||
NRF_LOG_INFO("ANS not found");
|
NRF_LOG_INFO("ANS not found");
|
||||||
onServiceDiscovered(connectionHandle);
|
onServiceDiscovered(connectionHandle);
|
||||||
|
@ -63,7 +55,7 @@ bool AlertNotificationClient::OnDiscoveryEvent(uint16_t connectionHandle, const
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (service != nullptr && ble_uuid_cmp(((ble_uuid_t *) &ansServiceUuid), &service->uuid.u) == 0) {
|
if (service != nullptr && ble_uuid_cmp(((ble_uuid_t*) &ansServiceUuid), &service->uuid.u) == 0) {
|
||||||
NRF_LOG_INFO("ANS discovered : 0x%x - 0x%x", service->start_handle, service->end_handle);
|
NRF_LOG_INFO("ANS discovered : 0x%x - 0x%x", service->start_handle, service->end_handle);
|
||||||
ansStartHandle = service->start_handle;
|
ansStartHandle = service->start_handle;
|
||||||
ansEndHandle = service->end_handle;
|
ansEndHandle = service->end_handle;
|
||||||
|
@ -72,8 +64,9 @@ bool AlertNotificationClient::OnDiscoveryEvent(uint16_t connectionHandle, const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int AlertNotificationClient::OnCharacteristicsDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error *error,
|
int AlertNotificationClient::OnCharacteristicsDiscoveryEvent(uint16_t connectionHandle,
|
||||||
const ble_gatt_chr *characteristic) {
|
const ble_gatt_error* error,
|
||||||
|
const ble_gatt_chr* characteristic) {
|
||||||
if (error->status != 0 && error->status != BLE_HS_EDONE) {
|
if (error->status != 0 && error->status != BLE_HS_EDONE) {
|
||||||
NRF_LOG_INFO("ANS Characteristic discovery ERROR");
|
NRF_LOG_INFO("ANS Characteristic discovery ERROR");
|
||||||
onServiceDiscovered(connectionHandle);
|
onServiceDiscovered(connectionHandle);
|
||||||
|
@ -83,41 +76,34 @@ int AlertNotificationClient::OnCharacteristicsDiscoveryEvent(uint16_t connection
|
||||||
if (characteristic == nullptr && error->status == BLE_HS_EDONE) {
|
if (characteristic == nullptr && error->status == BLE_HS_EDONE) {
|
||||||
NRF_LOG_INFO("ANS Characteristic discovery complete");
|
NRF_LOG_INFO("ANS Characteristic discovery complete");
|
||||||
if (isCharacteristicDiscovered) {
|
if (isCharacteristicDiscovered) {
|
||||||
ble_gattc_disc_all_dscs(connectionHandle,
|
ble_gattc_disc_all_dscs(connectionHandle, newAlertHandle, ansEndHandle, OnAlertNotificationDescriptorDiscoveryEventCallback, this);
|
||||||
newAlertHandle, ansEndHandle,
|
|
||||||
OnAlertNotificationDescriptorDiscoveryEventCallback, this);
|
|
||||||
} else
|
} else
|
||||||
onServiceDiscovered(connectionHandle);
|
onServiceDiscovered(connectionHandle);
|
||||||
} else {
|
} else {
|
||||||
if (characteristic != nullptr &&
|
if (characteristic != nullptr && ble_uuid_cmp(((ble_uuid_t*) &supportedNewAlertCategoryUuid), &characteristic->uuid.u) == 0) {
|
||||||
ble_uuid_cmp(((ble_uuid_t *) &supportedNewAlertCategoryUuid), &characteristic->uuid.u) == 0) {
|
|
||||||
NRF_LOG_INFO("ANS Characteristic discovered : supportedNewAlertCategoryUuid");
|
NRF_LOG_INFO("ANS Characteristic discovered : supportedNewAlertCategoryUuid");
|
||||||
supportedNewAlertCategoryHandle = characteristic->val_handle;
|
supportedNewAlertCategoryHandle = characteristic->val_handle;
|
||||||
} else if (characteristic != nullptr &&
|
} else if (characteristic != nullptr && ble_uuid_cmp(((ble_uuid_t*) &supportedUnreadAlertCategoryUuid), &characteristic->uuid.u) == 0) {
|
||||||
ble_uuid_cmp(((ble_uuid_t *) &supportedUnreadAlertCategoryUuid), &characteristic->uuid.u) == 0) {
|
|
||||||
NRF_LOG_INFO("ANS Characteristic discovered : supportedUnreadAlertCategoryUuid");
|
NRF_LOG_INFO("ANS Characteristic discovered : supportedUnreadAlertCategoryUuid");
|
||||||
supportedUnreadAlertCategoryHandle = characteristic->val_handle;
|
supportedUnreadAlertCategoryHandle = characteristic->val_handle;
|
||||||
} else if (characteristic != nullptr &&
|
} else if (characteristic != nullptr && ble_uuid_cmp(((ble_uuid_t*) &newAlertUuid), &characteristic->uuid.u) == 0) {
|
||||||
ble_uuid_cmp(((ble_uuid_t *) &newAlertUuid), &characteristic->uuid.u) == 0) {
|
|
||||||
NRF_LOG_INFO("ANS Characteristic discovered : newAlertUuid");
|
NRF_LOG_INFO("ANS Characteristic discovered : newAlertUuid");
|
||||||
newAlertHandle = characteristic->val_handle;
|
newAlertHandle = characteristic->val_handle;
|
||||||
newAlertDefHandle = characteristic->def_handle;
|
newAlertDefHandle = characteristic->def_handle;
|
||||||
isCharacteristicDiscovered = true;
|
isCharacteristicDiscovered = true;
|
||||||
} else if (characteristic != nullptr &&
|
} else if (characteristic != nullptr && ble_uuid_cmp(((ble_uuid_t*) &unreadAlertStatusUuid), &characteristic->uuid.u) == 0) {
|
||||||
ble_uuid_cmp(((ble_uuid_t *) &unreadAlertStatusUuid), &characteristic->uuid.u) == 0) {
|
|
||||||
NRF_LOG_INFO("ANS Characteristic discovered : unreadAlertStatusUuid");
|
NRF_LOG_INFO("ANS Characteristic discovered : unreadAlertStatusUuid");
|
||||||
unreadAlertStatusHandle = characteristic->val_handle;
|
unreadAlertStatusHandle = characteristic->val_handle;
|
||||||
} else if (characteristic != nullptr &&
|
} else if (characteristic != nullptr && ble_uuid_cmp(((ble_uuid_t*) &controlPointUuid), &characteristic->uuid.u) == 0) {
|
||||||
ble_uuid_cmp(((ble_uuid_t *) &controlPointUuid), &characteristic->uuid.u) == 0) {
|
|
||||||
NRF_LOG_INFO("ANS Characteristic discovered : controlPointUuid");
|
NRF_LOG_INFO("ANS Characteristic discovered : controlPointUuid");
|
||||||
controlPointHandle = characteristic->val_handle;
|
controlPointHandle = characteristic->val_handle;
|
||||||
} else NRF_LOG_INFO("ANS Characteristic discovered : 0x%x", characteristic->val_handle);
|
} else
|
||||||
|
NRF_LOG_INFO("ANS Characteristic discovered : 0x%x", characteristic->val_handle);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int AlertNotificationClient::OnNewAlertSubcribe(uint16_t connectionHandle, const ble_gatt_error *error,
|
int AlertNotificationClient::OnNewAlertSubcribe(uint16_t connectionHandle, const ble_gatt_error* error, ble_gatt_attr* attribute) {
|
||||||
ble_gatt_attr *attribute) {
|
|
||||||
if (error->status == 0) {
|
if (error->status == 0) {
|
||||||
NRF_LOG_INFO("ANS New alert subscribe OK");
|
NRF_LOG_INFO("ANS New alert subscribe OK");
|
||||||
} else {
|
} else {
|
||||||
|
@ -128,12 +114,12 @@ int AlertNotificationClient::OnNewAlertSubcribe(uint16_t connectionHandle, const
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int AlertNotificationClient::OnDescriptorDiscoveryEventCallback(uint16_t connectionHandle, const ble_gatt_error *error,
|
int AlertNotificationClient::OnDescriptorDiscoveryEventCallback(uint16_t connectionHandle,
|
||||||
|
const ble_gatt_error* error,
|
||||||
uint16_t characteristicValueHandle,
|
uint16_t characteristicValueHandle,
|
||||||
const ble_gatt_dsc *descriptor) {
|
const ble_gatt_dsc* descriptor) {
|
||||||
if (error->status == 0) {
|
if (error->status == 0) {
|
||||||
if (characteristicValueHandle == newAlertHandle &&
|
if (characteristicValueHandle == newAlertHandle && ble_uuid_cmp(((ble_uuid_t*) &newAlertUuid), &descriptor->uuid.u)) {
|
||||||
ble_uuid_cmp(((ble_uuid_t *) &newAlertUuid), &descriptor->uuid.u)) {
|
|
||||||
if (newAlertDescriptorHandle == 0) {
|
if (newAlertDescriptorHandle == 0) {
|
||||||
NRF_LOG_INFO("ANS Descriptor discovered : %d", descriptor->handle);
|
NRF_LOG_INFO("ANS Descriptor discovered : %d", descriptor->handle);
|
||||||
newAlertDescriptorHandle = descriptor->handle;
|
newAlertDescriptorHandle = descriptor->handle;
|
||||||
|
@ -151,16 +137,17 @@ int AlertNotificationClient::OnDescriptorDiscoveryEventCallback(uint16_t connect
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AlertNotificationClient::OnNotification(ble_gap_event *event) {
|
void AlertNotificationClient::OnNotification(ble_gap_event* event) {
|
||||||
if (event->notify_rx.attr_handle == newAlertHandle) {
|
if (event->notify_rx.attr_handle == newAlertHandle) {
|
||||||
constexpr size_t stringTerminatorSize = 1; // end of string '\0'
|
constexpr size_t stringTerminatorSize = 1; // end of string '\0'
|
||||||
constexpr size_t headerSize = 3;
|
constexpr size_t headerSize = 3;
|
||||||
const auto maxMessageSize{NotificationManager::MaximumMessageSize()};
|
const auto maxMessageSize {NotificationManager::MaximumMessageSize()};
|
||||||
const auto maxBufferSize{maxMessageSize + headerSize};
|
const auto maxBufferSize {maxMessageSize + headerSize};
|
||||||
|
|
||||||
// Ignore notifications with empty message
|
// Ignore notifications with empty message
|
||||||
const auto packetLen = OS_MBUF_PKTLEN(event->notify_rx.om);
|
const auto packetLen = OS_MBUF_PKTLEN(event->notify_rx.om);
|
||||||
if(packetLen <= headerSize) return;
|
if (packetLen <= headerSize)
|
||||||
|
return;
|
||||||
|
|
||||||
size_t bufferSize = std::min(packetLen + stringTerminatorSize, maxBufferSize);
|
size_t bufferSize = std::min(packetLen + stringTerminatorSize, maxBufferSize);
|
||||||
auto messageSize = std::min(maxMessageSize, (bufferSize - headerSize));
|
auto messageSize = std::min(maxMessageSize, (bufferSize - headerSize));
|
||||||
|
|
|
@ -19,68 +19,52 @@ namespace Pinetime {
|
||||||
class NotificationManager;
|
class NotificationManager;
|
||||||
|
|
||||||
class AlertNotificationClient : public BleClient {
|
class AlertNotificationClient : public BleClient {
|
||||||
public:
|
public:
|
||||||
explicit AlertNotificationClient(Pinetime::System::SystemTask &systemTask,
|
explicit AlertNotificationClient(Pinetime::System::SystemTask& systemTask,
|
||||||
Pinetime::Controllers::NotificationManager ¬ificationManager);
|
Pinetime::Controllers::NotificationManager& notificationManager);
|
||||||
|
|
||||||
bool OnDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error *error, const ble_gatt_svc *service);
|
bool OnDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error* error, const ble_gatt_svc* service);
|
||||||
int OnCharacteristicsDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error *error,
|
int OnCharacteristicsDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error* error, const ble_gatt_chr* characteristic);
|
||||||
const ble_gatt_chr *characteristic);
|
int OnNewAlertSubcribe(uint16_t connectionHandle, const ble_gatt_error* error, ble_gatt_attr* attribute);
|
||||||
int OnNewAlertSubcribe(uint16_t connectionHandle, const ble_gatt_error *error, ble_gatt_attr *attribute);
|
int OnDescriptorDiscoveryEventCallback(uint16_t connectionHandle,
|
||||||
int OnDescriptorDiscoveryEventCallback(uint16_t connectionHandle, const ble_gatt_error *error,
|
const ble_gatt_error* error,
|
||||||
uint16_t characteristicValueHandle, const ble_gatt_dsc *descriptor);
|
uint16_t characteristicValueHandle,
|
||||||
void OnNotification(ble_gap_event *event);
|
const ble_gatt_dsc* descriptor);
|
||||||
void Reset();
|
void OnNotification(ble_gap_event* event);
|
||||||
void Discover(uint16_t connectionHandle, std::function<void(uint16_t)> lambda) override;
|
void Reset();
|
||||||
|
void Discover(uint16_t connectionHandle, std::function<void(uint16_t)> lambda) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr uint16_t ansServiceId{0x1811};
|
static constexpr uint16_t ansServiceId {0x1811};
|
||||||
static constexpr uint16_t supportedNewAlertCategoryId = 0x2a47;
|
static constexpr uint16_t supportedNewAlertCategoryId = 0x2a47;
|
||||||
static constexpr uint16_t supportedUnreadAlertCategoryId = 0x2a48;
|
static constexpr uint16_t supportedUnreadAlertCategoryId = 0x2a48;
|
||||||
static constexpr uint16_t newAlertId = 0x2a46;
|
static constexpr uint16_t newAlertId = 0x2a46;
|
||||||
static constexpr uint16_t unreadAlertStatusId = 0x2a45;
|
static constexpr uint16_t unreadAlertStatusId = 0x2a45;
|
||||||
static constexpr uint16_t controlPointId = 0x2a44;
|
static constexpr uint16_t controlPointId = 0x2a44;
|
||||||
|
|
||||||
static constexpr ble_uuid16_t ansServiceUuid{
|
static constexpr ble_uuid16_t ansServiceUuid {.u {.type = BLE_UUID_TYPE_16}, .value = ansServiceId};
|
||||||
.u {.type = BLE_UUID_TYPE_16},
|
static constexpr ble_uuid16_t supportedNewAlertCategoryUuid {.u {.type = BLE_UUID_TYPE_16}, .value = supportedNewAlertCategoryId};
|
||||||
.value = ansServiceId
|
static constexpr ble_uuid16_t supportedUnreadAlertCategoryUuid {.u {.type = BLE_UUID_TYPE_16},
|
||||||
};
|
.value = supportedUnreadAlertCategoryId};
|
||||||
static constexpr ble_uuid16_t supportedNewAlertCategoryUuid{
|
static constexpr ble_uuid16_t newAlertUuid {.u {.type = BLE_UUID_TYPE_16}, .value = newAlertId};
|
||||||
.u {.type = BLE_UUID_TYPE_16},
|
static constexpr ble_uuid16_t unreadAlertStatusUuid {.u {.type = BLE_UUID_TYPE_16}, .value = unreadAlertStatusId};
|
||||||
.value = supportedNewAlertCategoryId
|
static constexpr ble_uuid16_t controlPointUuid {.u {.type = BLE_UUID_TYPE_16}, .value = controlPointId};
|
||||||
};
|
|
||||||
static constexpr ble_uuid16_t supportedUnreadAlertCategoryUuid{
|
|
||||||
.u {.type = BLE_UUID_TYPE_16},
|
|
||||||
.value = supportedUnreadAlertCategoryId
|
|
||||||
};
|
|
||||||
static constexpr ble_uuid16_t newAlertUuid{
|
|
||||||
.u {.type = BLE_UUID_TYPE_16},
|
|
||||||
.value = newAlertId
|
|
||||||
};
|
|
||||||
static constexpr ble_uuid16_t unreadAlertStatusUuid{
|
|
||||||
.u {.type = BLE_UUID_TYPE_16},
|
|
||||||
.value = unreadAlertStatusId
|
|
||||||
};
|
|
||||||
static constexpr ble_uuid16_t controlPointUuid{
|
|
||||||
.u {.type = BLE_UUID_TYPE_16},
|
|
||||||
.value = controlPointId
|
|
||||||
};
|
|
||||||
|
|
||||||
uint16_t ansStartHandle = 0;
|
uint16_t ansStartHandle = 0;
|
||||||
uint16_t ansEndHandle = 0;
|
uint16_t ansEndHandle = 0;
|
||||||
uint16_t supportedNewAlertCategoryHandle = 0;
|
uint16_t supportedNewAlertCategoryHandle = 0;
|
||||||
uint16_t supportedUnreadAlertCategoryHandle = 0;
|
uint16_t supportedUnreadAlertCategoryHandle = 0;
|
||||||
uint16_t newAlertHandle = 0;
|
uint16_t newAlertHandle = 0;
|
||||||
uint16_t newAlertDescriptorHandle = 0;
|
uint16_t newAlertDescriptorHandle = 0;
|
||||||
uint16_t newAlertDefHandle = 0;
|
uint16_t newAlertDefHandle = 0;
|
||||||
uint16_t unreadAlertStatusHandle = 0;
|
uint16_t unreadAlertStatusHandle = 0;
|
||||||
uint16_t controlPointHandle = 0;
|
uint16_t controlPointHandle = 0;
|
||||||
bool isDiscovered = false;
|
bool isDiscovered = false;
|
||||||
Pinetime::System::SystemTask &systemTask;
|
Pinetime::System::SystemTask& systemTask;
|
||||||
Pinetime::Controllers::NotificationManager ¬ificationManager;
|
Pinetime::Controllers::NotificationManager& notificationManager;
|
||||||
std::function<void(uint16_t)> onServiceDiscovered;
|
std::function<void(uint16_t)> onServiceDiscovered;
|
||||||
bool isCharacteristicDiscovered = false;
|
bool isCharacteristicDiscovered = false;
|
||||||
bool isDescriptorFound = false;
|
bool isDescriptorFound = false;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,8 +11,7 @@ constexpr ble_uuid16_t AlertNotificationService::ansUuid;
|
||||||
constexpr ble_uuid16_t AlertNotificationService::ansCharUuid;
|
constexpr ble_uuid16_t AlertNotificationService::ansCharUuid;
|
||||||
constexpr ble_uuid128_t AlertNotificationService::notificationEventUuid;
|
constexpr ble_uuid128_t AlertNotificationService::notificationEventUuid;
|
||||||
|
|
||||||
|
int AlertNotificationCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
|
||||||
int AlertNotificationCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) {
|
|
||||||
auto anService = static_cast<AlertNotificationService*>(arg);
|
auto anService = static_cast<AlertNotificationService*>(arg);
|
||||||
return anService->OnAlert(conn_handle, attr_handle, ctxt);
|
return anService->OnAlert(conn_handle, attr_handle, ctxt);
|
||||||
}
|
}
|
||||||
|
@ -26,62 +25,52 @@ void AlertNotificationService::Init() {
|
||||||
ASSERT(res == 0);
|
ASSERT(res == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
AlertNotificationService::AlertNotificationService ( System::SystemTask& systemTask, NotificationManager& notificationManager )
|
AlertNotificationService::AlertNotificationService(System::SystemTask& systemTask, NotificationManager& notificationManager)
|
||||||
: characteristicDefinition{
|
: characteristicDefinition {{.uuid = (ble_uuid_t*) &ansCharUuid,
|
||||||
{
|
.access_cb = AlertNotificationCallback,
|
||||||
.uuid = (ble_uuid_t *) &ansCharUuid,
|
.arg = this,
|
||||||
.access_cb = AlertNotificationCallback,
|
.flags = BLE_GATT_CHR_F_WRITE},
|
||||||
.arg = this,
|
{.uuid = (ble_uuid_t*) ¬ificationEventUuid,
|
||||||
.flags = BLE_GATT_CHR_F_WRITE
|
.access_cb = AlertNotificationCallback,
|
||||||
},
|
.arg = this,
|
||||||
{
|
.flags = BLE_GATT_CHR_F_NOTIFY,
|
||||||
.uuid = (ble_uuid_t *) ¬ificationEventUuid,
|
.val_handle = &eventHandle},
|
||||||
.access_cb = AlertNotificationCallback,
|
{0}},
|
||||||
.arg = this,
|
serviceDefinition {
|
||||||
.flags = BLE_GATT_CHR_F_NOTIFY,
|
{/* Device Information Service */
|
||||||
.val_handle = &eventHandle
|
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||||
},
|
.uuid = (ble_uuid_t*) &ansUuid,
|
||||||
{
|
.characteristics = characteristicDefinition},
|
||||||
0
|
{0},
|
||||||
}
|
},
|
||||||
},
|
systemTask {systemTask},
|
||||||
serviceDefinition{
|
notificationManager {notificationManager} {
|
||||||
{
|
|
||||||
/* 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,
|
int AlertNotificationService::OnAlert(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) {
|
||||||
struct ble_gatt_access_ctxt *ctxt) {
|
|
||||||
if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
|
if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
|
||||||
constexpr size_t stringTerminatorSize = 1; // end of string '\0'
|
constexpr size_t stringTerminatorSize = 1; // end of string '\0'
|
||||||
constexpr size_t headerSize = 3;
|
constexpr size_t headerSize = 3;
|
||||||
const auto maxMessageSize {NotificationManager::MaximumMessageSize()};
|
const auto maxMessageSize {NotificationManager::MaximumMessageSize()};
|
||||||
const auto maxBufferSize{maxMessageSize + headerSize};
|
const auto maxBufferSize {maxMessageSize + headerSize};
|
||||||
|
|
||||||
// Ignore notifications with empty message
|
// Ignore notifications with empty message
|
||||||
const auto packetLen = OS_MBUF_PKTLEN(ctxt->om);
|
const auto packetLen = OS_MBUF_PKTLEN(ctxt->om);
|
||||||
if(packetLen <= headerSize) return 0;
|
if (packetLen <= headerSize)
|
||||||
|
return 0;
|
||||||
|
|
||||||
size_t bufferSize = std::min(packetLen + stringTerminatorSize, maxBufferSize);
|
size_t bufferSize = std::min(packetLen + stringTerminatorSize, maxBufferSize);
|
||||||
auto messageSize = std::min(maxMessageSize, (bufferSize-headerSize));
|
auto messageSize = std::min(maxMessageSize, (bufferSize - headerSize));
|
||||||
Categories category;
|
Categories category;
|
||||||
|
|
||||||
NotificationManager::Notification notif;
|
NotificationManager::Notification notif;
|
||||||
os_mbuf_copydata(ctxt->om, headerSize, messageSize-1, notif.message.data());
|
os_mbuf_copydata(ctxt->om, headerSize, messageSize - 1, notif.message.data());
|
||||||
os_mbuf_copydata(ctxt->om, 0, 1, &category);
|
os_mbuf_copydata(ctxt->om, 0, 1, &category);
|
||||||
notif.message[messageSize-1] = '\0';
|
notif.message[messageSize - 1] = '\0';
|
||||||
notif.size = messageSize;
|
notif.size = messageSize;
|
||||||
|
|
||||||
// TODO convert all ANS categories to NotificationController categories
|
// TODO convert all ANS categories to NotificationController categories
|
||||||
switch(category) {
|
switch (category) {
|
||||||
case Categories::Call:
|
case Categories::Call:
|
||||||
notif.category = Pinetime::Controllers::NotificationManager::Categories::IncomingCall;
|
notif.category = Pinetime::Controllers::NotificationManager::Categories::IncomingCall;
|
||||||
break;
|
break;
|
||||||
|
@ -99,7 +88,7 @@ int AlertNotificationService::OnAlert(uint16_t conn_handle, uint16_t attr_handle
|
||||||
|
|
||||||
void AlertNotificationService::AcceptIncomingCall() {
|
void AlertNotificationService::AcceptIncomingCall() {
|
||||||
auto response = IncomingCallResponses::Answer;
|
auto response = IncomingCallResponses::Answer;
|
||||||
auto *om = ble_hs_mbuf_from_flat(&response, 1);
|
auto* om = ble_hs_mbuf_from_flat(&response, 1);
|
||||||
|
|
||||||
uint16_t connectionHandle = systemTask.nimble().connHandle();
|
uint16_t connectionHandle = systemTask.nimble().connHandle();
|
||||||
|
|
||||||
|
@ -112,7 +101,7 @@ void AlertNotificationService::AcceptIncomingCall() {
|
||||||
|
|
||||||
void AlertNotificationService::RejectIncomingCall() {
|
void AlertNotificationService::RejectIncomingCall() {
|
||||||
auto response = IncomingCallResponses::Reject;
|
auto response = IncomingCallResponses::Reject;
|
||||||
auto *om = ble_hs_mbuf_from_flat(&response, 1);
|
auto* om = ble_hs_mbuf_from_flat(&response, 1);
|
||||||
|
|
||||||
uint16_t connectionHandle = systemTask.nimble().connHandle();
|
uint16_t connectionHandle = systemTask.nimble().connHandle();
|
||||||
|
|
||||||
|
@ -125,7 +114,7 @@ void AlertNotificationService::RejectIncomingCall() {
|
||||||
|
|
||||||
void AlertNotificationService::MuteIncomingCall() {
|
void AlertNotificationService::MuteIncomingCall() {
|
||||||
auto response = IncomingCallResponses::Mute;
|
auto response = IncomingCallResponses::Mute;
|
||||||
auto *om = ble_hs_mbuf_from_flat(&response, 1);
|
auto* om = ble_hs_mbuf_from_flat(&response, 1);
|
||||||
|
|
||||||
uint16_t connectionHandle = systemTask.nimble().connHandle();
|
uint16_t connectionHandle = systemTask.nimble().connHandle();
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,9 @@
|
||||||
#undef max
|
#undef max
|
||||||
#undef min
|
#undef min
|
||||||
|
|
||||||
//00020001-78fc-48fe-8e23-433b3a1942d0
|
// 00020001-78fc-48fe-8e23-433b3a1942d0
|
||||||
#define NOTIFICATION_EVENT_SERVICE_UUID_BASE {0xd0, 0x42, 0x19, 0x3a, 0x3b, 0x43, 0x23, 0x8e, 0xfe, 0x48, 0xfc, 0x78, 0x01, 0x00, 0x02, 0x00}
|
#define NOTIFICATION_EVENT_SERVICE_UUID_BASE \
|
||||||
|
{ 0xd0, 0x42, 0x19, 0x3a, 0x3b, 0x43, 0x23, 0x8e, 0xfe, 0x48, 0xfc, 0x78, 0x01, 0x00, 0x02, 0x00 }
|
||||||
|
|
||||||
namespace Pinetime {
|
namespace Pinetime {
|
||||||
|
|
||||||
|
@ -19,64 +20,49 @@ namespace Pinetime {
|
||||||
class NotificationManager;
|
class NotificationManager;
|
||||||
|
|
||||||
class AlertNotificationService {
|
class AlertNotificationService {
|
||||||
public:
|
public:
|
||||||
AlertNotificationService(Pinetime::System::SystemTask &systemTask,
|
AlertNotificationService(Pinetime::System::SystemTask& systemTask, Pinetime::Controllers::NotificationManager& notificationManager);
|
||||||
Pinetime::Controllers::NotificationManager ¬ificationManager);
|
void Init();
|
||||||
void Init();
|
|
||||||
|
|
||||||
int OnAlert(uint16_t conn_handle, uint16_t attr_handle,
|
int OnAlert(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt);
|
||||||
struct ble_gatt_access_ctxt *ctxt);
|
|
||||||
|
|
||||||
void AcceptIncomingCall();
|
void AcceptIncomingCall();
|
||||||
void RejectIncomingCall();
|
void RejectIncomingCall();
|
||||||
void MuteIncomingCall();
|
void MuteIncomingCall();
|
||||||
|
|
||||||
enum class IncomingCallResponses : uint8_t {
|
enum class IncomingCallResponses : uint8_t { Reject = 0x00, Answer = 0x01, Mute = 0x02 };
|
||||||
Reject = 0x00,
|
|
||||||
Answer = 0x01,
|
|
||||||
Mute = 0x02
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum class Categories : uint8_t {
|
enum class Categories : uint8_t {
|
||||||
SimpleAlert = 0x00,
|
SimpleAlert = 0x00,
|
||||||
Email = 0x01,
|
Email = 0x01,
|
||||||
News = 0x02,
|
News = 0x02,
|
||||||
Call = 0x03,
|
Call = 0x03,
|
||||||
MissedCall = 0x04,
|
MissedCall = 0x04,
|
||||||
MmsSms = 0x05,
|
MmsSms = 0x05,
|
||||||
VoiceMail = 0x06,
|
VoiceMail = 0x06,
|
||||||
Schedule = 0x07,
|
Schedule = 0x07,
|
||||||
HighPrioritizedAlert = 0x08,
|
HighPrioritizedAlert = 0x08,
|
||||||
InstantMessage = 0x09,
|
InstantMessage = 0x09,
|
||||||
All = 0xff
|
All = 0xff
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr uint16_t ansId {0x1811};
|
static constexpr uint16_t ansId {0x1811};
|
||||||
static constexpr uint16_t ansCharId {0x2a46};
|
static constexpr uint16_t ansCharId {0x2a46};
|
||||||
|
|
||||||
static constexpr ble_uuid16_t ansUuid {
|
static constexpr ble_uuid16_t ansUuid {.u {.type = BLE_UUID_TYPE_16}, .value = ansId};
|
||||||
.u { .type = BLE_UUID_TYPE_16 },
|
|
||||||
.value = ansId
|
|
||||||
};
|
|
||||||
|
|
||||||
static constexpr ble_uuid16_t ansCharUuid {
|
static constexpr ble_uuid16_t ansCharUuid {.u {.type = BLE_UUID_TYPE_16}, .value = ansCharId};
|
||||||
.u { .type = BLE_UUID_TYPE_16 },
|
|
||||||
.value = ansCharId
|
|
||||||
};
|
|
||||||
|
|
||||||
static constexpr ble_uuid128_t notificationEventUuid {
|
static constexpr ble_uuid128_t notificationEventUuid {.u {.type = BLE_UUID_TYPE_128}, .value = NOTIFICATION_EVENT_SERVICE_UUID_BASE};
|
||||||
.u { .type = BLE_UUID_TYPE_128 },
|
|
||||||
.value = NOTIFICATION_EVENT_SERVICE_UUID_BASE
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ble_gatt_chr_def characteristicDefinition[3];
|
struct ble_gatt_chr_def characteristicDefinition[3];
|
||||||
struct ble_gatt_svc_def serviceDefinition[2];
|
struct ble_gatt_svc_def serviceDefinition[2];
|
||||||
|
|
||||||
Pinetime::System::SystemTask &systemTask;
|
Pinetime::System::SystemTask& systemTask;
|
||||||
NotificationManager ¬ificationManager;
|
NotificationManager& notificationManager;
|
||||||
|
|
||||||
uint16_t eventHandle;
|
uint16_t eventHandle;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,39 +7,26 @@ using namespace Pinetime::Controllers;
|
||||||
constexpr ble_uuid16_t BatteryInformationService::batteryInformationServiceUuid;
|
constexpr ble_uuid16_t BatteryInformationService::batteryInformationServiceUuid;
|
||||||
constexpr ble_uuid16_t BatteryInformationService::batteryLevelUuid;
|
constexpr ble_uuid16_t BatteryInformationService::batteryLevelUuid;
|
||||||
|
|
||||||
|
int BatteryInformationServiceCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
|
||||||
|
|
||||||
int BatteryInformationServiceCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) {
|
|
||||||
auto* batteryInformationService = static_cast<BatteryInformationService*>(arg);
|
auto* batteryInformationService = static_cast<BatteryInformationService*>(arg);
|
||||||
return batteryInformationService->OnBatteryServiceRequested(conn_handle, attr_handle, ctxt);
|
return batteryInformationService->OnBatteryServiceRequested(conn_handle, attr_handle, ctxt);
|
||||||
}
|
}
|
||||||
|
|
||||||
BatteryInformationService::BatteryInformationService(Controllers::Battery& batteryController) :
|
BatteryInformationService::BatteryInformationService(Controllers::Battery& batteryController)
|
||||||
batteryController{batteryController},
|
: batteryController {batteryController},
|
||||||
characteristicDefinition{
|
characteristicDefinition {{.uuid = (ble_uuid_t*) &batteryLevelUuid,
|
||||||
{
|
.access_cb = BatteryInformationServiceCallback,
|
||||||
.uuid = (ble_uuid_t *) &batteryLevelUuid,
|
.arg = this,
|
||||||
.access_cb = BatteryInformationServiceCallback,
|
.flags = BLE_GATT_CHR_F_READ,
|
||||||
.arg = this,
|
.val_handle = &batteryLevelHandle},
|
||||||
.flags = BLE_GATT_CHR_F_READ,
|
{0}},
|
||||||
.val_handle = &batteryLevelHandle
|
serviceDefinition {
|
||||||
},
|
{/* Device Information Service */
|
||||||
{
|
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||||
0
|
.uuid = (ble_uuid_t*) &batteryInformationServiceUuid,
|
||||||
}
|
.characteristics = characteristicDefinition},
|
||||||
},
|
{0},
|
||||||
serviceDefinition{
|
} {
|
||||||
{
|
|
||||||
/* Device Information Service */
|
|
||||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
|
||||||
.uuid = (ble_uuid_t *) &batteryInformationServiceUuid,
|
|
||||||
.characteristics = characteristicDefinition
|
|
||||||
},
|
|
||||||
{
|
|
||||||
0
|
|
||||||
},
|
|
||||||
}{
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BatteryInformationService::Init() {
|
void BatteryInformationService::Init() {
|
||||||
|
@ -51,9 +38,10 @@ void BatteryInformationService::Init() {
|
||||||
ASSERT(res == 0);
|
ASSERT(res == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int BatteryInformationService::OnBatteryServiceRequested(uint16_t connectionHandle, uint16_t attributeHandle,
|
int BatteryInformationService::OnBatteryServiceRequested(uint16_t connectionHandle,
|
||||||
ble_gatt_access_ctxt *context) {
|
uint16_t attributeHandle,
|
||||||
if(attributeHandle == batteryLevelHandle) {
|
ble_gatt_access_ctxt* context) {
|
||||||
|
if (attributeHandle == batteryLevelHandle) {
|
||||||
NRF_LOG_INFO("BATTERY : handle = %d", batteryLevelHandle);
|
NRF_LOG_INFO("BATTERY : handle = %d", batteryLevelHandle);
|
||||||
static uint8_t batteryValue = batteryController.PercentRemaining();
|
static uint8_t batteryValue = batteryController.PercentRemaining();
|
||||||
int res = os_mbuf_append(context->om, &batteryValue, 1);
|
int res = os_mbuf_append(context->om, &batteryValue, 1);
|
||||||
|
|
|
@ -12,33 +12,25 @@ namespace Pinetime {
|
||||||
namespace Controllers {
|
namespace Controllers {
|
||||||
class Battery;
|
class Battery;
|
||||||
class BatteryInformationService {
|
class BatteryInformationService {
|
||||||
public:
|
public:
|
||||||
BatteryInformationService(Controllers::Battery& batteryController);
|
BatteryInformationService(Controllers::Battery& batteryController);
|
||||||
void Init();
|
void Init();
|
||||||
|
|
||||||
int
|
int OnBatteryServiceRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context);
|
||||||
OnBatteryServiceRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt *context);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Controllers::Battery& batteryController;
|
Controllers::Battery& batteryController;
|
||||||
static constexpr uint16_t batteryInformationServiceId {0x180F};
|
static constexpr uint16_t batteryInformationServiceId {0x180F};
|
||||||
static constexpr uint16_t batteryLevelId {0x2A19};
|
static constexpr uint16_t batteryLevelId {0x2A19};
|
||||||
|
|
||||||
static constexpr ble_uuid16_t batteryInformationServiceUuid {
|
static constexpr ble_uuid16_t batteryInformationServiceUuid {.u {.type = BLE_UUID_TYPE_16}, .value = batteryInformationServiceId};
|
||||||
.u {.type = BLE_UUID_TYPE_16},
|
|
||||||
.value = batteryInformationServiceId
|
|
||||||
};
|
|
||||||
|
|
||||||
static constexpr ble_uuid16_t batteryLevelUuid {
|
static constexpr ble_uuid16_t batteryLevelUuid {.u {.type = BLE_UUID_TYPE_16}, .value = batteryLevelId};
|
||||||
.u {.type = BLE_UUID_TYPE_16},
|
|
||||||
.value = batteryLevelId
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ble_gatt_chr_def characteristicDefinition[3];
|
struct ble_gatt_chr_def characteristicDefinition[3];
|
||||||
struct ble_gatt_svc_def serviceDefinition[2];
|
struct ble_gatt_svc_def serviceDefinition[2];
|
||||||
|
|
||||||
uint16_t batteryLevelHandle;
|
|
||||||
|
|
||||||
|
uint16_t batteryLevelHandle;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,10 +3,10 @@
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
namespace Pinetime {
|
namespace Pinetime {
|
||||||
namespace Controllers{
|
namespace Controllers {
|
||||||
class BleClient {
|
class BleClient {
|
||||||
public:
|
public:
|
||||||
virtual void Discover(uint16_t connectionHandle, std::function<void(uint16_t)> lambda) = 0;
|
virtual void Discover(uint16_t connectionHandle, std::function<void(uint16_t)> lambda) = 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -25,5 +25,3 @@ void Ble::FirmwareUpdateTotalBytes(uint32_t totalBytes) {
|
||||||
void Ble::FirmwareUpdateCurrentBytes(uint32_t currentBytes) {
|
void Ble::FirmwareUpdateCurrentBytes(uint32_t currentBytes) {
|
||||||
firmwareUpdateCurrentBytes = currentBytes;
|
firmwareUpdateCurrentBytes = currentBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -6,39 +6,57 @@
|
||||||
namespace Pinetime {
|
namespace Pinetime {
|
||||||
namespace Controllers {
|
namespace Controllers {
|
||||||
class Ble {
|
class Ble {
|
||||||
public:
|
public:
|
||||||
using BleAddress = std::array<uint8_t, 6>;
|
using BleAddress = std::array<uint8_t, 6>;
|
||||||
enum class FirmwareUpdateStates {Idle, Running, Validated, Error};
|
enum class FirmwareUpdateStates { Idle, Running, Validated, Error };
|
||||||
enum class AddressTypes { Public, Random };
|
enum class AddressTypes { Public, Random };
|
||||||
|
|
||||||
Ble() = default;
|
Ble() = default;
|
||||||
bool IsConnected() const {return isConnected;}
|
bool IsConnected() const {
|
||||||
void Connect();
|
return isConnected;
|
||||||
void Disconnect();
|
}
|
||||||
|
void Connect();
|
||||||
|
void Disconnect();
|
||||||
|
|
||||||
void StartFirmwareUpdate();
|
void StartFirmwareUpdate();
|
||||||
void StopFirmwareUpdate();
|
void StopFirmwareUpdate();
|
||||||
void FirmwareUpdateTotalBytes(uint32_t totalBytes);
|
void FirmwareUpdateTotalBytes(uint32_t totalBytes);
|
||||||
void FirmwareUpdateCurrentBytes(uint32_t currentBytes);
|
void FirmwareUpdateCurrentBytes(uint32_t currentBytes);
|
||||||
void State(FirmwareUpdateStates state) { firmwareUpdateState = state; }
|
void State(FirmwareUpdateStates state) {
|
||||||
|
firmwareUpdateState = state;
|
||||||
|
}
|
||||||
|
|
||||||
bool IsFirmwareUpdating() const { return isFirmwareUpdating; }
|
bool IsFirmwareUpdating() const {
|
||||||
uint32_t FirmwareUpdateTotalBytes() const { return firmwareUpdateTotalBytes; }
|
return isFirmwareUpdating;
|
||||||
uint32_t FirmwareUpdateCurrentBytes() const { return firmwareUpdateCurrentBytes; }
|
}
|
||||||
FirmwareUpdateStates State() const { return firmwareUpdateState; }
|
uint32_t FirmwareUpdateTotalBytes() const {
|
||||||
|
return firmwareUpdateTotalBytes;
|
||||||
|
}
|
||||||
|
uint32_t FirmwareUpdateCurrentBytes() const {
|
||||||
|
return firmwareUpdateCurrentBytes;
|
||||||
|
}
|
||||||
|
FirmwareUpdateStates State() const {
|
||||||
|
return firmwareUpdateState;
|
||||||
|
}
|
||||||
|
|
||||||
void Address(BleAddress&& addr) { address = addr; }
|
void Address(BleAddress&& addr) {
|
||||||
const BleAddress& Address() const { return address; }
|
address = addr;
|
||||||
void AddressType(AddressTypes t) { addressType = t;}
|
}
|
||||||
private:
|
const BleAddress& Address() const {
|
||||||
bool isConnected = false;
|
return address;
|
||||||
bool isFirmwareUpdating = false;
|
}
|
||||||
uint32_t firmwareUpdateTotalBytes = 0;
|
void AddressType(AddressTypes t) {
|
||||||
uint32_t firmwareUpdateCurrentBytes = 0;
|
addressType = t;
|
||||||
FirmwareUpdateStates firmwareUpdateState = FirmwareUpdateStates::Idle;
|
}
|
||||||
BleAddress address;
|
|
||||||
AddressTypes addressType;
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool isConnected = false;
|
||||||
|
bool isFirmwareUpdating = false;
|
||||||
|
uint32_t firmwareUpdateTotalBytes = 0;
|
||||||
|
uint32_t firmwareUpdateCurrentBytes = 0;
|
||||||
|
FirmwareUpdateStates firmwareUpdateState = FirmwareUpdateStates::Idle;
|
||||||
|
BleAddress address;
|
||||||
|
AddressTypes addressType;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -9,39 +9,37 @@ constexpr ble_uuid16_t CurrentTimeClient::ctsServiceUuid;
|
||||||
constexpr ble_uuid16_t CurrentTimeClient::currentTimeCharacteristicUuid;
|
constexpr ble_uuid16_t CurrentTimeClient::currentTimeCharacteristicUuid;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
int OnDiscoveryEventCallback(uint16_t conn_handle, const struct ble_gatt_error *error, const struct ble_gatt_svc *service, void *arg) {
|
int OnDiscoveryEventCallback(uint16_t conn_handle, const struct ble_gatt_error* error, const struct ble_gatt_svc* service, void* arg) {
|
||||||
auto client = static_cast<CurrentTimeClient *>(arg);
|
auto client = static_cast<CurrentTimeClient*>(arg);
|
||||||
return client->OnDiscoveryEvent(conn_handle, error, service);
|
return client->OnDiscoveryEvent(conn_handle, error, service);
|
||||||
}
|
}
|
||||||
|
|
||||||
int OnCurrentTimeCharacteristicDiscoveredCallback(uint16_t conn_handle, const struct ble_gatt_error *error,
|
int OnCurrentTimeCharacteristicDiscoveredCallback(uint16_t conn_handle,
|
||||||
const struct ble_gatt_chr *chr, void *arg) {
|
const struct ble_gatt_error* error,
|
||||||
auto client = static_cast<CurrentTimeClient *>(arg);
|
const struct ble_gatt_chr* chr,
|
||||||
|
void* arg) {
|
||||||
|
auto client = static_cast<CurrentTimeClient*>(arg);
|
||||||
return client->OnCharacteristicDiscoveryEvent(conn_handle, error, chr);
|
return client->OnCharacteristicDiscoveryEvent(conn_handle, error, chr);
|
||||||
}
|
}
|
||||||
|
|
||||||
int CurrentTimeReadCallback(uint16_t conn_handle, const struct ble_gatt_error *error, struct ble_gatt_attr *attr, void *arg) {
|
int CurrentTimeReadCallback(uint16_t conn_handle, const struct ble_gatt_error* error, struct ble_gatt_attr* attr, void* arg) {
|
||||||
auto client = static_cast<CurrentTimeClient *>(arg);
|
auto client = static_cast<CurrentTimeClient*>(arg);
|
||||||
return client->OnCurrentTimeReadResult(conn_handle, error, attr);
|
return client->OnCurrentTimeReadResult(conn_handle, error, attr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CurrentTimeClient::CurrentTimeClient(DateTime &dateTimeController) : dateTimeController{dateTimeController} {
|
CurrentTimeClient::CurrentTimeClient(DateTime& dateTimeController) : dateTimeController {dateTimeController} {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CurrentTimeClient::Init() {
|
void CurrentTimeClient::Init() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CurrentTimeClient::OnDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error *error,
|
bool CurrentTimeClient::OnDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error* error, const ble_gatt_svc* service) {
|
||||||
const ble_gatt_svc *service) {
|
|
||||||
if (service == nullptr && error->status == BLE_HS_EDONE) {
|
if (service == nullptr && error->status == BLE_HS_EDONE) {
|
||||||
if (isDiscovered) {
|
if (isDiscovered) {
|
||||||
NRF_LOG_INFO("CTS found, starting characteristics discovery");
|
NRF_LOG_INFO("CTS found, starting characteristics discovery");
|
||||||
|
|
||||||
ble_gattc_disc_all_chrs(connectionHandle, ctsStartHandle, ctsEndHandle,
|
ble_gattc_disc_all_chrs(connectionHandle, ctsStartHandle, ctsEndHandle, OnCurrentTimeCharacteristicDiscoveredCallback, this);
|
||||||
OnCurrentTimeCharacteristicDiscoveredCallback, this);
|
|
||||||
} else {
|
} else {
|
||||||
NRF_LOG_INFO("CTS not found");
|
NRF_LOG_INFO("CTS not found");
|
||||||
onServiceDiscovered(connectionHandle);
|
onServiceDiscovered(connectionHandle);
|
||||||
|
@ -49,7 +47,7 @@ bool CurrentTimeClient::OnDiscoveryEvent(uint16_t connectionHandle, const ble_ga
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (service != nullptr && ble_uuid_cmp(((ble_uuid_t *) &ctsServiceUuid), &service->uuid.u) == 0) {
|
if (service != nullptr && ble_uuid_cmp(((ble_uuid_t*) &ctsServiceUuid), &service->uuid.u) == 0) {
|
||||||
NRF_LOG_INFO("CTS discovered : 0x%x - 0x%x", service->start_handle, service->end_handle);
|
NRF_LOG_INFO("CTS discovered : 0x%x - 0x%x", service->start_handle, service->end_handle);
|
||||||
isDiscovered = true;
|
isDiscovered = true;
|
||||||
ctsStartHandle = service->start_handle;
|
ctsStartHandle = service->start_handle;
|
||||||
|
@ -59,8 +57,9 @@ bool CurrentTimeClient::OnDiscoveryEvent(uint16_t connectionHandle, const ble_ga
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CurrentTimeClient::OnCharacteristicDiscoveryEvent(uint16_t conn_handle, const ble_gatt_error *error,
|
int CurrentTimeClient::OnCharacteristicDiscoveryEvent(uint16_t conn_handle,
|
||||||
const ble_gatt_chr *characteristic) {
|
const ble_gatt_error* error,
|
||||||
|
const ble_gatt_chr* characteristic) {
|
||||||
if (characteristic == nullptr && error->status == BLE_HS_EDONE) {
|
if (characteristic == nullptr && error->status == BLE_HS_EDONE) {
|
||||||
if (isCharacteristicDiscovered) {
|
if (isCharacteristicDiscovered) {
|
||||||
NRF_LOG_INFO("CTS Characteristic discovery complete, fetching time");
|
NRF_LOG_INFO("CTS Characteristic discovery complete, fetching time");
|
||||||
|
@ -73,8 +72,7 @@ int CurrentTimeClient::OnCharacteristicDiscoveryEvent(uint16_t conn_handle, cons
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (characteristic != nullptr &&
|
if (characteristic != nullptr && ble_uuid_cmp(((ble_uuid_t*) ¤tTimeCharacteristicUuid), &characteristic->uuid.u) == 0) {
|
||||||
ble_uuid_cmp(((ble_uuid_t *) ¤tTimeCharacteristicUuid), &characteristic->uuid.u) == 0) {
|
|
||||||
NRF_LOG_INFO("CTS Characteristic discovered : 0x%x", characteristic->val_handle);
|
NRF_LOG_INFO("CTS Characteristic discovered : 0x%x", characteristic->val_handle);
|
||||||
isCharacteristicDiscovered = true;
|
isCharacteristicDiscovered = true;
|
||||||
currentTimeHandle = characteristic->val_handle;
|
currentTimeHandle = characteristic->val_handle;
|
||||||
|
@ -82,17 +80,15 @@ int CurrentTimeClient::OnCharacteristicDiscoveryEvent(uint16_t conn_handle, cons
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CurrentTimeClient::OnCurrentTimeReadResult(uint16_t conn_handle, const ble_gatt_error *error,
|
int CurrentTimeClient::OnCurrentTimeReadResult(uint16_t conn_handle, const ble_gatt_error* error, const ble_gatt_attr* attribute) {
|
||||||
const ble_gatt_attr *attribute) {
|
|
||||||
if (error->status == 0) {
|
if (error->status == 0) {
|
||||||
// TODO check that attribute->handle equals the handle discovered in OnCharacteristicDiscoveryEvent
|
// TODO check that attribute->handle equals the handle discovered in OnCharacteristicDiscoveryEvent
|
||||||
CtsData result;
|
CtsData result;
|
||||||
os_mbuf_copydata(attribute->om, 0, sizeof(CtsData), &result);
|
os_mbuf_copydata(attribute->om, 0, sizeof(CtsData), &result);
|
||||||
NRF_LOG_INFO("Received data: %d-%d-%d %d:%d:%d", result.year,
|
NRF_LOG_INFO(
|
||||||
result.month, result.dayofmonth,
|
"Received data: %d-%d-%d %d:%d:%d", result.year, result.month, result.dayofmonth, result.hour, result.minute, result.second);
|
||||||
result.hour, result.minute, result.second);
|
dateTimeController.SetTime(
|
||||||
dateTimeController.SetTime(result.year, result.month, result.dayofmonth,
|
result.year, result.month, result.dayofmonth, 0, result.hour, result.minute, result.second, nrf_rtc_counter_get(portNRF_RTC_REG));
|
||||||
0, result.hour, result.minute, result.second, nrf_rtc_counter_get(portNRF_RTC_REG));
|
|
||||||
} else {
|
} else {
|
||||||
NRF_LOG_INFO("Error retrieving current time: %d", error->status);
|
NRF_LOG_INFO("Error retrieving current time: %d", error->status);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,54 +8,51 @@
|
||||||
#include "BleClient.h"
|
#include "BleClient.h"
|
||||||
|
|
||||||
namespace Pinetime {
|
namespace Pinetime {
|
||||||
namespace Controllers {
|
namespace Controllers {
|
||||||
class DateTime;
|
class DateTime;
|
||||||
|
|
||||||
class CurrentTimeClient : public BleClient {
|
class CurrentTimeClient : public BleClient {
|
||||||
public:
|
public:
|
||||||
explicit CurrentTimeClient(DateTime& dateTimeController);
|
explicit CurrentTimeClient(DateTime& dateTimeController);
|
||||||
void Init();
|
void Init();
|
||||||
void Reset();
|
void Reset();
|
||||||
bool OnDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error *error, const ble_gatt_svc *service);
|
bool OnDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error* error, const ble_gatt_svc* service);
|
||||||
int OnCharacteristicDiscoveryEvent(uint16_t conn_handle, const ble_gatt_error *error,
|
int OnCharacteristicDiscoveryEvent(uint16_t conn_handle, const ble_gatt_error* error, const ble_gatt_chr* characteristic);
|
||||||
const ble_gatt_chr *characteristic);
|
int OnCurrentTimeReadResult(uint16_t conn_handle, const ble_gatt_error* error, const ble_gatt_attr* attribute);
|
||||||
int OnCurrentTimeReadResult(uint16_t conn_handle, const ble_gatt_error *error, const ble_gatt_attr *attribute);
|
static constexpr const ble_uuid16_t* Uuid() {
|
||||||
static constexpr const ble_uuid16_t* Uuid() { return &CurrentTimeClient::ctsServiceUuid; }
|
return &CurrentTimeClient::ctsServiceUuid;
|
||||||
static constexpr const ble_uuid16_t* CurrentTimeCharacteristicUuid() { return &CurrentTimeClient::currentTimeCharacteristicUuid; }
|
}
|
||||||
void Discover(uint16_t connectionHandle, std::function<void(uint16_t)> lambda) override;
|
static constexpr const ble_uuid16_t* CurrentTimeCharacteristicUuid() {
|
||||||
|
return &CurrentTimeClient::currentTimeCharacteristicUuid;
|
||||||
|
}
|
||||||
|
void Discover(uint16_t connectionHandle, std::function<void(uint16_t)> lambda) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef struct __attribute__((packed)) {
|
typedef struct __attribute__((packed)) {
|
||||||
uint16_t year;
|
uint16_t year;
|
||||||
uint8_t month;
|
uint8_t month;
|
||||||
uint8_t dayofmonth;
|
uint8_t dayofmonth;
|
||||||
uint8_t hour;
|
uint8_t hour;
|
||||||
uint8_t minute;
|
uint8_t minute;
|
||||||
uint8_t second;
|
uint8_t second;
|
||||||
uint8_t millis;
|
uint8_t millis;
|
||||||
uint8_t reason;
|
uint8_t reason;
|
||||||
} CtsData;
|
} CtsData;
|
||||||
|
|
||||||
static constexpr uint16_t ctsServiceId {0x1805};
|
static constexpr uint16_t ctsServiceId {0x1805};
|
||||||
static constexpr uint16_t currentTimeCharacteristicId {0x2a2b};
|
static constexpr uint16_t currentTimeCharacteristicId {0x2a2b};
|
||||||
|
|
||||||
static constexpr ble_uuid16_t ctsServiceUuid {
|
static constexpr ble_uuid16_t ctsServiceUuid {.u {.type = BLE_UUID_TYPE_16}, .value = ctsServiceId};
|
||||||
.u { .type = BLE_UUID_TYPE_16 },
|
static constexpr ble_uuid16_t currentTimeCharacteristicUuid {.u {.type = BLE_UUID_TYPE_16}, .value = currentTimeCharacteristicId};
|
||||||
.value = ctsServiceId
|
|
||||||
};
|
|
||||||
static constexpr ble_uuid16_t currentTimeCharacteristicUuid {
|
|
||||||
.u { .type = BLE_UUID_TYPE_16 },
|
|
||||||
.value = currentTimeCharacteristicId
|
|
||||||
};
|
|
||||||
|
|
||||||
DateTime& dateTimeController;
|
DateTime& dateTimeController;
|
||||||
bool isDiscovered = false;
|
bool isDiscovered = false;
|
||||||
uint16_t ctsStartHandle;
|
uint16_t ctsStartHandle;
|
||||||
uint16_t ctsEndHandle;
|
uint16_t ctsEndHandle;
|
||||||
|
|
||||||
bool isCharacteristicDiscovered = false;
|
bool isCharacteristicDiscovered = false;
|
||||||
uint16_t currentTimeHandle;
|
uint16_t currentTimeHandle;
|
||||||
std::function<void(uint16_t)> onServiceDiscovered;
|
std::function<void(uint16_t)> onServiceDiscovered;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -7,8 +7,7 @@ using namespace Pinetime::Controllers;
|
||||||
constexpr ble_uuid16_t CurrentTimeService::ctsUuid;
|
constexpr ble_uuid16_t CurrentTimeService::ctsUuid;
|
||||||
constexpr ble_uuid16_t CurrentTimeService::ctChrUuid;
|
constexpr ble_uuid16_t CurrentTimeService::ctChrUuid;
|
||||||
|
|
||||||
|
int CTSCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
|
||||||
int CTSCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) {
|
|
||||||
auto cts = static_cast<CurrentTimeService*>(arg);
|
auto cts = static_cast<CurrentTimeService*>(arg);
|
||||||
return cts->OnTimeAccessed(conn_handle, attr_handle, ctxt);
|
return cts->OnTimeAccessed(conn_handle, attr_handle, ctxt);
|
||||||
}
|
}
|
||||||
|
@ -22,22 +21,19 @@ void CurrentTimeService::Init() {
|
||||||
ASSERT(res == 0);
|
ASSERT(res == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int CurrentTimeService::OnTimeAccessed(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) {
|
||||||
|
|
||||||
int CurrentTimeService::OnTimeAccessed(uint16_t conn_handle, uint16_t attr_handle,
|
NRF_LOG_INFO("Setting time...");
|
||||||
struct ble_gatt_access_ctxt *ctxt) {
|
|
||||||
|
|
||||||
NRF_LOG_INFO("Setting time...");
|
|
||||||
|
|
||||||
if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
|
if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
|
||||||
CtsData result;
|
CtsData result;
|
||||||
os_mbuf_copydata(ctxt->om, 0, sizeof(CtsData), &result);
|
os_mbuf_copydata(ctxt->om, 0, sizeof(CtsData), &result);
|
||||||
|
|
||||||
NRF_LOG_INFO("Received data: %d-%d-%d %d:%d:%d", result.year,
|
NRF_LOG_INFO(
|
||||||
result.month, result.dayofmonth,
|
"Received data: %d-%d-%d %d:%d:%d", result.year, result.month, result.dayofmonth, result.hour, result.minute, result.second);
|
||||||
result.hour, result.minute, result.second);
|
|
||||||
|
|
||||||
m_dateTimeController.SetTime(result.year, result.month, result.dayofmonth,
|
m_dateTimeController.SetTime(
|
||||||
0, result.hour, result.minute, result.second, nrf_rtc_counter_get(portNRF_RTC_REG));
|
result.year, result.month, result.dayofmonth, 0, result.hour, result.minute, result.second, nrf_rtc_counter_get(portNRF_RTC_REG));
|
||||||
|
|
||||||
} else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
|
} else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
|
||||||
CtsData currentDateTime;
|
CtsData currentDateTime;
|
||||||
|
@ -49,39 +45,26 @@ int CurrentTimeService::OnTimeAccessed(uint16_t conn_handle, uint16_t attr_handl
|
||||||
currentDateTime.second = m_dateTimeController.Seconds();
|
currentDateTime.second = m_dateTimeController.Seconds();
|
||||||
currentDateTime.millis = 0;
|
currentDateTime.millis = 0;
|
||||||
|
|
||||||
|
|
||||||
int res = os_mbuf_append(ctxt->om, ¤tDateTime, sizeof(CtsData));
|
int res = os_mbuf_append(ctxt->om, ¤tDateTime, sizeof(CtsData));
|
||||||
return (res == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
return (res == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
CurrentTimeService::CurrentTimeService(DateTime &dateTimeController) :
|
CurrentTimeService::CurrentTimeService(DateTime& dateTimeController)
|
||||||
characteristicDefinition{
|
: characteristicDefinition {{.uuid = (ble_uuid_t*) &ctChrUuid,
|
||||||
{
|
.access_cb = CTSCallback,
|
||||||
.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} {
|
|
||||||
|
|
||||||
|
.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} {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,42 +12,35 @@
|
||||||
namespace Pinetime {
|
namespace Pinetime {
|
||||||
namespace Controllers {
|
namespace Controllers {
|
||||||
class CurrentTimeService {
|
class CurrentTimeService {
|
||||||
public:
|
public:
|
||||||
CurrentTimeService(DateTime &dateTimeController);
|
CurrentTimeService(DateTime& dateTimeController);
|
||||||
void Init();
|
void Init();
|
||||||
|
|
||||||
int OnTimeAccessed(uint16_t conn_handle, uint16_t attr_handle,
|
int OnTimeAccessed(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt);
|
||||||
struct ble_gatt_access_ctxt *ctxt);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr uint16_t ctsId {0x1805};
|
static constexpr uint16_t ctsId {0x1805};
|
||||||
static constexpr uint16_t ctsCharId {0x2a2b};
|
static constexpr uint16_t ctsCharId {0x2a2b};
|
||||||
|
|
||||||
static constexpr ble_uuid16_t ctsUuid {
|
static constexpr ble_uuid16_t ctsUuid {.u {.type = BLE_UUID_TYPE_16}, .value = ctsId};
|
||||||
.u { .type = BLE_UUID_TYPE_16 },
|
|
||||||
.value = ctsId
|
|
||||||
};
|
|
||||||
|
|
||||||
static constexpr ble_uuid16_t ctChrUuid {
|
static constexpr ble_uuid16_t ctChrUuid {.u {.type = BLE_UUID_TYPE_16}, .value = ctsCharId};
|
||||||
.u { .type = BLE_UUID_TYPE_16 },
|
|
||||||
.value = ctsCharId
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ble_gatt_chr_def characteristicDefinition[2];
|
struct ble_gatt_chr_def characteristicDefinition[2];
|
||||||
struct ble_gatt_svc_def serviceDefinition[2];
|
struct ble_gatt_svc_def serviceDefinition[2];
|
||||||
|
|
||||||
typedef struct __attribute__((packed)) {
|
typedef struct __attribute__((packed)) {
|
||||||
uint16_t year;
|
uint16_t year;
|
||||||
uint8_t month;
|
uint8_t month;
|
||||||
uint8_t dayofmonth;
|
uint8_t dayofmonth;
|
||||||
uint8_t hour;
|
uint8_t hour;
|
||||||
uint8_t minute;
|
uint8_t minute;
|
||||||
uint8_t second;
|
uint8_t second;
|
||||||
uint8_t millis;
|
uint8_t millis;
|
||||||
uint8_t reason;
|
uint8_t reason;
|
||||||
} CtsData;
|
} CtsData;
|
||||||
|
|
||||||
DateTime &m_dateTimeController;
|
DateTime& m_dateTimeController;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,7 @@ constexpr ble_uuid16_t DeviceInformationService::deviceInfoUuid;
|
||||||
constexpr ble_uuid16_t DeviceInformationService::hwRevisionUuid;
|
constexpr ble_uuid16_t DeviceInformationService::hwRevisionUuid;
|
||||||
constexpr ble_uuid16_t DeviceInformationService::swRevisionUuid;
|
constexpr ble_uuid16_t DeviceInformationService::swRevisionUuid;
|
||||||
|
|
||||||
|
int DeviceInformationCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
|
||||||
int DeviceInformationCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) {
|
|
||||||
auto deviceInformationService = static_cast<DeviceInformationService*>(arg);
|
auto deviceInformationService = static_cast<DeviceInformationService*>(arg);
|
||||||
return deviceInformationService->OnDeviceInfoRequested(conn_handle, attr_handle, ctxt);
|
return deviceInformationService->OnDeviceInfoRequested(conn_handle, attr_handle, ctxt);
|
||||||
}
|
}
|
||||||
|
@ -25,10 +24,8 @@ void DeviceInformationService::Init() {
|
||||||
ASSERT(res == 0);
|
ASSERT(res == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int DeviceInformationService::OnDeviceInfoRequested(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) {
|
||||||
int DeviceInformationService::OnDeviceInfoRequested(uint16_t conn_handle, uint16_t attr_handle,
|
const char* str;
|
||||||
struct ble_gatt_access_ctxt *ctxt) {
|
|
||||||
const char *str;
|
|
||||||
|
|
||||||
switch (ble_uuid_u16(ctxt->chr->uuid)) {
|
switch (ble_uuid_u16(ctxt->chr->uuid)) {
|
||||||
case manufacturerNameId:
|
case manufacturerNameId:
|
||||||
|
@ -57,60 +54,49 @@ int DeviceInformationService::OnDeviceInfoRequested(uint16_t conn_handle, uint16
|
||||||
return (res == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
return (res == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceInformationService::DeviceInformationService() :
|
DeviceInformationService::DeviceInformationService()
|
||||||
characteristicDefinition{
|
: characteristicDefinition {{
|
||||||
{
|
.uuid = (ble_uuid_t*) &manufacturerNameUuid,
|
||||||
.uuid = (ble_uuid_t *) &manufacturerNameUuid,
|
.access_cb = DeviceInformationCallback,
|
||||||
.access_cb = DeviceInformationCallback,
|
.arg = this,
|
||||||
.arg = this,
|
.flags = BLE_GATT_CHR_F_READ,
|
||||||
.flags = BLE_GATT_CHR_F_READ,
|
},
|
||||||
},
|
{
|
||||||
{
|
.uuid = (ble_uuid_t*) &modelNumberUuid,
|
||||||
.uuid = (ble_uuid_t *) &modelNumberUuid,
|
.access_cb = DeviceInformationCallback,
|
||||||
.access_cb = DeviceInformationCallback,
|
.arg = this,
|
||||||
.arg = this,
|
.flags = BLE_GATT_CHR_F_READ,
|
||||||
.flags = BLE_GATT_CHR_F_READ,
|
},
|
||||||
},
|
{
|
||||||
{
|
.uuid = (ble_uuid_t*) &serialNumberUuid,
|
||||||
.uuid = (ble_uuid_t *) &serialNumberUuid,
|
.access_cb = DeviceInformationCallback,
|
||||||
.access_cb = DeviceInformationCallback,
|
.arg = this,
|
||||||
.arg = this,
|
.flags = BLE_GATT_CHR_F_READ,
|
||||||
.flags = BLE_GATT_CHR_F_READ,
|
},
|
||||||
},
|
{
|
||||||
{
|
.uuid = (ble_uuid_t*) &fwRevisionUuid,
|
||||||
.uuid = (ble_uuid_t *) &fwRevisionUuid,
|
.access_cb = DeviceInformationCallback,
|
||||||
.access_cb = DeviceInformationCallback,
|
.arg = this,
|
||||||
.arg = this,
|
.flags = BLE_GATT_CHR_F_READ,
|
||||||
.flags = BLE_GATT_CHR_F_READ,
|
},
|
||||||
},
|
{
|
||||||
{
|
.uuid = (ble_uuid_t*) &hwRevisionUuid,
|
||||||
.uuid = (ble_uuid_t *) &hwRevisionUuid,
|
.access_cb = DeviceInformationCallback,
|
||||||
.access_cb = DeviceInformationCallback,
|
.arg = this,
|
||||||
.arg = this,
|
.flags = BLE_GATT_CHR_F_READ,
|
||||||
.flags = BLE_GATT_CHR_F_READ,
|
},
|
||||||
},
|
{
|
||||||
{
|
.uuid = (ble_uuid_t*) &swRevisionUuid,
|
||||||
.uuid = (ble_uuid_t *) &swRevisionUuid,
|
.access_cb = DeviceInformationCallback,
|
||||||
.access_cb = DeviceInformationCallback,
|
.arg = this,
|
||||||
.arg = this,
|
.flags = BLE_GATT_CHR_F_READ,
|
||||||
.flags = BLE_GATT_CHR_F_READ,
|
},
|
||||||
},
|
{0}},
|
||||||
{
|
serviceDefinition {
|
||||||
0
|
{/* Device Information Service */
|
||||||
}
|
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||||
},
|
.uuid = (ble_uuid_t*) &deviceInfoUuid,
|
||||||
serviceDefinition{
|
.characteristics = characteristicDefinition},
|
||||||
{
|
{0},
|
||||||
/* Device Information Service */
|
} {
|
||||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
|
||||||
.uuid = (ble_uuid_t *) &deviceInfoUuid,
|
|
||||||
.characteristics = characteristicDefinition
|
|
||||||
},
|
|
||||||
{
|
|
||||||
0
|
|
||||||
},
|
|
||||||
}
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,69 +9,44 @@
|
||||||
namespace Pinetime {
|
namespace Pinetime {
|
||||||
namespace Controllers {
|
namespace Controllers {
|
||||||
class DeviceInformationService {
|
class DeviceInformationService {
|
||||||
public:
|
public:
|
||||||
DeviceInformationService();
|
DeviceInformationService();
|
||||||
void Init();
|
void Init();
|
||||||
|
|
||||||
int OnDeviceInfoRequested(uint16_t conn_handle, uint16_t attr_handle,
|
int OnDeviceInfoRequested(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt);
|
||||||
struct ble_gatt_access_ctxt *ctxt);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr uint16_t deviceInfoId {0x180a};
|
static constexpr uint16_t deviceInfoId {0x180a};
|
||||||
static constexpr uint16_t manufacturerNameId {0x2a29};
|
static constexpr uint16_t manufacturerNameId {0x2a29};
|
||||||
static constexpr uint16_t modelNumberId {0x2a24};
|
static constexpr uint16_t modelNumberId {0x2a24};
|
||||||
static constexpr uint16_t serialNumberId {0x2a25};
|
static constexpr uint16_t serialNumberId {0x2a25};
|
||||||
static constexpr uint16_t fwRevisionId {0x2a26};
|
static constexpr uint16_t fwRevisionId {0x2a26};
|
||||||
static constexpr uint16_t hwRevisionId {0x2a27};
|
static constexpr uint16_t hwRevisionId {0x2a27};
|
||||||
static constexpr uint16_t swRevisionId {0x2a28};
|
static constexpr uint16_t swRevisionId {0x2a28};
|
||||||
|
|
||||||
static constexpr const char* manufacturerName = "PINE64";
|
static constexpr const char* manufacturerName = "PINE64";
|
||||||
static constexpr const char* modelNumber = "PineTime";
|
static constexpr const char* modelNumber = "PineTime";
|
||||||
static constexpr const char* hwRevision = "1.0.0";
|
static constexpr const char* hwRevision = "1.0.0";
|
||||||
static constexpr const char* serialNumber = "0";
|
static constexpr const char* serialNumber = "0";
|
||||||
static constexpr const char* fwRevision = Version::VersionString();
|
static constexpr const char* fwRevision = Version::VersionString();
|
||||||
static constexpr const char* swRevision = "InfiniTime";
|
static constexpr const char* swRevision = "InfiniTime";
|
||||||
|
|
||||||
|
static constexpr ble_uuid16_t deviceInfoUuid {.u {.type = BLE_UUID_TYPE_16}, .value = deviceInfoId};
|
||||||
|
|
||||||
static constexpr ble_uuid16_t deviceInfoUuid {
|
static constexpr ble_uuid16_t manufacturerNameUuid {.u {.type = BLE_UUID_TYPE_16}, .value = manufacturerNameId};
|
||||||
.u { .type = BLE_UUID_TYPE_16 },
|
|
||||||
.value = deviceInfoId
|
|
||||||
};
|
|
||||||
|
|
||||||
static constexpr ble_uuid16_t manufacturerNameUuid {
|
static constexpr ble_uuid16_t modelNumberUuid {.u {.type = BLE_UUID_TYPE_16}, .value = modelNumberId};
|
||||||
.u { .type = BLE_UUID_TYPE_16 },
|
|
||||||
.value = manufacturerNameId
|
|
||||||
};
|
|
||||||
|
|
||||||
static constexpr ble_uuid16_t modelNumberUuid {
|
static constexpr ble_uuid16_t serialNumberUuid {.u {.type = BLE_UUID_TYPE_16}, .value = serialNumberId};
|
||||||
.u { .type = BLE_UUID_TYPE_16 },
|
|
||||||
.value = modelNumberId
|
|
||||||
};
|
|
||||||
|
|
||||||
static constexpr ble_uuid16_t serialNumberUuid {
|
static constexpr ble_uuid16_t fwRevisionUuid {.u {.type = BLE_UUID_TYPE_16}, .value = fwRevisionId};
|
||||||
.u { .type = BLE_UUID_TYPE_16 },
|
|
||||||
.value = serialNumberId
|
|
||||||
};
|
|
||||||
|
|
||||||
static constexpr ble_uuid16_t fwRevisionUuid {
|
static constexpr ble_uuid16_t hwRevisionUuid {.u {.type = BLE_UUID_TYPE_16}, .value = hwRevisionId};
|
||||||
.u { .type = BLE_UUID_TYPE_16 },
|
|
||||||
.value = fwRevisionId
|
|
||||||
};
|
|
||||||
|
|
||||||
static constexpr ble_uuid16_t hwRevisionUuid {
|
|
||||||
.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 swRevisionUuid {.u {.type = BLE_UUID_TYPE_16}, .value = swRevisionId};
|
||||||
|
|
||||||
|
struct ble_gatt_chr_def characteristicDefinition[7];
|
||||||
|
struct ble_gatt_svc_def serviceDefinition[2];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -11,67 +11,60 @@ constexpr ble_uuid128_t DfuService::controlPointCharacteristicUuid;
|
||||||
constexpr ble_uuid128_t DfuService::revisionCharacteristicUuid;
|
constexpr ble_uuid128_t DfuService::revisionCharacteristicUuid;
|
||||||
constexpr ble_uuid128_t DfuService::packetCharacteristicUuid;
|
constexpr ble_uuid128_t DfuService::packetCharacteristicUuid;
|
||||||
|
|
||||||
int DfuServiceCallback(uint16_t conn_handle, uint16_t attr_handle,
|
int DfuServiceCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
|
||||||
struct ble_gatt_access_ctxt *ctxt, void *arg) {
|
auto dfuService = static_cast<DfuService*>(arg);
|
||||||
auto dfuService = static_cast<DfuService *>(arg);
|
|
||||||
return dfuService->OnServiceData(conn_handle, attr_handle, ctxt);
|
return dfuService->OnServiceData(conn_handle, attr_handle, ctxt);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NotificationTimerCallback(TimerHandle_t xTimer) {
|
void NotificationTimerCallback(TimerHandle_t xTimer) {
|
||||||
auto notificationManager = static_cast<DfuService::NotificationManager *>(pvTimerGetTimerID(xTimer));
|
auto notificationManager = static_cast<DfuService::NotificationManager*>(pvTimerGetTimerID(xTimer));
|
||||||
notificationManager->OnNotificationTimer();
|
notificationManager->OnNotificationTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TimeoutTimerCallback(TimerHandle_t xTimer) {
|
void TimeoutTimerCallback(TimerHandle_t xTimer) {
|
||||||
auto dfuService = static_cast<DfuService *>(pvTimerGetTimerID(xTimer));
|
auto dfuService = static_cast<DfuService*>(pvTimerGetTimerID(xTimer));
|
||||||
dfuService->OnTimeout();
|
dfuService->OnTimeout();
|
||||||
}
|
}
|
||||||
|
|
||||||
DfuService::DfuService(Pinetime::System::SystemTask &systemTask, Pinetime::Controllers::Ble &bleController,
|
DfuService::DfuService(Pinetime::System::SystemTask& systemTask,
|
||||||
Pinetime::Drivers::SpiNorFlash &spiNorFlash) :
|
Pinetime::Controllers::Ble& bleController,
|
||||||
systemTask{systemTask},
|
Pinetime::Drivers::SpiNorFlash& spiNorFlash)
|
||||||
bleController{bleController},
|
: systemTask {systemTask},
|
||||||
dfuImage{spiNorFlash},
|
bleController {bleController},
|
||||||
characteristicDefinition{
|
dfuImage {spiNorFlash},
|
||||||
{
|
characteristicDefinition {{
|
||||||
.uuid = (ble_uuid_t *) &packetCharacteristicUuid,
|
.uuid = (ble_uuid_t*) &packetCharacteristicUuid,
|
||||||
.access_cb = DfuServiceCallback,
|
.access_cb = DfuServiceCallback,
|
||||||
.arg = this,
|
.arg = this,
|
||||||
.flags = BLE_GATT_CHR_F_WRITE_NO_RSP,
|
.flags = BLE_GATT_CHR_F_WRITE_NO_RSP,
|
||||||
.val_handle = nullptr,
|
.val_handle = nullptr,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.uuid = (ble_uuid_t *) &controlPointCharacteristicUuid,
|
.uuid = (ble_uuid_t*) &controlPointCharacteristicUuid,
|
||||||
.access_cb = DfuServiceCallback,
|
.access_cb = DfuServiceCallback,
|
||||||
.arg = this,
|
.arg = this,
|
||||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_NOTIFY,
|
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_NOTIFY,
|
||||||
.val_handle = nullptr,
|
.val_handle = nullptr,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.uuid = (ble_uuid_t *) &revisionCharacteristicUuid,
|
.uuid = (ble_uuid_t*) &revisionCharacteristicUuid,
|
||||||
.access_cb = DfuServiceCallback,
|
.access_cb = DfuServiceCallback,
|
||||||
.arg = this,
|
.arg = this,
|
||||||
.flags = BLE_GATT_CHR_F_READ,
|
.flags = BLE_GATT_CHR_F_READ,
|
||||||
.val_handle = &revision,
|
.val_handle = &revision,
|
||||||
|
|
||||||
},
|
},
|
||||||
{
|
{0}
|
||||||
0
|
|
||||||
}
|
|
||||||
|
|
||||||
},
|
},
|
||||||
serviceDefinition{
|
serviceDefinition {
|
||||||
{
|
{/* Device Information Service */
|
||||||
/* Device Information Service */
|
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
.uuid = (ble_uuid_t*) &serviceUuid,
|
||||||
.uuid = (ble_uuid_t *) &serviceUuid,
|
.characteristics = characteristicDefinition},
|
||||||
.characteristics = characteristicDefinition
|
{0},
|
||||||
},
|
} {
|
||||||
{
|
timeoutTimer = xTimerCreate("notificationTimer", 10000, pdFALSE, this, TimeoutTimerCallback);
|
||||||
0
|
|
||||||
},
|
|
||||||
} {
|
|
||||||
timeoutTimer = xTimerCreate ("notificationTimer", 10000, pdFALSE, this, TimeoutTimerCallback);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DfuService::Init() {
|
void DfuService::Init() {
|
||||||
|
@ -83,55 +76,54 @@ void DfuService::Init() {
|
||||||
ASSERT(res == 0);
|
ASSERT(res == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int DfuService::OnServiceData(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt *context) {
|
int DfuService::OnServiceData(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context) {
|
||||||
if(bleController.IsFirmwareUpdating()){
|
if (bleController.IsFirmwareUpdating()) {
|
||||||
xTimerStart(timeoutTimer, 0);
|
xTimerStart(timeoutTimer, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ble_gatts_find_chr((ble_uuid_t*) &serviceUuid, (ble_uuid_t*) &packetCharacteristicUuid, nullptr, &packetCharacteristicHandle);
|
||||||
ble_gatts_find_chr((ble_uuid_t *) &serviceUuid, (ble_uuid_t *) &packetCharacteristicUuid, nullptr,
|
ble_gatts_find_chr((ble_uuid_t*) &serviceUuid, (ble_uuid_t*) &controlPointCharacteristicUuid, nullptr, &controlPointCharacteristicHandle);
|
||||||
&packetCharacteristicHandle);
|
ble_gatts_find_chr((ble_uuid_t*) &serviceUuid, (ble_uuid_t*) &revisionCharacteristicUuid, nullptr, &revisionCharacteristicHandle);
|
||||||
ble_gatts_find_chr((ble_uuid_t *) &serviceUuid, (ble_uuid_t *) &controlPointCharacteristicUuid, nullptr,
|
|
||||||
&controlPointCharacteristicHandle);
|
|
||||||
ble_gatts_find_chr((ble_uuid_t *) &serviceUuid, (ble_uuid_t *) &revisionCharacteristicUuid, nullptr,
|
|
||||||
&revisionCharacteristicHandle);
|
|
||||||
|
|
||||||
if (attributeHandle == packetCharacteristicHandle) {
|
if (attributeHandle == packetCharacteristicHandle) {
|
||||||
if (context->op == BLE_GATT_ACCESS_OP_WRITE_CHR)
|
if (context->op == BLE_GATT_ACCESS_OP_WRITE_CHR)
|
||||||
return WritePacketHandler(connectionHandle, context->om);
|
return WritePacketHandler(connectionHandle, context->om);
|
||||||
else return 0;
|
else
|
||||||
|
return 0;
|
||||||
} else if (attributeHandle == controlPointCharacteristicHandle) {
|
} else if (attributeHandle == controlPointCharacteristicHandle) {
|
||||||
if (context->op == BLE_GATT_ACCESS_OP_WRITE_CHR)
|
if (context->op == BLE_GATT_ACCESS_OP_WRITE_CHR)
|
||||||
return ControlPointHandler(connectionHandle, context->om);
|
return ControlPointHandler(connectionHandle, context->om);
|
||||||
else return 0;
|
else
|
||||||
|
return 0;
|
||||||
} else if (attributeHandle == revisionCharacteristicHandle) {
|
} else if (attributeHandle == revisionCharacteristicHandle) {
|
||||||
if (context->op == BLE_GATT_ACCESS_OP_READ_CHR)
|
if (context->op == BLE_GATT_ACCESS_OP_READ_CHR)
|
||||||
return SendDfuRevision(context->om);
|
return SendDfuRevision(context->om);
|
||||||
else return 0;
|
else
|
||||||
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
NRF_LOG_INFO("[DFU] Unknown Characteristic : %d", attributeHandle);
|
NRF_LOG_INFO("[DFU] Unknown Characteristic : %d", attributeHandle);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int DfuService::SendDfuRevision(os_mbuf *om) const {
|
int DfuService::SendDfuRevision(os_mbuf* om) const {
|
||||||
int res = os_mbuf_append(om, &revision, sizeof(revision));
|
int res = os_mbuf_append(om, &revision, sizeof(revision));
|
||||||
return (res == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
return (res == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||||
}
|
}
|
||||||
|
|
||||||
int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf *om) {
|
int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf* om) {
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case States::Start: {
|
case States::Start: {
|
||||||
softdeviceSize = om->om_data[0] + (om->om_data[1] << 8) + (om->om_data[2] << 16) + (om->om_data[3] << 24);
|
softdeviceSize = om->om_data[0] + (om->om_data[1] << 8) + (om->om_data[2] << 16) + (om->om_data[3] << 24);
|
||||||
bootloaderSize = om->om_data[4] + (om->om_data[5] << 8) + (om->om_data[6] << 16) + (om->om_data[7] << 24);
|
bootloaderSize = om->om_data[4] + (om->om_data[5] << 8) + (om->om_data[6] << 16) + (om->om_data[7] << 24);
|
||||||
applicationSize = om->om_data[8] + (om->om_data[9] << 8) + (om->om_data[10] << 16) + (om->om_data[11] << 24);
|
applicationSize = om->om_data[8] + (om->om_data[9] << 8) + (om->om_data[10] << 16) + (om->om_data[11] << 24);
|
||||||
bleController.FirmwareUpdateTotalBytes(applicationSize);
|
bleController.FirmwareUpdateTotalBytes(applicationSize);
|
||||||
NRF_LOG_INFO("[DFU] -> Start data received : SD size : %d, BT size : %d, app size : %d", softdeviceSize,
|
NRF_LOG_INFO(
|
||||||
bootloaderSize, applicationSize);
|
"[DFU] -> Start data received : SD size : %d, BT size : %d, app size : %d", softdeviceSize, bootloaderSize, applicationSize);
|
||||||
|
|
||||||
dfuImage.Erase();
|
dfuImage.Erase();
|
||||||
|
|
||||||
uint8_t data[]{16, 1, 1};
|
uint8_t data[] {16, 1, 1};
|
||||||
notificationManager.Send(connectionHandle, controlPointCharacteristicHandle, data, 3);
|
notificationManager.Send(connectionHandle, controlPointCharacteristicHandle, data, 3);
|
||||||
state = States::Init;
|
state = States::Init;
|
||||||
}
|
}
|
||||||
|
@ -139,19 +131,22 @@ int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf *om) {
|
||||||
case States::Init: {
|
case States::Init: {
|
||||||
uint16_t deviceType = om->om_data[0] + (om->om_data[1] << 8);
|
uint16_t deviceType = om->om_data[0] + (om->om_data[1] << 8);
|
||||||
uint16_t deviceRevision = om->om_data[2] + (om->om_data[3] << 8);
|
uint16_t deviceRevision = om->om_data[2] + (om->om_data[3] << 8);
|
||||||
uint32_t applicationVersion =
|
uint32_t applicationVersion = om->om_data[4] + (om->om_data[5] << 8) + (om->om_data[6] << 16) + (om->om_data[7] << 24);
|
||||||
om->om_data[4] + (om->om_data[5] << 8) + (om->om_data[6] << 16) + (om->om_data[7] << 24);
|
|
||||||
uint16_t softdeviceArrayLength = om->om_data[8] + (om->om_data[9] << 8);
|
uint16_t softdeviceArrayLength = om->om_data[8] + (om->om_data[9] << 8);
|
||||||
uint16_t sd[softdeviceArrayLength];
|
uint16_t sd[softdeviceArrayLength];
|
||||||
for (int i = 0; i < softdeviceArrayLength; i++) {
|
for (int i = 0; i < softdeviceArrayLength; i++) {
|
||||||
sd[i] = om->om_data[10 + (i * 2)] + (om->om_data[10 + (i * 2) + 1] << 8);
|
sd[i] = om->om_data[10 + (i * 2)] + (om->om_data[10 + (i * 2) + 1] << 8);
|
||||||
}
|
}
|
||||||
expectedCrc =
|
expectedCrc = om->om_data[10 + (softdeviceArrayLength * 2)] + (om->om_data[10 + (softdeviceArrayLength * 2) + 1] << 8);
|
||||||
om->om_data[10 + (softdeviceArrayLength * 2)] + (om->om_data[10 + (softdeviceArrayLength * 2) + 1] << 8);
|
|
||||||
|
|
||||||
NRF_LOG_INFO(
|
NRF_LOG_INFO(
|
||||||
"[DFU] -> Init data received : deviceType = %d, deviceRevision = %d, applicationVersion = %d, nb SD = %d, First SD = %d, CRC = %u",
|
"[DFU] -> Init data received : deviceType = %d, deviceRevision = %d, applicationVersion = %d, nb SD = %d, First SD = %d, CRC = %u",
|
||||||
deviceType, deviceRevision, applicationVersion, softdeviceArrayLength, sd[0], expectedCrc);
|
deviceType,
|
||||||
|
deviceRevision,
|
||||||
|
applicationVersion,
|
||||||
|
softdeviceArrayLength,
|
||||||
|
sd[0],
|
||||||
|
expectedCrc);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -163,16 +158,18 @@ int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf *om) {
|
||||||
bleController.FirmwareUpdateCurrentBytes(bytesReceived);
|
bleController.FirmwareUpdateCurrentBytes(bytesReceived);
|
||||||
|
|
||||||
if ((nbPacketReceived % nbPacketsToNotify) == 0 && bytesReceived != applicationSize) {
|
if ((nbPacketReceived % nbPacketsToNotify) == 0 && bytesReceived != applicationSize) {
|
||||||
uint8_t data[5]{static_cast<uint8_t>(Opcodes::PacketReceiptNotification),
|
uint8_t data[5] {static_cast<uint8_t>(Opcodes::PacketReceiptNotification),
|
||||||
(uint8_t) (bytesReceived & 0x000000FFu), (uint8_t) (bytesReceived >> 8u),
|
(uint8_t) (bytesReceived & 0x000000FFu),
|
||||||
(uint8_t) (bytesReceived >> 16u), (uint8_t) (bytesReceived >> 24u)};
|
(uint8_t) (bytesReceived >> 8u),
|
||||||
|
(uint8_t) (bytesReceived >> 16u),
|
||||||
|
(uint8_t) (bytesReceived >> 24u)};
|
||||||
NRF_LOG_INFO("[DFU] -> Send packet notification: %d bytes received", bytesReceived);
|
NRF_LOG_INFO("[DFU] -> Send packet notification: %d bytes received", bytesReceived);
|
||||||
notificationManager.Send(connectionHandle, controlPointCharacteristicHandle, data, 5);
|
notificationManager.Send(connectionHandle, controlPointCharacteristicHandle, data, 5);
|
||||||
}
|
}
|
||||||
if (dfuImage.IsComplete()) {
|
if (dfuImage.IsComplete()) {
|
||||||
uint8_t data[3]{static_cast<uint8_t>(Opcodes::Response),
|
uint8_t data[3] {static_cast<uint8_t>(Opcodes::Response),
|
||||||
static_cast<uint8_t>(Opcodes::ReceiveFirmwareImage),
|
static_cast<uint8_t>(Opcodes::ReceiveFirmwareImage),
|
||||||
static_cast<uint8_t>(ErrorCodes::NoError)};
|
static_cast<uint8_t>(ErrorCodes::NoError)};
|
||||||
NRF_LOG_INFO("[DFU] -> Send packet notification : all bytes received!");
|
NRF_LOG_INFO("[DFU] -> Send packet notification : all bytes received!");
|
||||||
notificationManager.Send(connectionHandle, controlPointCharacteristicHandle, data, 3);
|
notificationManager.Send(connectionHandle, controlPointCharacteristicHandle, data, 3);
|
||||||
state = States::Validate;
|
state = States::Validate;
|
||||||
|
@ -186,7 +183,7 @@ int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf *om) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int DfuService::ControlPointHandler(uint16_t connectionHandle, os_mbuf *om) {
|
int DfuService::ControlPointHandler(uint16_t connectionHandle, os_mbuf* om) {
|
||||||
auto opcode = static_cast<Opcodes>(om->om_data[0]);
|
auto opcode = static_cast<Opcodes>(om->om_data[0]);
|
||||||
NRF_LOG_INFO("[DFU] -> ControlPointHandler");
|
NRF_LOG_INFO("[DFU] -> ControlPointHandler");
|
||||||
|
|
||||||
|
@ -214,8 +211,7 @@ int DfuService::ControlPointHandler(uint16_t connectionHandle, os_mbuf *om) {
|
||||||
NRF_LOG_INFO("[DFU] -> Start DFU, mode %d not supported!", imageType);
|
NRF_LOG_INFO("[DFU] -> Start DFU, mode %d not supported!", imageType);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
} break;
|
||||||
break;
|
|
||||||
case Opcodes::InitDFUParameters: {
|
case Opcodes::InitDFUParameters: {
|
||||||
if (state != States::Init) {
|
if (state != States::Init) {
|
||||||
NRF_LOG_INFO("[DFU] -> Init DFU requested, but we are not in Init state");
|
NRF_LOG_INFO("[DFU] -> Init DFU requested, but we are not in Init state");
|
||||||
|
@ -225,11 +221,9 @@ int DfuService::ControlPointHandler(uint16_t connectionHandle, os_mbuf *om) {
|
||||||
NRF_LOG_INFO("[DFU] -> Init DFU parameters %s", isInitComplete ? " complete" : " not complete");
|
NRF_LOG_INFO("[DFU] -> Init DFU parameters %s", isInitComplete ? " complete" : " not complete");
|
||||||
|
|
||||||
if (isInitComplete) {
|
if (isInitComplete) {
|
||||||
uint8_t data[3] {
|
uint8_t data[3] {static_cast<uint8_t>(Opcodes::Response),
|
||||||
static_cast<uint8_t>(Opcodes::Response),
|
static_cast<uint8_t>(Opcodes::InitDFUParameters),
|
||||||
static_cast<uint8_t>(Opcodes::InitDFUParameters),
|
(isInitComplete ? uint8_t {1} : uint8_t {0})};
|
||||||
(isInitComplete ? uint8_t{1} : uint8_t{0})
|
|
||||||
};
|
|
||||||
notificationManager.AsyncSend(connectionHandle, controlPointCharacteristicHandle, data, 3);
|
notificationManager.AsyncSend(connectionHandle, controlPointCharacteristicHandle, data, 3);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -257,26 +251,22 @@ int DfuService::ControlPointHandler(uint16_t connectionHandle, os_mbuf *om) {
|
||||||
|
|
||||||
NRF_LOG_INFO("[DFU] -> Validate firmware image requested -- %d", connectionHandle);
|
NRF_LOG_INFO("[DFU] -> Validate firmware image requested -- %d", connectionHandle);
|
||||||
|
|
||||||
if(dfuImage.Validate()){
|
if (dfuImage.Validate()) {
|
||||||
state = States::Validated;
|
state = States::Validated;
|
||||||
bleController.State(Pinetime::Controllers::Ble::FirmwareUpdateStates::Validated);
|
bleController.State(Pinetime::Controllers::Ble::FirmwareUpdateStates::Validated);
|
||||||
NRF_LOG_INFO("Image OK");
|
NRF_LOG_INFO("Image OK");
|
||||||
|
|
||||||
uint8_t data[3] {
|
uint8_t data[3] {static_cast<uint8_t>(Opcodes::Response),
|
||||||
static_cast<uint8_t>(Opcodes::Response),
|
static_cast<uint8_t>(Opcodes::ValidateFirmware),
|
||||||
static_cast<uint8_t>(Opcodes::ValidateFirmware),
|
static_cast<uint8_t>(ErrorCodes::NoError)};
|
||||||
static_cast<uint8_t>(ErrorCodes::NoError)
|
|
||||||
};
|
|
||||||
notificationManager.AsyncSend(connectionHandle, controlPointCharacteristicHandle, data, 3);
|
notificationManager.AsyncSend(connectionHandle, controlPointCharacteristicHandle, data, 3);
|
||||||
} else {
|
} else {
|
||||||
bleController.State(Pinetime::Controllers::Ble::FirmwareUpdateStates::Error);
|
bleController.State(Pinetime::Controllers::Ble::FirmwareUpdateStates::Error);
|
||||||
NRF_LOG_INFO("Image Error : bad CRC");
|
NRF_LOG_INFO("Image Error : bad CRC");
|
||||||
|
|
||||||
uint8_t data[3] {
|
uint8_t data[3] {static_cast<uint8_t>(Opcodes::Response),
|
||||||
static_cast<uint8_t>(Opcodes::Response),
|
static_cast<uint8_t>(Opcodes::ValidateFirmware),
|
||||||
static_cast<uint8_t>(Opcodes::ValidateFirmware),
|
static_cast<uint8_t>(ErrorCodes::CrcError)};
|
||||||
static_cast<uint8_t>(ErrorCodes::CrcError)
|
|
||||||
};
|
|
||||||
notificationManager.AsyncSend(connectionHandle, controlPointCharacteristicHandle, data, 3);
|
notificationManager.AsyncSend(connectionHandle, controlPointCharacteristicHandle, data, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -318,11 +308,11 @@ void DfuService::Reset() {
|
||||||
}
|
}
|
||||||
|
|
||||||
DfuService::NotificationManager::NotificationManager() {
|
DfuService::NotificationManager::NotificationManager() {
|
||||||
timer = xTimerCreate ("notificationTimer", 1000, pdFALSE, this, NotificationTimerCallback);
|
timer = xTimerCreate("notificationTimer", 1000, pdFALSE, this, NotificationTimerCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DfuService::NotificationManager::AsyncSend(uint16_t connection, uint16_t charactHandle, uint8_t *data, size_t s) {
|
bool DfuService::NotificationManager::AsyncSend(uint16_t connection, uint16_t charactHandle, uint8_t* data, size_t s) {
|
||||||
if(size != 0 || s > 10)
|
if (size != 0 || s > 10)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
connectionHandle = connection;
|
connectionHandle = connection;
|
||||||
|
@ -334,14 +324,14 @@ bool DfuService::NotificationManager::AsyncSend(uint16_t connection, uint16_t ch
|
||||||
}
|
}
|
||||||
|
|
||||||
void DfuService::NotificationManager::OnNotificationTimer() {
|
void DfuService::NotificationManager::OnNotificationTimer() {
|
||||||
if(size > 0) {
|
if (size > 0) {
|
||||||
Send(connectionHandle, characteristicHandle, buffer, size);
|
Send(connectionHandle, characteristicHandle, buffer, size);
|
||||||
size = 0;
|
size = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DfuService::NotificationManager::Send(uint16_t connection, uint16_t charactHandle, const uint8_t *data, const size_t s) {
|
void DfuService::NotificationManager::Send(uint16_t connection, uint16_t charactHandle, const uint8_t* data, const size_t s) {
|
||||||
auto *om = ble_hs_mbuf_from_flat(data, s);
|
auto* om = ble_hs_mbuf_from_flat(data, s);
|
||||||
auto ret = ble_gattc_notify_custom(connection, charactHandle, om);
|
auto ret = ble_gattc_notify_custom(connection, charactHandle, om);
|
||||||
ASSERT(ret == 0);
|
ASSERT(ret == 0);
|
||||||
}
|
}
|
||||||
|
@ -354,27 +344,29 @@ void DfuService::NotificationManager::Reset() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DfuService::DfuImage::Init(size_t chunkSize, size_t totalSize, uint16_t expectedCrc) {
|
void DfuService::DfuImage::Init(size_t chunkSize, size_t totalSize, uint16_t expectedCrc) {
|
||||||
if(chunkSize != 20) return;
|
if (chunkSize != 20)
|
||||||
|
return;
|
||||||
this->chunkSize = chunkSize;
|
this->chunkSize = chunkSize;
|
||||||
this->totalSize = totalSize;
|
this->totalSize = totalSize;
|
||||||
this->expectedCrc = expectedCrc;
|
this->expectedCrc = expectedCrc;
|
||||||
this->ready = true;
|
this->ready = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DfuService::DfuImage::Append(uint8_t *data, size_t size) {
|
void DfuService::DfuImage::Append(uint8_t* data, size_t size) {
|
||||||
if(!ready) return;
|
if (!ready)
|
||||||
|
return;
|
||||||
ASSERT(size <= 20);
|
ASSERT(size <= 20);
|
||||||
|
|
||||||
std::memcpy(tempBuffer + bufferWriteIndex, data, size);
|
std::memcpy(tempBuffer + bufferWriteIndex, data, size);
|
||||||
bufferWriteIndex += size;
|
bufferWriteIndex += size;
|
||||||
|
|
||||||
if(bufferWriteIndex == bufferSize) {
|
if (bufferWriteIndex == bufferSize) {
|
||||||
spiNorFlash.Write(writeOffset + totalWriteIndex, tempBuffer, bufferWriteIndex);
|
spiNorFlash.Write(writeOffset + totalWriteIndex, tempBuffer, bufferWriteIndex);
|
||||||
totalWriteIndex += bufferWriteIndex;
|
totalWriteIndex += bufferWriteIndex;
|
||||||
bufferWriteIndex = 0;
|
bufferWriteIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(bufferWriteIndex > 0 && totalWriteIndex + bufferWriteIndex == totalSize) {
|
if (bufferWriteIndex > 0 && totalWriteIndex + bufferWriteIndex == totalSize) {
|
||||||
spiNorFlash.Write(writeOffset + totalWriteIndex, tempBuffer, bufferWriteIndex);
|
spiNorFlash.Write(writeOffset + totalWriteIndex, tempBuffer, bufferWriteIndex);
|
||||||
totalWriteIndex += bufferWriteIndex;
|
totalWriteIndex += bufferWriteIndex;
|
||||||
if (totalSize < maxSize)
|
if (totalSize < maxSize)
|
||||||
|
@ -383,15 +375,16 @@ void DfuService::DfuImage::Append(uint8_t *data, size_t size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DfuService::DfuImage::WriteMagicNumber() {
|
void DfuService::DfuImage::WriteMagicNumber() {
|
||||||
uint32_t magic[4] = { // TODO When this variable is a static constexpr, the values written to the memory are not correct. Why?
|
uint32_t magic[4] = {
|
||||||
0xf395c277,
|
// TODO When this variable is a static constexpr, the values written to the memory are not correct. Why?
|
||||||
0x7fefd260,
|
0xf395c277,
|
||||||
0x0f505235,
|
0x7fefd260,
|
||||||
0x8079b62c,
|
0x0f505235,
|
||||||
|
0x8079b62c,
|
||||||
};
|
};
|
||||||
|
|
||||||
uint32_t offset = writeOffset + (maxSize - (4 * sizeof(uint32_t)));
|
uint32_t offset = writeOffset + (maxSize - (4 * sizeof(uint32_t)));
|
||||||
spiNorFlash.Write(offset, reinterpret_cast<const uint8_t *>(magic), 4 * sizeof(uint32_t));
|
spiNorFlash.Write(offset, reinterpret_cast<const uint8_t*>(magic), 4 * sizeof(uint32_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DfuService::DfuImage::Erase() {
|
void DfuService::DfuImage::Erase() {
|
||||||
|
@ -421,7 +414,7 @@ bool DfuService::DfuImage::Validate() {
|
||||||
return (crc == expectedCrc);
|
return (crc == expectedCrc);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t DfuService::DfuImage::ComputeCrc(uint8_t const *p_data, uint32_t size, uint16_t const *p_crc) {
|
uint16_t DfuService::DfuImage::ComputeCrc(uint8_t const* p_data, uint32_t size, uint16_t const* p_crc) {
|
||||||
uint16_t crc = (p_crc == NULL) ? 0xFFFF : *p_crc;
|
uint16_t crc = (p_crc == NULL) ? 0xFFFF : *p_crc;
|
||||||
|
|
||||||
for (uint32_t i = 0; i < size; i++) {
|
for (uint32_t i = 0; i < size; i++) {
|
||||||
|
@ -436,6 +429,7 @@ uint16_t DfuService::DfuImage::ComputeCrc(uint8_t const *p_data, uint32_t size,
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DfuService::DfuImage::IsComplete() {
|
bool DfuService::DfuImage::IsComplete() {
|
||||||
if(!ready) return false;
|
if (!ready)
|
||||||
|
return false;
|
||||||
return totalWriteIndex == totalSize;
|
return totalWriteIndex == totalSize;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,146 +20,139 @@ namespace Pinetime {
|
||||||
class Ble;
|
class Ble;
|
||||||
|
|
||||||
class DfuService {
|
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:
|
public:
|
||||||
DfuService(Pinetime::System::SystemTask &systemTask, Pinetime::Controllers::Ble &bleController,
|
NotificationManager();
|
||||||
Pinetime::Drivers::SpiNorFlash &spiNorFlash);
|
bool AsyncSend(uint16_t connection, uint16_t charactHandle, uint8_t* data, size_t size);
|
||||||
void Init();
|
void Send(uint16_t connection, uint16_t characteristicHandle, const uint8_t* data, const size_t s);
|
||||||
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);
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Pinetime::System::SystemTask &systemTask;
|
TimerHandle_t timer;
|
||||||
Pinetime::Controllers::Ble &bleController;
|
uint16_t connectionHandle = 0;
|
||||||
DfuImage dfuImage;
|
uint16_t characteristicHandle = 0;
|
||||||
NotificationManager notificationManager;
|
size_t size = 0;
|
||||||
|
uint8_t buffer[10];
|
||||||
|
|
||||||
static constexpr uint16_t dfuServiceId{0x1530};
|
public:
|
||||||
static constexpr uint16_t packetCharacteristicId{0x1532};
|
void OnNotificationTimer();
|
||||||
static constexpr uint16_t controlPointCharacteristicId{0x1531};
|
void Reset();
|
||||||
static constexpr uint16_t revisionCharacteristicId{0x1534};
|
};
|
||||||
|
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};
|
private:
|
||||||
|
Pinetime::Drivers::SpiNorFlash& spiNorFlash;
|
||||||
static constexpr ble_uuid128_t serviceUuid{
|
static constexpr size_t bufferSize = 200;
|
||||||
.u {.type = BLE_UUID_TYPE_128},
|
bool ready = false;
|
||||||
.value = {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15,
|
size_t chunkSize = 0;
|
||||||
0xDE, 0xEF, 0x12, 0x12, 0x30, 0x15, 0x00, 0x00}
|
size_t totalSize = 0;
|
||||||
};
|
size_t maxSize = 475136;
|
||||||
|
size_t bufferWriteIndex = 0;
|
||||||
static constexpr ble_uuid128_t packetCharacteristicUuid{
|
size_t totalWriteIndex = 0;
|
||||||
.u {.type = BLE_UUID_TYPE_128},
|
static constexpr size_t writeOffset = 0x40000;
|
||||||
.value = {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15,
|
uint8_t tempBuffer[bufferSize];
|
||||||
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;
|
uint16_t expectedCrc = 0;
|
||||||
|
|
||||||
int SendDfuRevision(os_mbuf *om) const;
|
void WriteMagicNumber();
|
||||||
int WritePacketHandler(uint16_t connectionHandle, os_mbuf *om);
|
uint16_t ComputeCrc(uint8_t const* p_data, uint32_t size, uint16_t const* p_crc);
|
||||||
int ControlPointHandler(uint16_t connectionHandle, os_mbuf *om);
|
};
|
||||||
|
|
||||||
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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -8,39 +8,29 @@ constexpr ble_uuid16_t HeartRateService::heartRateServiceUuid;
|
||||||
constexpr ble_uuid16_t HeartRateService::heartRateMeasurementUuid;
|
constexpr ble_uuid16_t HeartRateService::heartRateMeasurementUuid;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
int HeartRateServiceServiceCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) {
|
int HeartRateServiceServiceCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
|
||||||
auto* heartRateService = static_cast<HeartRateService*>(arg);
|
auto* heartRateService = static_cast<HeartRateService*>(arg);
|
||||||
return heartRateService->OnHeartRateRequested(conn_handle, attr_handle, ctxt);
|
return heartRateService->OnHeartRateRequested(conn_handle, attr_handle, ctxt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Refactoring - remove dependency to SystemTask
|
// TODO Refactoring - remove dependency to SystemTask
|
||||||
HeartRateService::HeartRateService(Pinetime::System::SystemTask &system, Controllers::HeartRateController& heartRateController) :
|
HeartRateService::HeartRateService(Pinetime::System::SystemTask& system, Controllers::HeartRateController& heartRateController)
|
||||||
system{system},
|
: system {system},
|
||||||
heartRateController{heartRateController},
|
heartRateController {heartRateController},
|
||||||
characteristicDefinition{
|
characteristicDefinition {{.uuid = (ble_uuid_t*) &heartRateMeasurementUuid,
|
||||||
{
|
.access_cb = HeartRateServiceServiceCallback,
|
||||||
.uuid = (ble_uuid_t *) &heartRateMeasurementUuid,
|
.arg = this,
|
||||||
.access_cb = HeartRateServiceServiceCallback,
|
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY,
|
||||||
.arg = this,
|
.val_handle = &heartRateMeasurementHandle},
|
||||||
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY,
|
{0}},
|
||||||
.val_handle = &heartRateMeasurementHandle
|
serviceDefinition {
|
||||||
},
|
{/* Device Information Service */
|
||||||
{
|
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||||
0
|
.uuid = (ble_uuid_t*) &heartRateServiceUuid,
|
||||||
}
|
.characteristics = characteristicDefinition},
|
||||||
},
|
{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)
|
// TODO refactor to prevent this loop dependency (service depends on controller and controller depends on service)
|
||||||
heartRateController.SetService(this);
|
heartRateController.SetService(this);
|
||||||
}
|
}
|
||||||
|
@ -54,9 +44,8 @@ void HeartRateService::Init() {
|
||||||
ASSERT(res == 0);
|
ASSERT(res == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int HeartRateService::OnHeartRateRequested(uint16_t connectionHandle, uint16_t attributeHandle,
|
int HeartRateService::OnHeartRateRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context) {
|
||||||
ble_gatt_access_ctxt *context) {
|
if (attributeHandle == heartRateMeasurementHandle) {
|
||||||
if(attributeHandle == heartRateMeasurementHandle) {
|
|
||||||
NRF_LOG_INFO("HEARTRATE : handle = %d", heartRateMeasurementHandle);
|
NRF_LOG_INFO("HEARTRATE : handle = %d", heartRateMeasurementHandle);
|
||||||
uint8_t buffer[2] = {0, heartRateController.HeartRate()}; // [0] = flags, [1] = hr value
|
uint8_t buffer[2] = {0, heartRateController.HeartRate()}; // [0] = flags, [1] = hr value
|
||||||
|
|
||||||
|
@ -68,7 +57,7 @@ int HeartRateService::OnHeartRateRequested(uint16_t connectionHandle, uint16_t a
|
||||||
|
|
||||||
void HeartRateService::OnNewHeartRateValue(uint8_t heartRateValue) {
|
void HeartRateService::OnNewHeartRateValue(uint8_t heartRateValue) {
|
||||||
uint8_t buffer[2] = {0, heartRateController.HeartRate()}; // [0] = flags, [1] = hr value
|
uint8_t buffer[2] = {0, heartRateController.HeartRate()}; // [0] = flags, [1] = hr value
|
||||||
auto *om = ble_hs_mbuf_from_flat(buffer, 2);
|
auto* om = ble_hs_mbuf_from_flat(buffer, 2);
|
||||||
|
|
||||||
uint16_t connectionHandle = system.nimble().connHandle();
|
uint16_t connectionHandle = system.nimble().connHandle();
|
||||||
|
|
||||||
|
|
|
@ -12,33 +12,26 @@ namespace Pinetime {
|
||||||
namespace Controllers {
|
namespace Controllers {
|
||||||
class HeartRateController;
|
class HeartRateController;
|
||||||
class HeartRateService {
|
class HeartRateService {
|
||||||
public:
|
public:
|
||||||
HeartRateService(Pinetime::System::SystemTask &system, Controllers::HeartRateController& heartRateController);
|
HeartRateService(Pinetime::System::SystemTask& system, Controllers::HeartRateController& heartRateController);
|
||||||
void Init();
|
void Init();
|
||||||
int OnHeartRateRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt *context);
|
int OnHeartRateRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context);
|
||||||
void OnNewHeartRateValue(uint8_t hearRateValue);
|
void OnNewHeartRateValue(uint8_t hearRateValue);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Pinetime::System::SystemTask &system;
|
Pinetime::System::SystemTask& system;
|
||||||
Controllers::HeartRateController& heartRateController;
|
Controllers::HeartRateController& heartRateController;
|
||||||
static constexpr uint16_t heartRateServiceId {0x180D};
|
static constexpr uint16_t heartRateServiceId {0x180D};
|
||||||
static constexpr uint16_t heartRateMeasurementId {0x2A37};
|
static constexpr uint16_t heartRateMeasurementId {0x2A37};
|
||||||
|
|
||||||
static constexpr ble_uuid16_t heartRateServiceUuid {
|
static constexpr ble_uuid16_t heartRateServiceUuid {.u {.type = BLE_UUID_TYPE_16}, .value = heartRateServiceId};
|
||||||
.u {.type = BLE_UUID_TYPE_16},
|
|
||||||
.value = heartRateServiceId
|
|
||||||
};
|
|
||||||
|
|
||||||
static constexpr ble_uuid16_t heartRateMeasurementUuid {
|
static constexpr ble_uuid16_t heartRateMeasurementUuid {.u {.type = BLE_UUID_TYPE_16}, .value = heartRateMeasurementId};
|
||||||
.u {.type = BLE_UUID_TYPE_16},
|
|
||||||
.value = heartRateMeasurementId
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ble_gatt_chr_def characteristicDefinition[3];
|
struct ble_gatt_chr_def characteristicDefinition[3];
|
||||||
struct ble_gatt_svc_def serviceDefinition[2];
|
struct ble_gatt_svc_def serviceDefinition[2];
|
||||||
|
|
||||||
uint16_t heartRateMeasurementHandle;
|
|
||||||
|
|
||||||
|
uint16_t heartRateMeasurementHandle;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,49 +9,42 @@ constexpr ble_uuid16_t ImmediateAlertService::immediateAlertServiceUuid;
|
||||||
constexpr ble_uuid16_t ImmediateAlertService::alertLevelUuid;
|
constexpr ble_uuid16_t ImmediateAlertService::alertLevelUuid;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
int AlertLevelCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) {
|
int AlertLevelCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
|
||||||
auto *immediateAlertService = static_cast<ImmediateAlertService *>(arg);
|
auto* immediateAlertService = static_cast<ImmediateAlertService*>(arg);
|
||||||
return immediateAlertService->OnAlertLevelChanged(conn_handle, attr_handle, ctxt);
|
return immediateAlertService->OnAlertLevelChanged(conn_handle, attr_handle, ctxt);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* ToString(ImmediateAlertService::Levels level) {
|
const char* ToString(ImmediateAlertService::Levels level) {
|
||||||
switch (level) {
|
switch (level) {
|
||||||
case ImmediateAlertService::Levels::NoAlert: return "Alert : None";
|
case ImmediateAlertService::Levels::NoAlert:
|
||||||
case ImmediateAlertService::Levels::HighAlert: return "Alert : High";
|
return "Alert : None";
|
||||||
case ImmediateAlertService::Levels::MildAlert: return "Alert : Mild";
|
case ImmediateAlertService::Levels::HighAlert:
|
||||||
default: return "";
|
return "Alert : High";
|
||||||
|
case ImmediateAlertService::Levels::MildAlert:
|
||||||
|
return "Alert : Mild";
|
||||||
|
default:
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ImmediateAlertService::ImmediateAlertService(Pinetime::System::SystemTask &systemTask,
|
ImmediateAlertService::ImmediateAlertService(Pinetime::System::SystemTask& systemTask,
|
||||||
Pinetime::Controllers::NotificationManager ¬ificationManager) :
|
Pinetime::Controllers::NotificationManager& notificationManager)
|
||||||
systemTask{systemTask},
|
: systemTask {systemTask},
|
||||||
notificationManager{notificationManager},
|
notificationManager {notificationManager},
|
||||||
characteristicDefinition{
|
characteristicDefinition {{.uuid = (ble_uuid_t*) &alertLevelUuid,
|
||||||
{
|
.access_cb = AlertLevelCallback,
|
||||||
.uuid = (ble_uuid_t *) &alertLevelUuid,
|
.arg = this,
|
||||||
.access_cb = AlertLevelCallback,
|
.flags = BLE_GATT_CHR_F_WRITE_NO_RSP,
|
||||||
.arg = this,
|
.val_handle = &alertLevelHandle},
|
||||||
.flags = BLE_GATT_CHR_F_WRITE_NO_RSP,
|
{0}},
|
||||||
.val_handle = &alertLevelHandle
|
serviceDefinition {
|
||||||
},
|
{/* Device Information Service */
|
||||||
{
|
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||||
0
|
.uuid = (ble_uuid_t*) &immediateAlertServiceUuid,
|
||||||
}
|
.characteristics = characteristicDefinition},
|
||||||
},
|
{0},
|
||||||
serviceDefinition{
|
} {
|
||||||
{
|
|
||||||
/* Device Information Service */
|
|
||||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
|
||||||
.uuid = (ble_uuid_t *) &immediateAlertServiceUuid,
|
|
||||||
.characteristics = characteristicDefinition
|
|
||||||
},
|
|
||||||
{
|
|
||||||
0
|
|
||||||
},
|
|
||||||
}{
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImmediateAlertService::Init() {
|
void ImmediateAlertService::Init() {
|
||||||
|
@ -63,9 +56,9 @@ void ImmediateAlertService::Init() {
|
||||||
ASSERT(res == 0);
|
ASSERT(res == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ImmediateAlertService::OnAlertLevelChanged(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt *context) {
|
int ImmediateAlertService::OnAlertLevelChanged(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context) {
|
||||||
if(attributeHandle == alertLevelHandle) {
|
if (attributeHandle == alertLevelHandle) {
|
||||||
if(context->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
|
if (context->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
|
||||||
auto alertLevel = static_cast<Levels>(context->om->om_data[0]);
|
auto alertLevel = static_cast<Levels>(context->om->om_data[0]);
|
||||||
auto* alertString = ToString(alertLevel);
|
auto* alertString = ToString(alertLevel);
|
||||||
|
|
||||||
|
|
|
@ -12,39 +12,28 @@ namespace Pinetime {
|
||||||
namespace Controllers {
|
namespace Controllers {
|
||||||
class NotificationManager;
|
class NotificationManager;
|
||||||
class ImmediateAlertService {
|
class ImmediateAlertService {
|
||||||
public:
|
public:
|
||||||
enum class Levels : uint8_t {
|
enum class Levels : uint8_t { NoAlert = 0, MildAlert = 1, HighAlert = 2 };
|
||||||
NoAlert = 0,
|
|
||||||
MildAlert = 1,
|
|
||||||
HighAlert = 2
|
|
||||||
};
|
|
||||||
|
|
||||||
ImmediateAlertService(Pinetime::System::SystemTask &systemTask,
|
ImmediateAlertService(Pinetime::System::SystemTask& systemTask, Pinetime::Controllers::NotificationManager& notificationManager);
|
||||||
Pinetime::Controllers::NotificationManager ¬ificationManager);
|
void Init();
|
||||||
void Init();
|
int OnAlertLevelChanged(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context);
|
||||||
int OnAlertLevelChanged(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt *context);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Pinetime::System::SystemTask& systemTask;
|
Pinetime::System::SystemTask& systemTask;
|
||||||
NotificationManager& notificationManager;
|
NotificationManager& notificationManager;
|
||||||
|
|
||||||
static constexpr uint16_t immediateAlertServiceId {0x1802};
|
static constexpr uint16_t immediateAlertServiceId {0x1802};
|
||||||
static constexpr uint16_t alertLevelId {0x2A06};
|
static constexpr uint16_t alertLevelId {0x2A06};
|
||||||
|
|
||||||
static constexpr ble_uuid16_t immediateAlertServiceUuid {
|
static constexpr ble_uuid16_t immediateAlertServiceUuid {.u {.type = BLE_UUID_TYPE_16}, .value = immediateAlertServiceId};
|
||||||
.u {.type = BLE_UUID_TYPE_16},
|
|
||||||
.value = immediateAlertServiceId
|
|
||||||
};
|
|
||||||
|
|
||||||
static constexpr ble_uuid16_t alertLevelUuid {
|
static constexpr ble_uuid16_t alertLevelUuid {.u {.type = BLE_UUID_TYPE_16}, .value = alertLevelId};
|
||||||
.u {.type = BLE_UUID_TYPE_16},
|
|
||||||
.value = alertLevelId
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ble_gatt_chr_def characteristicDefinition[3];
|
struct ble_gatt_chr_def characteristicDefinition[3];
|
||||||
struct ble_gatt_svc_def serviceDefinition[2];
|
struct ble_gatt_svc_def serviceDefinition[2];
|
||||||
|
|
||||||
uint16_t alertLevelHandle;
|
uint16_t alertLevelHandle;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,12 +18,12 @@
|
||||||
#include "MusicService.h"
|
#include "MusicService.h"
|
||||||
#include "systemtask/SystemTask.h"
|
#include "systemtask/SystemTask.h"
|
||||||
|
|
||||||
int MSCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) {
|
int MSCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
|
||||||
auto musicService = static_cast<Pinetime::Controllers::MusicService *>(arg);
|
auto musicService = static_cast<Pinetime::Controllers::MusicService*>(arg);
|
||||||
return musicService->OnCommand(conn_handle, attr_handle, ctxt);
|
return musicService->OnCommand(conn_handle, attr_handle, ctxt);
|
||||||
}
|
}
|
||||||
|
|
||||||
Pinetime::Controllers::MusicService::MusicService(Pinetime::System::SystemTask &system) : m_system(system) {
|
Pinetime::Controllers::MusicService::MusicService(Pinetime::System::SystemTask& system) : m_system(system) {
|
||||||
msUuid.value[14] = msId[0];
|
msUuid.value[14] = msId[0];
|
||||||
msUuid.value[15] = msId[1];
|
msUuid.value[15] = msId[1];
|
||||||
|
|
||||||
|
@ -87,79 +87,48 @@ Pinetime::Controllers::MusicService::MusicService(Pinetime::System::SystemTask &
|
||||||
msShuffleCharUuid.value[14] = msId[0];
|
msShuffleCharUuid.value[14] = msId[0];
|
||||||
msShuffleCharUuid.value[15] = msId[1];
|
msShuffleCharUuid.value[15] = msId[1];
|
||||||
|
|
||||||
characteristicDefinition[0] = {.uuid = (ble_uuid_t *) (&msEventCharUuid),
|
characteristicDefinition[0] = {.uuid = (ble_uuid_t*) (&msEventCharUuid),
|
||||||
.access_cb = MSCallback,
|
.access_cb = MSCallback,
|
||||||
.arg = this,
|
.arg = this,
|
||||||
.flags = BLE_GATT_CHR_F_NOTIFY,
|
.flags = BLE_GATT_CHR_F_NOTIFY,
|
||||||
.val_handle = &eventHandle
|
.val_handle = &eventHandle};
|
||||||
};
|
characteristicDefinition[1] = {
|
||||||
characteristicDefinition[1] = {.uuid = (ble_uuid_t *) (&msStatusCharUuid),
|
.uuid = (ble_uuid_t*) (&msStatusCharUuid), .access_cb = MSCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||||
.access_cb = MSCallback,
|
characteristicDefinition[2] = {
|
||||||
.arg = this,
|
.uuid = (ble_uuid_t*) (&msTrackCharUuid), .access_cb = MSCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
|
characteristicDefinition[3] = {
|
||||||
};
|
.uuid = (ble_uuid_t*) (&msArtistCharUuid), .access_cb = MSCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||||
characteristicDefinition[2] = {.uuid = (ble_uuid_t *) (&msTrackCharUuid),
|
characteristicDefinition[4] = {
|
||||||
.access_cb = MSCallback,
|
.uuid = (ble_uuid_t*) (&msAlbumCharUuid), .access_cb = MSCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||||
.arg = this,
|
characteristicDefinition[5] = {
|
||||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
|
.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),
|
||||||
characteristicDefinition[3] = {.uuid = (ble_uuid_t *) (&msArtistCharUuid),
|
.access_cb = MSCallback,
|
||||||
.access_cb = MSCallback,
|
.arg = this,
|
||||||
.arg = this,
|
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
|
characteristicDefinition[7] = {.uuid = (ble_uuid_t*) (&msTotalLengthCharUuid),
|
||||||
};
|
.access_cb = MSCallback,
|
||||||
characteristicDefinition[4] = {.uuid = (ble_uuid_t *) (&msAlbumCharUuid),
|
.arg = this,
|
||||||
.access_cb = MSCallback,
|
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||||
.arg = this,
|
characteristicDefinition[8] = {.uuid = (ble_uuid_t*) (&msTrackNumberCharUuid),
|
||||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
|
.access_cb = MSCallback,
|
||||||
};
|
.arg = this,
|
||||||
characteristicDefinition[5] = {.uuid = (ble_uuid_t *) (&msPositionCharUuid),
|
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||||
.access_cb = MSCallback,
|
characteristicDefinition[9] = {.uuid = (ble_uuid_t*) (&msTrackTotalCharUuid),
|
||||||
.arg = this,
|
.access_cb = MSCallback,
|
||||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
|
.arg = this,
|
||||||
};
|
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||||
characteristicDefinition[6] = {.uuid = (ble_uuid_t *) (&msTotalLengthCharUuid),
|
characteristicDefinition[10] = {.uuid = (ble_uuid_t*) (&msPlaybackSpeedCharUuid),
|
||||||
.access_cb = MSCallback,
|
.access_cb = MSCallback,
|
||||||
.arg = this,
|
.arg = this,
|
||||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
|
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||||
};
|
characteristicDefinition[11] = {
|
||||||
characteristicDefinition[7] = {.uuid = (ble_uuid_t *) (&msTotalLengthCharUuid),
|
.uuid = (ble_uuid_t*) (&msRepeatCharUuid), .access_cb = MSCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||||
.access_cb = MSCallback,
|
characteristicDefinition[12] = {
|
||||||
.arg = this,
|
.uuid = (ble_uuid_t*) (&msShuffleCharUuid), .access_cb = MSCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
|
|
||||||
};
|
|
||||||
characteristicDefinition[8] = {.uuid = (ble_uuid_t *) (&msTrackNumberCharUuid),
|
|
||||||
.access_cb = MSCallback,
|
|
||||||
.arg = this,
|
|
||||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
|
|
||||||
};
|
|
||||||
characteristicDefinition[9] = {.uuid = (ble_uuid_t *) (&msTrackTotalCharUuid),
|
|
||||||
.access_cb = MSCallback,
|
|
||||||
.arg = this,
|
|
||||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
|
|
||||||
};
|
|
||||||
characteristicDefinition[10] = {.uuid = (ble_uuid_t *) (&msPlaybackSpeedCharUuid),
|
|
||||||
.access_cb = MSCallback,
|
|
||||||
.arg = this,
|
|
||||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
|
|
||||||
};
|
|
||||||
characteristicDefinition[11] = {.uuid = (ble_uuid_t *) (&msRepeatCharUuid),
|
|
||||||
.access_cb = MSCallback,
|
|
||||||
.arg = this,
|
|
||||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
|
|
||||||
};
|
|
||||||
characteristicDefinition[12] = {.uuid = (ble_uuid_t *) (&msShuffleCharUuid),
|
|
||||||
.access_cb = MSCallback,
|
|
||||||
.arg = this,
|
|
||||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
|
|
||||||
};
|
|
||||||
characteristicDefinition[13] = {0};
|
characteristicDefinition[13] = {0};
|
||||||
|
|
||||||
serviceDefinition[0] = {
|
serviceDefinition[0] = {.type = BLE_GATT_SVC_TYPE_PRIMARY, .uuid = (ble_uuid_t*) &msUuid, .characteristics = characteristicDefinition};
|
||||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
|
||||||
.uuid = (ble_uuid_t *) &msUuid,
|
|
||||||
.characteristics = characteristicDefinition
|
|
||||||
};
|
|
||||||
serviceDefinition[1] = {0};
|
serviceDefinition[1] = {0};
|
||||||
|
|
||||||
artistName = "Waiting for";
|
artistName = "Waiting for";
|
||||||
|
@ -182,36 +151,35 @@ void Pinetime::Controllers::MusicService::Init() {
|
||||||
ASSERT(res == 0);
|
ASSERT(res == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Pinetime::Controllers::MusicService::OnCommand(uint16_t conn_handle, uint16_t attr_handle,
|
int Pinetime::Controllers::MusicService::OnCommand(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) {
|
||||||
struct ble_gatt_access_ctxt *ctxt) {
|
|
||||||
|
|
||||||
if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
|
if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
|
||||||
size_t notifSize = OS_MBUF_PKTLEN(ctxt->om);
|
size_t notifSize = OS_MBUF_PKTLEN(ctxt->om);
|
||||||
uint8_t data[notifSize + 1];
|
uint8_t data[notifSize + 1];
|
||||||
data[notifSize] = '\0';
|
data[notifSize] = '\0';
|
||||||
os_mbuf_copydata(ctxt->om, 0, notifSize, data);
|
os_mbuf_copydata(ctxt->om, 0, notifSize, data);
|
||||||
char *s = (char *) &data[0];
|
char* s = (char*) &data[0];
|
||||||
if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msArtistCharUuid) == 0) {
|
if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msArtistCharUuid) == 0) {
|
||||||
artistName = s;
|
artistName = s;
|
||||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msTrackCharUuid) == 0) {
|
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msTrackCharUuid) == 0) {
|
||||||
trackName = s;
|
trackName = s;
|
||||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msAlbumCharUuid) == 0) {
|
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msAlbumCharUuid) == 0) {
|
||||||
albumName = s;
|
albumName = s;
|
||||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msStatusCharUuid) == 0) {
|
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msStatusCharUuid) == 0) {
|
||||||
playing = s[0];
|
playing = s[0];
|
||||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msRepeatCharUuid) == 0) {
|
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msRepeatCharUuid) == 0) {
|
||||||
repeat = s[0];
|
repeat = s[0];
|
||||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msShuffleCharUuid) == 0) {
|
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msShuffleCharUuid) == 0) {
|
||||||
shuffle = s[0];
|
shuffle = s[0];
|
||||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msPositionCharUuid) == 0) {
|
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msPositionCharUuid) == 0) {
|
||||||
trackProgress = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
|
trackProgress = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
|
||||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msTotalLengthCharUuid) == 0) {
|
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msTotalLengthCharUuid) == 0) {
|
||||||
trackLength = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
|
trackLength = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
|
||||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msTrackNumberCharUuid) == 0) {
|
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msTrackNumberCharUuid) == 0) {
|
||||||
trackNumber = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
|
trackNumber = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
|
||||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msTrackTotalCharUuid) == 0) {
|
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msTrackTotalCharUuid) == 0) {
|
||||||
tracksTotal = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
|
tracksTotal = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
|
||||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msPlaybackSpeedCharUuid) == 0) {
|
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msPlaybackSpeedCharUuid) == 0) {
|
||||||
playbackSpeed = static_cast<float>(((s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3])) / 100.0f;
|
playbackSpeed = static_cast<float>(((s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3])) / 100.0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -239,7 +207,7 @@ float Pinetime::Controllers::MusicService::getPlaybackSpeed() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Pinetime::Controllers::MusicService::event(char event) {
|
void Pinetime::Controllers::MusicService::event(char event) {
|
||||||
auto *om = ble_hs_mbuf_from_flat(&event, 1);
|
auto* om = ble_hs_mbuf_from_flat(&event, 1);
|
||||||
|
|
||||||
uint16_t connectionHandle = m_system.nimble().connHandle();
|
uint16_t connectionHandle = m_system.nimble().connHandle();
|
||||||
|
|
||||||
|
@ -257,4 +225,3 @@ int Pinetime::Controllers::MusicService::getProgress() {
|
||||||
int Pinetime::Controllers::MusicService::getTrackLength() {
|
int Pinetime::Controllers::MusicService::getTrackLength() {
|
||||||
return trackLength;
|
return trackLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,8 +26,9 @@
|
||||||
#undef max
|
#undef max
|
||||||
#undef min
|
#undef min
|
||||||
|
|
||||||
//00000000-78fc-48fe-8e23-433b3a1942d0
|
// 00000000-78fc-48fe-8e23-433b3a1942d0
|
||||||
#define MUSIC_SERVICE_UUID_BASE {0xd0, 0x42, 0x19, 0x3a, 0x3b, 0x43, 0x23, 0x8e, 0xfe, 0x48, 0xfc, 0x78, 0x00, 0x00, 0x00, 0x00}
|
#define MUSIC_SERVICE_UUID_BASE \
|
||||||
|
{ 0xd0, 0x42, 0x19, 0x3a, 0x3b, 0x43, 0x23, 0x8e, 0xfe, 0x48, 0xfc, 0x78, 0x00, 0x00, 0x00, 0x00 }
|
||||||
|
|
||||||
namespace Pinetime {
|
namespace Pinetime {
|
||||||
namespace System {
|
namespace System {
|
||||||
|
@ -37,12 +38,11 @@ namespace Pinetime {
|
||||||
|
|
||||||
class MusicService {
|
class MusicService {
|
||||||
public:
|
public:
|
||||||
explicit MusicService(Pinetime::System::SystemTask &system);
|
explicit MusicService(Pinetime::System::SystemTask& system);
|
||||||
|
|
||||||
void Init();
|
void Init();
|
||||||
|
|
||||||
int OnCommand(uint16_t conn_handle, uint16_t attr_handle,
|
int OnCommand(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt);
|
||||||
struct ble_gatt_access_ctxt *ctxt);
|
|
||||||
|
|
||||||
void event(char event);
|
void event(char event);
|
||||||
|
|
||||||
|
@ -68,10 +68,8 @@ namespace Pinetime {
|
||||||
static const char EVENT_MUSIC_VOLUP = 0x05;
|
static const char EVENT_MUSIC_VOLUP = 0x05;
|
||||||
static const char EVENT_MUSIC_VOLDOWN = 0x06;
|
static const char EVENT_MUSIC_VOLDOWN = 0x06;
|
||||||
|
|
||||||
enum MusicStatus {
|
enum MusicStatus { NotPlaying = 0x00, Playing = 0x01 };
|
||||||
NotPlaying = 0x00,
|
|
||||||
Playing = 0x01
|
|
||||||
};
|
|
||||||
private:
|
private:
|
||||||
static constexpr uint8_t msId[2] = {0x00, 0x00};
|
static constexpr uint8_t msId[2] = {0x00, 0x00};
|
||||||
static constexpr uint8_t msEventCharId[2] = {0x01, 0x00};
|
static constexpr uint8_t msEventCharId[2] = {0x01, 0x00};
|
||||||
|
@ -87,59 +85,20 @@ namespace Pinetime {
|
||||||
static constexpr uint8_t msRepeatCharId[2] = {0x0b, 0x00};
|
static constexpr uint8_t msRepeatCharId[2] = {0x0b, 0x00};
|
||||||
static constexpr uint8_t msShuffleCharId[2] = {0x0c, 0x00};
|
static constexpr uint8_t msShuffleCharId[2] = {0x0c, 0x00};
|
||||||
|
|
||||||
ble_uuid128_t msUuid{
|
ble_uuid128_t msUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||||
.u = {.type = BLE_UUID_TYPE_128},
|
|
||||||
.value = MUSIC_SERVICE_UUID_BASE
|
|
||||||
};
|
|
||||||
|
|
||||||
ble_uuid128_t msEventCharUuid{
|
ble_uuid128_t msEventCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||||
.u = {.type = BLE_UUID_TYPE_128},
|
ble_uuid128_t msStatusCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||||
.value = MUSIC_SERVICE_UUID_BASE
|
ble_uuid128_t msArtistCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||||
};
|
ble_uuid128_t msTrackCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||||
ble_uuid128_t msStatusCharUuid{
|
ble_uuid128_t msAlbumCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||||
.u = {.type = BLE_UUID_TYPE_128},
|
ble_uuid128_t msPositionCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||||
.value = MUSIC_SERVICE_UUID_BASE
|
ble_uuid128_t msTotalLengthCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||||
};
|
ble_uuid128_t msTrackNumberCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||||
ble_uuid128_t msArtistCharUuid{
|
ble_uuid128_t msTrackTotalCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||||
.u = {.type = BLE_UUID_TYPE_128},
|
ble_uuid128_t msPlaybackSpeedCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||||
.value = MUSIC_SERVICE_UUID_BASE
|
ble_uuid128_t msRepeatCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||||
};
|
ble_uuid128_t msShuffleCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||||
ble_uuid128_t msTrackCharUuid{
|
|
||||||
.u = {.type = BLE_UUID_TYPE_128},
|
|
||||||
.value = MUSIC_SERVICE_UUID_BASE
|
|
||||||
};
|
|
||||||
ble_uuid128_t msAlbumCharUuid{
|
|
||||||
.u = {.type = BLE_UUID_TYPE_128},
|
|
||||||
.value = MUSIC_SERVICE_UUID_BASE
|
|
||||||
};
|
|
||||||
ble_uuid128_t msPositionCharUuid{
|
|
||||||
.u = {.type = BLE_UUID_TYPE_128},
|
|
||||||
.value = MUSIC_SERVICE_UUID_BASE
|
|
||||||
};
|
|
||||||
ble_uuid128_t msTotalLengthCharUuid{
|
|
||||||
.u = {.type = BLE_UUID_TYPE_128},
|
|
||||||
.value = MUSIC_SERVICE_UUID_BASE
|
|
||||||
};
|
|
||||||
ble_uuid128_t msTrackNumberCharUuid{
|
|
||||||
.u = {.type = BLE_UUID_TYPE_128},
|
|
||||||
.value = MUSIC_SERVICE_UUID_BASE
|
|
||||||
};
|
|
||||||
ble_uuid128_t msTrackTotalCharUuid{
|
|
||||||
.u = {.type = BLE_UUID_TYPE_128},
|
|
||||||
.value = MUSIC_SERVICE_UUID_BASE
|
|
||||||
};
|
|
||||||
ble_uuid128_t msPlaybackSpeedCharUuid{
|
|
||||||
.u = {.type = BLE_UUID_TYPE_128},
|
|
||||||
.value = MUSIC_SERVICE_UUID_BASE
|
|
||||||
};
|
|
||||||
ble_uuid128_t msRepeatCharUuid{
|
|
||||||
.u = {.type = BLE_UUID_TYPE_128},
|
|
||||||
.value = MUSIC_SERVICE_UUID_BASE
|
|
||||||
};
|
|
||||||
ble_uuid128_t msShuffleCharUuid{
|
|
||||||
.u = {.type = BLE_UUID_TYPE_128},
|
|
||||||
.value = MUSIC_SERVICE_UUID_BASE
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ble_gatt_chr_def characteristicDefinition[14];
|
struct ble_gatt_chr_def characteristicDefinition[14];
|
||||||
struct ble_gatt_svc_def serviceDefinition[2];
|
struct ble_gatt_svc_def serviceDefinition[2];
|
||||||
|
@ -162,8 +121,7 @@ namespace Pinetime {
|
||||||
bool repeat;
|
bool repeat;
|
||||||
bool shuffle;
|
bool shuffle;
|
||||||
|
|
||||||
Pinetime::System::SystemTask &m_system;
|
Pinetime::System::SystemTask& m_system;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,12 +20,12 @@
|
||||||
|
|
||||||
#include "systemtask/SystemTask.h"
|
#include "systemtask/SystemTask.h"
|
||||||
|
|
||||||
int NAVCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) {
|
int NAVCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
|
||||||
auto navService = static_cast<Pinetime::Controllers::NavigationService *>(arg);
|
auto navService = static_cast<Pinetime::Controllers::NavigationService*>(arg);
|
||||||
return navService->OnCommand(conn_handle, attr_handle, ctxt);
|
return navService->OnCommand(conn_handle, attr_handle, ctxt);
|
||||||
}
|
}
|
||||||
|
|
||||||
Pinetime::Controllers::NavigationService::NavigationService(Pinetime::System::SystemTask &system) : m_system(system) {
|
Pinetime::Controllers::NavigationService::NavigationService(Pinetime::System::SystemTask& system) : m_system(system) {
|
||||||
navUuid.value[14] = navId[0];
|
navUuid.value[14] = navId[0];
|
||||||
navUuid.value[15] = navId[1];
|
navUuid.value[15] = navId[1];
|
||||||
|
|
||||||
|
@ -49,35 +49,25 @@ Pinetime::Controllers::NavigationService::NavigationService(Pinetime::System::Sy
|
||||||
navProgressCharUuid.value[14] = navId[0];
|
navProgressCharUuid.value[14] = navId[0];
|
||||||
navProgressCharUuid.value[15] = navId[1];
|
navProgressCharUuid.value[15] = navId[1];
|
||||||
|
|
||||||
characteristicDefinition[0] = {.uuid = (ble_uuid_t *) (&navFlagCharUuid),
|
characteristicDefinition[0] = {
|
||||||
.access_cb = NAVCallback,
|
.uuid = (ble_uuid_t*) (&navFlagCharUuid), .access_cb = NAVCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||||
.arg = this,
|
|
||||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
|
|
||||||
};
|
|
||||||
|
|
||||||
characteristicDefinition[1] = {.uuid = (ble_uuid_t *) (&navNarrativeCharUuid),
|
characteristicDefinition[1] = {.uuid = (ble_uuid_t*) (&navNarrativeCharUuid),
|
||||||
.access_cb = NAVCallback,
|
.access_cb = NAVCallback,
|
||||||
.arg = this,
|
.arg = this,
|
||||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
|
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||||
};
|
characteristicDefinition[2] = {.uuid = (ble_uuid_t*) (&navManDistCharUuid),
|
||||||
characteristicDefinition[2] = {.uuid = (ble_uuid_t *) (&navManDistCharUuid),
|
.access_cb = NAVCallback,
|
||||||
.access_cb = NAVCallback,
|
.arg = this,
|
||||||
.arg = this,
|
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
|
characteristicDefinition[3] = {.uuid = (ble_uuid_t*) (&navProgressCharUuid),
|
||||||
};
|
.access_cb = NAVCallback,
|
||||||
characteristicDefinition[3] = {.uuid = (ble_uuid_t *) (&navProgressCharUuid),
|
.arg = this,
|
||||||
.access_cb = NAVCallback,
|
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||||
.arg = this,
|
|
||||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
|
|
||||||
};
|
|
||||||
|
|
||||||
characteristicDefinition[4] = {0};
|
characteristicDefinition[4] = {0};
|
||||||
|
|
||||||
serviceDefinition[0] = {
|
serviceDefinition[0] = {.type = BLE_GATT_SVC_TYPE_PRIMARY, .uuid = (ble_uuid_t*) &navUuid, .characteristics = characteristicDefinition};
|
||||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
|
||||||
.uuid = (ble_uuid_t *) &navUuid,
|
|
||||||
.characteristics = characteristicDefinition
|
|
||||||
};
|
|
||||||
serviceDefinition[1] = {0};
|
serviceDefinition[1] = {0};
|
||||||
|
|
||||||
m_progress = 0;
|
m_progress = 0;
|
||||||
|
@ -92,45 +82,39 @@ void Pinetime::Controllers::NavigationService::Init() {
|
||||||
ASSERT(res == 0);
|
ASSERT(res == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Pinetime::Controllers::NavigationService::OnCommand(uint16_t conn_handle, uint16_t attr_handle,
|
int Pinetime::Controllers::NavigationService::OnCommand(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) {
|
||||||
struct ble_gatt_access_ctxt *ctxt) {
|
|
||||||
|
|
||||||
if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
|
if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
|
||||||
size_t notifSize = OS_MBUF_PKTLEN(ctxt->om);
|
size_t notifSize = OS_MBUF_PKTLEN(ctxt->om);
|
||||||
uint8_t data[notifSize + 1];
|
uint8_t data[notifSize + 1];
|
||||||
data[notifSize] = '\0';
|
data[notifSize] = '\0';
|
||||||
os_mbuf_copydata(ctxt->om, 0, notifSize, data);
|
os_mbuf_copydata(ctxt->om, 0, notifSize, data);
|
||||||
char *s = (char *) &data[0];
|
char* s = (char*) &data[0];
|
||||||
if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &navFlagCharUuid) == 0) {
|
if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &navFlagCharUuid) == 0) {
|
||||||
m_flag = s;
|
m_flag = s;
|
||||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &navNarrativeCharUuid) == 0) {
|
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &navNarrativeCharUuid) == 0) {
|
||||||
m_narrative = s;
|
m_narrative = s;
|
||||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &navManDistCharUuid) == 0) {
|
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &navManDistCharUuid) == 0) {
|
||||||
m_manDist = s;
|
m_manDist = s;
|
||||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &navProgressCharUuid) == 0) {
|
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &navProgressCharUuid) == 0) {
|
||||||
m_progress = data[0];
|
m_progress = data[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Pinetime::Controllers::NavigationService::getFlag()
|
std::string Pinetime::Controllers::NavigationService::getFlag() {
|
||||||
{
|
return m_flag;
|
||||||
return m_flag;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Pinetime::Controllers::NavigationService::getNarrative()
|
std::string Pinetime::Controllers::NavigationService::getNarrative() {
|
||||||
{
|
return m_narrative;
|
||||||
return m_narrative;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Pinetime::Controllers::NavigationService::getManDist()
|
std::string Pinetime::Controllers::NavigationService::getManDist() {
|
||||||
{
|
return m_manDist;
|
||||||
return m_manDist;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int Pinetime::Controllers::NavigationService::getProgress()
|
int Pinetime::Controllers::NavigationService::getProgress() {
|
||||||
{
|
return m_progress;
|
||||||
return m_progress;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,8 +26,9 @@
|
||||||
#undef max
|
#undef max
|
||||||
#undef min
|
#undef min
|
||||||
|
|
||||||
//c7e60000-78fc-48fe-8e23-433b3a1942d0
|
// c7e60000-78fc-48fe-8e23-433b3a1942d0
|
||||||
#define NAVIGATION_SERVICE_UUID_BASE {0xd0, 0x42, 0x19, 0x3a, 0x3b, 0x43, 0x23, 0x8e, 0xfe, 0x48, 0xfc, 0x78, 0x00, 0x00, 0x00, 0x00}
|
#define NAVIGATION_SERVICE_UUID_BASE \
|
||||||
|
{ 0xd0, 0x42, 0x19, 0x3a, 0x3b, 0x43, 0x23, 0x8e, 0xfe, 0x48, 0xfc, 0x78, 0x00, 0x00, 0x00, 0x00 }
|
||||||
|
|
||||||
namespace Pinetime {
|
namespace Pinetime {
|
||||||
namespace System {
|
namespace System {
|
||||||
|
@ -37,12 +38,11 @@ namespace Pinetime {
|
||||||
|
|
||||||
class NavigationService {
|
class NavigationService {
|
||||||
public:
|
public:
|
||||||
explicit NavigationService(Pinetime::System::SystemTask &system);
|
explicit NavigationService(Pinetime::System::SystemTask& system);
|
||||||
|
|
||||||
void Init();
|
void Init();
|
||||||
|
|
||||||
int OnCommand(uint16_t conn_handle, uint16_t attr_handle,
|
int OnCommand(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt);
|
||||||
struct ble_gatt_access_ctxt *ctxt);
|
|
||||||
|
|
||||||
std::string getFlag();
|
std::string getFlag();
|
||||||
|
|
||||||
|
@ -59,27 +59,12 @@ namespace Pinetime {
|
||||||
static constexpr uint8_t navManDistCharId[2] = {0x03, 0x00};
|
static constexpr uint8_t navManDistCharId[2] = {0x03, 0x00};
|
||||||
static constexpr uint8_t navProgressCharId[2] = {0x04, 0x00};
|
static constexpr uint8_t navProgressCharId[2] = {0x04, 0x00};
|
||||||
|
|
||||||
ble_uuid128_t navUuid{
|
ble_uuid128_t navUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = NAVIGATION_SERVICE_UUID_BASE};
|
||||||
.u = {.type = BLE_UUID_TYPE_128},
|
|
||||||
.value = NAVIGATION_SERVICE_UUID_BASE
|
|
||||||
};
|
|
||||||
|
|
||||||
ble_uuid128_t navFlagCharUuid{
|
ble_uuid128_t navFlagCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = NAVIGATION_SERVICE_UUID_BASE};
|
||||||
.u = {.type = BLE_UUID_TYPE_128},
|
ble_uuid128_t navNarrativeCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = NAVIGATION_SERVICE_UUID_BASE};
|
||||||
.value = NAVIGATION_SERVICE_UUID_BASE
|
ble_uuid128_t navManDistCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = NAVIGATION_SERVICE_UUID_BASE};
|
||||||
};
|
ble_uuid128_t navProgressCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = NAVIGATION_SERVICE_UUID_BASE};
|
||||||
ble_uuid128_t navNarrativeCharUuid{
|
|
||||||
.u = {.type = BLE_UUID_TYPE_128},
|
|
||||||
.value = NAVIGATION_SERVICE_UUID_BASE
|
|
||||||
};
|
|
||||||
ble_uuid128_t navManDistCharUuid{
|
|
||||||
.u = {.type = BLE_UUID_TYPE_128},
|
|
||||||
.value = NAVIGATION_SERVICE_UUID_BASE
|
|
||||||
};
|
|
||||||
ble_uuid128_t navProgressCharUuid{
|
|
||||||
.u = {.type = BLE_UUID_TYPE_128},
|
|
||||||
.value = NAVIGATION_SERVICE_UUID_BASE
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ble_gatt_chr_def characteristicDefinition[5];
|
struct ble_gatt_chr_def characteristicDefinition[5];
|
||||||
struct ble_gatt_svc_def serviceDefinition[2];
|
struct ble_gatt_svc_def serviceDefinition[2];
|
||||||
|
@ -89,8 +74,7 @@ namespace Pinetime {
|
||||||
std::string m_manDist;
|
std::string m_manDist;
|
||||||
int m_progress;
|
int m_progress;
|
||||||
|
|
||||||
Pinetime::System::SystemTask &m_system;
|
Pinetime::System::SystemTask& m_system;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,36 +19,37 @@ using namespace Pinetime::Controllers;
|
||||||
|
|
||||||
NimbleController::NimbleController(Pinetime::System::SystemTask& systemTask,
|
NimbleController::NimbleController(Pinetime::System::SystemTask& systemTask,
|
||||||
Pinetime::Controllers::Ble& bleController,
|
Pinetime::Controllers::Ble& bleController,
|
||||||
DateTime& dateTimeController,
|
DateTime& dateTimeController,
|
||||||
Pinetime::Controllers::NotificationManager& notificationManager,
|
Pinetime::Controllers::NotificationManager& notificationManager,
|
||||||
Controllers::Battery& batteryController,
|
Controllers::Battery& batteryController,
|
||||||
Pinetime::Drivers::SpiNorFlash& spiNorFlash,
|
Pinetime::Drivers::SpiNorFlash& spiNorFlash,
|
||||||
Controllers::HeartRateController& heartRateController) :
|
Controllers::HeartRateController& heartRateController)
|
||||||
systemTask{systemTask},
|
: systemTask {systemTask},
|
||||||
bleController{bleController},
|
bleController {bleController},
|
||||||
dateTimeController{dateTimeController},
|
dateTimeController {dateTimeController},
|
||||||
notificationManager{notificationManager},
|
notificationManager {notificationManager},
|
||||||
spiNorFlash{spiNorFlash},
|
spiNorFlash {spiNorFlash},
|
||||||
dfuService{systemTask, bleController, spiNorFlash},
|
dfuService {systemTask, bleController, spiNorFlash},
|
||||||
currentTimeClient{dateTimeController},
|
currentTimeClient {dateTimeController},
|
||||||
anService{systemTask, notificationManager},
|
anService {systemTask, notificationManager},
|
||||||
alertNotificationClient{systemTask, notificationManager},
|
alertNotificationClient {systemTask, notificationManager},
|
||||||
currentTimeService{dateTimeController},
|
currentTimeService {dateTimeController},
|
||||||
musicService{systemTask},
|
musicService {systemTask},
|
||||||
navService{systemTask},
|
navService {systemTask},
|
||||||
batteryInformationService{batteryController},
|
batteryInformationService {batteryController},
|
||||||
immediateAlertService{systemTask, notificationManager},
|
immediateAlertService {systemTask, notificationManager},
|
||||||
heartRateService{systemTask, heartRateController},
|
heartRateService {systemTask, heartRateController},
|
||||||
serviceDiscovery({¤tTimeClient, &alertNotificationClient}) {
|
serviceDiscovery({¤tTimeClient, &alertNotificationClient}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int GAPEventCallback(struct ble_gap_event *event, void *arg) {
|
int GAPEventCallback(struct ble_gap_event* event, void* arg) {
|
||||||
auto nimbleController = static_cast<NimbleController*>(arg);
|
auto nimbleController = static_cast<NimbleController*>(arg);
|
||||||
return nimbleController->OnGAPEvent(event);
|
return nimbleController->OnGAPEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NimbleController::Init() {
|
void NimbleController::Init() {
|
||||||
while (!ble_hs_synced()) {}
|
while (!ble_hs_synced()) {
|
||||||
|
}
|
||||||
|
|
||||||
ble_svc_gap_init();
|
ble_svc_gap_init();
|
||||||
ble_svc_gatt_init();
|
ble_svc_gatt_init();
|
||||||
|
@ -81,7 +82,8 @@ void NimbleController::Init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void NimbleController::StartAdvertising() {
|
void NimbleController::StartAdvertising() {
|
||||||
if(bleController.IsConnected() || ble_gap_conn_active() || ble_gap_adv_active()) return;
|
if (bleController.IsConnected() || ble_gap_conn_active() || ble_gap_adv_active())
|
||||||
|
return;
|
||||||
|
|
||||||
ble_svc_gap_device_name_set(deviceName);
|
ble_svc_gap_device_name_set(deviceName);
|
||||||
|
|
||||||
|
@ -101,29 +103,27 @@ void NimbleController::StartAdvertising() {
|
||||||
adv_params.conn_mode = BLE_GAP_CONN_MODE_UND;
|
adv_params.conn_mode = BLE_GAP_CONN_MODE_UND;
|
||||||
adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN;
|
adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN;
|
||||||
|
|
||||||
fields.flags = BLE_HS_ADV_F_DISC_GEN |
|
fields.flags = BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP;
|
||||||
BLE_HS_ADV_F_BREDR_UNSUP;
|
// fields.uuids128 = BLE_UUID128(BLE_UUID128_DECLARE(
|
||||||
// fields.uuids128 = BLE_UUID128(BLE_UUID128_DECLARE(
|
// 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
|
||||||
// 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
|
// 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff));
|
||||||
// 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff));
|
|
||||||
fields.uuids128 = &dfuServiceUuid;
|
fields.uuids128 = &dfuServiceUuid;
|
||||||
fields.num_uuids128 = 1;
|
fields.num_uuids128 = 1;
|
||||||
fields.uuids128_is_complete = 1;
|
fields.uuids128_is_complete = 1;
|
||||||
fields.tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO;
|
fields.tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO;
|
||||||
|
|
||||||
rsp_fields.name = (uint8_t *)deviceName;
|
rsp_fields.name = (uint8_t*) deviceName;
|
||||||
rsp_fields.name_len = strlen(deviceName);
|
rsp_fields.name_len = strlen(deviceName);
|
||||||
rsp_fields.name_is_complete = 1;
|
rsp_fields.name_is_complete = 1;
|
||||||
|
|
||||||
ble_gap_adv_set_fields(&fields);
|
ble_gap_adv_set_fields(&fields);
|
||||||
// ASSERT(res == 0); // TODO this one sometimes fails with error 22 (notsync)
|
// ASSERT(res == 0); // TODO this one sometimes fails with error 22 (notsync)
|
||||||
|
|
||||||
ble_gap_adv_rsp_set_fields(&rsp_fields);
|
ble_gap_adv_rsp_set_fields(&rsp_fields);
|
||||||
// ASSERT(res == 0);
|
// ASSERT(res == 0);
|
||||||
|
|
||||||
ble_gap_adv_start(addrType, NULL, 180000,
|
ble_gap_adv_start(addrType, NULL, 180000, &adv_params, GAPEventCallback, this);
|
||||||
&adv_params, GAPEventCallback, this);
|
// ASSERT(res == 0);// TODO I've disabled these ASSERT as they sometime asserts and reset the mcu.
|
||||||
// ASSERT(res == 0);// TODO I've disabled these ASSERT as they sometime asserts and reset the mcu.
|
|
||||||
// For now, the advertising is restarted as soon as it ends. There may be a race condition
|
// For now, the advertising is restarted as soon as it ends. There may be a race condition
|
||||||
// that prevent the advertising from restarting reliably.
|
// that prevent the advertising from restarting reliably.
|
||||||
// I remove the assert to prevent this uncesseray crash, but in the long term, the management of
|
// I remove the assert to prevent this uncesseray crash, but in the long term, the management of
|
||||||
|
@ -131,7 +131,7 @@ void NimbleController::StartAdvertising() {
|
||||||
// the application has been woken up, for example.
|
// the application has been woken up, for example.
|
||||||
}
|
}
|
||||||
|
|
||||||
int NimbleController::OnGAPEvent(ble_gap_event *event) {
|
int NimbleController::OnGAPEvent(ble_gap_event* event) {
|
||||||
switch (event->type) {
|
switch (event->type) {
|
||||||
case BLE_GAP_EVENT_ADV_COMPLETE:
|
case BLE_GAP_EVENT_ADV_COMPLETE:
|
||||||
NRF_LOG_INFO("Advertising event : BLE_GAP_EVENT_ADV_COMPLETE");
|
NRF_LOG_INFO("Advertising event : BLE_GAP_EVENT_ADV_COMPLETE");
|
||||||
|
@ -141,8 +141,7 @@ int NimbleController::OnGAPEvent(ble_gap_event *event) {
|
||||||
NRF_LOG_INFO("Advertising event : BLE_GAP_EVENT_CONNECT");
|
NRF_LOG_INFO("Advertising event : BLE_GAP_EVENT_CONNECT");
|
||||||
|
|
||||||
/* A new connection was established or a connection attempt failed. */
|
/* A new connection was established or a connection attempt failed. */
|
||||||
NRF_LOG_INFO("connection %s; status=%d ", event->connect.status == 0 ? "established" : "failed",
|
NRF_LOG_INFO("connection %s; status=%d ", event->connect.status == 0 ? "established" : "failed", event->connect.status);
|
||||||
event->connect.status);
|
|
||||||
|
|
||||||
if (event->connect.status != 0) {
|
if (event->connect.status != 0) {
|
||||||
/* Connection failed; resume advertising. */
|
/* Connection failed; resume advertising. */
|
||||||
|
@ -154,8 +153,7 @@ int NimbleController::OnGAPEvent(ble_gap_event *event) {
|
||||||
connectionHandle = event->connect.conn_handle;
|
connectionHandle = event->connect.conn_handle;
|
||||||
// Service discovery is deffered via systemtask
|
// Service discovery is deffered via systemtask
|
||||||
}
|
}
|
||||||
}
|
} break;
|
||||||
break;
|
|
||||||
case BLE_GAP_EVENT_DISCONNECT:
|
case BLE_GAP_EVENT_DISCONNECT:
|
||||||
NRF_LOG_INFO("Advertising event : BLE_GAP_EVENT_DISCONNECT");
|
NRF_LOG_INFO("Advertising event : BLE_GAP_EVENT_DISCONNECT");
|
||||||
NRF_LOG_INFO("disconnect; reason=%d", event->disconnect.reason);
|
NRF_LOG_INFO("disconnect; reason=%d", event->disconnect.reason);
|
||||||
|
@ -178,19 +176,16 @@ int NimbleController::OnGAPEvent(ble_gap_event *event) {
|
||||||
return 0;
|
return 0;
|
||||||
case BLE_GAP_EVENT_SUBSCRIBE:
|
case BLE_GAP_EVENT_SUBSCRIBE:
|
||||||
NRF_LOG_INFO("subscribe event; conn_handle=%d attr_handle=%d "
|
NRF_LOG_INFO("subscribe event; conn_handle=%d attr_handle=%d "
|
||||||
"reason=%d prevn=%d curn=%d previ=%d curi=???\n",
|
"reason=%d prevn=%d curn=%d previ=%d curi=???\n",
|
||||||
event->subscribe.conn_handle,
|
event->subscribe.conn_handle,
|
||||||
event->subscribe.attr_handle,
|
event->subscribe.attr_handle,
|
||||||
event->subscribe.reason,
|
event->subscribe.reason,
|
||||||
event->subscribe.prev_notify,
|
event->subscribe.prev_notify,
|
||||||
event->subscribe.cur_notify,
|
event->subscribe.cur_notify,
|
||||||
event->subscribe.prev_indicate);
|
event->subscribe.prev_indicate);
|
||||||
return 0;
|
return 0;
|
||||||
case BLE_GAP_EVENT_MTU:
|
case BLE_GAP_EVENT_MTU:
|
||||||
NRF_LOG_INFO("mtu update event; conn_handle=%d cid=%d mtu=%d\n",
|
NRF_LOG_INFO("mtu update event; conn_handle=%d cid=%d mtu=%d\n", event->mtu.conn_handle, event->mtu.channel_id, event->mtu.value);
|
||||||
event->mtu.conn_handle,
|
|
||||||
event->mtu.channel_id,
|
|
||||||
event->mtu.value);
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case BLE_GAP_EVENT_REPEAT_PAIRING: {
|
case BLE_GAP_EVENT_REPEAT_PAIRING: {
|
||||||
|
@ -216,9 +211,7 @@ int NimbleController::OnGAPEvent(ble_gap_event *event) {
|
||||||
|
|
||||||
NRF_LOG_INFO("received %s; conn_handle=%d attr_handle=%d "
|
NRF_LOG_INFO("received %s; conn_handle=%d attr_handle=%d "
|
||||||
"attr_len=%d",
|
"attr_len=%d",
|
||||||
event->notify_rx.indication ?
|
event->notify_rx.indication ? "indication" : "notification",
|
||||||
"indication" :
|
|
||||||
"notification",
|
|
||||||
event->notify_rx.conn_handle,
|
event->notify_rx.conn_handle,
|
||||||
event->notify_rx.attr_handle,
|
event->notify_rx.attr_handle,
|
||||||
notifSize);
|
notifSize);
|
||||||
|
@ -229,7 +222,7 @@ int NimbleController::OnGAPEvent(ble_gap_event *event) {
|
||||||
/* Attribute data is contained in event->notify_rx.attr_data. */
|
/* Attribute data is contained in event->notify_rx.attr_data. */
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// NRF_LOG_INFO("Advertising event : %d", event->type);
|
// NRF_LOG_INFO("Advertising event : %d", event->type);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -239,8 +232,6 @@ void NimbleController::StartDiscovery() {
|
||||||
serviceDiscovery.StartDiscovery(connectionHandle);
|
serviceDiscovery.StartDiscovery(connectionHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
uint16_t NimbleController::connHandle() {
|
uint16_t NimbleController::connHandle() {
|
||||||
return connectionHandle;
|
return connectionHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,62 +36,69 @@ namespace Pinetime {
|
||||||
|
|
||||||
class NimbleController {
|
class NimbleController {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
NimbleController(Pinetime::System::SystemTask& systemTask, Pinetime::Controllers::Ble& bleController,
|
NimbleController(Pinetime::System::SystemTask& systemTask,
|
||||||
DateTime& dateTimeController, Pinetime::Controllers::NotificationManager& notificationManager,
|
Pinetime::Controllers::Ble& bleController,
|
||||||
Controllers::Battery& batteryController, Pinetime::Drivers::SpiNorFlash& spiNorFlash,
|
DateTime& dateTimeController,
|
||||||
Controllers::HeartRateController& heartRateController);
|
Pinetime::Controllers::NotificationManager& notificationManager,
|
||||||
void Init();
|
Controllers::Battery& batteryController,
|
||||||
void StartAdvertising();
|
Pinetime::Drivers::SpiNorFlash& spiNorFlash,
|
||||||
int OnGAPEvent(ble_gap_event *event);
|
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 OnDiscoveryEvent(uint16_t i, const ble_gatt_error* pError, const ble_gatt_svc* pSvc);
|
||||||
int OnCTSCharacteristicDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error *error,
|
int OnCTSCharacteristicDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error* error, const ble_gatt_chr* characteristic);
|
||||||
const ble_gatt_chr *characteristic);
|
int OnANSCharacteristicDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error* error, const ble_gatt_chr* characteristic);
|
||||||
int OnANSCharacteristicDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error *error,
|
int OnCurrentTimeReadResult(uint16_t connectionHandle, const ble_gatt_error* error, ble_gatt_attr* attribute);
|
||||||
const ble_gatt_chr *characteristic);
|
int OnANSDescriptorDiscoveryEventCallback(uint16_t connectionHandle,
|
||||||
int OnCurrentTimeReadResult(uint16_t connectionHandle, const ble_gatt_error *error, ble_gatt_attr *attribute);
|
const ble_gatt_error* error,
|
||||||
int OnANSDescriptorDiscoveryEventCallback(uint16_t connectionHandle, const ble_gatt_error *error,
|
uint16_t characteristicValueHandle,
|
||||||
uint16_t characteristicValueHandle, const ble_gatt_dsc *descriptor);
|
const ble_gatt_dsc* descriptor);
|
||||||
|
|
||||||
void StartDiscovery();
|
void StartDiscovery();
|
||||||
|
|
||||||
Pinetime::Controllers::MusicService& music() {return musicService;};
|
Pinetime::Controllers::MusicService& music() {
|
||||||
Pinetime::Controllers::NavigationService& navigation() {return navService;};
|
return musicService;
|
||||||
Pinetime::Controllers::AlertNotificationService& alertService() {return anService;};
|
};
|
||||||
|
Pinetime::Controllers::NavigationService& navigation() {
|
||||||
|
return navService;
|
||||||
|
};
|
||||||
|
Pinetime::Controllers::AlertNotificationService& alertService() {
|
||||||
|
return anService;
|
||||||
|
};
|
||||||
|
|
||||||
uint16_t connHandle();
|
uint16_t connHandle();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr const char* deviceName = "InfiniTime";
|
static constexpr const char* deviceName = "InfiniTime";
|
||||||
Pinetime::System::SystemTask& systemTask;
|
Pinetime::System::SystemTask& systemTask;
|
||||||
Pinetime::Controllers::Ble& bleController;
|
Pinetime::Controllers::Ble& bleController;
|
||||||
DateTime& dateTimeController;
|
DateTime& dateTimeController;
|
||||||
Pinetime::Controllers::NotificationManager& notificationManager;
|
Pinetime::Controllers::NotificationManager& notificationManager;
|
||||||
Pinetime::Drivers::SpiNorFlash& spiNorFlash;
|
Pinetime::Drivers::SpiNorFlash& spiNorFlash;
|
||||||
Pinetime::Controllers::DfuService dfuService;
|
Pinetime::Controllers::DfuService dfuService;
|
||||||
|
|
||||||
DeviceInformationService deviceInformationService;
|
DeviceInformationService deviceInformationService;
|
||||||
CurrentTimeClient currentTimeClient;
|
CurrentTimeClient currentTimeClient;
|
||||||
AlertNotificationService anService;
|
AlertNotificationService anService;
|
||||||
AlertNotificationClient alertNotificationClient;
|
AlertNotificationClient alertNotificationClient;
|
||||||
CurrentTimeService currentTimeService;
|
CurrentTimeService currentTimeService;
|
||||||
MusicService musicService;
|
MusicService musicService;
|
||||||
NavigationService navService;
|
NavigationService navService;
|
||||||
BatteryInformationService batteryInformationService;
|
BatteryInformationService batteryInformationService;
|
||||||
ImmediateAlertService immediateAlertService;
|
ImmediateAlertService immediateAlertService;
|
||||||
HeartRateService heartRateService;
|
HeartRateService heartRateService;
|
||||||
|
|
||||||
uint8_t addrType; // 1 = Random, 0 = PUBLIC
|
uint8_t addrType; // 1 = Random, 0 = PUBLIC
|
||||||
uint16_t connectionHandle = 0;
|
uint16_t connectionHandle = 0;
|
||||||
|
|
||||||
ble_uuid128_t dfuServiceUuid {
|
ble_uuid128_t dfuServiceUuid {
|
||||||
.u { .type = BLE_UUID_TYPE_128},
|
.u {.type = BLE_UUID_TYPE_128},
|
||||||
.value = {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15,
|
.value = {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15, 0xDE, 0xEF, 0x12, 0x12, 0x30, 0x15, 0x00, 0x00}};
|
||||||
0xDE, 0xEF, 0x12, 0x12, 0x30, 0x15, 0x00, 0x00}
|
|
||||||
};
|
|
||||||
|
|
||||||
ServiceDiscovery serviceDiscovery;
|
ServiceDiscovery serviceDiscovery;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,15 +6,15 @@ using namespace Pinetime::Controllers;
|
||||||
|
|
||||||
constexpr uint8_t NotificationManager::MessageSize;
|
constexpr uint8_t NotificationManager::MessageSize;
|
||||||
|
|
||||||
|
void NotificationManager::Push(NotificationManager::Notification&& notif) {
|
||||||
void NotificationManager::Push(NotificationManager::Notification &¬if) {
|
|
||||||
notif.id = GetNextId();
|
notif.id = GetNextId();
|
||||||
notif.valid = true;
|
notif.valid = true;
|
||||||
notifications[writeIndex] = std::move(notif);
|
notifications[writeIndex] = std::move(notif);
|
||||||
writeIndex = (writeIndex + 1 < TotalNbNotifications) ? writeIndex + 1 : 0;
|
writeIndex = (writeIndex + 1 < TotalNbNotifications) ? writeIndex + 1 : 0;
|
||||||
if(!empty)
|
if (!empty)
|
||||||
readIndex = (readIndex + 1 < TotalNbNotifications) ? readIndex + 1 : 0;
|
readIndex = (readIndex + 1 < TotalNbNotifications) ? readIndex + 1 : 0;
|
||||||
else empty = false;
|
else
|
||||||
|
empty = false;
|
||||||
|
|
||||||
newNotification = true;
|
newNotification = true;
|
||||||
}
|
}
|
||||||
|
@ -30,40 +30,48 @@ NotificationManager::Notification::Id NotificationManager::GetNextId() {
|
||||||
}
|
}
|
||||||
|
|
||||||
NotificationManager::Notification NotificationManager::GetNext(NotificationManager::Notification::Id id) {
|
NotificationManager::Notification NotificationManager::GetNext(NotificationManager::Notification::Id id) {
|
||||||
auto currentIterator = std::find_if(notifications.begin(), notifications.end(), [id](const Notification& n){return n.valid && n.id == id;});
|
auto currentIterator = std::find_if(notifications.begin(), notifications.end(), [id](const Notification& n) {
|
||||||
if(currentIterator == notifications.end() || currentIterator->id != id) return Notification{};
|
return n.valid && n.id == id;
|
||||||
|
});
|
||||||
|
if (currentIterator == notifications.end() || currentIterator->id != id)
|
||||||
|
return Notification {};
|
||||||
|
|
||||||
auto& lastNotification = notifications[readIndex];
|
auto& lastNotification = notifications[readIndex];
|
||||||
|
|
||||||
NotificationManager::Notification result;
|
NotificationManager::Notification result;
|
||||||
|
|
||||||
if(currentIterator == (notifications.end()-1))
|
if (currentIterator == (notifications.end() - 1))
|
||||||
result = *(notifications.begin());
|
result = *(notifications.begin());
|
||||||
else
|
else
|
||||||
result = *(currentIterator+1);
|
result = *(currentIterator + 1);
|
||||||
|
|
||||||
if(result.id <= id) return {};
|
if (result.id <= id)
|
||||||
|
return {};
|
||||||
|
|
||||||
result.index = (lastNotification.id - result.id)+1;
|
result.index = (lastNotification.id - result.id) + 1;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
NotificationManager::Notification NotificationManager::GetPrevious(NotificationManager::Notification::Id id) {
|
NotificationManager::Notification NotificationManager::GetPrevious(NotificationManager::Notification::Id id) {
|
||||||
auto currentIterator = std::find_if(notifications.begin(), notifications.end(), [id](const Notification& n){return n.valid && n.id == id;});
|
auto currentIterator = std::find_if(notifications.begin(), notifications.end(), [id](const Notification& n) {
|
||||||
if(currentIterator == notifications.end() || currentIterator->id != id) return Notification{};
|
return n.valid && n.id == id;
|
||||||
|
});
|
||||||
|
if (currentIterator == notifications.end() || currentIterator->id != id)
|
||||||
|
return Notification {};
|
||||||
|
|
||||||
auto& lastNotification = notifications[readIndex];
|
auto& lastNotification = notifications[readIndex];
|
||||||
|
|
||||||
NotificationManager::Notification result;
|
NotificationManager::Notification result;
|
||||||
|
|
||||||
if(currentIterator == notifications.begin())
|
if (currentIterator == notifications.begin())
|
||||||
result = *(notifications.end()-1);
|
result = *(notifications.end() - 1);
|
||||||
else
|
else
|
||||||
result = *(currentIterator-1);
|
result = *(currentIterator - 1);
|
||||||
|
|
||||||
if(result.id >= id) return {};
|
if (result.id >= id)
|
||||||
|
return {};
|
||||||
|
|
||||||
result.index = (lastNotification.id - result.id)+1;
|
result.index = (lastNotification.id - result.id) + 1;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,21 +92,23 @@ bool NotificationManager::ClearNewNotificationFlag() {
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t NotificationManager::NbNotifications() const {
|
size_t NotificationManager::NbNotifications() const {
|
||||||
return std::count_if(notifications.begin(), notifications.end(), [](const Notification& n){ return n.valid;});
|
return std::count_if(notifications.begin(), notifications.end(), [](const Notification& n) {
|
||||||
|
return n.valid;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* NotificationManager::Notification::Message() const {
|
const char* NotificationManager::Notification::Message() const {
|
||||||
const char* itField = std::find(message.begin(), message.begin()+size-1, '\0');
|
const char* itField = std::find(message.begin(), message.begin() + size - 1, '\0');
|
||||||
if(itField != message.begin()+size-1) {
|
if (itField != message.begin() + size - 1) {
|
||||||
const char* ptr = (itField)+1;
|
const char* ptr = (itField) + 1;
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
return const_cast<char*>(message.data());
|
return const_cast<char*>(message.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* NotificationManager::Notification::Title() const {
|
const char* NotificationManager::Notification::Title() const {
|
||||||
const char * itField = std::find(message.begin(), message.begin()+size-1, '\0');
|
const char* itField = std::find(message.begin(), message.begin() + size - 1, '\0');
|
||||||
if(itField != message.begin()+size-1) {
|
if (itField != message.begin() + size - 1) {
|
||||||
return message.data();
|
return message.data();
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
|
|
|
@ -8,23 +8,35 @@
|
||||||
namespace Pinetime {
|
namespace Pinetime {
|
||||||
namespace Controllers {
|
namespace Controllers {
|
||||||
class NotificationManager {
|
class NotificationManager {
|
||||||
public:
|
public:
|
||||||
enum class Categories {Unknown, SimpleAlert, Email, News, IncomingCall, MissedCall, Sms, VoiceMail, Schedule, HighProriotyAlert, InstantMessage };
|
enum class Categories {
|
||||||
static constexpr uint8_t MessageSize{100};
|
Unknown,
|
||||||
|
SimpleAlert,
|
||||||
|
Email,
|
||||||
|
News,
|
||||||
|
IncomingCall,
|
||||||
|
MissedCall,
|
||||||
|
Sms,
|
||||||
|
VoiceMail,
|
||||||
|
Schedule,
|
||||||
|
HighProriotyAlert,
|
||||||
|
InstantMessage
|
||||||
|
};
|
||||||
|
static constexpr uint8_t MessageSize {100};
|
||||||
|
|
||||||
struct Notification {
|
struct Notification {
|
||||||
using Id = uint8_t;
|
using Id = uint8_t;
|
||||||
Id id;
|
Id id;
|
||||||
bool valid = false;
|
bool valid = false;
|
||||||
uint8_t index;
|
uint8_t index;
|
||||||
uint8_t size;
|
uint8_t size;
|
||||||
std::array<char, MessageSize+1> message;
|
std::array<char, MessageSize + 1> message;
|
||||||
Categories category = Categories::Unknown;
|
Categories category = Categories::Unknown;
|
||||||
|
|
||||||
const char* Message() const;
|
const char* Message() const;
|
||||||
const char* Title() const;
|
const char* Title() const;
|
||||||
};
|
};
|
||||||
Notification::Id nextId {0};
|
Notification::Id nextId {0};
|
||||||
|
|
||||||
void Push(Notification&& notif);
|
void Push(Notification&& notif);
|
||||||
Notification GetLastNotification();
|
Notification GetLastNotification();
|
||||||
|
@ -35,18 +47,20 @@ namespace Pinetime {
|
||||||
bool IsVibrationEnabled();
|
bool IsVibrationEnabled();
|
||||||
void ToggleVibrations();
|
void ToggleVibrations();
|
||||||
|
|
||||||
static constexpr size_t MaximumMessageSize() { return MessageSize; };
|
static constexpr size_t MaximumMessageSize() {
|
||||||
|
return MessageSize;
|
||||||
|
};
|
||||||
size_t NbNotifications() const;
|
size_t NbNotifications() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Notification::Id GetNextId();
|
Notification::Id GetNextId();
|
||||||
static constexpr uint8_t TotalNbNotifications = 5;
|
static constexpr uint8_t TotalNbNotifications = 5;
|
||||||
std::array<Notification, TotalNbNotifications> notifications;
|
std::array<Notification, TotalNbNotifications> notifications;
|
||||||
uint8_t readIndex = 0;
|
uint8_t readIndex = 0;
|
||||||
uint8_t writeIndex = 0;
|
uint8_t writeIndex = 0;
|
||||||
bool empty = true;
|
bool empty = true;
|
||||||
std::atomic<bool> newNotification{false};
|
std::atomic<bool> newNotification {false};
|
||||||
bool vibrationEnabled = true;
|
bool vibrationEnabled = true;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -4,8 +4,7 @@
|
||||||
|
|
||||||
using namespace Pinetime::Controllers;
|
using namespace Pinetime::Controllers;
|
||||||
|
|
||||||
ServiceDiscovery::ServiceDiscovery(std::array<BleClient*, 2>&& clients) : clients{clients} {
|
ServiceDiscovery::ServiceDiscovery(std::array<BleClient*, 2>&& clients) : clients {clients} {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServiceDiscovery::StartDiscovery(uint16_t connectionHandle) {
|
void ServiceDiscovery::StartDiscovery(uint16_t connectionHandle) {
|
||||||
|
@ -16,7 +15,7 @@ void ServiceDiscovery::StartDiscovery(uint16_t connectionHandle) {
|
||||||
|
|
||||||
void ServiceDiscovery::OnServiceDiscovered(uint16_t connectionHandle) {
|
void ServiceDiscovery::OnServiceDiscovered(uint16_t connectionHandle) {
|
||||||
clientIterator++;
|
clientIterator++;
|
||||||
if(clientIterator != clients.end()) {
|
if (clientIterator != clients.end()) {
|
||||||
DiscoverNextService(connectionHandle);
|
DiscoverNextService(connectionHandle);
|
||||||
} else {
|
} else {
|
||||||
NRF_LOG_INFO("End of service discovery");
|
NRF_LOG_INFO("End of service discovery");
|
||||||
|
@ -26,7 +25,7 @@ void ServiceDiscovery::OnServiceDiscovered(uint16_t connectionHandle) {
|
||||||
void ServiceDiscovery::DiscoverNextService(uint16_t connectionHandle) {
|
void ServiceDiscovery::DiscoverNextService(uint16_t connectionHandle) {
|
||||||
NRF_LOG_INFO("[Discovery] Discover next service");
|
NRF_LOG_INFO("[Discovery] Discover next service");
|
||||||
|
|
||||||
auto discoverNextService = [this](uint16_t connectionHandle){
|
auto discoverNextService = [this](uint16_t connectionHandle) {
|
||||||
this->OnServiceDiscovered(connectionHandle);
|
this->OnServiceDiscovered(connectionHandle);
|
||||||
};
|
};
|
||||||
(*clientIterator)->Discover(connectionHandle, discoverNextService);
|
(*clientIterator)->Discover(connectionHandle, discoverNextService);
|
||||||
|
|
|
@ -8,17 +8,16 @@ namespace Pinetime {
|
||||||
class BleClient;
|
class BleClient;
|
||||||
|
|
||||||
class ServiceDiscovery {
|
class ServiceDiscovery {
|
||||||
public:
|
public:
|
||||||
ServiceDiscovery(std::array<BleClient*, 2>&& bleClients);
|
ServiceDiscovery(std::array<BleClient*, 2>&& bleClients);
|
||||||
|
|
||||||
void StartDiscovery(uint16_t connectionHandle);
|
void StartDiscovery(uint16_t connectionHandle);
|
||||||
|
|
||||||
|
private:
|
||||||
private:
|
BleClient** clientIterator;
|
||||||
BleClient** clientIterator;
|
std::array<BleClient*, 2> clients;
|
||||||
std::array<BleClient*, 2> clients;
|
void OnServiceDiscovered(uint16_t connectionHandle);
|
||||||
void OnServiceDiscovered(uint16_t connectionHandle);
|
void DiscoverNextService(uint16_t connectionHandle);
|
||||||
void DiscoverNextService(uint16_t connectionHandle);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
|
|
||||||
using namespace Pinetime::Controllers;
|
using namespace Pinetime::Controllers;
|
||||||
|
|
||||||
|
|
||||||
void BrightnessController::Init() {
|
void BrightnessController::Init() {
|
||||||
nrf_gpio_cfg_output(pinLcdBacklight1);
|
nrf_gpio_cfg_output(pinLcdBacklight1);
|
||||||
nrf_gpio_cfg_output(pinLcdBacklight2);
|
nrf_gpio_cfg_output(pinLcdBacklight2);
|
||||||
|
@ -14,7 +13,7 @@ void BrightnessController::Init() {
|
||||||
|
|
||||||
void BrightnessController::Set(BrightnessController::Levels level) {
|
void BrightnessController::Set(BrightnessController::Levels level) {
|
||||||
this->level = level;
|
this->level = level;
|
||||||
switch(level) {
|
switch (level) {
|
||||||
default:
|
default:
|
||||||
case Levels::High:
|
case Levels::High:
|
||||||
nrf_gpio_pin_clear(pinLcdBacklight1);
|
nrf_gpio_pin_clear(pinLcdBacklight1);
|
||||||
|
@ -40,20 +39,34 @@ void BrightnessController::Set(BrightnessController::Levels level) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void BrightnessController::Lower() {
|
void BrightnessController::Lower() {
|
||||||
switch(level) {
|
switch (level) {
|
||||||
case Levels::High: Set(Levels::Medium); break;
|
case Levels::High:
|
||||||
case Levels::Medium: Set(Levels::Low); break;
|
Set(Levels::Medium);
|
||||||
case Levels::Low: Set(Levels::Off); break;
|
break;
|
||||||
default: break;
|
case Levels::Medium:
|
||||||
|
Set(Levels::Low);
|
||||||
|
break;
|
||||||
|
case Levels::Low:
|
||||||
|
Set(Levels::Off);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BrightnessController::Higher() {
|
void BrightnessController::Higher() {
|
||||||
switch(level) {
|
switch (level) {
|
||||||
case Levels::Off: Set(Levels::Low); break;
|
case Levels::Off:
|
||||||
case Levels::Low: Set(Levels::Medium); break;
|
Set(Levels::Low);
|
||||||
case Levels::Medium: Set(Levels::High); break;
|
break;
|
||||||
default: break;
|
case Levels::Low:
|
||||||
|
Set(Levels::Medium);
|
||||||
|
break;
|
||||||
|
case Levels::Medium:
|
||||||
|
Set(Levels::High);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,29 +83,44 @@ void BrightnessController::Restore() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void BrightnessController::Step() {
|
void BrightnessController::Step() {
|
||||||
switch(level) {
|
switch (level) {
|
||||||
case Levels::Low: Set(Levels::Medium); break;
|
case Levels::Low:
|
||||||
case Levels::Medium: Set(Levels::High); break;
|
Set(Levels::Medium);
|
||||||
case Levels::High: Set(Levels::Low); break;
|
break;
|
||||||
default: break;
|
case Levels::Medium:
|
||||||
|
Set(Levels::High);
|
||||||
|
break;
|
||||||
|
case Levels::High:
|
||||||
|
Set(Levels::Low);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* BrightnessController::GetIcon() {
|
const char* BrightnessController::GetIcon() {
|
||||||
switch(level) {
|
switch (level) {
|
||||||
case Levels::Medium: return Applications::Screens::Symbols::brightnessMedium;
|
case Levels::Medium:
|
||||||
case Levels::High: return Applications::Screens::Symbols::brightnessHigh;
|
return Applications::Screens::Symbols::brightnessMedium;
|
||||||
default: break;
|
case Levels::High:
|
||||||
|
return Applications::Screens::Symbols::brightnessHigh;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return Applications::Screens::Symbols::brightnessLow;
|
return Applications::Screens::Symbols::brightnessLow;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* BrightnessController::ToString() {
|
const char* BrightnessController::ToString() {
|
||||||
switch(level) {
|
switch (level) {
|
||||||
case Levels::Off: return "Off";
|
case Levels::Off:
|
||||||
case Levels::Low: return "Low";
|
return "Off";
|
||||||
case Levels::Medium: return "Medium";
|
case Levels::Low:
|
||||||
case Levels::High: return "High";
|
return "Low";
|
||||||
default : return "???";
|
case Levels::Medium:
|
||||||
|
return "Medium";
|
||||||
|
case Levels::High:
|
||||||
|
return "High";
|
||||||
|
default:
|
||||||
|
return "???";
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -6,7 +6,7 @@ namespace Pinetime {
|
||||||
namespace Controllers {
|
namespace Controllers {
|
||||||
class BrightnessController {
|
class BrightnessController {
|
||||||
public:
|
public:
|
||||||
enum class Levels {Off, Low, Medium, High};
|
enum class Levels { Off, Low, Medium, High };
|
||||||
void Init();
|
void Init();
|
||||||
|
|
||||||
void Set(Levels level);
|
void Set(Levels level);
|
||||||
|
|
|
@ -5,22 +5,21 @@
|
||||||
|
|
||||||
using namespace Pinetime::Controllers;
|
using namespace Pinetime::Controllers;
|
||||||
|
|
||||||
DateTime::DateTime(System::SystemTask& systemTask) : systemTask{systemTask} {
|
DateTime::DateTime(System::SystemTask& systemTask) : systemTask {systemTask} {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DateTime::SetTime(
|
||||||
void DateTime::SetTime(uint16_t year, uint8_t month, uint8_t day, uint8_t dayOfWeek, uint8_t hour, uint8_t minute,
|
uint16_t year, uint8_t month, uint8_t day, uint8_t dayOfWeek, uint8_t hour, uint8_t minute, uint8_t second, uint32_t systickCounter) {
|
||||||
uint8_t second, uint32_t systickCounter) {
|
std::tm tm = {
|
||||||
std::tm tm = { /* .tm_sec = */ second,
|
/* .tm_sec = */ second,
|
||||||
/* .tm_min = */ minute,
|
/* .tm_min = */ minute,
|
||||||
/* .tm_hour = */ hour,
|
/* .tm_hour = */ hour,
|
||||||
/* .tm_mday = */ day,
|
/* .tm_mday = */ day,
|
||||||
/* .tm_mon = */ month - 1,
|
/* .tm_mon = */ month - 1,
|
||||||
/* .tm_year = */ year - 1900,
|
/* .tm_year = */ year - 1900,
|
||||||
};
|
};
|
||||||
tm.tm_isdst = -1; // Use DST value from local time zone
|
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 ", day, month, year);
|
||||||
NRF_LOG_INFO("%d %d %d ", hour, minute, second);
|
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) {
|
void DateTime::UpdateTime(uint32_t systickCounter) {
|
||||||
// Handle systick counter overflow
|
// Handle systick counter overflow
|
||||||
uint32_t systickDelta = 0;
|
uint32_t systickDelta = 0;
|
||||||
if(systickCounter < previousSystickCounter) {
|
if (systickCounter < previousSystickCounter) {
|
||||||
systickDelta = 0xffffff - previousSystickCounter;
|
systickDelta = 0xffffff - previousSystickCounter;
|
||||||
systickDelta += systickCounter + 1;
|
systickDelta += systickCounter + 1;
|
||||||
} else {
|
} else {
|
||||||
|
@ -42,11 +41,11 @@ void DateTime::UpdateTime(uint32_t systickCounter) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 1000 ms = 1024 ticks
|
* 1000 ms = 1024 ticks
|
||||||
*/
|
*/
|
||||||
auto correctedDelta = systickDelta / 1024;
|
auto correctedDelta = systickDelta / 1024;
|
||||||
auto rest = (systickDelta - (correctedDelta*1024));
|
auto rest = (systickDelta - (correctedDelta * 1024));
|
||||||
if(systickCounter >= rest) {
|
if (systickCounter >= rest) {
|
||||||
previousSystickCounter = systickCounter - rest;
|
previousSystickCounter = systickCounter - rest;
|
||||||
} else {
|
} else {
|
||||||
previousSystickCounter = 0xffffff - (rest - systickCounter);
|
previousSystickCounter = 0xffffff - (rest - systickCounter);
|
||||||
|
@ -56,12 +55,12 @@ void DateTime::UpdateTime(uint32_t systickCounter) {
|
||||||
uptime += std::chrono::seconds(correctedDelta);
|
uptime += std::chrono::seconds(correctedDelta);
|
||||||
|
|
||||||
auto dp = date::floor<date::days>(currentDateTime);
|
auto dp = date::floor<date::days>(currentDateTime);
|
||||||
auto time = date::make_time(currentDateTime-dp);
|
auto time = date::make_time(currentDateTime - dp);
|
||||||
auto yearMonthDay = date::year_month_day(dp);
|
auto yearMonthDay = date::year_month_day(dp);
|
||||||
|
|
||||||
year = (int)yearMonthDay.year();
|
year = (int) yearMonthDay.year();
|
||||||
month = static_cast<Months>((unsigned)yearMonthDay.month());
|
month = static_cast<Months>((unsigned) yearMonthDay.month());
|
||||||
day = (unsigned)yearMonthDay.day();
|
day = (unsigned) yearMonthDay.day();
|
||||||
dayOfWeek = static_cast<Days>(date::weekday(yearMonthDay).iso_encoding());
|
dayOfWeek = static_cast<Days>(date::weekday(yearMonthDay).iso_encoding());
|
||||||
|
|
||||||
hour = time.hours().count();
|
hour = time.hours().count();
|
||||||
|
@ -69,7 +68,7 @@ void DateTime::UpdateTime(uint32_t systickCounter) {
|
||||||
second = time.seconds().count();
|
second = time.seconds().count();
|
||||||
|
|
||||||
// Notify new day to SystemTask
|
// Notify new day to SystemTask
|
||||||
if(hour == 0 and not isMidnightAlreadyNotified) {
|
if (hour == 0 and not isMidnightAlreadyNotified) {
|
||||||
isMidnightAlreadyNotified = true;
|
isMidnightAlreadyNotified = true;
|
||||||
systemTask.PushMessage(System::SystemTask::Messages::OnNewDay);
|
systemTask.PushMessage(System::SystemTask::Messages::OnNewDay);
|
||||||
} else if (hour != 0) {
|
} else if (hour != 0) {
|
||||||
|
@ -77,123 +76,45 @@ void DateTime::UpdateTime(uint32_t systickCounter) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *DateTime::MonthShortToString() {
|
const char* DateTime::MonthShortToString() {
|
||||||
return DateTime::MonthsString[(uint8_t)month];
|
return DateTime::MonthsString[(uint8_t) month];
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *DateTime::MonthShortToStringLow() {
|
const char* DateTime::MonthShortToStringLow() {
|
||||||
return DateTime::MonthsStringLow[(uint8_t)month];
|
return DateTime::MonthsStringLow[(uint8_t) month];
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *DateTime::MonthsToStringLow() {
|
const char* DateTime::MonthsToStringLow() {
|
||||||
return DateTime::MonthsLow[(uint8_t)month];
|
return DateTime::MonthsLow[(uint8_t) month];
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *DateTime::DayOfWeekToString() {
|
const char* DateTime::DayOfWeekToString() {
|
||||||
return DateTime::DaysString[(uint8_t)dayOfWeek];
|
return DateTime::DaysString[(uint8_t) dayOfWeek];
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *DateTime::DayOfWeekShortToString() {
|
const char* DateTime::DayOfWeekShortToString() {
|
||||||
return DateTime::DaysStringShort[(uint8_t)dayOfWeek];
|
return DateTime::DaysStringShort[(uint8_t) dayOfWeek];
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *DateTime::DayOfWeekToStringLow() {
|
const char* DateTime::DayOfWeekToStringLow() {
|
||||||
return DateTime::DaysStringLow[(uint8_t)dayOfWeek];
|
return DateTime::DaysStringLow[(uint8_t) dayOfWeek];
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *DateTime::DayOfWeekShortToStringLow() {
|
const char* DateTime::DayOfWeekShortToStringLow() {
|
||||||
return DateTime::DaysStringShortLow[(uint8_t)dayOfWeek];
|
return DateTime::DaysStringShortLow[(uint8_t) dayOfWeek];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char const* DateTime::DaysStringLow[] = {"--", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"};
|
||||||
|
|
||||||
char const *DateTime::DaysStringLow[] = {
|
char const* DateTime::DaysStringShortLow[] = {"--", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
|
||||||
"--",
|
|
||||||
"Monday",
|
|
||||||
"Tuesday",
|
|
||||||
"Wednesday",
|
|
||||||
"Thursday",
|
|
||||||
"Friday",
|
|
||||||
"Saturday",
|
|
||||||
"Sunday"
|
|
||||||
};
|
|
||||||
|
|
||||||
char const *DateTime::DaysStringShortLow[] = {
|
char const* DateTime::DaysStringShort[] = {"--", "MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"};
|
||||||
"--",
|
|
||||||
"Mon",
|
|
||||||
"Tue",
|
|
||||||
"Wed",
|
|
||||||
"Thu",
|
|
||||||
"Fri",
|
|
||||||
"Sat",
|
|
||||||
"Sun"
|
|
||||||
};
|
|
||||||
|
|
||||||
char const *DateTime::DaysStringShort[] = {
|
char const* DateTime::DaysString[] = {"--", "MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY", "SUNDAY"};
|
||||||
"--",
|
|
||||||
"MON",
|
|
||||||
"TUE",
|
|
||||||
"WED",
|
|
||||||
"THU",
|
|
||||||
"FRI",
|
|
||||||
"SAT",
|
|
||||||
"SUN"
|
|
||||||
};
|
|
||||||
|
|
||||||
char const *DateTime::DaysString[] = {
|
char const* DateTime::MonthsString[] = {"--", "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
|
||||||
"--",
|
|
||||||
"MONDAY",
|
|
||||||
"TUESDAY",
|
|
||||||
"WEDNESDAY",
|
|
||||||
"THURSDAY",
|
|
||||||
"FRIDAY",
|
|
||||||
"SATURDAY",
|
|
||||||
"SUNDAY"
|
|
||||||
};
|
|
||||||
|
|
||||||
char const *DateTime::MonthsString[] = {
|
char const* DateTime::MonthsStringLow[] = {"--", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
|
||||||
"--",
|
|
||||||
"JAN",
|
|
||||||
"FEB",
|
|
||||||
"MAR",
|
|
||||||
"APR",
|
|
||||||
"MAY",
|
|
||||||
"JUN",
|
|
||||||
"JUL",
|
|
||||||
"AUG",
|
|
||||||
"SEP",
|
|
||||||
"OCT",
|
|
||||||
"NOV",
|
|
||||||
"DEC"
|
|
||||||
};
|
|
||||||
|
|
||||||
char const *DateTime::MonthsStringLow[] = {
|
char const* DateTime::MonthsLow[] = {
|
||||||
"--",
|
"--", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"};
|
||||||
"Jan",
|
|
||||||
"Feb",
|
|
||||||
"Mar",
|
|
||||||
"Apr",
|
|
||||||
"May",
|
|
||||||
"Jun",
|
|
||||||
"Jul",
|
|
||||||
"Aug",
|
|
||||||
"Sep",
|
|
||||||
"Oct",
|
|
||||||
"Nov",
|
|
||||||
"Dec"
|
|
||||||
};
|
|
||||||
|
|
||||||
char const *DateTime::MonthsLow[] = {
|
|
||||||
"--",
|
|
||||||
"January",
|
|
||||||
"February",
|
|
||||||
"March",
|
|
||||||
"April",
|
|
||||||
"May",
|
|
||||||
"June",
|
|
||||||
"July",
|
|
||||||
"August",
|
|
||||||
"September",
|
|
||||||
"October",
|
|
||||||
"November",
|
|
||||||
"December"
|
|
||||||
};
|
|
|
@ -9,56 +9,95 @@ namespace Pinetime {
|
||||||
}
|
}
|
||||||
namespace Controllers {
|
namespace Controllers {
|
||||||
class DateTime {
|
class DateTime {
|
||||||
public:
|
public:
|
||||||
enum class Days : uint8_t {Unknown, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday};
|
enum class Days : uint8_t { Unknown, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday };
|
||||||
enum class Months : uint8_t {Unknown, January, February, March, April, May, June, July, August, September, October, November, December};
|
enum class Months : uint8_t {
|
||||||
|
Unknown,
|
||||||
|
January,
|
||||||
|
February,
|
||||||
|
March,
|
||||||
|
April,
|
||||||
|
May,
|
||||||
|
June,
|
||||||
|
July,
|
||||||
|
August,
|
||||||
|
September,
|
||||||
|
October,
|
||||||
|
November,
|
||||||
|
December
|
||||||
|
};
|
||||||
|
|
||||||
DateTime(System::SystemTask& systemTask);
|
DateTime(System::SystemTask& systemTask);
|
||||||
|
|
||||||
void SetTime(uint16_t year, uint8_t month, uint8_t day, uint8_t dayOfWeek, uint8_t hour, uint8_t minute, uint8_t second, uint32_t systickCounter);
|
void SetTime(uint16_t year,
|
||||||
void UpdateTime(uint32_t systickCounter);
|
uint8_t month,
|
||||||
uint16_t Year() const { return year; }
|
uint8_t day,
|
||||||
Months Month() const { return month; }
|
uint8_t dayOfWeek,
|
||||||
uint8_t Day() const { return day; }
|
uint8_t hour,
|
||||||
Days DayOfWeek() const { return dayOfWeek; }
|
uint8_t minute,
|
||||||
uint8_t Hours() const { return hour; }
|
uint8_t second,
|
||||||
uint8_t Minutes() const { return minute; }
|
uint32_t systickCounter);
|
||||||
uint8_t Seconds() const { return second; }
|
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* MonthShortToString();
|
||||||
const char *MonthShortToStringLow();
|
const char* MonthShortToStringLow();
|
||||||
const char *MonthsToStringLow();
|
const char* MonthsToStringLow();
|
||||||
const char *DayOfWeekToString();
|
const char* DayOfWeekToString();
|
||||||
const char *DayOfWeekShortToString();
|
const char* DayOfWeekShortToString();
|
||||||
const char *DayOfWeekToStringLow();
|
const char* DayOfWeekToStringLow();
|
||||||
const char *DayOfWeekShortToStringLow();
|
const char* DayOfWeekShortToStringLow();
|
||||||
|
|
||||||
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> CurrentDateTime() const { return currentDateTime; }
|
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> CurrentDateTime() const {
|
||||||
std::chrono::seconds Uptime() const { return uptime; }
|
return currentDateTime;
|
||||||
private:
|
}
|
||||||
System::SystemTask& systemTask;
|
std::chrono::seconds Uptime() const {
|
||||||
uint16_t year = 0;
|
return uptime;
|
||||||
Months month = Months::Unknown;
|
}
|
||||||
uint8_t day = 0;
|
|
||||||
Days dayOfWeek = Days::Unknown;
|
|
||||||
uint8_t hour = 0;
|
|
||||||
uint8_t minute = 0;
|
|
||||||
uint8_t second = 0;
|
|
||||||
|
|
||||||
uint32_t previousSystickCounter = 0;
|
private:
|
||||||
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> currentDateTime;
|
System::SystemTask& systemTask;
|
||||||
std::chrono::seconds uptime {0};
|
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[];
|
bool isMidnightAlreadyNotified = false;
|
||||||
static char const *DaysStringShort[];
|
|
||||||
static char const *DaysStringLow[];
|
|
||||||
static char const *DaysStringShortLow[];
|
|
||||||
static char const *MonthsString[];
|
|
||||||
static char const *MonthsStringLow[];
|
|
||||||
static char const *MonthsLow[];
|
|
||||||
|
|
||||||
|
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[];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -6,12 +6,12 @@
|
||||||
using namespace Pinetime::Controllers;
|
using namespace Pinetime::Controllers;
|
||||||
|
|
||||||
bool FirmwareValidator::IsValidated() const {
|
bool FirmwareValidator::IsValidated() const {
|
||||||
auto* imageOkPtr = reinterpret_cast<uint32_t *>(validBitAdress);
|
auto* imageOkPtr = reinterpret_cast<uint32_t*>(validBitAdress);
|
||||||
return (*imageOkPtr) == validBitValue;
|
return (*imageOkPtr) == validBitValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FirmwareValidator::Validate() {
|
void FirmwareValidator::Validate() {
|
||||||
if(!IsValidated())
|
if (!IsValidated())
|
||||||
Pinetime::Drivers::InternalFlash::WriteWord(validBitAdress, validBitValue);
|
Pinetime::Drivers::InternalFlash::WriteWord(validBitAdress, validBitValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,14 +5,15 @@
|
||||||
namespace Pinetime {
|
namespace Pinetime {
|
||||||
namespace Controllers {
|
namespace Controllers {
|
||||||
class FirmwareValidator {
|
class FirmwareValidator {
|
||||||
public:
|
public:
|
||||||
void Validate();
|
void Validate();
|
||||||
bool IsValidated() const;
|
bool IsValidated() const;
|
||||||
|
|
||||||
void Reset();
|
void Reset();
|
||||||
private:
|
|
||||||
static constexpr uint32_t validBitAdress {0x7BFE8};
|
private:
|
||||||
static constexpr uint32_t validBitValue {1};
|
static constexpr uint32_t validBitAdress {0x7BFE8};
|
||||||
|
static constexpr uint32_t validBitValue {1};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,11 +2,10 @@
|
||||||
#include "drivers/St7789.h"
|
#include "drivers/St7789.h"
|
||||||
using namespace Pinetime::Components;
|
using namespace Pinetime::Components;
|
||||||
|
|
||||||
Gfx::Gfx(Pinetime::Drivers::St7789 &lcd) : lcd{lcd} {
|
Gfx::Gfx(Pinetime::Drivers::St7789& lcd) : lcd {lcd} {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Gfx::Init() {
|
void Gfx::Init() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Gfx::ClearScreen() {
|
void Gfx::ClearScreen() {
|
||||||
|
@ -18,9 +17,8 @@ void Gfx::ClearScreen() {
|
||||||
state.action = Action::FillRectangle;
|
state.action = Action::FillRectangle;
|
||||||
state.taskToNotify = xTaskGetCurrentTaskHandle();
|
state.taskToNotify = xTaskGetCurrentTaskHandle();
|
||||||
|
|
||||||
lcd.DrawBuffer(0, 0, width, height, reinterpret_cast<const uint8_t *>(buffer), width * 2);
|
lcd.DrawBuffer(0, 0, width, height, reinterpret_cast<const uint8_t*>(buffer), width * 2);
|
||||||
WaitTransferFinished();
|
WaitTransferFinished();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Gfx::FillRectangle(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint16_t color) {
|
void Gfx::FillRectangle(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint16_t color) {
|
||||||
|
@ -33,7 +31,7 @@ void Gfx::FillRectangle(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint16_t col
|
||||||
state.color = color;
|
state.color = color;
|
||||||
state.taskToNotify = xTaskGetCurrentTaskHandle();
|
state.taskToNotify = xTaskGetCurrentTaskHandle();
|
||||||
|
|
||||||
lcd.DrawBuffer(x, y, w, h, reinterpret_cast<const uint8_t *>(buffer), width * 2);
|
lcd.DrawBuffer(x, y, w, h, reinterpret_cast<const uint8_t*>(buffer), width * 2);
|
||||||
|
|
||||||
WaitTransferFinished();
|
WaitTransferFinished();
|
||||||
}
|
}
|
||||||
|
@ -46,12 +44,12 @@ void Gfx::FillRectangle(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t* b)
|
||||||
state.color = 0x00;
|
state.color = 0x00;
|
||||||
state.taskToNotify = xTaskGetCurrentTaskHandle();
|
state.taskToNotify = xTaskGetCurrentTaskHandle();
|
||||||
|
|
||||||
lcd.DrawBuffer(x, y, w, h, reinterpret_cast<const uint8_t *>(b), width * 2);
|
lcd.DrawBuffer(x, y, w, h, reinterpret_cast<const uint8_t*>(b), width * 2);
|
||||||
|
|
||||||
WaitTransferFinished();
|
WaitTransferFinished();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Gfx::DrawString(uint8_t x, uint8_t y, uint16_t color, const char *text, const FONT_INFO *p_font, bool wrap) {
|
void Gfx::DrawString(uint8_t x, uint8_t y, uint16_t color, const char* text, const FONT_INFO* p_font, bool wrap) {
|
||||||
if (y > (height - p_font->height)) {
|
if (y > (height - p_font->height)) {
|
||||||
// Not enough space to write even single char.
|
// Not enough space to write even single char.
|
||||||
return;
|
return;
|
||||||
|
@ -86,7 +84,7 @@ void Gfx::DrawString(uint8_t x, uint8_t y, uint16_t color, const char *text, con
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Gfx::DrawChar(const FONT_INFO *font, uint8_t c, uint8_t *x, uint8_t y, uint16_t color) {
|
void Gfx::DrawChar(const FONT_INFO* font, uint8_t c, uint8_t* x, uint8_t y, uint16_t color) {
|
||||||
uint8_t char_idx = c - font->startChar;
|
uint8_t char_idx = c - font->startChar;
|
||||||
uint16_t bytes_in_line = CEIL_DIV(font->charInfo[char_idx].widthBits, 8);
|
uint16_t bytes_in_line = CEIL_DIV(font->charInfo[char_idx].widthBits, 8);
|
||||||
uint16_t bg = 0x0000;
|
uint16_t bg = 0x0000;
|
||||||
|
@ -100,10 +98,9 @@ void Gfx::DrawChar(const FONT_INFO *font, uint8_t c, uint8_t *x, uint8_t y, uint
|
||||||
for (uint16_t j = 0; j < bytes_in_line; j++) {
|
for (uint16_t j = 0; j < bytes_in_line; j++) {
|
||||||
for (uint8_t k = 0; k < 8; k++) {
|
for (uint8_t k = 0; k < 8; k++) {
|
||||||
if ((1 << (7 - k)) & font->data[font->charInfo[char_idx].offset + j]) {
|
if ((1 << (7 - k)) & font->data[font->charInfo[char_idx].offset + j]) {
|
||||||
buffer[(j*8)+k] = color;
|
buffer[(j * 8) + k] = color;
|
||||||
}
|
} else {
|
||||||
else {
|
buffer[(j * 8) + k] = bg;
|
||||||
buffer[(j*8)+k] = bg;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -112,12 +109,12 @@ void Gfx::DrawChar(const FONT_INFO *font, uint8_t c, uint8_t *x, uint8_t y, uint
|
||||||
state.currentIteration = 0;
|
state.currentIteration = 0;
|
||||||
state.busy = true;
|
state.busy = true;
|
||||||
state.action = Action::DrawChar;
|
state.action = Action::DrawChar;
|
||||||
state.font = const_cast<FONT_INFO *>(font);
|
state.font = const_cast<FONT_INFO*>(font);
|
||||||
state.character = c;
|
state.character = c;
|
||||||
state.color = color;
|
state.color = color;
|
||||||
state.taskToNotify = xTaskGetCurrentTaskHandle();
|
state.taskToNotify = xTaskGetCurrentTaskHandle();
|
||||||
|
|
||||||
lcd.DrawBuffer(*x, y, bytes_in_line*8, font->height, reinterpret_cast<const uint8_t *>(&buffer), bytes_in_line*8*2);
|
lcd.DrawBuffer(*x, y, bytes_in_line * 8, font->height, reinterpret_cast<const uint8_t*>(&buffer), bytes_in_line * 8 * 2);
|
||||||
WaitTransferFinished();
|
WaitTransferFinished();
|
||||||
|
|
||||||
*x += font->charInfo[char_idx].widthBits + font->spacePixels;
|
*x += font->charInfo[char_idx].widthBits + font->spacePixels;
|
||||||
|
@ -136,13 +133,14 @@ void Gfx::Wakeup() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Gfx::SetBackgroundColor(uint16_t color) {
|
void Gfx::SetBackgroundColor(uint16_t color) {
|
||||||
for(int i = 0; i < width; i++) {
|
for (int i = 0; i < width; i++) {
|
||||||
buffer[i] = color;
|
buffer[i] = color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Gfx::GetNextBuffer(uint8_t **data, size_t &size) {
|
bool Gfx::GetNextBuffer(uint8_t** data, size_t& size) {
|
||||||
if(!state.busy) return false;
|
if (!state.busy)
|
||||||
|
return false;
|
||||||
state.remainingIterations--;
|
state.remainingIterations--;
|
||||||
if (state.remainingIterations == 0) {
|
if (state.remainingIterations == 0) {
|
||||||
state.busy = false;
|
state.busy = false;
|
||||||
|
@ -150,27 +148,26 @@ bool Gfx::GetNextBuffer(uint8_t **data, size_t &size) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(state.action == Action::FillRectangle) {
|
if (state.action == Action::FillRectangle) {
|
||||||
*data = reinterpret_cast<uint8_t *>(buffer);
|
*data = reinterpret_cast<uint8_t*>(buffer);
|
||||||
size = width * 2;
|
size = width * 2;
|
||||||
} else if(state.action == Action::DrawChar) {
|
} else if (state.action == Action::DrawChar) {
|
||||||
uint16_t bg = 0x0000;
|
uint16_t bg = 0x0000;
|
||||||
uint8_t char_idx = state.character - state.font->startChar;
|
uint8_t char_idx = state.character - state.font->startChar;
|
||||||
uint16_t bytes_in_line = CEIL_DIV(state.font->charInfo[char_idx].widthBits, 8);
|
uint16_t bytes_in_line = CEIL_DIV(state.font->charInfo[char_idx].widthBits, 8);
|
||||||
|
|
||||||
for (uint16_t j = 0; j < bytes_in_line; j++) {
|
for (uint16_t j = 0; j < bytes_in_line; j++) {
|
||||||
for (uint8_t k = 0; k < 8; k++) {
|
for (uint8_t k = 0; k < 8; k++) {
|
||||||
if ((1 << (7 - k)) & state.font->data[state.font->charInfo[char_idx].offset + ((state.currentIteration+1) * bytes_in_line) + j]) {
|
if ((1 << (7 - k)) & state.font->data[state.font->charInfo[char_idx].offset + ((state.currentIteration + 1) * bytes_in_line) + j]) {
|
||||||
buffer[(j*8)+k] = state.color;
|
buffer[(j * 8) + k] = state.color;
|
||||||
}
|
} else {
|
||||||
else {
|
buffer[(j * 8) + k] = bg;
|
||||||
buffer[(j*8)+k] = bg;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*data = reinterpret_cast<uint8_t *>(buffer);
|
*data = reinterpret_cast<uint8_t*>(buffer);
|
||||||
size = bytes_in_line*8*2;
|
size = bytes_in_line * 8 * 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
state.currentIteration++;
|
state.currentIteration++;
|
||||||
|
@ -179,7 +176,7 @@ bool Gfx::GetNextBuffer(uint8_t **data, size_t &size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Gfx::NotifyEndOfTransfer(TaskHandle_t task) {
|
void Gfx::NotifyEndOfTransfer(TaskHandle_t task) {
|
||||||
if(task != nullptr) {
|
if (task != nullptr) {
|
||||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||||
vTaskNotifyGiveFromISR(task, &xHigherPriorityTaskWoken);
|
vTaskNotifyGiveFromISR(task, &xHigherPriorityTaskWoken);
|
||||||
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
||||||
|
|
|
@ -12,49 +12,48 @@ namespace Pinetime {
|
||||||
}
|
}
|
||||||
namespace Components {
|
namespace Components {
|
||||||
class Gfx : public Pinetime::Drivers::BufferProvider {
|
class Gfx : public Pinetime::Drivers::BufferProvider {
|
||||||
public:
|
public:
|
||||||
explicit Gfx(Drivers::St7789& lcd);
|
explicit Gfx(Drivers::St7789& lcd);
|
||||||
void Init();
|
void Init();
|
||||||
void ClearScreen();
|
void ClearScreen();
|
||||||
void DrawString(uint8_t x, uint8_t y, uint16_t color, const char* text, const FONT_INFO *p_font, bool wrap);
|
void DrawString(uint8_t x, uint8_t y, uint16_t color, const char* text, const FONT_INFO* p_font, bool wrap);
|
||||||
void DrawChar(const FONT_INFO *font, uint8_t c, uint8_t *x, uint8_t y, uint16_t color);
|
void DrawChar(const FONT_INFO* font, uint8_t c, uint8_t* x, uint8_t y, uint16_t color);
|
||||||
void FillRectangle(uint8_t x, uint8_t y, uint8_t width, uint8_t height, uint16_t color);
|
void FillRectangle(uint8_t x, uint8_t y, uint8_t width, uint8_t height, uint16_t color);
|
||||||
void FillRectangle(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t* b);
|
void FillRectangle(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t* b);
|
||||||
void SetScrollArea(uint16_t topFixedLines, uint16_t scrollLines, uint16_t bottomFixedLines);
|
void SetScrollArea(uint16_t topFixedLines, uint16_t scrollLines, uint16_t bottomFixedLines);
|
||||||
void SetScrollStartLine(uint16_t line);
|
void SetScrollStartLine(uint16_t line);
|
||||||
|
|
||||||
|
void Sleep();
|
||||||
|
void Wakeup();
|
||||||
|
bool GetNextBuffer(uint8_t** buffer, size_t& size) override;
|
||||||
|
void pixel_draw(uint8_t x, uint8_t y, uint16_t color);
|
||||||
|
|
||||||
void Sleep();
|
private:
|
||||||
void Wakeup();
|
static constexpr uint8_t width = 240;
|
||||||
bool GetNextBuffer(uint8_t **buffer, size_t &size) override;
|
static constexpr uint8_t height = 240;
|
||||||
void pixel_draw(uint8_t x, uint8_t y, uint16_t color);
|
|
||||||
|
|
||||||
|
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:
|
volatile State state;
|
||||||
static constexpr uint8_t width = 240;
|
|
||||||
static constexpr uint8_t height = 240;
|
|
||||||
|
|
||||||
enum class Action { None, FillRectangle, DrawChar};
|
uint16_t buffer[width]; // 1 line buffer
|
||||||
struct State {
|
Drivers::St7789& lcd;
|
||||||
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
volatile State state;
|
void SetBackgroundColor(uint16_t color);
|
||||||
|
void WaitTransferFinished() const;
|
||||||
uint16_t buffer[width]; // 1 line buffer
|
void NotifyEndOfTransfer(TaskHandle_t task);
|
||||||
Drivers::St7789& lcd;
|
|
||||||
|
|
||||||
void SetBackgroundColor(uint16_t color);
|
|
||||||
void WaitTransferFinished() const;
|
|
||||||
void NotifyEndOfTransfer(TaskHandle_t task);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,7 @@
|
||||||
using namespace Pinetime::Controllers;
|
using namespace Pinetime::Controllers;
|
||||||
|
|
||||||
/** Original implementation from wasp-os : https://github.com/daniel-thompson/wasp-os/blob/master/wasp/ppg.py */
|
/** Original implementation from wasp-os : https://github.com/daniel-thompson/wasp-os/blob/master/wasp/ppg.py */
|
||||||
Biquad::Biquad(float b0, float b1, float b2, float a1, float a2) : b0{b0}, b1{b1}, b2{b2}, a1{a1}, a2{a2} {
|
Biquad::Biquad(float b0, float b1, float b2, float a1, float a2) : b0 {b0}, b1 {b1}, b2 {b2}, a1 {a1}, a2 {a2} {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float Biquad::Step(float x) {
|
float Biquad::Step(float x) {
|
||||||
|
|
|
@ -5,7 +5,7 @@ namespace Pinetime {
|
||||||
/// Direct Form II Biquad Filter
|
/// Direct Form II Biquad Filter
|
||||||
class Biquad {
|
class Biquad {
|
||||||
public:
|
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);
|
float Step(float x);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -4,38 +4,35 @@
|
||||||
|
|
||||||
using namespace Pinetime::Controllers;
|
using namespace Pinetime::Controllers;
|
||||||
|
|
||||||
HeartRateController::HeartRateController(Pinetime::System::SystemTask &systemTask) : systemTask{systemTask} {
|
HeartRateController::HeartRateController(Pinetime::System::SystemTask& systemTask) : systemTask {systemTask} {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void HeartRateController::Update(HeartRateController::States newState, uint8_t heartRate) {
|
void HeartRateController::Update(HeartRateController::States newState, uint8_t heartRate) {
|
||||||
this->state = newState;
|
this->state = newState;
|
||||||
if(this->heartRate != heartRate) {
|
if (this->heartRate != heartRate) {
|
||||||
this->heartRate = heartRate;
|
this->heartRate = heartRate;
|
||||||
service->OnNewHeartRateValue(heartRate);
|
service->OnNewHeartRateValue(heartRate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HeartRateController::Start() {
|
void HeartRateController::Start() {
|
||||||
if(task != nullptr) {
|
if (task != nullptr) {
|
||||||
state = States::NotEnoughData;
|
state = States::NotEnoughData;
|
||||||
task->PushMessage(Pinetime::Applications::HeartRateTask::Messages::StartMeasurement);
|
task->PushMessage(Pinetime::Applications::HeartRateTask::Messages::StartMeasurement);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HeartRateController::Stop() {
|
void HeartRateController::Stop() {
|
||||||
if(task != nullptr) {
|
if (task != nullptr) {
|
||||||
state = States::Stopped;
|
state = States::Stopped;
|
||||||
task->PushMessage(Pinetime::Applications::HeartRateTask::Messages::StopMeasurement);
|
task->PushMessage(Pinetime::Applications::HeartRateTask::Messages::StopMeasurement);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HeartRateController::SetHeartRateTask(Pinetime::Applications::HeartRateTask *task) {
|
void HeartRateController::SetHeartRateTask(Pinetime::Applications::HeartRateTask* task) {
|
||||||
this->task = task;
|
this->task = task;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HeartRateController::SetService(Pinetime::Controllers::HeartRateService *service) {
|
void HeartRateController::SetService(Pinetime::Controllers::HeartRateService* service) {
|
||||||
this->service = service;
|
this->service = service;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ namespace Pinetime {
|
||||||
namespace Controllers {
|
namespace Controllers {
|
||||||
class HeartRateController {
|
class HeartRateController {
|
||||||
public:
|
public:
|
||||||
enum class States { Stopped, NotEnoughData, NoTouch, Running};
|
enum class States { Stopped, NotEnoughData, NoTouch, Running };
|
||||||
|
|
||||||
explicit HeartRateController(System::SystemTask& systemTask);
|
explicit HeartRateController(System::SystemTask& systemTask);
|
||||||
|
|
||||||
|
@ -22,10 +22,14 @@ namespace Pinetime {
|
||||||
void Update(States newState, uint8_t heartRate);
|
void Update(States newState, uint8_t heartRate);
|
||||||
|
|
||||||
void SetHeartRateTask(Applications::HeartRateTask* task);
|
void SetHeartRateTask(Applications::HeartRateTask* task);
|
||||||
States State() const { return state; }
|
States State() const {
|
||||||
uint8_t HeartRate() const { return heartRate; }
|
return state;
|
||||||
|
}
|
||||||
|
uint8_t HeartRate() const {
|
||||||
|
return heartRate;
|
||||||
|
}
|
||||||
|
|
||||||
void SetService(Pinetime::Controllers::HeartRateService *service);
|
void SetService(Pinetime::Controllers::HeartRateService* service);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
System::SystemTask& systemTask;
|
System::SystemTask& systemTask;
|
||||||
|
|
|
@ -13,7 +13,7 @@ using namespace Pinetime::Controllers;
|
||||||
namespace {
|
namespace {
|
||||||
int Compare(int* d1, int* d2, size_t count) {
|
int Compare(int* d1, int* d2, size_t count) {
|
||||||
int e = 0;
|
int e = 0;
|
||||||
for(size_t i = 0; i < count; i++) {
|
for (size_t i = 0; i < count; i++) {
|
||||||
auto d = d1[i] - d2[i];
|
auto d = d1[i] - d2[i];
|
||||||
e += d * d;
|
e += d * d;
|
||||||
}
|
}
|
||||||
|
@ -21,15 +21,15 @@ namespace {
|
||||||
}
|
}
|
||||||
|
|
||||||
int CompareShift(int* d, int shift, size_t count) {
|
int CompareShift(int* d, int shift, size_t count) {
|
||||||
return Compare(d +shift, d, count - shift);
|
return Compare(d + shift, d, count - shift);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Trough(int* d, size_t size, float mn, float mx) {
|
int Trough(int* d, size_t size, float mn, float mx) {
|
||||||
auto z2 = CompareShift(d, mn-2, size);
|
auto z2 = CompareShift(d, mn - 2, size);
|
||||||
auto z1 = CompareShift(d, mn-1, size);
|
auto z1 = CompareShift(d, mn - 1, size);
|
||||||
for(int i = mn; i < mx + 1; i++) {
|
for (int i = mn; i < mx + 1; i++) {
|
||||||
auto z = CompareShift(d, i, size);
|
auto z = CompareShift(d, i, size);
|
||||||
if(z2 > z1 && z1 < z)
|
if (z2 > z1 && z1 < z)
|
||||||
return i;
|
return i;
|
||||||
z2 = z1;
|
z2 = z1;
|
||||||
z1 = z;
|
z1 = z;
|
||||||
|
@ -38,11 +38,11 @@ namespace {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ppg::Ppg(float spl) : offset{spl},
|
Ppg::Ppg(float spl)
|
||||||
hpf{0.87033078, -1.74066156, 0.87033078,-1.72377617, 0.75754694},
|
: offset {spl},
|
||||||
agc{20, 0.971, 2},
|
hpf {0.87033078, -1.74066156, 0.87033078, -1.72377617, 0.75754694},
|
||||||
lpf{0.11595249, 0.23190498, 0.11595249,-0.72168143, 0.18549138} {
|
agc {20, 0.971, 2},
|
||||||
|
lpf {0.11595249, 0.23190498, 0.11595249, -0.72168143, 0.18549138} {
|
||||||
}
|
}
|
||||||
|
|
||||||
int Ppg::Preprocess(float spl) {
|
int Ppg::Preprocess(float spl) {
|
||||||
|
@ -53,13 +53,13 @@ int Ppg::Preprocess(float spl) {
|
||||||
|
|
||||||
auto spl_int = static_cast<int>(spl);
|
auto spl_int = static_cast<int>(spl);
|
||||||
|
|
||||||
if(dataIndex < 200)
|
if (dataIndex < 200)
|
||||||
data[dataIndex++] = spl_int;
|
data[dataIndex++] = spl_int;
|
||||||
return spl_int;
|
return spl_int;
|
||||||
}
|
}
|
||||||
|
|
||||||
float Ppg::HeartRate() {
|
float Ppg::HeartRate() {
|
||||||
if(dataIndex < 200)
|
if (dataIndex < 200)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
NRF_LOG_INFO("PREPROCESS, offset = %d", offset);
|
NRF_LOG_INFO("PREPROCESS, offset = %d", offset);
|
||||||
|
@ -71,26 +71,26 @@ float Ppg::HeartRate() {
|
||||||
int cccount = 0;
|
int cccount = 0;
|
||||||
float Ppg::ProcessHeartRate() {
|
float Ppg::ProcessHeartRate() {
|
||||||
|
|
||||||
if(cccount > 2)
|
if (cccount > 2)
|
||||||
asm("nop");
|
asm("nop");
|
||||||
cccount ++;
|
cccount++;
|
||||||
auto t0 = Trough(data.data(), dataIndex, 7, 48);
|
auto t0 = Trough(data.data(), dataIndex, 7, 48);
|
||||||
if(t0 < 0)
|
if (t0 < 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
float t1 = t0 * 2;
|
float t1 = t0 * 2;
|
||||||
t1 = Trough(data.data(), dataIndex, t1-5, t1+5);
|
t1 = Trough(data.data(), dataIndex, t1 - 5, t1 + 5);
|
||||||
if(t1 < 0)
|
if (t1 < 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
float t2 = static_cast<int>(t1 * 3) / 2;
|
float t2 = static_cast<int>(t1 * 3) / 2;
|
||||||
t2 = Trough(data.data(), dataIndex, t2 - 5, t2 + 5);
|
t2 = Trough(data.data(), dataIndex, t2 - 5, t2 + 5);
|
||||||
if(t2 < 0)
|
if (t2 < 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
float t3 = static_cast<int>(t2 * 4) / 3;
|
float t3 = static_cast<int>(t2 * 4) / 3;
|
||||||
t3 = Trough(data.data(), dataIndex, t3 - 4, t3 + 4);
|
t3 = Trough(data.data(), dataIndex, t3 - 4, t3 + 4);
|
||||||
if(t3 < 0)
|
if (t3 < 0)
|
||||||
return static_cast<int>(60 * 24 * 3) / static_cast<int>(t2);
|
return static_cast<int>(60 * 24 * 3) / static_cast<int>(t2);
|
||||||
|
|
||||||
return static_cast<int>(60 * 24 * 4) / static_cast<int>(t3);
|
return static_cast<int>(60 * 24 * 4) / static_cast<int>(t3);
|
||||||
|
|
|
@ -24,7 +24,6 @@ namespace Pinetime {
|
||||||
Ptagc agc;
|
Ptagc agc;
|
||||||
Biquad lpf;
|
Biquad lpf;
|
||||||
|
|
||||||
|
|
||||||
float ProcessHeartRate();
|
float ProcessHeartRate();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,17 +10,16 @@
|
||||||
using namespace Pinetime::Controllers;
|
using namespace Pinetime::Controllers;
|
||||||
|
|
||||||
/** Original implementation from wasp-os : https://github.com/daniel-thompson/wasp-os/blob/master/wasp/ppg.py */
|
/** Original implementation from wasp-os : https://github.com/daniel-thompson/wasp-os/blob/master/wasp/ppg.py */
|
||||||
Ptagc::Ptagc(float start, float decay, float threshold) : peak{start}, decay{decay}, boost{1.0f/decay}, threshold{threshold} {
|
Ptagc::Ptagc(float start, float decay, float threshold) : peak {start}, decay {decay}, boost {1.0f / decay}, threshold {threshold} {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float Ptagc::Step(float spl) {
|
float Ptagc::Step(float spl) {
|
||||||
if(std::abs(spl) > peak)
|
if (std::abs(spl) > peak)
|
||||||
peak *= boost;
|
peak *= boost;
|
||||||
else
|
else
|
||||||
peak *= decay;
|
peak *= decay;
|
||||||
|
|
||||||
if((spl > (peak * threshold)) || (spl < (peak * -threshold)))
|
if ((spl > (peak * threshold)) || (spl < (peak * -threshold)))
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
|
|
||||||
spl = 100.0f * spl / (2.0f * peak);
|
spl = 100.0f * spl / (2.0f * peak);
|
||||||
|
|
|
@ -12,7 +12,6 @@ namespace Pinetime {
|
||||||
float decay;
|
float decay;
|
||||||
float boost;
|
float boost;
|
||||||
float threshold;
|
float threshold;
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,14 +8,24 @@ namespace Pinetime {
|
||||||
public:
|
public:
|
||||||
void Update(int16_t x, int16_t y, int16_t z, uint32_t nbSteps);
|
void Update(int16_t x, int16_t y, int16_t z, uint32_t nbSteps);
|
||||||
|
|
||||||
int16_t X() const { return x; }
|
int16_t X() const {
|
||||||
int16_t Y() const { return y; }
|
return x;
|
||||||
int16_t Z() const { return z; }
|
}
|
||||||
uint32_t NbSteps() const { return nbSteps; }
|
int16_t Y() const {
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
int16_t Z() const {
|
||||||
|
return z;
|
||||||
|
}
|
||||||
|
uint32_t NbSteps() const {
|
||||||
|
return nbSteps;
|
||||||
|
}
|
||||||
bool ShouldWakeUp(bool isSleeping);
|
bool ShouldWakeUp(bool isSleeping);
|
||||||
|
|
||||||
void IsSensorOk(bool isOk);
|
void IsSensorOk(bool isOk);
|
||||||
bool IsSensorOk() const { return isSensorOk; }
|
bool IsSensorOk() const {
|
||||||
|
return isSensorOk;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint32_t nbSteps;
|
uint32_t nbSteps;
|
||||||
|
|
|
@ -7,24 +7,26 @@ APP_TIMER_DEF(vibTimer);
|
||||||
|
|
||||||
using namespace Pinetime::Controllers;
|
using namespace Pinetime::Controllers;
|
||||||
|
|
||||||
MotorController::MotorController( Controllers::Settings &settingsController ) : settingsController{settingsController} {}
|
MotorController::MotorController(Controllers::Settings& settingsController) : settingsController {settingsController} {
|
||||||
|
}
|
||||||
|
|
||||||
void MotorController::Init() {
|
void MotorController::Init() {
|
||||||
nrf_gpio_cfg_output(pinMotor);
|
nrf_gpio_cfg_output(pinMotor);
|
||||||
nrf_gpio_pin_set(pinMotor);
|
nrf_gpio_pin_set(pinMotor);
|
||||||
app_timer_init();
|
app_timer_init();
|
||||||
app_timer_create(&vibTimer, APP_TIMER_MODE_SINGLE_SHOT, vibrate);
|
app_timer_create(&vibTimer, APP_TIMER_MODE_SINGLE_SHOT, vibrate);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MotorController::SetDuration(uint8_t motorDuration) {
|
void MotorController::SetDuration(uint8_t motorDuration) {
|
||||||
|
|
||||||
if ( settingsController.GetVibrationStatus() == Controllers::Settings::Vibration::OFF ) return;
|
if (settingsController.GetVibrationStatus() == Controllers::Settings::Vibration::OFF)
|
||||||
|
return;
|
||||||
|
|
||||||
nrf_gpio_pin_clear(pinMotor);
|
nrf_gpio_pin_clear(pinMotor);
|
||||||
/* Start timer for motorDuration miliseconds and timer triggers vibrate() when it finishes*/
|
/* Start timer for motorDuration miliseconds and timer triggers vibrate() when it finishes*/
|
||||||
app_timer_start(vibTimer, APP_TIMER_TICKS(motorDuration), NULL);
|
app_timer_start(vibTimer, APP_TIMER_TICKS(motorDuration), NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MotorController::vibrate(void * p_context) {
|
void MotorController::vibrate(void* p_context) {
|
||||||
nrf_gpio_pin_set(pinMotor);
|
nrf_gpio_pin_set(pinMotor);
|
||||||
}
|
}
|
|
@ -9,14 +9,14 @@ namespace Pinetime {
|
||||||
static constexpr uint8_t pinMotor = 16;
|
static constexpr uint8_t pinMotor = 16;
|
||||||
|
|
||||||
class MotorController {
|
class MotorController {
|
||||||
public:
|
public:
|
||||||
MotorController( Controllers::Settings &settingsController );
|
MotorController(Controllers::Settings& settingsController);
|
||||||
void Init();
|
void Init();
|
||||||
void SetDuration(uint8_t motorDuration);
|
void SetDuration(uint8_t motorDuration);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Controllers::Settings& settingsController;
|
Controllers::Settings& settingsController;
|
||||||
static void vibrate(void * p_context);
|
static void vibrate(void* p_context);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,18 +2,16 @@
|
||||||
|
|
||||||
using namespace Pinetime::Tools;
|
using namespace Pinetime::Tools;
|
||||||
|
|
||||||
RleDecoder::RleDecoder(const uint8_t *buffer, size_t size) : buffer{buffer}, size{size} {
|
RleDecoder::RleDecoder(const uint8_t* buffer, size_t size) : buffer {buffer}, size {size} {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RleDecoder::RleDecoder(const uint8_t *buffer, size_t size, uint16_t foregroundColor, uint16_t backgroundColor) : RleDecoder{buffer, size} {
|
RleDecoder::RleDecoder(const uint8_t* buffer, size_t size, uint16_t foregroundColor, uint16_t backgroundColor) : RleDecoder {buffer, size} {
|
||||||
this->foregroundColor = foregroundColor;
|
this->foregroundColor = foregroundColor;
|
||||||
this->backgroundColor = backgroundColor;
|
this->backgroundColor = backgroundColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RleDecoder::DecodeNext(uint8_t* output, size_t maxBytes) {
|
||||||
void RleDecoder::DecodeNext(uint8_t *output, size_t maxBytes) {
|
for (; encodedBufferIndex < size; encodedBufferIndex++) {
|
||||||
for (;encodedBufferIndex<size; encodedBufferIndex++) {
|
|
||||||
uint8_t rl = buffer[encodedBufferIndex] - processedCount;
|
uint8_t rl = buffer[encodedBufferIndex] - processedCount;
|
||||||
while (rl) {
|
while (rl) {
|
||||||
output[bp] = color >> 8;
|
output[bp] = color >> 8;
|
||||||
|
@ -36,4 +34,3 @@ void RleDecoder::DecodeNext(uint8_t *output, size_t maxBytes) {
|
||||||
color = backgroundColor;
|
color = backgroundColor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,110 +5,107 @@
|
||||||
using namespace Pinetime::Controllers;
|
using namespace Pinetime::Controllers;
|
||||||
|
|
||||||
struct SettingsHeader {
|
struct SettingsHeader {
|
||||||
uint8_t isActive; // 0xF1 = Block is active, 0xF0 = Block is inactive
|
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
|
uint16_t version; // Current version, to verify if the saved data is for the current Version
|
||||||
};
|
};
|
||||||
|
|
||||||
#define HEADER_SIZE sizeof(SettingsHeader)
|
#define HEADER_SIZE sizeof(SettingsHeader)
|
||||||
|
|
||||||
|
Settings::Settings(Pinetime::Drivers::SpiNorFlash& spiNorFlash) : spiNorFlash {spiNorFlash} {
|
||||||
Settings::Settings( Pinetime::Drivers::SpiNorFlash &spiNorFlash ) : spiNorFlash{spiNorFlash} {}
|
}
|
||||||
|
|
||||||
void Settings::Init() {
|
void Settings::Init() {
|
||||||
|
|
||||||
// Load default settings from Flash
|
// Load default settings from Flash
|
||||||
LoadSettingsFromFlash();
|
LoadSettingsFromFlash();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Settings::SaveSettings() {
|
void Settings::SaveSettings() {
|
||||||
|
|
||||||
// verify if is necessary to save
|
// verify if is necessary to save
|
||||||
if ( settingsChanged ) {
|
if (settingsChanged) {
|
||||||
SaveSettingsToFlash();
|
SaveSettingsToFlash();
|
||||||
}
|
}
|
||||||
settingsChanged = false;
|
settingsChanged = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Settings::FindHeader() {
|
bool Settings::FindHeader() {
|
||||||
SettingsHeader settingsHeader;
|
SettingsHeader settingsHeader;
|
||||||
uint8_t bufferHead[sizeof(settingsHeader)];
|
uint8_t bufferHead[sizeof(settingsHeader)];
|
||||||
|
|
||||||
for (uint8_t block = 0; block < 10; block++) {
|
for (uint8_t block = 0; block < 10; block++) {
|
||||||
|
|
||||||
spiNorFlash.Read( settingsBaseAddr + (block * 0x1000), bufferHead, sizeof(settingsHeader) );
|
spiNorFlash.Read(settingsBaseAddr + (block * 0x1000), bufferHead, sizeof(settingsHeader));
|
||||||
std::memcpy(&settingsHeader, bufferHead, sizeof(settingsHeader));
|
std::memcpy(&settingsHeader, bufferHead, sizeof(settingsHeader));
|
||||||
if ( settingsHeader.isActive == 0xF1 && settingsHeader.version == settingsVersion ) {
|
if (settingsHeader.isActive == 0xF1 && settingsHeader.version == settingsVersion) {
|
||||||
settingsFlashBlock = block;
|
settingsFlashBlock = block;
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Settings::ReadSettingsData() {
|
void Settings::ReadSettingsData() {
|
||||||
uint8_t bufferSettings[sizeof(settings)];
|
uint8_t bufferSettings[sizeof(settings)];
|
||||||
spiNorFlash.Read( settingsBaseAddr + (settingsFlashBlock * 0x1000) + HEADER_SIZE, bufferSettings, sizeof(settings) );
|
spiNorFlash.Read(settingsBaseAddr + (settingsFlashBlock * 0x1000) + HEADER_SIZE, bufferSettings, sizeof(settings));
|
||||||
std::memcpy(&settings, bufferSettings, sizeof(settings));
|
std::memcpy(&settings, bufferSettings, sizeof(settings));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Settings::EraseBlock() {
|
void Settings::EraseBlock() {
|
||||||
|
|
||||||
spiNorFlash.SectorErase(settingsBaseAddr + (settingsFlashBlock * 0x1000));
|
spiNorFlash.SectorErase(settingsBaseAddr + (settingsFlashBlock * 0x1000));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Settings::SetHeader( bool state ) {
|
void Settings::SetHeader(bool state) {
|
||||||
SettingsHeader settingsHeader;
|
SettingsHeader settingsHeader;
|
||||||
uint8_t bufferHead[sizeof(settingsHeader)];
|
uint8_t bufferHead[sizeof(settingsHeader)];
|
||||||
settingsHeader.isActive = state ? 0xF1 : 0xF0;
|
settingsHeader.isActive = state ? 0xF1 : 0xF0;
|
||||||
settingsHeader.version = settingsVersion;
|
settingsHeader.version = settingsVersion;
|
||||||
|
|
||||||
std::memcpy(bufferHead, &settingsHeader, sizeof(settingsHeader));
|
|
||||||
spiNorFlash.Write(settingsBaseAddr + (settingsFlashBlock * 0x1000), bufferHead, sizeof(settingsHeader));
|
|
||||||
|
|
||||||
|
std::memcpy(bufferHead, &settingsHeader, sizeof(settingsHeader));
|
||||||
|
spiNorFlash.Write(settingsBaseAddr + (settingsFlashBlock * 0x1000), bufferHead, sizeof(settingsHeader));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Settings::SaveSettingsData() {
|
void Settings::SaveSettingsData() {
|
||||||
uint8_t bufferSettings[sizeof(settings)];
|
uint8_t bufferSettings[sizeof(settings)];
|
||||||
std::memcpy(bufferSettings, &settings, sizeof(settings));
|
std::memcpy(bufferSettings, &settings, sizeof(settings));
|
||||||
spiNorFlash.Write(settingsBaseAddr + (settingsFlashBlock * 0x1000) + HEADER_SIZE, bufferSettings, sizeof(settings));
|
spiNorFlash.Write(settingsBaseAddr + (settingsFlashBlock * 0x1000) + HEADER_SIZE, bufferSettings, sizeof(settings));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Settings::LoadSettingsFromFlash() {
|
void Settings::LoadSettingsFromFlash() {
|
||||||
|
|
||||||
if ( settingsFlashBlock == 99 ) {
|
if (settingsFlashBlock == 99) {
|
||||||
// Find current Block, if can't find use default settings and set block to 0 ans save !
|
// Find current Block, if can't find use default settings and set block to 0 ans save !
|
||||||
if ( FindHeader() ) {
|
if (FindHeader()) {
|
||||||
ReadSettingsData();
|
ReadSettingsData();
|
||||||
} else {
|
|
||||||
SaveSettingsToFlash();
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// Read Settings from flash...
|
SaveSettingsToFlash();
|
||||||
// never used :)
|
|
||||||
ReadSettingsData();
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// Read Settings from flash...
|
||||||
|
// never used :)
|
||||||
|
ReadSettingsData();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Settings::SaveSettingsToFlash() {
|
void Settings::SaveSettingsToFlash() {
|
||||||
|
|
||||||
// calculate where to save...
|
// calculate where to save...
|
||||||
// mark current to inactive
|
// mark current to inactive
|
||||||
// erase the new location and save
|
// erase the new location and save
|
||||||
// set settingsFlashBlock
|
// 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 ) {
|
if (settingsFlashBlock != 99) {
|
||||||
SetHeader( false );
|
SetHeader(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
settingsFlashBlock++;
|
settingsFlashBlock++;
|
||||||
if ( settingsFlashBlock > 9 ) settingsFlashBlock = 0;
|
if (settingsFlashBlock > 9)
|
||||||
|
settingsFlashBlock = 0;
|
||||||
|
|
||||||
EraseBlock();
|
EraseBlock();
|
||||||
SetHeader( true );
|
SetHeader(true);
|
||||||
SaveSettingsData();
|
SaveSettingsData();
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,104 +8,129 @@
|
||||||
namespace Pinetime {
|
namespace Pinetime {
|
||||||
namespace Controllers {
|
namespace Controllers {
|
||||||
class Settings {
|
class Settings {
|
||||||
public:
|
public:
|
||||||
enum class ClockType {H24, H12};
|
enum class ClockType { H24, H12 };
|
||||||
enum class Vibration {ON, OFF};
|
enum class Vibration { ON, OFF };
|
||||||
enum class WakeUpMode {None, SingleTap, DoubleTap, RaiseWrist};
|
enum class WakeUpMode { None, SingleTap, DoubleTap, RaiseWrist };
|
||||||
|
|
||||||
Settings( Pinetime::Drivers::SpiNorFlash &spiNorFlash );
|
Settings(Pinetime::Drivers::SpiNorFlash& spiNorFlash);
|
||||||
|
|
||||||
void Init();
|
void Init();
|
||||||
void SaveSettings();
|
void SaveSettings();
|
||||||
|
|
||||||
void SetClockFace( uint8_t face ) {
|
void SetClockFace(uint8_t face) {
|
||||||
if ( face != settings.clockFace ) settingsChanged = true;
|
if (face != settings.clockFace)
|
||||||
settings.clockFace = face;
|
settingsChanged = true;
|
||||||
};
|
settings.clockFace = face;
|
||||||
uint8_t GetClockFace() const { return settings.clockFace; };
|
};
|
||||||
|
uint8_t GetClockFace() const {
|
||||||
|
return settings.clockFace;
|
||||||
|
};
|
||||||
|
|
||||||
void SetAppMenu( uint8_t menu ) { appMenu = menu; };
|
void SetAppMenu(uint8_t menu) {
|
||||||
uint8_t GetAppMenu() { return appMenu; };
|
appMenu = menu;
|
||||||
|
};
|
||||||
|
uint8_t GetAppMenu() {
|
||||||
|
return appMenu;
|
||||||
|
};
|
||||||
|
|
||||||
void SetSettingsMenu( uint8_t menu ) { settingsMenu = menu; };
|
void SetSettingsMenu(uint8_t menu) {
|
||||||
uint8_t GetSettingsMenu() const { return settingsMenu; };
|
settingsMenu = menu;
|
||||||
|
};
|
||||||
|
uint8_t GetSettingsMenu() const {
|
||||||
|
return settingsMenu;
|
||||||
|
};
|
||||||
|
|
||||||
void SetClockType( ClockType clocktype ) {
|
void SetClockType(ClockType clocktype) {
|
||||||
if ( clocktype != settings.clockType ) settingsChanged = true;
|
if (clocktype != settings.clockType)
|
||||||
settings.clockType = clocktype;
|
settingsChanged = true;
|
||||||
};
|
settings.clockType = clocktype;
|
||||||
ClockType GetClockType() const { return settings.clockType; };
|
};
|
||||||
|
ClockType GetClockType() const {
|
||||||
|
return settings.clockType;
|
||||||
|
};
|
||||||
|
|
||||||
void SetVibrationStatus( Vibration status ) {
|
void SetVibrationStatus(Vibration status) {
|
||||||
if ( status != settings.vibrationStatus ) settingsChanged = true;
|
if (status != settings.vibrationStatus)
|
||||||
settings.vibrationStatus = status;
|
settingsChanged = true;
|
||||||
};
|
settings.vibrationStatus = status;
|
||||||
Vibration GetVibrationStatus() const { return settings.vibrationStatus; };
|
};
|
||||||
|
Vibration GetVibrationStatus() const {
|
||||||
|
return settings.vibrationStatus;
|
||||||
|
};
|
||||||
|
|
||||||
void SetScreenTimeOut( uint32_t timeout ) {
|
void SetScreenTimeOut(uint32_t timeout) {
|
||||||
if ( timeout != settings.screenTimeOut ) settingsChanged = true;
|
if (timeout != settings.screenTimeOut)
|
||||||
settings.screenTimeOut = timeout;
|
settingsChanged = true;
|
||||||
};
|
settings.screenTimeOut = timeout;
|
||||||
uint32_t GetScreenTimeOut() const { return settings.screenTimeOut; };
|
};
|
||||||
|
uint32_t GetScreenTimeOut() const {
|
||||||
|
return settings.screenTimeOut;
|
||||||
|
};
|
||||||
|
|
||||||
void setWakeUpMode( WakeUpMode wakeUp ) {
|
void setWakeUpMode(WakeUpMode wakeUp) {
|
||||||
if ( wakeUp != settings.wakeUpMode ) settingsChanged = true;
|
if (wakeUp != settings.wakeUpMode)
|
||||||
settings.wakeUpMode = wakeUp;
|
settingsChanged = true;
|
||||||
};
|
settings.wakeUpMode = wakeUp;
|
||||||
WakeUpMode getWakeUpMode() const { return settings.wakeUpMode; };
|
};
|
||||||
|
WakeUpMode getWakeUpMode() const {
|
||||||
|
return settings.wakeUpMode;
|
||||||
|
};
|
||||||
|
|
||||||
void SetBrightness( Controllers::BrightnessController::Levels level ) {
|
void SetBrightness(Controllers::BrightnessController::Levels level) {
|
||||||
if ( level != settings.brightLevel ) settingsChanged = true;
|
if (level != settings.brightLevel)
|
||||||
settings.brightLevel = level;
|
settingsChanged = true;
|
||||||
};
|
settings.brightLevel = level;
|
||||||
Controllers::BrightnessController::Levels GetBrightness() const { return settings.brightLevel; };
|
};
|
||||||
|
Controllers::BrightnessController::Levels GetBrightness() const {
|
||||||
|
return settings.brightLevel;
|
||||||
|
};
|
||||||
|
|
||||||
void SetStepsGoal( uint32_t goal ) {
|
void SetStepsGoal( uint32_t goal ) {
|
||||||
if ( goal != settings.stepsGoal ) settingsChanged = true;
|
if ( goal != settings.stepsGoal )
|
||||||
settings.stepsGoal = goal;
|
settingsChanged = true;
|
||||||
};
|
settings.stepsGoal = goal;
|
||||||
uint32_t GetStepsGoal() const { return settings.stepsGoal; };
|
};
|
||||||
|
|
||||||
private:
|
uint32_t GetStepsGoal() const { return settings.stepsGoal; };
|
||||||
|
|
||||||
Pinetime::Drivers::SpiNorFlash& spiNorFlash;
|
private:
|
||||||
struct SettingsData {
|
Pinetime::Drivers::SpiNorFlash& spiNorFlash;
|
||||||
|
struct SettingsData {
|
||||||
|
|
||||||
ClockType clockType = ClockType::H24;
|
ClockType clockType = ClockType::H24;
|
||||||
Vibration vibrationStatus = Vibration::ON;
|
Vibration vibrationStatus = Vibration::ON;
|
||||||
|
|
||||||
uint8_t clockFace = 0;
|
uint8_t clockFace = 0;
|
||||||
|
|
||||||
uint32_t stepsGoal = 10000;
|
uint32_t stepsGoal = 10000;
|
||||||
uint32_t screenTimeOut = 15000;
|
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;
|
uint8_t appMenu = 0;
|
||||||
bool settingsChanged = false;
|
uint8_t settingsMenu = 0;
|
||||||
|
|
||||||
uint8_t appMenu = 0;
|
// There are 10 blocks of reserved flash to save settings
|
||||||
uint8_t settingsMenu = 0;
|
// 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
|
static constexpr uint32_t settingsBaseAddr = 0x3F6000; // Flash Settings Location
|
||||||
// to minimize wear, the recording is done in a rotating way by the 10 blocks
|
static constexpr uint16_t settingsVersion = 0x0100; // Flash Settings Version
|
||||||
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();
|
|
||||||
|
|
||||||
|
bool FindHeader();
|
||||||
|
void ReadSettingsData();
|
||||||
|
void EraseBlock();
|
||||||
|
void SetHeader(bool state);
|
||||||
|
void SaveSettingsData();
|
||||||
|
void LoadSettingsFromFlash();
|
||||||
|
void SaveSettingsToFlash();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -3,9 +3,32 @@
|
||||||
namespace Pinetime {
|
namespace Pinetime {
|
||||||
namespace Applications {
|
namespace Applications {
|
||||||
enum class Apps {
|
enum class Apps {
|
||||||
None, Launcher, Clock, SysInfo, FirmwareUpdate, FirmwareValidation, NotificationsPreview, Notifications, FlashLight, BatteryInfo,
|
None,
|
||||||
Music, Paint, Paddle, Twos, HeartRate, Navigation, StopWatch, Motion, Steps,
|
Launcher,
|
||||||
QuickSettings, Settings, SettingWatchFace, SettingTimeFormat, SettingDisplay, SettingWakeUp, SettingSteps
|
Clock,
|
||||||
|
SysInfo,
|
||||||
|
FirmwareUpdate,
|
||||||
|
FirmwareValidation,
|
||||||
|
NotificationsPreview,
|
||||||
|
Notifications,
|
||||||
|
FlashLight,
|
||||||
|
BatteryInfo,
|
||||||
|
Music,
|
||||||
|
Paint,
|
||||||
|
Paddle,
|
||||||
|
Twos,
|
||||||
|
HeartRate,
|
||||||
|
Navigation,
|
||||||
|
StopWatch,
|
||||||
|
Motion,
|
||||||
|
Steps,
|
||||||
|
QuickSettings,
|
||||||
|
Settings,
|
||||||
|
SettingWatchFace,
|
||||||
|
SettingTimeFormat,
|
||||||
|
SettingDisplay,
|
||||||
|
SettingWakeUp,
|
||||||
|
SettingSteps
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,29 +42,33 @@
|
||||||
using namespace Pinetime::Applications;
|
using namespace Pinetime::Applications;
|
||||||
using namespace Pinetime::Applications::Display;
|
using namespace Pinetime::Applications::Display;
|
||||||
|
|
||||||
DisplayApp::DisplayApp(Drivers::St7789 &lcd, Components::LittleVgl &lvgl, Drivers::Cst816S &touchPanel,
|
DisplayApp::DisplayApp(Drivers::St7789& lcd,
|
||||||
Controllers::Battery &batteryController, Controllers::Ble &bleController,
|
Components::LittleVgl& lvgl,
|
||||||
Controllers::DateTime &dateTimeController, Drivers::WatchdogView &watchdog,
|
Drivers::Cst816S& touchPanel,
|
||||||
System::SystemTask &systemTask,
|
Controllers::Battery& batteryController,
|
||||||
|
Controllers::Ble& bleController,
|
||||||
|
Controllers::DateTime& dateTimeController,
|
||||||
|
Drivers::WatchdogView& watchdog,
|
||||||
|
System::SystemTask& systemTask,
|
||||||
Pinetime::Controllers::NotificationManager& notificationManager,
|
Pinetime::Controllers::NotificationManager& notificationManager,
|
||||||
Pinetime::Controllers::HeartRateController& heartRateController,
|
Pinetime::Controllers::HeartRateController& heartRateController,
|
||||||
Controllers::Settings &settingsController,
|
Controllers::Settings& settingsController,
|
||||||
Pinetime::Controllers::MotionController& motionController) :
|
Pinetime::Controllers::MotionController& motionController)
|
||||||
lcd{lcd},
|
: lcd {lcd},
|
||||||
lvgl{lvgl},
|
lvgl {lvgl},
|
||||||
touchPanel{touchPanel},
|
touchPanel {touchPanel},
|
||||||
batteryController{batteryController},
|
batteryController {batteryController},
|
||||||
bleController{bleController},
|
bleController {bleController},
|
||||||
dateTimeController{dateTimeController},
|
dateTimeController {dateTimeController},
|
||||||
watchdog{watchdog},
|
watchdog {watchdog},
|
||||||
systemTask{systemTask},
|
systemTask {systemTask},
|
||||||
notificationManager{notificationManager},
|
notificationManager {notificationManager},
|
||||||
heartRateController{heartRateController},
|
heartRateController {heartRateController},
|
||||||
settingsController{settingsController},
|
settingsController {settingsController},
|
||||||
motionController{motionController} {
|
motionController {motionController} {
|
||||||
msgQueue = xQueueCreate(queueSize, itemSize);
|
msgQueue = xQueueCreate(queueSize, itemSize);
|
||||||
// Start clock when smartwatch boots
|
// Start clock when smartwatch boots
|
||||||
LoadApp( Apps::Clock, DisplayApp::FullRefreshDirections::None );
|
LoadApp(Apps::Clock, DisplayApp::FullRefreshDirections::None);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisplayApp::Start() {
|
void DisplayApp::Start() {
|
||||||
|
@ -72,8 +76,8 @@ void DisplayApp::Start() {
|
||||||
APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);
|
APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisplayApp::Process(void *instance) {
|
void DisplayApp::Process(void* instance) {
|
||||||
auto *app = static_cast<DisplayApp *>(instance);
|
auto* app = static_cast<DisplayApp*>(instance);
|
||||||
NRF_LOG_INFO("displayapp task started!");
|
NRF_LOG_INFO("displayapp task started!");
|
||||||
app->InitHw();
|
app->InitHw();
|
||||||
|
|
||||||
|
@ -114,7 +118,7 @@ void DisplayApp::Refresh() {
|
||||||
switch (msg) {
|
switch (msg) {
|
||||||
case Messages::GoToSleep:
|
case Messages::GoToSleep:
|
||||||
brightnessController.Backup();
|
brightnessController.Backup();
|
||||||
while(brightnessController.Level() != Controllers::BrightnessController::Levels::Off) {
|
while (brightnessController.Level() != Controllers::BrightnessController::Levels::Off) {
|
||||||
brightnessController.Lower();
|
brightnessController.Lower();
|
||||||
vTaskDelay(100);
|
vTaskDelay(100);
|
||||||
}
|
}
|
||||||
|
@ -129,30 +133,32 @@ void DisplayApp::Refresh() {
|
||||||
break;
|
break;
|
||||||
case Messages::UpdateTimeOut:
|
case Messages::UpdateTimeOut:
|
||||||
systemTask.PushMessage(System::SystemTask::Messages::UpdateTimeOut);
|
systemTask.PushMessage(System::SystemTask::Messages::UpdateTimeOut);
|
||||||
break;
|
break;
|
||||||
case Messages::UpdateBleConnection:
|
case Messages::UpdateBleConnection:
|
||||||
// clockScreen.SetBleConnectionState(bleController.IsConnected() ? Screens::Clock::BleConnectionStates::Connected : Screens::Clock::BleConnectionStates::NotConnected);
|
// clockScreen.SetBleConnectionState(bleController.IsConnected() ? Screens::Clock::BleConnectionStates::Connected :
|
||||||
|
// Screens::Clock::BleConnectionStates::NotConnected);
|
||||||
break;
|
break;
|
||||||
case Messages::UpdateBatteryLevel:
|
case Messages::UpdateBatteryLevel:
|
||||||
batteryController.Update();
|
batteryController.Update();
|
||||||
break;
|
break;
|
||||||
case Messages::NewNotification:
|
case Messages::NewNotification:
|
||||||
LoadApp( Apps::NotificationsPreview, DisplayApp::FullRefreshDirections::Down );
|
LoadApp(Apps::NotificationsPreview, DisplayApp::FullRefreshDirections::Down);
|
||||||
break;
|
break;
|
||||||
case Messages::TouchEvent: {
|
case Messages::TouchEvent: {
|
||||||
if (state != States::Running) break;
|
if (state != States::Running)
|
||||||
|
break;
|
||||||
auto gesture = OnTouchEvent();
|
auto gesture = OnTouchEvent();
|
||||||
if(!currentScreen->OnTouchEvent(gesture)) {
|
if (!currentScreen->OnTouchEvent(gesture)) {
|
||||||
if ( currentApp == Apps::Clock ) {
|
if (currentApp == Apps::Clock) {
|
||||||
switch (gesture) {
|
switch (gesture) {
|
||||||
case TouchEvents::SwipeUp:
|
case TouchEvents::SwipeUp:
|
||||||
LoadApp( Apps::Launcher, DisplayApp::FullRefreshDirections::Up );
|
LoadApp(Apps::Launcher, DisplayApp::FullRefreshDirections::Up);
|
||||||
break;
|
break;
|
||||||
case TouchEvents::SwipeDown:
|
case TouchEvents::SwipeDown:
|
||||||
LoadApp( Apps::Notifications, DisplayApp::FullRefreshDirections::Down );
|
LoadApp(Apps::Notifications, DisplayApp::FullRefreshDirections::Down);
|
||||||
break;
|
break;
|
||||||
case TouchEvents::SwipeRight:
|
case TouchEvents::SwipeRight:
|
||||||
LoadApp( Apps::QuickSettings, DisplayApp::FullRefreshDirections::RightAnim );
|
LoadApp(Apps::QuickSettings, DisplayApp::FullRefreshDirections::RightAnim);
|
||||||
break;
|
break;
|
||||||
case TouchEvents::DoubleTap:
|
case TouchEvents::DoubleTap:
|
||||||
systemTask.PushMessage(System::SystemTask::Messages::GoToSleep);
|
systemTask.PushMessage(System::SystemTask::Messages::GoToSleep);
|
||||||
|
@ -160,36 +166,35 @@ void DisplayApp::Refresh() {
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if ( returnTouchEvent == gesture ) {
|
} else if (returnTouchEvent == gesture) {
|
||||||
LoadApp( returnToApp, returnDirection );
|
LoadApp(returnToApp, returnDirection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} break;
|
||||||
break;
|
|
||||||
case Messages::ButtonPushed:
|
case Messages::ButtonPushed:
|
||||||
if( currentApp == Apps::Clock ) {
|
if (currentApp == Apps::Clock) {
|
||||||
systemTask.PushMessage(System::SystemTask::Messages::GoToSleep);
|
systemTask.PushMessage(System::SystemTask::Messages::GoToSleep);
|
||||||
} else {
|
} else {
|
||||||
if ( !currentScreen->OnButtonPushed() ) {
|
if (!currentScreen->OnButtonPushed()) {
|
||||||
LoadApp( returnToApp, returnDirection );
|
LoadApp(returnToApp, returnDirection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Messages::BleFirmwareUpdateStarted:
|
case Messages::BleFirmwareUpdateStarted:
|
||||||
LoadApp( Apps::FirmwareUpdate, DisplayApp::FullRefreshDirections::Down );
|
LoadApp(Apps::FirmwareUpdate, DisplayApp::FullRefreshDirections::Down);
|
||||||
|
break;
|
||||||
|
case Messages::UpdateDateTime:
|
||||||
|
// Added to remove warning
|
||||||
|
// What should happen here?
|
||||||
break;
|
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();
|
auto info = touchPanel.GetTouchInfo();
|
||||||
if(info.action == 2) {// 2 = contact
|
if (info.action == 2) { // 2 = contact
|
||||||
if(!currentScreen->OnTouchEvent(info.x, info.y)) {
|
if (!currentScreen->OnTouchEvent(info.x, info.y)) {
|
||||||
lvgl.SetNewTapEvent(info.x, info.y);
|
lvgl.SetNewTapEvent(info.x, info.y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -197,14 +202,14 @@ void DisplayApp::Refresh() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisplayApp::RunningState() {
|
void DisplayApp::RunningState() {
|
||||||
if(!currentScreen->Refresh()) {
|
if (!currentScreen->Refresh()) {
|
||||||
LoadApp( returnToApp, returnDirection );
|
LoadApp(returnToApp, returnDirection);
|
||||||
}
|
}
|
||||||
lv_task_handler();
|
lv_task_handler();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisplayApp::StartApp(Apps app, DisplayApp::FullRefreshDirections direction) {
|
void DisplayApp::StartApp(Apps app, DisplayApp::FullRefreshDirections direction) {
|
||||||
LoadApp( app, direction );
|
LoadApp(app, direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisplayApp::returnApp(Apps app, DisplayApp::FullRefreshDirections direction, TouchEvents touchEvent) {
|
void DisplayApp::returnApp(Apps app, DisplayApp::FullRefreshDirections direction, TouchEvents touchEvent) {
|
||||||
|
@ -215,19 +220,26 @@ void DisplayApp::returnApp(Apps app, DisplayApp::FullRefreshDirections direction
|
||||||
|
|
||||||
void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction) {
|
void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction) {
|
||||||
currentScreen.reset(nullptr);
|
currentScreen.reset(nullptr);
|
||||||
SetFullRefresh( direction );
|
SetFullRefresh(direction);
|
||||||
|
|
||||||
// default return to launcher
|
// default return to launcher
|
||||||
returnApp(Apps::Launcher, FullRefreshDirections::Down, TouchEvents::SwipeDown);
|
returnApp(Apps::Launcher, FullRefreshDirections::Down, TouchEvents::SwipeDown);
|
||||||
|
|
||||||
switch(app) {
|
switch (app) {
|
||||||
case Apps::Launcher:
|
case Apps::Launcher:
|
||||||
currentScreen = std::make_unique<Screens::ApplicationList>(this, settingsController, batteryController, dateTimeController);
|
currentScreen = std::make_unique<Screens::ApplicationList>(this, settingsController, batteryController, dateTimeController);
|
||||||
returnApp(Apps::Clock, FullRefreshDirections::Down, TouchEvents::SwipeDown);
|
returnApp(Apps::Clock, FullRefreshDirections::Down, TouchEvents::SwipeDown);
|
||||||
break;
|
break;
|
||||||
case Apps::None:
|
case Apps::None:
|
||||||
case Apps::Clock:
|
case Apps::Clock:
|
||||||
currentScreen = std::make_unique<Screens::Clock>(this, dateTimeController, batteryController, bleController, notificationManager, settingsController, heartRateController, motionController);
|
currentScreen = std::make_unique<Screens::Clock>(this,
|
||||||
|
dateTimeController,
|
||||||
|
batteryController,
|
||||||
|
bleController,
|
||||||
|
notificationManager,
|
||||||
|
settingsController,
|
||||||
|
heartRateController,
|
||||||
|
motionController);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Apps::FirmwareValidation:
|
case Apps::FirmwareValidation:
|
||||||
|
@ -239,17 +251,20 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Apps::Notifications:
|
case Apps::Notifications:
|
||||||
currentScreen = std::make_unique<Screens::Notifications>(this, notificationManager, systemTask.nimble().alertService(), Screens::Notifications::Modes::Normal);
|
currentScreen = std::make_unique<Screens::Notifications>(
|
||||||
|
this, notificationManager, systemTask.nimble().alertService(), Screens::Notifications::Modes::Normal);
|
||||||
returnApp(Apps::Clock, FullRefreshDirections::Up, TouchEvents::SwipeUp);
|
returnApp(Apps::Clock, FullRefreshDirections::Up, TouchEvents::SwipeUp);
|
||||||
break;
|
break;
|
||||||
case Apps::NotificationsPreview:
|
case Apps::NotificationsPreview:
|
||||||
currentScreen = std::make_unique<Screens::Notifications>(this, notificationManager, systemTask.nimble().alertService(), Screens::Notifications::Modes::Preview);
|
currentScreen = std::make_unique<Screens::Notifications>(
|
||||||
|
this, notificationManager, systemTask.nimble().alertService(), Screens::Notifications::Modes::Preview);
|
||||||
returnApp(Apps::Clock, FullRefreshDirections::Up, TouchEvents::SwipeUp);
|
returnApp(Apps::Clock, FullRefreshDirections::Up, TouchEvents::SwipeUp);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Settings
|
// Settings
|
||||||
case Apps::QuickSettings:
|
case Apps::QuickSettings:
|
||||||
currentScreen = std::make_unique<Screens::QuickSettings>(this, batteryController, dateTimeController, brightnessController, settingsController);
|
currentScreen =
|
||||||
|
std::make_unique<Screens::QuickSettings>(this, batteryController, dateTimeController, brightnessController, settingsController);
|
||||||
returnApp(Apps::Clock, FullRefreshDirections::LeftAnim, TouchEvents::SwipeLeft);
|
returnApp(Apps::Clock, FullRefreshDirections::LeftAnim, TouchEvents::SwipeLeft);
|
||||||
break;
|
break;
|
||||||
case Apps::Settings:
|
case Apps::Settings:
|
||||||
|
@ -281,10 +296,11 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction)
|
||||||
returnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
|
returnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
|
||||||
break;
|
break;
|
||||||
case Apps::SysInfo:
|
case Apps::SysInfo:
|
||||||
currentScreen = std::make_unique<Screens::SystemInfo>(this, dateTimeController, batteryController, brightnessController, bleController, watchdog);
|
currentScreen =
|
||||||
|
std::make_unique<Screens::SystemInfo>(this, dateTimeController, batteryController, brightnessController, bleController, watchdog);
|
||||||
returnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
|
returnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
|
||||||
break;
|
break;
|
||||||
//
|
//
|
||||||
|
|
||||||
case Apps::FlashLight:
|
case Apps::FlashLight:
|
||||||
currentScreen = std::make_unique<Screens::FlashLight>(this, systemTask, brightnessController);
|
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::IdleState() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisplayApp::PushMessage(Messages msg) {
|
void DisplayApp::PushMessage(Messages msg) {
|
||||||
|
@ -337,10 +352,10 @@ void DisplayApp::PushMessage(Messages msg) {
|
||||||
|
|
||||||
TouchEvents DisplayApp::OnTouchEvent() {
|
TouchEvents DisplayApp::OnTouchEvent() {
|
||||||
auto info = touchPanel.GetTouchInfo();
|
auto info = touchPanel.GetTouchInfo();
|
||||||
if(info.isTouch) {
|
if (info.isTouch) {
|
||||||
switch(info.gesture) {
|
switch (info.gesture) {
|
||||||
case Pinetime::Drivers::Cst816S::Gestures::SingleTap:
|
case Pinetime::Drivers::Cst816S::Gestures::SingleTap:
|
||||||
if(touchMode == TouchModes::Gestures)
|
if (touchMode == TouchModes::Gestures)
|
||||||
lvgl.SetNewTapEvent(info.x, info.y);
|
lvgl.SetNewTapEvent(info.x, info.y);
|
||||||
return TouchEvents::Tap;
|
return TouchEvents::Tap;
|
||||||
case Pinetime::Drivers::Cst816S::Gestures::LongPress:
|
case Pinetime::Drivers::Cst816S::Gestures::LongPress:
|
||||||
|
@ -364,7 +379,7 @@ TouchEvents DisplayApp::OnTouchEvent() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisplayApp::SetFullRefresh(DisplayApp::FullRefreshDirections direction) {
|
void DisplayApp::SetFullRefresh(DisplayApp::FullRefreshDirections direction) {
|
||||||
switch(direction){
|
switch (direction) {
|
||||||
case DisplayApp::FullRefreshDirections::Down:
|
case DisplayApp::FullRefreshDirections::Down:
|
||||||
lvgl.SetFullRefresh(Components::LittleVgl::FullRefreshDirections::Down);
|
lvgl.SetFullRefresh(Components::LittleVgl::FullRefreshDirections::Down);
|
||||||
break;
|
break;
|
||||||
|
@ -383,11 +398,11 @@ void DisplayApp::SetFullRefresh(DisplayApp::FullRefreshDirections direction) {
|
||||||
case DisplayApp::FullRefreshDirections::RightAnim:
|
case DisplayApp::FullRefreshDirections::RightAnim:
|
||||||
lvgl.SetFullRefresh(Components::LittleVgl::FullRefreshDirections::RightAnim);
|
lvgl.SetFullRefresh(Components::LittleVgl::FullRefreshDirections::RightAnim);
|
||||||
break;
|
break;
|
||||||
default: break;
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisplayApp::SetTouchMode(DisplayApp::TouchModes mode) {
|
void DisplayApp::SetTouchMode(DisplayApp::TouchModes mode) {
|
||||||
touchMode = mode;
|
touchMode = mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,74 +35,73 @@ namespace Pinetime {
|
||||||
};
|
};
|
||||||
namespace Applications {
|
namespace Applications {
|
||||||
class DisplayApp {
|
class DisplayApp {
|
||||||
public:
|
public:
|
||||||
enum class States {Idle, Running};
|
enum class States { Idle, Running };
|
||||||
enum class FullRefreshDirections { None, Up, Down, Left, Right, LeftAnim, RightAnim };
|
enum class FullRefreshDirections { None, Up, Down, Left, Right, LeftAnim, RightAnim };
|
||||||
enum class TouchModes { Gestures, Polling };
|
enum class TouchModes { Gestures, Polling };
|
||||||
|
|
||||||
DisplayApp(Drivers::St7789 &lcd, Components::LittleVgl &lvgl, Drivers::Cst816S &,
|
DisplayApp(Drivers::St7789& lcd,
|
||||||
Controllers::Battery &batteryController, Controllers::Ble &bleController,
|
Components::LittleVgl& lvgl,
|
||||||
Controllers::DateTime &dateTimeController, Drivers::WatchdogView &watchdog,
|
Drivers::Cst816S&,
|
||||||
System::SystemTask &systemTask,
|
Controllers::Battery& batteryController,
|
||||||
Pinetime::Controllers::NotificationManager& notificationManager,
|
Controllers::Ble& bleController,
|
||||||
Pinetime::Controllers::HeartRateController& heartRateController,
|
Controllers::DateTime& dateTimeController,
|
||||||
Controllers::Settings &settingsController,
|
Drivers::WatchdogView& watchdog,
|
||||||
Pinetime::Controllers::MotionController& motionController
|
System::SystemTask& systemTask,
|
||||||
);
|
Pinetime::Controllers::NotificationManager& notificationManager,
|
||||||
void Start();
|
Pinetime::Controllers::HeartRateController& heartRateController,
|
||||||
void PushMessage(Display::Messages msg);
|
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 SetFullRefresh(FullRefreshDirections direction);
|
||||||
void SetTouchMode(TouchModes mode);
|
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::Controllers::FirmwareValidator validator;
|
||||||
Pinetime::Components::LittleVgl& lvgl;
|
Controllers::BrightnessController brightnessController;
|
||||||
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;
|
TaskHandle_t taskHandle;
|
||||||
Controllers::BrightnessController brightnessController;
|
|
||||||
|
|
||||||
TaskHandle_t taskHandle;
|
States state = States::Running;
|
||||||
|
QueueHandle_t msgQueue;
|
||||||
|
|
||||||
States state = States::Running;
|
static constexpr uint8_t queueSize = 10;
|
||||||
QueueHandle_t msgQueue;
|
static constexpr uint8_t itemSize = 1;
|
||||||
|
|
||||||
static constexpr uint8_t queueSize = 10;
|
std::unique_ptr<Screens::Screen> currentScreen;
|
||||||
static constexpr uint8_t itemSize = 1;
|
|
||||||
|
|
||||||
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;
|
TouchModes touchMode = TouchModes::Gestures;
|
||||||
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);
|
|
||||||
|
|
||||||
|
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);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,17 +7,20 @@
|
||||||
|
|
||||||
using namespace Pinetime::Applications;
|
using namespace Pinetime::Applications;
|
||||||
|
|
||||||
DisplayApp::DisplayApp(Drivers::St7789 &lcd, Components::LittleVgl &lvgl, Drivers::Cst816S &touchPanel,
|
DisplayApp::DisplayApp(Drivers::St7789& lcd,
|
||||||
Controllers::Battery &batteryController, Controllers::Ble &bleController,
|
Components::LittleVgl& lvgl,
|
||||||
Controllers::DateTime &dateTimeController, Drivers::WatchdogView &watchdog,
|
Drivers::Cst816S& touchPanel,
|
||||||
System::SystemTask &systemTask,
|
Controllers::Battery& batteryController,
|
||||||
|
Controllers::Ble& bleController,
|
||||||
|
Controllers::DateTime& dateTimeController,
|
||||||
|
Drivers::WatchdogView& watchdog,
|
||||||
|
System::SystemTask& systemTask,
|
||||||
Pinetime::Controllers::NotificationManager& notificationManager,
|
Pinetime::Controllers::NotificationManager& notificationManager,
|
||||||
Pinetime::Controllers::HeartRateController& heartRateController,
|
Pinetime::Controllers::HeartRateController& heartRateController,
|
||||||
Pinetime::Controllers::Settings& settingsController,
|
Pinetime::Controllers::Settings& settingsController,
|
||||||
Pinetime::Controllers::MotionController& motionController):
|
Pinetime::Controllers::MotionController& motionController)
|
||||||
lcd{lcd}, bleController{bleController} {
|
: lcd {lcd}, bleController {bleController} {
|
||||||
msgQueue = xQueueCreate(queueSize, itemSize);
|
msgQueue = xQueueCreate(queueSize, itemSize);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisplayApp::Start() {
|
void DisplayApp::Start() {
|
||||||
|
@ -25,8 +28,8 @@ void DisplayApp::Start() {
|
||||||
APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);
|
APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisplayApp::Process(void *instance) {
|
void DisplayApp::Process(void* instance) {
|
||||||
auto *app = static_cast<DisplayApp *>(instance);
|
auto* app = static_cast<DisplayApp*>(instance);
|
||||||
NRF_LOG_INFO("displayapp task started!");
|
NRF_LOG_INFO("displayapp task started!");
|
||||||
|
|
||||||
// Send a dummy notification to unlock the lvgl display driver for the first iteration
|
// Send a dummy notification to unlock the lvgl display driver for the first iteration
|
||||||
|
@ -61,8 +64,9 @@ void DisplayApp::Refresh() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bleController.IsFirmwareUpdating()) {
|
if (bleController.IsFirmwareUpdating()) {
|
||||||
uint8_t percent = (static_cast<float>(bleController.FirmwareUpdateCurrentBytes()) /
|
uint8_t percent =
|
||||||
static_cast<float>(bleController.FirmwareUpdateTotalBytes())) * 100.0f;
|
(static_cast<float>(bleController.FirmwareUpdateCurrentBytes()) / static_cast<float>(bleController.FirmwareUpdateTotalBytes())) *
|
||||||
|
100.0f;
|
||||||
switch (bleController.State()) {
|
switch (bleController.State()) {
|
||||||
case Controllers::Ble::FirmwareUpdateStates::Running:
|
case Controllers::Ble::FirmwareUpdateStates::Running:
|
||||||
DisplayOtaProgress(percent, colorWhite);
|
DisplayOtaProgress(percent, colorWhite);
|
||||||
|
@ -81,20 +85,20 @@ void DisplayApp::Refresh() {
|
||||||
|
|
||||||
void DisplayApp::DisplayLogo(uint16_t color) {
|
void DisplayApp::DisplayLogo(uint16_t color) {
|
||||||
Pinetime::Tools::RleDecoder rleDecoder(infinitime_nb, sizeof(infinitime_nb), color, colorBlack);
|
Pinetime::Tools::RleDecoder rleDecoder(infinitime_nb, sizeof(infinitime_nb), color, colorBlack);
|
||||||
for(int i = 0; i < displayWidth; i++) {
|
for (int i = 0; i < displayWidth; i++) {
|
||||||
rleDecoder.DecodeNext(displayBuffer, displayWidth * bytesPerPixel);
|
rleDecoder.DecodeNext(displayBuffer, displayWidth * bytesPerPixel);
|
||||||
ulTaskNotifyTake(pdTRUE, 500);
|
ulTaskNotifyTake(pdTRUE, 500);
|
||||||
lcd.DrawBuffer(0, i, displayWidth, 1, reinterpret_cast<const uint8_t *>(displayBuffer), displayWidth * bytesPerPixel);
|
lcd.DrawBuffer(0, i, displayWidth, 1, reinterpret_cast<const uint8_t*>(displayBuffer), displayWidth * bytesPerPixel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisplayApp::DisplayOtaProgress(uint8_t percent, uint16_t color) {
|
void DisplayApp::DisplayOtaProgress(uint8_t percent, uint16_t color) {
|
||||||
const uint8_t barHeight = 20;
|
const uint8_t barHeight = 20;
|
||||||
std::fill(displayBuffer, displayBuffer+(displayWidth * bytesPerPixel), color);
|
std::fill(displayBuffer, displayBuffer + (displayWidth * bytesPerPixel), color);
|
||||||
for(int i = 0; i < barHeight; i++) {
|
for (int i = 0; i < barHeight; i++) {
|
||||||
ulTaskNotifyTake(pdTRUE, 500);
|
ulTaskNotifyTake(pdTRUE, 500);
|
||||||
uint16_t barWidth = std::min(static_cast<float>(percent) * 2.4f, static_cast<float>(displayWidth));
|
uint16_t barWidth = std::min(static_cast<float>(percent) * 2.4f, static_cast<float>(displayWidth));
|
||||||
lcd.DrawBuffer(0, displayWidth - barHeight + i, barWidth, 1, reinterpret_cast<const uint8_t *>(displayBuffer), barWidth * bytesPerPixel);
|
lcd.DrawBuffer(0, displayWidth - barHeight + i, barWidth, 1, reinterpret_cast<const uint8_t*>(displayBuffer), barWidth * bytesPerPixel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,10 +30,14 @@ namespace Pinetime {
|
||||||
namespace Applications {
|
namespace Applications {
|
||||||
class DisplayApp {
|
class DisplayApp {
|
||||||
public:
|
public:
|
||||||
DisplayApp(Drivers::St7789 &lcd, Components::LittleVgl &lvgl, Drivers::Cst816S &,
|
DisplayApp(Drivers::St7789& lcd,
|
||||||
Controllers::Battery &batteryController, Controllers::Ble &bleController,
|
Components::LittleVgl& lvgl,
|
||||||
Controllers::DateTime &dateTimeController, Drivers::WatchdogView &watchdog,
|
Drivers::Cst816S&,
|
||||||
System::SystemTask &systemTask,
|
Controllers::Battery& batteryController,
|
||||||
|
Controllers::Ble& bleController,
|
||||||
|
Controllers::DateTime& dateTimeController,
|
||||||
|
Drivers::WatchdogView& watchdog,
|
||||||
|
System::SystemTask& systemTask,
|
||||||
Pinetime::Controllers::NotificationManager& notificationManager,
|
Pinetime::Controllers::NotificationManager& notificationManager,
|
||||||
Pinetime::Controllers::HeartRateController& heartRateController,
|
Pinetime::Controllers::HeartRateController& heartRateController,
|
||||||
Pinetime::Controllers::Settings& settingsController,
|
Pinetime::Controllers::Settings& settingsController,
|
||||||
|
@ -49,7 +53,7 @@ namespace Pinetime {
|
||||||
void InitHw();
|
void InitHw();
|
||||||
void Refresh();
|
void Refresh();
|
||||||
Pinetime::Drivers::St7789& lcd;
|
Pinetime::Drivers::St7789& lcd;
|
||||||
Controllers::Ble &bleController;
|
Controllers::Ble& bleController;
|
||||||
|
|
||||||
static constexpr uint8_t queueSize = 10;
|
static constexpr uint8_t queueSize = 10;
|
||||||
static constexpr uint8_t itemSize = 1;
|
static constexpr uint8_t itemSize = 1;
|
||||||
|
@ -66,10 +70,6 @@ namespace Pinetime {
|
||||||
static constexpr uint16_t colorRedSwapped = 0x00ff;
|
static constexpr uint16_t colorRedSwapped = 0x00ff;
|
||||||
static constexpr uint16_t colorBlack = 0x0000;
|
static constexpr uint16_t colorBlack = 0x0000;
|
||||||
uint8_t displayBuffer[displayWidth * bytesPerPixel];
|
uint8_t displayBuffer[displayWidth * bytesPerPixel];
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -9,22 +9,25 @@
|
||||||
namespace Pinetime {
|
namespace Pinetime {
|
||||||
namespace Components {
|
namespace Components {
|
||||||
class LittleVgl {
|
class LittleVgl {
|
||||||
public:
|
public:
|
||||||
enum class FullRefreshDirections { None, Up, Down };
|
enum class FullRefreshDirections { None, Up, Down };
|
||||||
LittleVgl(Pinetime::Drivers::St7789& lcd, Pinetime::Drivers::Cst816S& touchPanel) {}
|
LittleVgl(Pinetime::Drivers::St7789& lcd, Pinetime::Drivers::Cst816S& touchPanel) {
|
||||||
|
}
|
||||||
LittleVgl(const LittleVgl&) = delete;
|
|
||||||
LittleVgl& 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) {}
|
|
||||||
|
|
||||||
|
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) {
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,17 +11,18 @@ using namespace Pinetime::Components;
|
||||||
|
|
||||||
lv_style_t* LabelBigStyle = nullptr;
|
lv_style_t* LabelBigStyle = nullptr;
|
||||||
|
|
||||||
static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p) {
|
static void disp_flush(lv_disp_drv_t* disp_drv, const lv_area_t* area, lv_color_t* color_p) {
|
||||||
auto* lvgl = static_cast<LittleVgl*>(disp_drv->user_data);
|
auto* lvgl = static_cast<LittleVgl*>(disp_drv->user_data);
|
||||||
lvgl->FlushDisplay(area, color_p);
|
lvgl->FlushDisplay(area, color_p);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool touchpad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data) {
|
bool touchpad_read(lv_indev_drv_t* indev_drv, lv_indev_data_t* data) {
|
||||||
auto* lvgl = static_cast<LittleVgl*>(indev_drv->user_data);
|
auto* lvgl = static_cast<LittleVgl*>(indev_drv->user_data);
|
||||||
return lvgl->GetTouchPadInfo(data);
|
return lvgl->GetTouchPadInfo(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
LittleVgl::LittleVgl(Pinetime::Drivers::St7789& lcd, Pinetime::Drivers::Cst816S& touchPanel) : lcd{lcd}, touchPanel{touchPanel}, previousClick{0,0} {
|
LittleVgl::LittleVgl(Pinetime::Drivers::St7789& lcd, Pinetime::Drivers::Cst816S& touchPanel)
|
||||||
|
: lcd {lcd}, touchPanel {touchPanel}, previousClick {0, 0} {
|
||||||
lv_init();
|
lv_init();
|
||||||
InitTheme();
|
InitTheme();
|
||||||
InitDisplay();
|
InitDisplay();
|
||||||
|
@ -29,8 +30,8 @@ LittleVgl::LittleVgl(Pinetime::Drivers::St7789& lcd, Pinetime::Drivers::Cst816S&
|
||||||
}
|
}
|
||||||
|
|
||||||
void LittleVgl::InitDisplay() {
|
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_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_drv_init(&disp_drv); /*Basic initialization*/
|
||||||
|
|
||||||
/*Set up the functions to access to your display*/
|
/*Set up the functions to access to your display*/
|
||||||
|
|
||||||
|
@ -59,7 +60,7 @@ void LittleVgl::InitTouchpad() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void LittleVgl::SetFullRefresh(FullRefreshDirections direction) {
|
void LittleVgl::SetFullRefresh(FullRefreshDirections direction) {
|
||||||
if(scrollDirection == FullRefreshDirections::None) {
|
if (scrollDirection == FullRefreshDirections::None) {
|
||||||
scrollDirection = direction;
|
scrollDirection = direction;
|
||||||
if (scrollDirection == FullRefreshDirections::Down) {
|
if (scrollDirection == FullRefreshDirections::Down) {
|
||||||
lv_disp_set_direction(lv_disp_get_default(), 1);
|
lv_disp_set_direction(lv_disp_get_default(), 1);
|
||||||
|
@ -75,16 +76,16 @@ void LittleVgl::SetFullRefresh(FullRefreshDirections direction) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LittleVgl::FlushDisplay(const lv_area_t *area, lv_color_t *color_p) {
|
void LittleVgl::FlushDisplay(const lv_area_t* area, lv_color_t* color_p) {
|
||||||
uint16_t y1, y2, width, height = 0;
|
uint16_t y1, y2, width, height = 0;
|
||||||
|
|
||||||
ulTaskNotifyTake(pdTRUE, 200);
|
ulTaskNotifyTake(pdTRUE, 200);
|
||||||
// NOtification is still needed (even if there is a mutex on SPI) because of the DataCommand pin
|
// NOtification is still needed (even if there is a mutex on SPI) because of the DataCommand pin
|
||||||
// which cannot be set/clear during a transfert.
|
// which cannot be set/clear during a transfert.
|
||||||
|
|
||||||
if( (scrollDirection == LittleVgl::FullRefreshDirections::Down) && (area->y2 == visibleNbLines - 1)) {
|
if ((scrollDirection == LittleVgl::FullRefreshDirections::Down) && (area->y2 == visibleNbLines - 1)) {
|
||||||
writeOffset = ((writeOffset + totalNbLines) - visibleNbLines) % totalNbLines;
|
writeOffset = ((writeOffset + totalNbLines) - visibleNbLines) % totalNbLines;
|
||||||
} else if( (scrollDirection == FullRefreshDirections::Up) && (area->y1 == 0) ) {
|
} else if ((scrollDirection == FullRefreshDirections::Up) && (area->y1 == 0)) {
|
||||||
writeOffset = (writeOffset + visibleNbLines) % totalNbLines;
|
writeOffset = (writeOffset + visibleNbLines) % totalNbLines;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,11 +95,11 @@ void LittleVgl::FlushDisplay(const lv_area_t *area, lv_color_t *color_p) {
|
||||||
width = (area->x2 - area->x1) + 1;
|
width = (area->x2 - area->x1) + 1;
|
||||||
height = (area->y2 - area->y1) + 1;
|
height = (area->y2 - area->y1) + 1;
|
||||||
|
|
||||||
if(scrollDirection == LittleVgl::FullRefreshDirections::Down) {
|
if (scrollDirection == LittleVgl::FullRefreshDirections::Down) {
|
||||||
|
|
||||||
if(area->y2 < visibleNbLines - 1) {
|
if (area->y2 < visibleNbLines - 1) {
|
||||||
uint16_t toScroll = 0;
|
uint16_t toScroll = 0;
|
||||||
if(area->y1 == 0) {
|
if (area->y1 == 0) {
|
||||||
toScroll = height * 2;
|
toScroll = height * 2;
|
||||||
scrollDirection = FullRefreshDirections::None;
|
scrollDirection = FullRefreshDirections::None;
|
||||||
lv_disp_set_direction(lv_disp_get_default(), 0);
|
lv_disp_set_direction(lv_disp_get_default(), 0);
|
||||||
|
@ -106,19 +107,19 @@ void LittleVgl::FlushDisplay(const lv_area_t *area, lv_color_t *color_p) {
|
||||||
toScroll = height;
|
toScroll = height;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(scrollOffset >= toScroll)
|
if (scrollOffset >= toScroll)
|
||||||
scrollOffset -= toScroll;
|
scrollOffset -= toScroll;
|
||||||
else {
|
else {
|
||||||
toScroll -= scrollOffset;
|
toScroll -= scrollOffset;
|
||||||
scrollOffset = (totalNbLines) - toScroll;
|
scrollOffset = (totalNbLines) -toScroll;
|
||||||
}
|
}
|
||||||
lcd.VerticalScrollStartAddress(scrollOffset);
|
lcd.VerticalScrollStartAddress(scrollOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if(scrollDirection == FullRefreshDirections::Up) {
|
} else if (scrollDirection == FullRefreshDirections::Up) {
|
||||||
|
|
||||||
if(area->y1 > 0) {
|
if (area->y1 > 0) {
|
||||||
if(area->y2 == visibleNbLines - 1) {
|
if (area->y2 == visibleNbLines - 1) {
|
||||||
scrollOffset += (height * 2);
|
scrollOffset += (height * 2);
|
||||||
scrollDirection = FullRefreshDirections::None;
|
scrollDirection = FullRefreshDirections::None;
|
||||||
lv_disp_set_direction(lv_disp_get_default(), 0);
|
lv_disp_set_direction(lv_disp_get_default(), 0);
|
||||||
|
@ -128,13 +129,13 @@ void LittleVgl::FlushDisplay(const lv_area_t *area, lv_color_t *color_p) {
|
||||||
scrollOffset = scrollOffset % totalNbLines;
|
scrollOffset = scrollOffset % totalNbLines;
|
||||||
lcd.VerticalScrollStartAddress(scrollOffset);
|
lcd.VerticalScrollStartAddress(scrollOffset);
|
||||||
}
|
}
|
||||||
} else if(scrollDirection == FullRefreshDirections::Left or scrollDirection == FullRefreshDirections::LeftAnim) {
|
} else if (scrollDirection == FullRefreshDirections::Left or scrollDirection == FullRefreshDirections::LeftAnim) {
|
||||||
if(area->x2 == visibleNbLines - 1) {
|
if (area->x2 == visibleNbLines - 1) {
|
||||||
scrollDirection = FullRefreshDirections::None;
|
scrollDirection = FullRefreshDirections::None;
|
||||||
lv_disp_set_direction(lv_disp_get_default(), 0);
|
lv_disp_set_direction(lv_disp_get_default(), 0);
|
||||||
}
|
}
|
||||||
} else if(scrollDirection == FullRefreshDirections::Right or scrollDirection == FullRefreshDirections::RightAnim) {
|
} else if (scrollDirection == FullRefreshDirections::Right or scrollDirection == FullRefreshDirections::RightAnim) {
|
||||||
if(area->x1 == 0) {
|
if (area->x1 == 0) {
|
||||||
scrollDirection = FullRefreshDirections::None;
|
scrollDirection = FullRefreshDirections::None;
|
||||||
lv_disp_set_direction(lv_disp_get_default(), 0);
|
lv_disp_set_direction(lv_disp_get_default(), 0);
|
||||||
}
|
}
|
||||||
|
@ -143,17 +144,17 @@ void LittleVgl::FlushDisplay(const lv_area_t *area, lv_color_t *color_p) {
|
||||||
if (y2 < y1) {
|
if (y2 < y1) {
|
||||||
height = totalNbLines - y1;
|
height = totalNbLines - y1;
|
||||||
|
|
||||||
if ( height > 0 ) {
|
if (height > 0) {
|
||||||
lcd.DrawBuffer(area->x1, y1, width, height, reinterpret_cast<const uint8_t *>(color_p), width * height * 2);
|
lcd.DrawBuffer(area->x1, y1, width, height, reinterpret_cast<const uint8_t*>(color_p), width * height * 2);
|
||||||
ulTaskNotifyTake(pdTRUE, 100);
|
ulTaskNotifyTake(pdTRUE, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t pixOffset = width * height;
|
uint16_t pixOffset = width * height;
|
||||||
height = y2 + 1;
|
height = y2 + 1;
|
||||||
lcd.DrawBuffer(area->x1, 0, width, height, reinterpret_cast<const uint8_t *>(color_p + pixOffset), width * height * 2);
|
lcd.DrawBuffer(area->x1, 0, width, height, reinterpret_cast<const uint8_t*>(color_p + pixOffset), width * height * 2);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
lcd.DrawBuffer(area->x1, y1, width, height, reinterpret_cast<const uint8_t *>(color_p), width * height * 2);
|
lcd.DrawBuffer(area->x1, y1, width, height, reinterpret_cast<const uint8_t*>(color_p), width * height * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// IMPORTANT!!!
|
// IMPORTANT!!!
|
||||||
|
@ -167,8 +168,8 @@ void LittleVgl::SetNewTapEvent(uint16_t x, uint16_t y) {
|
||||||
tapped = true;
|
tapped = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LittleVgl::GetTouchPadInfo(lv_indev_data_t *ptr) {
|
bool LittleVgl::GetTouchPadInfo(lv_indev_data_t* ptr) {
|
||||||
if(tapped) {
|
if (tapped) {
|
||||||
ptr->point.x = tap_x;
|
ptr->point.x = tap_x;
|
||||||
ptr->point.y = tap_y;
|
ptr->point.y = tap_y;
|
||||||
ptr->state = LV_INDEV_STATE_PR;
|
ptr->state = LV_INDEV_STATE_PR;
|
||||||
|
@ -202,14 +203,8 @@ bool LittleVgl::GetTouchPadInfo(lv_indev_data_t *ptr) {
|
||||||
|
|
||||||
void LittleVgl::InitTheme() {
|
void LittleVgl::InitTheme() {
|
||||||
|
|
||||||
lv_theme_t * th = lv_pinetime_theme_init(
|
lv_theme_t* th = lv_pinetime_theme_init(
|
||||||
LV_COLOR_WHITE, LV_COLOR_SILVER,
|
LV_COLOR_WHITE, LV_COLOR_SILVER, 0, &jetbrains_mono_bold_20, &jetbrains_mono_bold_20, &jetbrains_mono_bold_20, &jetbrains_mono_bold_20);
|
||||||
0,
|
|
||||||
&jetbrains_mono_bold_20,
|
|
||||||
&jetbrains_mono_bold_20,
|
|
||||||
&jetbrains_mono_bold_20,
|
|
||||||
&jetbrains_mono_bold_20);
|
|
||||||
|
|
||||||
lv_theme_set_act(th);
|
lv_theme_set_act(th);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,50 +10,49 @@ namespace Pinetime {
|
||||||
|
|
||||||
namespace Components {
|
namespace Components {
|
||||||
class LittleVgl {
|
class LittleVgl {
|
||||||
public:
|
public:
|
||||||
enum class FullRefreshDirections { None, Up, Down, Left, Right, LeftAnim, RightAnim };
|
enum class FullRefreshDirections { None, Up, Down, Left, Right, LeftAnim, RightAnim };
|
||||||
LittleVgl(Pinetime::Drivers::St7789& lcd, Pinetime::Drivers::Cst816S& touchPanel);
|
LittleVgl(Pinetime::Drivers::St7789& lcd, Pinetime::Drivers::Cst816S& touchPanel);
|
||||||
|
|
||||||
LittleVgl(const LittleVgl&) = delete;
|
LittleVgl(const LittleVgl&) = delete;
|
||||||
LittleVgl& operator=(const LittleVgl&) = delete;
|
LittleVgl& operator=(const LittleVgl&) = delete;
|
||||||
LittleVgl(LittleVgl&&) = delete;
|
LittleVgl(LittleVgl&&) = delete;
|
||||||
LittleVgl& operator=(LittleVgl&&) = delete;
|
LittleVgl& operator=(LittleVgl&&) = delete;
|
||||||
|
|
||||||
void FlushDisplay(const lv_area_t * area, lv_color_t * color_p);
|
void FlushDisplay(const lv_area_t* area, lv_color_t* color_p);
|
||||||
bool GetTouchPadInfo(lv_indev_data_t *ptr);
|
bool GetTouchPadInfo(lv_indev_data_t* ptr);
|
||||||
void SetFullRefresh(FullRefreshDirections direction);
|
void SetFullRefresh(FullRefreshDirections direction);
|
||||||
void SetNewTapEvent(uint16_t x, uint16_t y);
|
void SetNewTapEvent(uint16_t x, uint16_t y);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void InitDisplay();
|
void InitDisplay();
|
||||||
void InitTouchpad();
|
void InitTouchpad();
|
||||||
void InitTheme();
|
void InitTheme();
|
||||||
|
|
||||||
|
Pinetime::Drivers::St7789& lcd;
|
||||||
|
Pinetime::Drivers::Cst816S& touchPanel;
|
||||||
|
|
||||||
Pinetime::Drivers::St7789& lcd;
|
lv_disp_buf_t disp_buf_2;
|
||||||
Pinetime::Drivers::Cst816S& touchPanel;
|
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;
|
bool firstTouch = true;
|
||||||
lv_color_t buf2_1[LV_HOR_RES_MAX * 4];
|
static constexpr uint8_t nbWriteLines = 4;
|
||||||
lv_color_t buf2_2[LV_HOR_RES_MAX * 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;
|
uint16_t tap_x = 0;
|
||||||
lv_point_t previousClick;
|
uint16_t tap_y = 0;
|
||||||
|
bool tapped = false;
|
||||||
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;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,16 @@ namespace Pinetime {
|
||||||
namespace Applications {
|
namespace Applications {
|
||||||
namespace Display {
|
namespace Display {
|
||||||
enum class Messages : uint8_t {
|
enum class Messages : uint8_t {
|
||||||
GoToSleep, GoToRunning, UpdateDateTime, UpdateBleConnection, UpdateBatteryLevel, TouchEvent, ButtonPushed,
|
GoToSleep,
|
||||||
NewNotification, BleFirmwareUpdateStarted, UpdateTimeOut
|
GoToRunning,
|
||||||
|
UpdateDateTime,
|
||||||
|
UpdateBleConnection,
|
||||||
|
UpdateBatteryLevel,
|
||||||
|
TouchEvent,
|
||||||
|
ButtonPushed,
|
||||||
|
NewNotification,
|
||||||
|
BleFirmwareUpdateStarted,
|
||||||
|
UpdateTimeOut
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,6 @@
|
||||||
namespace Pinetime {
|
namespace Pinetime {
|
||||||
namespace Applications {
|
namespace Applications {
|
||||||
|
|
||||||
enum class TouchEvents { None, Tap, SwipeLeft, SwipeRight, SwipeUp, SwipeDown, LongTap, DoubleTap};
|
enum class TouchEvents { None, Tap, SwipeLeft, SwipeRight, SwipeUp, SwipeDown, LongTap, DoubleTap };
|
||||||
}
|
}
|
||||||
}
|
}
|
44
src/displayapp/fonts/README.md
Normal file
44
src/displayapp/fonts/README.md
Normal 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
|
|
@ -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
|
|
|
@ -19,7 +19,7 @@
|
||||||
/**********************
|
/**********************
|
||||||
* STATIC PROTOTYPES
|
* STATIC PROTOTYPES
|
||||||
**********************/
|
**********************/
|
||||||
static void theme_apply(lv_obj_t * obj, lv_theme_style_t name);
|
static void theme_apply(lv_obj_t* obj, lv_theme_style_t name);
|
||||||
|
|
||||||
/**********************
|
/**********************
|
||||||
* STATIC VARIABLES
|
* STATIC VARIABLES
|
||||||
|
@ -67,244 +67,240 @@ static bool inited;
|
||||||
* STATIC FUNCTIONS
|
* STATIC FUNCTIONS
|
||||||
**********************/
|
**********************/
|
||||||
|
|
||||||
static void style_init_reset(lv_style_t * style)
|
static void style_init_reset(lv_style_t* style) {
|
||||||
{
|
if (inited)
|
||||||
if(inited) lv_style_reset(style);
|
lv_style_reset(style);
|
||||||
else lv_style_init(style);
|
else
|
||||||
|
lv_style_init(style);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void basic_init(void) {
|
||||||
|
|
||||||
static void basic_init(void)
|
style_init_reset(&style_pad);
|
||||||
{
|
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);
|
style_init_reset(&style_circle);
|
||||||
lv_style_set_pad_top(&style_pad, LV_STATE_DEFAULT, LV_VER_RES / 30);
|
lv_style_set_radius(&style_circle, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
|
||||||
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);
|
style_init_reset(&style_bg);
|
||||||
lv_style_set_radius(&style_circle, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
|
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);
|
style_init_reset(&style_box);
|
||||||
lv_style_set_bg_opa(&style_bg, LV_STATE_DEFAULT, LV_OPA_COVER);
|
lv_style_set_bg_opa(&style_box, LV_STATE_DEFAULT, LV_OPA_COVER);
|
||||||
lv_style_set_bg_color(&style_bg, LV_STATE_DEFAULT, LV_COLOR_BLACK);
|
lv_style_set_radius(&style_box, LV_STATE_DEFAULT, 10);
|
||||||
lv_style_set_text_font(&style_bg, LV_STATE_DEFAULT, theme.font_normal);
|
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);
|
style_init_reset(&style_box_border);
|
||||||
lv_style_set_bg_opa(&style_box, LV_STATE_DEFAULT, LV_OPA_COVER);
|
lv_style_set_bg_opa(&style_box_border, LV_STATE_DEFAULT, LV_OPA_TRANSP);
|
||||||
lv_style_set_radius(&style_box, LV_STATE_DEFAULT, 10);
|
lv_style_set_border_width(&style_box_border, LV_STATE_DEFAULT, 2);
|
||||||
lv_style_set_value_color(&style_box, LV_STATE_DEFAULT, LV_PINETIME_BLUE);
|
lv_style_set_border_color(&style_box_border, LV_STATE_DEFAULT, LV_PINETIME_GRAY);
|
||||||
lv_style_set_value_font(&style_box, LV_STATE_DEFAULT, theme.font_normal);
|
lv_style_set_text_color(&style_box, LV_STATE_DEFAULT, LV_PINETIME_BLUE);
|
||||||
|
|
||||||
style_init_reset(&style_box_border);
|
style_init_reset(&style_title);
|
||||||
lv_style_set_bg_opa(&style_box_border, LV_STATE_DEFAULT, LV_OPA_TRANSP);
|
lv_style_set_text_color(&style_title, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
|
||||||
lv_style_set_border_width(&style_box_border, LV_STATE_DEFAULT, 2);
|
lv_style_set_text_font(&style_title, LV_STATE_DEFAULT, theme.font_subtitle);
|
||||||
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_label_white);
|
||||||
|
lv_style_set_text_color(&style_label_white, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
|
||||||
|
|
||||||
style_init_reset(&style_title);
|
style_init_reset(&style_btn);
|
||||||
lv_style_set_text_color(&style_title, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
|
lv_style_set_radius(&style_btn, LV_STATE_DEFAULT, 10);
|
||||||
lv_style_set_text_font(&style_title, LV_STATE_DEFAULT, theme.font_subtitle);
|
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_btn, LV_STATE_DEFAULT, lv_color_hex(0xffffff));
|
||||||
lv_style_set_text_color(&style_label_white, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
|
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_value_color(&style_btn, LV_STATE_DEFAULT, lv_color_hex(0xffffff));
|
||||||
lv_style_set_radius(&style_btn, LV_STATE_DEFAULT, 10);
|
lv_style_set_value_color(&style_btn, LV_STATE_CHECKED, lv_color_hex(0xffffff));
|
||||||
lv_style_set_bg_opa(&style_btn, LV_STATE_DEFAULT, LV_OPA_COVER);
|
lv_style_set_value_color(&style_btn, LV_STATE_CHECKED, lv_color_hex(0xffffff));
|
||||||
lv_style_set_bg_color(&style_btn, LV_STATE_DEFAULT, lv_color_hex(0x2F3540));
|
lv_style_set_value_color(&style_btn, LV_STATE_DISABLED, lv_color_hex(0x888888));
|
||||||
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_text_color(&style_btn, LV_STATE_DEFAULT, lv_color_hex(0xffffff));
|
lv_style_set_pad_left(&style_btn, LV_STATE_DEFAULT, LV_DPX(20));
|
||||||
lv_style_set_text_color(&style_btn, LV_STATE_CHECKED, lv_color_hex(0xffffff));
|
lv_style_set_pad_right(&style_btn, LV_STATE_DEFAULT, LV_DPX(20));
|
||||||
lv_style_set_text_color(&style_btn, LV_STATE_CHECKED, lv_color_hex(0xffffff));
|
lv_style_set_pad_top(&style_btn, LV_STATE_DEFAULT, LV_DPX(20));
|
||||||
lv_style_set_text_color(&style_btn, LV_STATE_DISABLED, lv_color_hex(0x888888));
|
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));
|
style_init_reset(&style_btn_border);
|
||||||
lv_style_set_value_color(&style_btn, LV_STATE_CHECKED, lv_color_hex(0xffffff));
|
lv_style_set_radius(&style_btn_border, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
|
||||||
lv_style_set_value_color(&style_btn, LV_STATE_CHECKED, lv_color_hex(0xffffff));
|
lv_style_set_border_color(&style_btn_border, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
|
||||||
lv_style_set_value_color(&style_btn, LV_STATE_DISABLED, lv_color_hex(0x888888));
|
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));
|
style_init_reset(&style_icon);
|
||||||
lv_style_set_pad_right(&style_btn, LV_STATE_DEFAULT, LV_DPX(20));
|
lv_style_set_text_color(&style_icon, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
|
||||||
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_btn_border);
|
style_init_reset(&style_back);
|
||||||
lv_style_set_radius(&style_btn_border, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
|
lv_style_set_value_color(&style_back, LV_STATE_DEFAULT, LV_PINETIME_GRAY);
|
||||||
lv_style_set_border_color(&style_btn_border, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
|
lv_style_set_value_str(&style_back, LV_STATE_DEFAULT, LV_SYMBOL_LEFT);
|
||||||
lv_style_set_border_width(&style_btn_border, LV_STATE_DEFAULT, 2);
|
lv_style_set_value_font(&style_back, LV_STATE_DEFAULT, theme.font_subtitle);
|
||||||
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_icon);
|
style_init_reset(&style_bar_indic);
|
||||||
lv_style_set_text_color(&style_icon, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
|
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);
|
style_init_reset(&style_scrollbar);
|
||||||
lv_style_set_value_color(&style_back, LV_STATE_DEFAULT, LV_PINETIME_GRAY);
|
lv_style_set_bg_opa(&style_scrollbar, LV_STATE_DEFAULT, LV_OPA_COVER);
|
||||||
lv_style_set_value_str(&style_back, LV_STATE_DEFAULT, LV_SYMBOL_LEFT);
|
lv_style_set_radius(&style_scrollbar, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
|
||||||
lv_style_set_value_font(&style_back, LV_STATE_DEFAULT, theme.font_subtitle);
|
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);
|
style_init_reset(&style_list_btn);
|
||||||
lv_style_set_bg_opa(&style_bar_indic, LV_STATE_DEFAULT, LV_OPA_COVER);
|
lv_style_set_bg_opa(&style_list_btn, LV_STATE_DEFAULT, LV_OPA_COVER);
|
||||||
lv_style_set_radius(&style_bar_indic, LV_STATE_DEFAULT, 10);
|
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);
|
style_init_reset(&style_ddlist_list);
|
||||||
lv_style_set_bg_opa(&style_scrollbar, LV_STATE_DEFAULT, LV_OPA_COVER);
|
lv_style_set_text_line_space(&style_ddlist_list, LV_STATE_DEFAULT, LV_VER_RES / 25);
|
||||||
lv_style_set_radius(&style_scrollbar, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
|
lv_style_set_shadow_width(&style_ddlist_list, LV_STATE_DEFAULT, LV_VER_RES / 20);
|
||||||
lv_style_set_bg_color(&style_scrollbar, LV_STATE_DEFAULT, LV_PINETIME_LIGHT_GRAY);
|
lv_style_set_shadow_color(&style_ddlist_list, LV_STATE_DEFAULT, LV_PINETIME_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_list_btn);
|
style_init_reset(&style_ddlist_selected);
|
||||||
lv_style_set_bg_opa(&style_list_btn, LV_STATE_DEFAULT, LV_OPA_COVER);
|
lv_style_set_bg_opa(&style_ddlist_selected, 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_ddlist_selected, LV_STATE_DEFAULT, LV_PINETIME_BLUE);
|
||||||
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_list);
|
style_init_reset(&style_sw_bg);
|
||||||
lv_style_set_text_line_space(&style_ddlist_list, LV_STATE_DEFAULT, LV_VER_RES / 25);
|
lv_style_set_bg_opa(&style_sw_bg, LV_STATE_DEFAULT, LV_OPA_COVER);
|
||||||
lv_style_set_shadow_width(&style_ddlist_list, LV_STATE_DEFAULT, LV_VER_RES / 20);
|
lv_style_set_bg_color(&style_sw_bg, LV_STATE_DEFAULT, LV_PINETIME_LIGHT_GRAY);
|
||||||
lv_style_set_shadow_color(&style_ddlist_list, LV_STATE_DEFAULT, LV_PINETIME_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);
|
style_init_reset(&style_sw_indic);
|
||||||
lv_style_set_bg_opa(&style_ddlist_selected, LV_STATE_DEFAULT, LV_OPA_COVER);
|
lv_style_set_bg_opa(&style_sw_indic, LV_STATE_DEFAULT, LV_OPA_COVER);
|
||||||
lv_style_set_bg_color(&style_ddlist_selected, LV_STATE_DEFAULT, LV_PINETIME_BLUE);
|
lv_style_set_bg_color(&style_sw_indic, LV_STATE_DEFAULT, LV_PINETIME_GREEN);
|
||||||
|
|
||||||
style_init_reset(&style_sw_bg);
|
style_init_reset(&style_sw_knob);
|
||||||
lv_style_set_bg_opa(&style_sw_bg, LV_STATE_DEFAULT, LV_OPA_COVER);
|
lv_style_set_bg_opa(&style_sw_knob, LV_STATE_DEFAULT, LV_OPA_COVER);
|
||||||
lv_style_set_bg_color(&style_sw_bg, LV_STATE_DEFAULT, LV_PINETIME_LIGHT_GRAY);
|
lv_style_set_bg_color(&style_sw_knob, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
|
||||||
lv_style_set_radius(&style_sw_bg, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
|
lv_style_set_radius(&style_sw_knob, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
|
||||||
lv_style_set_value_color(&style_sw_bg, LV_STATE_DEFAULT, LV_PINETIME_BLUE);
|
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);
|
style_init_reset(&style_slider_knob);
|
||||||
lv_style_set_bg_opa(&style_sw_indic, LV_STATE_DEFAULT, LV_OPA_COVER);
|
lv_style_set_bg_opa(&style_slider_knob, LV_STATE_DEFAULT, LV_OPA_COVER);
|
||||||
lv_style_set_bg_color(&style_sw_indic, LV_STATE_DEFAULT, LV_PINETIME_GREEN);
|
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);
|
style_init_reset(&style_arc_indic);
|
||||||
lv_style_set_bg_opa(&style_sw_knob, LV_STATE_DEFAULT, LV_OPA_COVER);
|
lv_style_set_line_color(&style_arc_indic, LV_STATE_DEFAULT, LV_PINETIME_BLUE);
|
||||||
lv_style_set_bg_color(&style_sw_knob, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
|
lv_style_set_line_width(&style_arc_indic, LV_STATE_DEFAULT, LV_DPX(25));
|
||||||
lv_style_set_radius(&style_sw_knob, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
|
lv_style_set_line_rounded(&style_arc_indic, LV_STATE_DEFAULT, true);
|
||||||
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_slider_knob);
|
style_init_reset(&style_arc_bg);
|
||||||
lv_style_set_bg_opa(&style_slider_knob, LV_STATE_DEFAULT, LV_OPA_COVER);
|
lv_style_set_line_color(&style_arc_bg, LV_STATE_DEFAULT, LV_PINETIME_GRAY);
|
||||||
lv_style_set_bg_color(&style_slider_knob, LV_STATE_DEFAULT, LV_COLOR_RED);
|
lv_style_set_line_width(&style_arc_bg, LV_STATE_DEFAULT, LV_DPX(25));
|
||||||
lv_style_set_border_color(&style_slider_knob, LV_STATE_DEFAULT, LV_COLOR_WHITE);
|
lv_style_set_line_rounded(&style_arc_bg, LV_STATE_DEFAULT, true);
|
||||||
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_indic);
|
style_init_reset(&style_table_cell);
|
||||||
lv_style_set_line_color(&style_arc_indic, LV_STATE_DEFAULT, LV_PINETIME_BLUE);
|
lv_style_set_border_color(&style_table_cell, LV_STATE_DEFAULT, LV_PINETIME_GRAY);
|
||||||
lv_style_set_line_width(&style_arc_indic, LV_STATE_DEFAULT, LV_DPX(25));
|
lv_style_set_border_width(&style_table_cell, LV_STATE_DEFAULT, 1);
|
||||||
lv_style_set_line_rounded(&style_arc_indic, LV_STATE_DEFAULT, true);
|
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);
|
style_init_reset(&style_pad_small);
|
||||||
lv_style_set_line_color(&style_arc_bg, LV_STATE_DEFAULT, LV_PINETIME_GRAY);
|
lv_style_int_t pad_small_value = 10;
|
||||||
lv_style_set_line_width(&style_arc_bg, LV_STATE_DEFAULT, LV_DPX(25));
|
lv_style_set_pad_left(&style_pad_small, LV_STATE_DEFAULT, pad_small_value);
|
||||||
lv_style_set_line_rounded(&style_arc_bg, LV_STATE_DEFAULT, true);
|
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);
|
style_init_reset(&style_bg_grad);
|
||||||
lv_style_set_border_color(&style_table_cell, LV_STATE_DEFAULT, LV_PINETIME_GRAY);
|
lv_style_set_bg_color(&style_bg_grad, LV_STATE_DEFAULT, lv_color_hsv_to_rgb(10, 10, 40));
|
||||||
lv_style_set_border_width(&style_table_cell, LV_STATE_DEFAULT, 1);
|
lv_style_set_bg_grad_color(&style_bg_grad, LV_STATE_DEFAULT, lv_color_hsv_to_rgb(10, 10, 20));
|
||||||
lv_style_set_border_side(&style_table_cell, LV_STATE_DEFAULT, LV_BORDER_SIDE_FULL);
|
lv_style_set_bg_grad_dir(&style_bg_grad, LV_STATE_DEFAULT, LV_GRAD_DIR_VER);
|
||||||
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_pad_small);
|
style_init_reset(&style_lmeter);
|
||||||
lv_style_int_t pad_small_value = 10;
|
lv_style_set_radius(&style_lmeter, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
|
||||||
lv_style_set_pad_left(&style_pad_small, LV_STATE_DEFAULT, pad_small_value);
|
lv_style_set_pad_left(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(20));
|
||||||
lv_style_set_pad_right(&style_pad_small, LV_STATE_DEFAULT, pad_small_value);
|
lv_style_set_pad_right(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(20));
|
||||||
lv_style_set_pad_top(&style_pad_small, LV_STATE_DEFAULT, pad_small_value);
|
lv_style_set_pad_top(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(20));
|
||||||
lv_style_set_pad_bottom(&style_pad_small, LV_STATE_DEFAULT, pad_small_value);
|
lv_style_set_pad_inner(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(30));
|
||||||
lv_style_set_pad_inner(&style_pad_small, LV_STATE_DEFAULT, pad_small_value);
|
lv_style_set_scale_width(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(25));
|
||||||
|
|
||||||
style_init_reset(&style_bg_grad);
|
lv_style_set_line_color(&style_lmeter, LV_STATE_DEFAULT, theme.color_primary);
|
||||||
lv_style_set_bg_color(&style_bg_grad, LV_STATE_DEFAULT, lv_color_hsv_to_rgb(10, 10, 40));
|
lv_style_set_scale_grad_color(&style_lmeter, LV_STATE_DEFAULT, theme.color_primary);
|
||||||
lv_style_set_bg_grad_color(&style_bg_grad, LV_STATE_DEFAULT, lv_color_hsv_to_rgb(10, 10, 20));
|
lv_style_set_scale_end_color(&style_lmeter, LV_STATE_DEFAULT, lv_color_hex3(0x888));
|
||||||
lv_style_set_bg_grad_dir(&style_bg_grad, LV_STATE_DEFAULT, LV_GRAD_DIR_VER);
|
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);
|
style_init_reset(&style_chart_serie);
|
||||||
lv_style_set_radius(&style_lmeter, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
|
lv_style_set_line_color(&style_chart_serie, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
|
||||||
lv_style_set_pad_left(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(20));
|
lv_style_set_line_width(&style_chart_serie, LV_STATE_DEFAULT, 4);
|
||||||
lv_style_set_pad_right(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(20));
|
lv_style_set_size(&style_chart_serie, LV_STATE_DEFAULT, 4);
|
||||||
lv_style_set_pad_top(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(20));
|
lv_style_set_bg_opa(&style_chart_serie, LV_STATE_DEFAULT, 0);
|
||||||
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));
|
|
||||||
|
|
||||||
lv_style_set_line_color(&style_lmeter, LV_STATE_DEFAULT, theme.color_primary);
|
lv_style_reset(&style_cb_bg);
|
||||||
lv_style_set_scale_grad_color(&style_lmeter, LV_STATE_DEFAULT, theme.color_primary);
|
lv_style_set_radius(&style_cb_bg, LV_STATE_DEFAULT, LV_DPX(4));
|
||||||
lv_style_set_scale_end_color(&style_lmeter, LV_STATE_DEFAULT, lv_color_hex3(0x888));
|
lv_style_set_pad_inner(&style_cb_bg, LV_STATE_DEFAULT, LV_DPX(10));
|
||||||
lv_style_set_line_width(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(10));
|
lv_style_set_outline_color(&style_cb_bg, LV_STATE_DEFAULT, theme.color_primary);
|
||||||
lv_style_set_scale_end_line_width(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(7));
|
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));
|
||||||
style_init_reset(&style_chart_serie);
|
lv_style_set_transition_time(&style_cb_bg, LV_STATE_DEFAULT, 0);
|
||||||
lv_style_set_line_color(&style_chart_serie, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
|
lv_style_set_transition_prop_6(&style_cb_bg, LV_STATE_DEFAULT, LV_STYLE_OUTLINE_OPA);
|
||||||
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_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
|
* GLOBAL FUNCTIONS
|
||||||
**********************/
|
**********************/
|
||||||
|
@ -320,221 +316,216 @@ static void basic_init(void)
|
||||||
* @param font_title pointer to a extra large font
|
* @param font_title pointer to a extra large font
|
||||||
* @return a pointer to reference this theme later
|
* @return a pointer to reference this theme later
|
||||||
*/
|
*/
|
||||||
lv_theme_t * lv_pinetime_theme_init(lv_color_t color_primary, lv_color_t color_secondary, uint32_t flags,
|
lv_theme_t* lv_pinetime_theme_init(lv_color_t color_primary,
|
||||||
const lv_font_t * font_small, const lv_font_t * font_normal, const lv_font_t * font_subtitle,
|
lv_color_t color_secondary,
|
||||||
const lv_font_t * font_title)
|
uint32_t flags,
|
||||||
{
|
const lv_font_t* font_small,
|
||||||
theme.color_primary = color_primary;
|
const lv_font_t* font_normal,
|
||||||
theme.color_secondary = color_secondary;
|
const lv_font_t* font_subtitle,
|
||||||
theme.font_small = font_small;
|
const lv_font_t* font_title) {
|
||||||
theme.font_normal = font_normal;
|
theme.color_primary = color_primary;
|
||||||
theme.font_subtitle = font_subtitle;
|
theme.color_secondary = color_secondary;
|
||||||
theme.font_title = font_title;
|
theme.font_small = font_small;
|
||||||
theme.flags = flags;
|
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)
|
/*To avoid warnings*/
|
||||||
{
|
uint32_t name_int = (uint32_t) name;
|
||||||
lv_style_list_t * list;
|
switch (name_int) {
|
||||||
|
case LV_THEME_NONE:
|
||||||
|
break;
|
||||||
|
|
||||||
/*To avoid warnings*/
|
case LV_THEME_SCR:
|
||||||
uint32_t name_int = (uint32_t) name;
|
lv_obj_clean_style_list(obj, LV_OBJ_PART_MAIN);
|
||||||
switch(name_int) {
|
list = lv_obj_get_style_list(obj, LV_OBJ_PART_MAIN);
|
||||||
case LV_THEME_NONE:
|
_lv_style_list_add_style(list, &style_bg);
|
||||||
break;
|
_lv_style_list_add_style(list, &style_label_white);
|
||||||
|
break;
|
||||||
|
|
||||||
case LV_THEME_SCR:
|
case LV_THEME_OBJ:
|
||||||
lv_obj_clean_style_list(obj, LV_OBJ_PART_MAIN);
|
lv_obj_clean_style_list(obj, LV_OBJ_PART_MAIN);
|
||||||
list = lv_obj_get_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_box);
|
||||||
_lv_style_list_add_style(list, &style_label_white);
|
break;
|
||||||
break;
|
|
||||||
|
|
||||||
case LV_THEME_OBJ:
|
case LV_THEME_CONT:
|
||||||
lv_obj_clean_style_list(obj, LV_OBJ_PART_MAIN);
|
lv_obj_clean_style_list(obj, LV_OBJ_PART_MAIN);
|
||||||
list = lv_obj_get_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);
|
_lv_style_list_add_style(list, &style_box);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LV_THEME_CONT:
|
case LV_THEME_BTN:
|
||||||
lv_obj_clean_style_list(obj, LV_OBJ_PART_MAIN);
|
lv_obj_clean_style_list(obj, LV_BTN_PART_MAIN);
|
||||||
list = lv_obj_get_style_list(obj, LV_CONT_PART_MAIN);
|
list = lv_obj_get_style_list(obj, LV_BTN_PART_MAIN);
|
||||||
_lv_style_list_add_style(list, &style_box);
|
_lv_style_list_add_style(list, &style_btn);
|
||||||
break;
|
//_lv_style_list_add_style(list, &style_bg_grad);
|
||||||
|
break;
|
||||||
|
|
||||||
case LV_THEME_BTN:
|
case LV_THEME_BTNMATRIX:
|
||||||
lv_obj_clean_style_list(obj, LV_BTN_PART_MAIN);
|
list = lv_obj_get_style_list(obj, LV_BTNMATRIX_PART_BG);
|
||||||
list = lv_obj_get_style_list(obj, LV_BTN_PART_MAIN);
|
_lv_style_list_add_style(list, &style_bg);
|
||||||
_lv_style_list_add_style(list, &style_btn);
|
_lv_style_list_add_style(list, &style_pad_small);
|
||||||
//_lv_style_list_add_style(list, &style_bg_grad);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case LV_THEME_BTNMATRIX:
|
list = lv_obj_get_style_list(obj, LV_BTNMATRIX_PART_BTN);
|
||||||
list = lv_obj_get_style_list(obj, LV_BTNMATRIX_PART_BG);
|
_lv_style_list_add_style(list, &style_btn);
|
||||||
_lv_style_list_add_style(list, &style_bg);
|
//_lv_style_list_add_style(list, &style_bg_grad);
|
||||||
_lv_style_list_add_style(list, &style_pad_small);
|
//_lv_style_list_add_style(list, &style_bg_click);
|
||||||
|
break;
|
||||||
|
|
||||||
list = lv_obj_get_style_list(obj, LV_BTNMATRIX_PART_BTN);
|
case LV_THEME_BAR:
|
||||||
_lv_style_list_add_style(list, &style_btn);
|
lv_obj_clean_style_list(obj, LV_BAR_PART_BG);
|
||||||
//_lv_style_list_add_style(list, &style_bg_grad);
|
list = lv_obj_get_style_list(obj, LV_BAR_PART_BG);
|
||||||
//_lv_style_list_add_style(list, &style_bg_click);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case LV_THEME_BAR:
|
lv_obj_clean_style_list(obj, LV_BAR_PART_INDIC);
|
||||||
lv_obj_clean_style_list(obj, LV_BAR_PART_BG);
|
list = lv_obj_get_style_list(obj, LV_BAR_PART_INDIC);
|
||||||
list = lv_obj_get_style_list(obj, LV_BAR_PART_BG);
|
_lv_style_list_add_style(list, &style_bar_indic);
|
||||||
|
break;
|
||||||
|
|
||||||
lv_obj_clean_style_list(obj, LV_BAR_PART_INDIC);
|
case LV_THEME_IMAGE:
|
||||||
list = lv_obj_get_style_list(obj, LV_BAR_PART_INDIC);
|
lv_obj_clean_style_list(obj, LV_IMG_PART_MAIN);
|
||||||
_lv_style_list_add_style(list, &style_bar_indic);
|
list = lv_obj_get_style_list(obj, LV_IMG_PART_MAIN);
|
||||||
break;
|
_lv_style_list_add_style(list, &style_icon);
|
||||||
|
break;
|
||||||
|
|
||||||
case LV_THEME_IMAGE:
|
case LV_THEME_LABEL:
|
||||||
lv_obj_clean_style_list(obj, LV_IMG_PART_MAIN);
|
lv_obj_clean_style_list(obj, LV_LABEL_PART_MAIN);
|
||||||
list = lv_obj_get_style_list(obj, LV_IMG_PART_MAIN);
|
list = lv_obj_get_style_list(obj, LV_LABEL_PART_MAIN);
|
||||||
_lv_style_list_add_style(list, &style_icon);
|
_lv_style_list_add_style(list, &style_label_white);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LV_THEME_LABEL:
|
case LV_THEME_SLIDER:
|
||||||
lv_obj_clean_style_list(obj, LV_LABEL_PART_MAIN);
|
lv_obj_clean_style_list(obj, LV_SLIDER_PART_BG);
|
||||||
list = lv_obj_get_style_list(obj, LV_LABEL_PART_MAIN);
|
list = lv_obj_get_style_list(obj, LV_SLIDER_PART_BG);
|
||||||
_lv_style_list_add_style(list, &style_label_white);
|
_lv_style_list_add_style(list, &style_sw_bg);
|
||||||
break;
|
|
||||||
|
|
||||||
case LV_THEME_SLIDER:
|
lv_obj_clean_style_list(obj, LV_SLIDER_PART_INDIC);
|
||||||
lv_obj_clean_style_list(obj, LV_SLIDER_PART_BG);
|
list = lv_obj_get_style_list(obj, LV_SLIDER_PART_INDIC);
|
||||||
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);
|
lv_obj_clean_style_list(obj, LV_SLIDER_PART_KNOB);
|
||||||
list = lv_obj_get_style_list(obj, LV_SLIDER_PART_INDIC);
|
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);
|
case LV_THEME_LIST:
|
||||||
list = lv_obj_get_style_list(obj, LV_SLIDER_PART_KNOB);
|
lv_obj_clean_style_list(obj, LV_LIST_PART_BG);
|
||||||
_lv_style_list_add_style(list, &style_slider_knob);
|
list = lv_obj_get_style_list(obj, LV_LIST_PART_BG);
|
||||||
break;
|
_lv_style_list_add_style(list, &style_box);
|
||||||
|
|
||||||
case LV_THEME_LIST:
|
lv_obj_clean_style_list(obj, LV_LIST_PART_SCROLLABLE);
|
||||||
lv_obj_clean_style_list(obj, LV_LIST_PART_BG);
|
list = lv_obj_get_style_list(obj, LV_LIST_PART_SCROLLABLE);
|
||||||
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);
|
lv_obj_clean_style_list(obj, LV_LIST_PART_SCROLLBAR);
|
||||||
list = lv_obj_get_style_list(obj, LV_LIST_PART_SCROLLABLE);
|
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);
|
case LV_THEME_LIST_BTN:
|
||||||
list = lv_obj_get_style_list(obj, LV_LIST_PART_SCROLLBAR);
|
lv_obj_clean_style_list(obj, LV_BTN_PART_MAIN);
|
||||||
_lv_style_list_add_style(list, &style_scrollbar);
|
list = lv_obj_get_style_list(obj, LV_BTN_PART_MAIN);
|
||||||
break;
|
_lv_style_list_add_style(list, &style_list_btn);
|
||||||
|
break;
|
||||||
|
|
||||||
case LV_THEME_LIST_BTN:
|
case LV_THEME_ARC:
|
||||||
lv_obj_clean_style_list(obj, LV_BTN_PART_MAIN);
|
lv_obj_clean_style_list(obj, LV_ARC_PART_BG);
|
||||||
list = lv_obj_get_style_list(obj, LV_BTN_PART_MAIN);
|
list = lv_obj_get_style_list(obj, LV_ARC_PART_BG);
|
||||||
_lv_style_list_add_style(list, &style_list_btn);
|
_lv_style_list_add_style(list, &style_arc_bg);
|
||||||
break;
|
|
||||||
|
|
||||||
|
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:
|
case LV_THEME_SWITCH:
|
||||||
lv_obj_clean_style_list(obj, LV_ARC_PART_BG);
|
lv_obj_clean_style_list(obj, LV_SWITCH_PART_BG);
|
||||||
list = lv_obj_get_style_list(obj, LV_ARC_PART_BG);
|
list = lv_obj_get_style_list(obj, LV_SWITCH_PART_BG);
|
||||||
_lv_style_list_add_style(list, &style_arc_bg);
|
_lv_style_list_add_style(list, &style_sw_bg);
|
||||||
|
|
||||||
lv_obj_clean_style_list(obj, LV_ARC_PART_INDIC);
|
lv_obj_clean_style_list(obj, LV_SWITCH_PART_INDIC);
|
||||||
list = lv_obj_get_style_list(obj, LV_ARC_PART_INDIC);
|
list = lv_obj_get_style_list(obj, LV_SWITCH_PART_INDIC);
|
||||||
_lv_style_list_add_style(list, &style_arc_indic);
|
_lv_style_list_add_style(list, &style_sw_indic);
|
||||||
break;
|
|
||||||
|
|
||||||
|
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:
|
case LV_THEME_DROPDOWN:
|
||||||
lv_obj_clean_style_list(obj, LV_SWITCH_PART_BG);
|
lv_obj_clean_style_list(obj, LV_DROPDOWN_PART_MAIN);
|
||||||
list = lv_obj_get_style_list(obj, LV_SWITCH_PART_BG);
|
list = lv_obj_get_style_list(obj, LV_DROPDOWN_PART_MAIN);
|
||||||
_lv_style_list_add_style(list, &style_sw_bg);
|
_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);
|
lv_obj_clean_style_list(obj, LV_DROPDOWN_PART_LIST);
|
||||||
list = lv_obj_get_style_list(obj, LV_SWITCH_PART_INDIC);
|
list = lv_obj_get_style_list(obj, LV_DROPDOWN_PART_LIST);
|
||||||
_lv_style_list_add_style(list, &style_sw_indic);
|
_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);
|
lv_obj_clean_style_list(obj, LV_DROPDOWN_PART_SELECTED);
|
||||||
list = lv_obj_get_style_list(obj, LV_SWITCH_PART_KNOB);
|
list = lv_obj_get_style_list(obj, LV_DROPDOWN_PART_SELECTED);
|
||||||
_lv_style_list_add_style(list, &style_sw_knob);
|
_lv_style_list_add_style(list, &style_ddlist_selected);
|
||||||
break;
|
|
||||||
|
|
||||||
case LV_THEME_DROPDOWN:
|
lv_obj_clean_style_list(obj, LV_DROPDOWN_PART_SCROLLBAR);
|
||||||
lv_obj_clean_style_list(obj, LV_DROPDOWN_PART_MAIN);
|
list = lv_obj_get_style_list(obj, LV_DROPDOWN_PART_SCROLLBAR);
|
||||||
list = lv_obj_get_style_list(obj, LV_DROPDOWN_PART_MAIN);
|
_lv_style_list_add_style(list, &style_scrollbar);
|
||||||
_lv_style_list_add_style(list, &style_btn);
|
break;
|
||||||
_lv_style_list_add_style(list, &style_pad);
|
|
||||||
|
|
||||||
lv_obj_clean_style_list(obj, LV_DROPDOWN_PART_LIST);
|
case LV_THEME_TABLE:
|
||||||
list = lv_obj_get_style_list(obj, LV_DROPDOWN_PART_LIST);
|
list = lv_obj_get_style_list(obj, LV_TABLE_PART_BG);
|
||||||
_lv_style_list_add_style(list, &style_box);
|
_lv_style_list_add_style(list, &style_bg);
|
||||||
_lv_style_list_add_style(list, &style_ddlist_list);
|
|
||||||
_lv_style_list_add_style(list, &style_pad);
|
|
||||||
|
|
||||||
lv_obj_clean_style_list(obj, LV_DROPDOWN_PART_SELECTED);
|
int idx = 1; /* start value should be 1, not zero, since cell styles
|
||||||
list = lv_obj_get_style_list(obj, LV_DROPDOWN_PART_SELECTED);
|
start at 1 due to presence of LV_TABLE_PART_BG=0
|
||||||
_lv_style_list_add_style(list, &style_ddlist_selected);
|
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);
|
case LV_THEME_LINEMETER:
|
||||||
list = lv_obj_get_style_list(obj, LV_DROPDOWN_PART_SCROLLBAR);
|
list = lv_obj_get_style_list(obj, LV_LINEMETER_PART_MAIN);
|
||||||
_lv_style_list_add_style(list, &style_scrollbar);
|
_lv_style_list_add_style(list, &style_bg);
|
||||||
break;
|
_lv_style_list_add_style(list, &style_lmeter);
|
||||||
|
break;
|
||||||
|
|
||||||
case LV_THEME_TABLE:
|
case LV_THEME_CHART:
|
||||||
list = lv_obj_get_style_list(obj, LV_TABLE_PART_BG);
|
lv_obj_clean_style_list(obj, LV_CHART_PART_SERIES);
|
||||||
_lv_style_list_add_style(list, &style_bg);
|
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
|
case LV_THEME_CHECKBOX:
|
||||||
start at 1 due to presence of LV_TABLE_PART_BG=0
|
list = lv_obj_get_style_list(obj, LV_CHECKBOX_PART_BG);
|
||||||
in the enum (lv_table.h) */
|
_lv_style_list_add_style(list, &style_cb_bg);
|
||||||
/* 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_LINEMETER:
|
list = lv_obj_get_style_list(obj, LV_CHECKBOX_PART_BULLET);
|
||||||
list = lv_obj_get_style_list(obj, LV_LINEMETER_PART_MAIN);
|
_lv_style_list_add_style(list, &style_btn);
|
||||||
_lv_style_list_add_style(list, &style_bg);
|
_lv_style_list_add_style(list, &style_cb_bullet);
|
||||||
_lv_style_list_add_style(list, &style_lmeter);
|
break;
|
||||||
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);
|
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
lv_obj_refresh_style(obj, LV_OBJ_PART_ALL, LV_STYLE_PROP_ALL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**********************
|
/**********************
|
||||||
|
|
|
@ -19,24 +19,22 @@ extern "C" {
|
||||||
* DEFINES
|
* DEFINES
|
||||||
*********************/
|
*********************/
|
||||||
/*Colors*/
|
/*Colors*/
|
||||||
#define LV_PINETIME_WHITE lv_color_hex(0xffffff)
|
#define LV_PINETIME_WHITE lv_color_hex(0xffffff)
|
||||||
#define LV_PINETIME_LIGHT lv_color_hex(0xf3f8fe)
|
#define LV_PINETIME_LIGHT lv_color_hex(0xf3f8fe)
|
||||||
#define LV_PINETIME_GRAY lv_color_hex(0x8a8a8a)
|
#define LV_PINETIME_GRAY lv_color_hex(0x8a8a8a)
|
||||||
#define LV_PINETIME_LIGHT_GRAY lv_color_hex(0xc4c4c4)
|
#define LV_PINETIME_LIGHT_GRAY lv_color_hex(0xc4c4c4)
|
||||||
#define LV_PINETIME_BLUE lv_color_hex(0x2f3243) //006fb6
|
#define LV_PINETIME_BLUE lv_color_hex(0x2f3243) // 006fb6
|
||||||
#define LV_PINETIME_GREEN lv_color_hex(0x4cb242)
|
#define LV_PINETIME_GREEN lv_color_hex(0x4cb242)
|
||||||
#define LV_PINETIME_RED lv_color_hex(0xd51732)
|
#define LV_PINETIME_RED lv_color_hex(0xd51732)
|
||||||
|
|
||||||
/**********************
|
/**********************
|
||||||
* TYPEDEFS
|
* TYPEDEFS
|
||||||
**********************/
|
**********************/
|
||||||
|
|
||||||
|
|
||||||
/**********************
|
/**********************
|
||||||
* GLOBAL PROTOTYPES
|
* GLOBAL PROTOTYPES
|
||||||
**********************/
|
**********************/
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the default
|
* Initialize the default
|
||||||
* @param color_primary the primary color of the theme
|
* @param color_primary the primary color of the theme
|
||||||
|
@ -48,9 +46,13 @@ extern "C" {
|
||||||
* @param font_title pointer to a extra large font
|
* @param font_title pointer to a extra large font
|
||||||
* @return a pointer to reference this theme later
|
* @return a pointer to reference this theme later
|
||||||
*/
|
*/
|
||||||
lv_theme_t * lv_pinetime_theme_init(lv_color_t color_primary, lv_color_t color_secondary, uint32_t flags,
|
lv_theme_t* lv_pinetime_theme_init(lv_color_t color_primary,
|
||||||
const lv_font_t * font_small, const lv_font_t * font_normal, const lv_font_t * font_subtitle,
|
lv_color_t color_secondary,
|
||||||
const lv_font_t * font_title);
|
uint32_t flags,
|
||||||
|
const lv_font_t* font_small,
|
||||||
|
const lv_font_t* font_normal,
|
||||||
|
const lv_font_t* font_subtitle,
|
||||||
|
const lv_font_t* font_title);
|
||||||
/**********************
|
/**********************
|
||||||
* MACROS
|
* MACROS
|
||||||
**********************/
|
**********************/
|
||||||
|
|
|
@ -8,31 +8,34 @@
|
||||||
|
|
||||||
using namespace Pinetime::Applications::Screens;
|
using namespace Pinetime::Applications::Screens;
|
||||||
|
|
||||||
ApplicationList::ApplicationList(Pinetime::Applications::DisplayApp *app,
|
ApplicationList::ApplicationList(Pinetime::Applications::DisplayApp* app,
|
||||||
Pinetime::Controllers::Settings &settingsController,
|
Pinetime::Controllers::Settings& settingsController,
|
||||||
Pinetime::Controllers::Battery& batteryController,
|
Pinetime::Controllers::Battery& batteryController,
|
||||||
Controllers::DateTime& dateTimeController) :
|
Controllers::DateTime& dateTimeController)
|
||||||
Screen(app),
|
: Screen(app),
|
||||||
settingsController{settingsController},
|
settingsController {settingsController},
|
||||||
batteryController{batteryController},
|
batteryController {batteryController},
|
||||||
dateTimeController{dateTimeController},
|
dateTimeController {dateTimeController},
|
||||||
screens{app,
|
screens {app,
|
||||||
settingsController.GetAppMenu(),
|
settingsController.GetAppMenu(),
|
||||||
{
|
{
|
||||||
[this]() -> std::unique_ptr<Screen> { return CreateScreen1(); },
|
[this]() -> std::unique_ptr<Screen> {
|
||||||
[this]() -> std::unique_ptr<Screen> { return CreateScreen2(); },
|
return CreateScreen1();
|
||||||
//[this]() -> std::unique_ptr<Screen> { return CreateScreen3(); }
|
},
|
||||||
},
|
[this]() -> std::unique_ptr<Screen> {
|
||||||
Screens::ScreenListModes::UpDown
|
return CreateScreen2();
|
||||||
} {}
|
},
|
||||||
|
//[this]() -> std::unique_ptr<Screen> { return CreateScreen3(); }
|
||||||
|
},
|
||||||
|
Screens::ScreenListModes::UpDown} {
|
||||||
|
}
|
||||||
|
|
||||||
ApplicationList::~ApplicationList() {
|
ApplicationList::~ApplicationList() {
|
||||||
lv_obj_clean(lv_scr_act());
|
lv_obj_clean(lv_scr_act());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ApplicationList::Refresh() {
|
bool ApplicationList::Refresh() {
|
||||||
if(running)
|
if (running)
|
||||||
running = screens.Refresh();
|
running = screens.Refresh();
|
||||||
return running;
|
return running;
|
||||||
}
|
}
|
||||||
|
@ -42,31 +45,27 @@ bool ApplicationList::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Screen> ApplicationList::CreateScreen1() {
|
std::unique_ptr<Screen> ApplicationList::CreateScreen1() {
|
||||||
std::array<Screens::Tile::Applications, 6> applications {
|
std::array<Screens::Tile::Applications, 6> applications {{
|
||||||
{
|
{Symbols::stopWatch, Apps::StopWatch},
|
||||||
{Symbols::stopWatch, Apps::StopWatch},
|
{Symbols::music, Apps::Music},
|
||||||
{Symbols::music, Apps::Music},
|
{Symbols::map, Apps::Navigation},
|
||||||
{Symbols::map, Apps::Navigation},
|
{Symbols::shoe, Apps::Steps},
|
||||||
{Symbols::shoe, Apps::Steps},
|
{Symbols::heartBeat, Apps::HeartRate},
|
||||||
{Symbols::heartBeat, Apps::HeartRate},
|
{"", Apps::None},
|
||||||
{"", Apps::None},
|
}};
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return std::make_unique<Screens::Tile>(0, 2, app, settingsController, batteryController, dateTimeController, applications);
|
return std::make_unique<Screens::Tile>(0, 2, app, settingsController, batteryController, dateTimeController, applications);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Screen> ApplicationList::CreateScreen2() {
|
std::unique_ptr<Screen> ApplicationList::CreateScreen2() {
|
||||||
std::array<Screens::Tile::Applications, 6> applications {
|
std::array<Screens::Tile::Applications, 6> applications {{
|
||||||
{
|
{Symbols::paintbrush, Apps::Paint},
|
||||||
{Symbols::paintbrush, Apps::Paint},
|
{Symbols::paddle, Apps::Paddle},
|
||||||
{Symbols::paddle, Apps::Paddle},
|
{"2", Apps::Twos},
|
||||||
{"2", Apps::Twos},
|
{"M", Apps::Motion},
|
||||||
{"M", Apps::Motion},
|
{"", Apps::None},
|
||||||
{"", Apps::None},
|
{"", Apps::None},
|
||||||
{"", Apps::None},
|
}};
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return std::make_unique<Screens::Tile>(1, 2, app, settingsController, batteryController, dateTimeController, applications);
|
return std::make_unique<Screens::Tile>(1, 2, app, settingsController, batteryController, dateTimeController, applications);
|
||||||
}
|
}
|
||||||
|
@ -84,4 +83,3 @@ std::unique_ptr<Screen> ApplicationList::CreateScreen2() {
|
||||||
|
|
||||||
return std::make_unique<Screens::Tile>(2, 3, app, settingsController, batteryController, dateTimeController, applications);
|
return std::make_unique<Screens::Tile>(2, 3, app, settingsController, batteryController, dateTimeController, applications);
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
|
|
|
@ -12,24 +12,24 @@ namespace Pinetime {
|
||||||
namespace Applications {
|
namespace Applications {
|
||||||
namespace Screens {
|
namespace Screens {
|
||||||
class ApplicationList : public Screen {
|
class ApplicationList : public Screen {
|
||||||
public:
|
public:
|
||||||
explicit ApplicationList(DisplayApp* app,
|
explicit ApplicationList(DisplayApp* app,
|
||||||
Pinetime::Controllers::Settings &settingsController,
|
Pinetime::Controllers::Settings& settingsController,
|
||||||
Pinetime::Controllers::Battery& batteryController,
|
Pinetime::Controllers::Battery& batteryController,
|
||||||
Controllers::DateTime& dateTimeController);
|
Controllers::DateTime& dateTimeController);
|
||||||
~ApplicationList() override;
|
~ApplicationList() override;
|
||||||
bool Refresh() override;
|
bool Refresh() override;
|
||||||
bool OnTouchEvent(TouchEvents event) override;
|
bool OnTouchEvent(TouchEvents event) override;
|
||||||
private:
|
|
||||||
|
|
||||||
Controllers::Settings& settingsController;
|
private:
|
||||||
Pinetime::Controllers::Battery& batteryController;
|
Controllers::Settings& settingsController;
|
||||||
Controllers::DateTime& dateTimeController;
|
Pinetime::Controllers::Battery& batteryController;
|
||||||
|
Controllers::DateTime& dateTimeController;
|
||||||
|
|
||||||
ScreenList<2> screens;
|
ScreenList<2> screens;
|
||||||
std::unique_ptr<Screen> CreateScreen1();
|
std::unique_ptr<Screen> CreateScreen1();
|
||||||
std::unique_ptr<Screen> CreateScreen2();
|
std::unique_ptr<Screen> CreateScreen2();
|
||||||
//std::unique_ptr<Screen> CreateScreen3();
|
// std::unique_ptr<Screen> CreateScreen3();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,10 +4,14 @@
|
||||||
using namespace Pinetime::Applications::Screens;
|
using namespace Pinetime::Applications::Screens;
|
||||||
|
|
||||||
const char* BatteryIcon::GetBatteryIcon(int batteryPercent) {
|
const char* BatteryIcon::GetBatteryIcon(int batteryPercent) {
|
||||||
if(batteryPercent > 90) return Symbols::batteryFull;
|
if (batteryPercent > 90)
|
||||||
if(batteryPercent > 75) return Symbols::batteryThreeQuarter;
|
return Symbols::batteryFull;
|
||||||
if(batteryPercent > 50) return Symbols::batteryHalf;
|
if (batteryPercent > 75)
|
||||||
if(batteryPercent > 25) return Symbols::batteryOneQuarter;
|
return Symbols::batteryThreeQuarter;
|
||||||
|
if (batteryPercent > 50)
|
||||||
|
return Symbols::batteryHalf;
|
||||||
|
if (batteryPercent > 25)
|
||||||
|
return Symbols::batteryOneQuarter;
|
||||||
return Symbols::batteryEmpty;
|
return Symbols::batteryEmpty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,8 +19,9 @@ const char* BatteryIcon::GetUnknownIcon() {
|
||||||
return Symbols::batteryEmpty;
|
return Symbols::batteryEmpty;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *BatteryIcon::GetPlugIcon(bool isCharging) {
|
const char* BatteryIcon::GetPlugIcon(bool isCharging) {
|
||||||
if(isCharging)
|
if (isCharging)
|
||||||
return Symbols::plug;
|
return Symbols::plug;
|
||||||
else return "";
|
else
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,8 +6,8 @@ namespace Pinetime {
|
||||||
class BatteryIcon {
|
class BatteryIcon {
|
||||||
public:
|
public:
|
||||||
static const char* GetUnknownIcon();
|
static const char* GetUnknownIcon();
|
||||||
static const char* GetBatteryIcon(int batteryPercent);
|
static const char* GetBatteryIcon(int batteryPercent);
|
||||||
static const char* GetPlugIcon(bool isCharging);
|
static const char* GetPlugIcon(bool isCharging);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,22 +4,18 @@
|
||||||
|
|
||||||
using namespace Pinetime::Applications::Screens;
|
using namespace Pinetime::Applications::Screens;
|
||||||
|
|
||||||
static void lv_update_task(struct _lv_task_t *task) {
|
static void lv_update_task(struct _lv_task_t* task) {
|
||||||
auto user_data = static_cast<BatteryInfo *>(task->user_data);
|
auto user_data = static_cast<BatteryInfo*>(task->user_data);
|
||||||
user_data->UpdateScreen();
|
user_data->UpdateScreen();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lv_anim_task(struct _lv_task_t *task) {
|
static void lv_anim_task(struct _lv_task_t* task) {
|
||||||
auto user_data = static_cast<BatteryInfo *>(task->user_data);
|
auto user_data = static_cast<BatteryInfo*>(task->user_data);
|
||||||
user_data->UpdateAnim();
|
user_data->UpdateAnim();
|
||||||
}
|
}
|
||||||
|
|
||||||
BatteryInfo::BatteryInfo(
|
BatteryInfo::BatteryInfo(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Battery& batteryController)
|
||||||
Pinetime::Applications::DisplayApp *app,
|
: Screen(app), batteryController {batteryController} {
|
||||||
Pinetime::Controllers::Battery& batteryController) :
|
|
||||||
Screen(app),
|
|
||||||
batteryController{batteryController}
|
|
||||||
{
|
|
||||||
|
|
||||||
batteryPercent = batteryController.PercentRemaining();
|
batteryPercent = batteryController.PercentRemaining();
|
||||||
batteryVoltage = batteryController.Voltage();
|
batteryVoltage = batteryController.Voltage();
|
||||||
|
@ -32,37 +28,38 @@ BatteryInfo::BatteryInfo(
|
||||||
lv_obj_set_style_local_radius(charging_bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
|
lv_obj_set_style_local_radius(charging_bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
|
||||||
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, lv_color_hex(0x222222));
|
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, lv_color_hex(0x222222));
|
||||||
lv_obj_set_style_local_bg_opa(charging_bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, LV_OPA_100);
|
lv_obj_set_style_local_bg_opa(charging_bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, LV_OPA_100);
|
||||||
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC , LV_STATE_DEFAULT, lv_color_hex(0xFF0000));
|
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, lv_color_hex(0xFF0000));
|
||||||
lv_bar_set_value(charging_bar, batteryPercent, LV_ANIM_OFF);
|
lv_bar_set_value(charging_bar, batteryPercent, LV_ANIM_OFF);
|
||||||
|
|
||||||
status = lv_label_create(lv_scr_act(), nullptr);
|
status = lv_label_create(lv_scr_act(), nullptr);
|
||||||
lv_label_set_text_static(status,"Reading Battery status");
|
lv_label_set_text_static(status, "Reading Battery status");
|
||||||
lv_label_set_align(status, LV_LABEL_ALIGN_CENTER);
|
lv_label_set_align(status, LV_LABEL_ALIGN_CENTER);
|
||||||
lv_obj_align(status, charging_bar, LV_ALIGN_OUT_BOTTOM_MID, 0, 20);
|
lv_obj_align(status, charging_bar, LV_ALIGN_OUT_BOTTOM_MID, 0, 20);
|
||||||
|
|
||||||
percent = lv_label_create(lv_scr_act(), nullptr);
|
percent = lv_label_create(lv_scr_act(), nullptr);
|
||||||
lv_obj_set_style_local_text_font(percent, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76);
|
lv_obj_set_style_local_text_font(percent, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76);
|
||||||
if ( batteryPercent >= 0) {
|
if (batteryPercent >= 0) {
|
||||||
lv_label_set_text_fmt(percent,"%02i%%", batteryPercent);
|
lv_label_set_text_fmt(percent, "%02i%%", batteryPercent);
|
||||||
} else {
|
} else {
|
||||||
lv_label_set_text(percent,"--%");
|
lv_label_set_text(percent, "--%");
|
||||||
}
|
}
|
||||||
lv_label_set_align(percent, LV_LABEL_ALIGN_LEFT);
|
lv_label_set_align(percent, LV_LABEL_ALIGN_LEFT);
|
||||||
lv_obj_align(percent, nullptr, LV_ALIGN_CENTER, 0, -60);
|
lv_obj_align(percent, nullptr, LV_ALIGN_CENTER, 0, -60);
|
||||||
|
|
||||||
// hack to not use the flot functions from printf
|
// hack to not use the flot functions from printf
|
||||||
uint8_t batteryVoltageBytes[2];
|
uint8_t batteryVoltageBytes[2];
|
||||||
batteryVoltageBytes[1] = static_cast<uint8_t>(batteryVoltage); //truncate whole numbers
|
batteryVoltageBytes[1] = static_cast<uint8_t>(batteryVoltage); // truncate whole numbers
|
||||||
batteryVoltageBytes[0] = static_cast<uint8_t>((batteryVoltage - batteryVoltageBytes[1]) * 100); //remove whole part of flt and shift 2 places over
|
batteryVoltageBytes[0] =
|
||||||
|
static_cast<uint8_t>((batteryVoltage - batteryVoltageBytes[1]) * 100); // remove whole part of flt and shift 2 places over
|
||||||
//
|
//
|
||||||
|
|
||||||
voltage = lv_label_create(lv_scr_act(), nullptr);
|
voltage = lv_label_create(lv_scr_act(), nullptr);
|
||||||
lv_obj_set_style_local_text_color(voltage, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xC6A600));
|
lv_obj_set_style_local_text_color(voltage, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xC6A600));
|
||||||
lv_label_set_text_fmt(voltage,"%1i.%02i volts", batteryVoltageBytes[1], batteryVoltageBytes[0]);
|
lv_label_set_text_fmt(voltage, "%1i.%02i volts", batteryVoltageBytes[1], batteryVoltageBytes[0]);
|
||||||
lv_label_set_align(voltage, LV_LABEL_ALIGN_CENTER);
|
lv_label_set_align(voltage, LV_LABEL_ALIGN_CENTER);
|
||||||
lv_obj_align(voltage, nullptr, LV_ALIGN_CENTER, 0, 95);
|
lv_obj_align(voltage, nullptr, LV_ALIGN_CENTER, 0, 95);
|
||||||
|
|
||||||
lv_obj_t * backgroundLabel = lv_label_create(lv_scr_act(), nullptr);
|
lv_obj_t* backgroundLabel = lv_label_create(lv_scr_act(), nullptr);
|
||||||
lv_label_set_long_mode(backgroundLabel, LV_LABEL_LONG_CROP);
|
lv_label_set_long_mode(backgroundLabel, LV_LABEL_LONG_CROP);
|
||||||
lv_obj_set_size(backgroundLabel, 240, 240);
|
lv_obj_set_size(backgroundLabel, 240, 240);
|
||||||
lv_obj_set_pos(backgroundLabel, 0, 0);
|
lv_obj_set_pos(backgroundLabel, 0, 0);
|
||||||
|
@ -73,7 +70,6 @@ BatteryInfo::BatteryInfo(
|
||||||
UpdateScreen();
|
UpdateScreen();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
BatteryInfo::~BatteryInfo() {
|
BatteryInfo::~BatteryInfo() {
|
||||||
lv_task_del(taskUpdate);
|
lv_task_del(taskUpdate);
|
||||||
lv_task_del(taskAnim);
|
lv_task_del(taskAnim);
|
||||||
|
@ -83,9 +79,9 @@ BatteryInfo::~BatteryInfo() {
|
||||||
void BatteryInfo::UpdateAnim() {
|
void BatteryInfo::UpdateAnim() {
|
||||||
batteryPercent = batteryController.PercentRemaining();
|
batteryPercent = batteryController.PercentRemaining();
|
||||||
|
|
||||||
if ( batteryPercent >= 0 ) {
|
if (batteryPercent >= 0) {
|
||||||
if ( batteryController.IsCharging() and batteryPercent < 100 ) {
|
if (batteryController.IsCharging() and batteryPercent < 100) {
|
||||||
animation +=1;
|
animation += 1;
|
||||||
if (animation >= 100) {
|
if (animation >= 100) {
|
||||||
animation = 0;
|
animation = 0;
|
||||||
}
|
}
|
||||||
|
@ -110,40 +106,39 @@ void BatteryInfo::UpdateScreen() {
|
||||||
batteryPercent = batteryController.PercentRemaining();
|
batteryPercent = batteryController.PercentRemaining();
|
||||||
batteryVoltage = batteryController.Voltage();
|
batteryVoltage = batteryController.Voltage();
|
||||||
|
|
||||||
if ( batteryPercent >= 0 ) {
|
if (batteryPercent >= 0) {
|
||||||
if ( batteryController.IsCharging() and batteryPercent < 100 ) {
|
if (batteryController.IsCharging() and batteryPercent < 100) {
|
||||||
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC , LV_STATE_DEFAULT, LV_COLOR_RED);
|
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_RED);
|
||||||
lv_label_set_text_static(status,"Battery charging");
|
lv_label_set_text_static(status, "Battery charging");
|
||||||
} else if ( batteryPercent == 100 ) {
|
} else if (batteryPercent == 100) {
|
||||||
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC , LV_STATE_DEFAULT, LV_COLOR_BLUE);
|
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_BLUE);
|
||||||
lv_label_set_text_static(status,"Battery is fully charged");
|
lv_label_set_text_static(status, "Battery is fully charged");
|
||||||
} else if ( batteryPercent < 10 ) {
|
} else if (batteryPercent < 10) {
|
||||||
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC , LV_STATE_DEFAULT, LV_COLOR_YELLOW);
|
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_YELLOW);
|
||||||
lv_label_set_text_static(status,"Battery is low");
|
lv_label_set_text_static(status, "Battery is low");
|
||||||
} else {
|
} else {
|
||||||
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC , LV_STATE_DEFAULT, LV_COLOR_GREEN);
|
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_GREEN);
|
||||||
lv_label_set_text_static(status,"Battery discharging");
|
lv_label_set_text_static(status, "Battery discharging");
|
||||||
}
|
}
|
||||||
|
|
||||||
lv_label_set_text_fmt(percent,"%02i%%", batteryPercent);
|
lv_label_set_text_fmt(percent, "%02i%%", batteryPercent);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
lv_label_set_text_static(status,"Reading Battery status");
|
lv_label_set_text_static(status, "Reading Battery status");
|
||||||
lv_label_set_text(percent,"--%");
|
lv_label_set_text(percent, "--%");
|
||||||
}
|
}
|
||||||
|
|
||||||
lv_obj_align(status, charging_bar, LV_ALIGN_OUT_BOTTOM_MID, 0, 20);
|
lv_obj_align(status, charging_bar, LV_ALIGN_OUT_BOTTOM_MID, 0, 20);
|
||||||
// hack to not use the flot functions from printf
|
// hack to not use the flot functions from printf
|
||||||
uint8_t batteryVoltageBytes[2];
|
uint8_t batteryVoltageBytes[2];
|
||||||
batteryVoltageBytes[1] = static_cast<uint8_t>(batteryVoltage); //truncate whole numbers
|
batteryVoltageBytes[1] = static_cast<uint8_t>(batteryVoltage); // truncate whole numbers
|
||||||
batteryVoltageBytes[0] = static_cast<uint8_t>((batteryVoltage - batteryVoltageBytes[1]) * 100); //remove whole part of flt and shift 2 places over
|
batteryVoltageBytes[0] =
|
||||||
|
static_cast<uint8_t>((batteryVoltage - batteryVoltageBytes[1]) * 100); // remove whole part of flt and shift 2 places over
|
||||||
//
|
//
|
||||||
lv_label_set_text_fmt(voltage,"%1i.%02i volts", batteryVoltageBytes[1], batteryVoltageBytes[0]);
|
lv_label_set_text_fmt(voltage, "%1i.%02i volts", batteryVoltageBytes[1], batteryVoltageBytes[0]);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BatteryInfo::Refresh() {
|
bool BatteryInfo::Refresh() {
|
||||||
|
|
||||||
return running;
|
return running;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
#include "Screen.h"
|
#include "Screen.h"
|
||||||
#include <lvgl/lvgl.h>
|
#include <lvgl/lvgl.h>
|
||||||
|
|
||||||
|
|
||||||
namespace Pinetime {
|
namespace Pinetime {
|
||||||
namespace Controllers {
|
namespace Controllers {
|
||||||
class Battery;
|
class Battery;
|
||||||
|
@ -15,34 +14,30 @@ namespace Pinetime {
|
||||||
namespace Applications {
|
namespace Applications {
|
||||||
namespace Screens {
|
namespace Screens {
|
||||||
|
|
||||||
class BatteryInfo : public Screen{
|
class BatteryInfo : public Screen {
|
||||||
public:
|
public:
|
||||||
BatteryInfo(DisplayApp* app,
|
BatteryInfo(DisplayApp* app, Pinetime::Controllers::Battery& batteryController);
|
||||||
Pinetime::Controllers::Battery& batteryController);
|
~BatteryInfo() override;
|
||||||
~BatteryInfo() override;
|
|
||||||
|
|
||||||
bool Refresh() override;
|
bool Refresh() override;
|
||||||
|
|
||||||
|
void UpdateScreen();
|
||||||
|
void UpdateAnim();
|
||||||
|
|
||||||
void UpdateScreen();
|
private:
|
||||||
void UpdateAnim();
|
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_task_t* taskUpdate;
|
||||||
|
lv_task_t* taskAnim;
|
||||||
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;
|
|
||||||
|
|
||||||
|
int8_t animation = 0;
|
||||||
|
int8_t batteryPercent = -1;
|
||||||
|
float batteryVoltage = 0.0f;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
using namespace Pinetime::Applications::Screens;
|
using namespace Pinetime::Applications::Screens;
|
||||||
|
|
||||||
const char* BleIcon::GetIcon(bool isConnected) {
|
const char* BleIcon::GetIcon(bool isConnected) {
|
||||||
if(isConnected) return Symbols::bluetooth;
|
if (isConnected)
|
||||||
else return "";
|
return Symbols::bluetooth;
|
||||||
|
else
|
||||||
|
return "";
|
||||||
}
|
}
|
|
@ -3,14 +3,15 @@
|
||||||
|
|
||||||
using namespace Pinetime::Applications::Screens;
|
using namespace Pinetime::Applications::Screens;
|
||||||
|
|
||||||
void slider_event_cb(lv_obj_t * slider, lv_event_t event) {
|
void slider_event_cb(lv_obj_t* slider, lv_event_t event) {
|
||||||
if(event == LV_EVENT_VALUE_CHANGED) {
|
if (event == LV_EVENT_VALUE_CHANGED) {
|
||||||
auto* brightnessSlider = static_cast<Brightness*>(slider->user_data);
|
auto* brightnessSlider = static_cast<Brightness*>(slider->user_data);
|
||||||
brightnessSlider->OnValueChanged();
|
brightnessSlider->OnValueChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Brightness::Brightness(Pinetime::Applications::DisplayApp *app, Controllers::BrightnessController& brightness) : Screen(app), brightness{brightness} {
|
Brightness::Brightness(Pinetime::Applications::DisplayApp* app, Controllers::BrightnessController& brightness)
|
||||||
|
: Screen(app), brightness {brightness} {
|
||||||
slider = lv_slider_create(lv_scr_act(), nullptr);
|
slider = lv_slider_create(lv_scr_act(), nullptr);
|
||||||
lv_obj_set_user_data(slider, this);
|
lv_obj_set_user_data(slider, this);
|
||||||
lv_obj_set_width(slider, LV_DPI * 2);
|
lv_obj_set_width(slider, LV_DPI * 2);
|
||||||
|
@ -33,13 +34,18 @@ bool Brightness::Refresh() {
|
||||||
return running;
|
return running;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *Brightness::LevelToString(Pinetime::Controllers::BrightnessController::Levels level) {
|
const char* Brightness::LevelToString(Pinetime::Controllers::BrightnessController::Levels level) {
|
||||||
switch(level) {
|
switch (level) {
|
||||||
case Pinetime::Controllers::BrightnessController::Levels::Off: return "Off";
|
case Pinetime::Controllers::BrightnessController::Levels::Off:
|
||||||
case Pinetime::Controllers::BrightnessController::Levels::Low: return "Low";
|
return "Off";
|
||||||
case Pinetime::Controllers::BrightnessController::Levels::Medium: return "Medium";
|
case Pinetime::Controllers::BrightnessController::Levels::Low:
|
||||||
case Pinetime::Controllers::BrightnessController::Levels::High: return "High";
|
return "Low";
|
||||||
default : return "???";
|
case Pinetime::Controllers::BrightnessController::Levels::Medium:
|
||||||
|
return "Medium";
|
||||||
|
case Pinetime::Controllers::BrightnessController::Levels::High:
|
||||||
|
return "High";
|
||||||
|
default:
|
||||||
|
return "???";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,29 +54,40 @@ void Brightness::OnValueChanged() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Brightness::SetValue(uint8_t value) {
|
void Brightness::SetValue(uint8_t value) {
|
||||||
switch(value) {
|
switch (value) {
|
||||||
case 0: brightness.Set(Controllers::BrightnessController::Levels::Low); break;
|
case 0:
|
||||||
case 1: brightness.Set(Controllers::BrightnessController::Levels::Medium); break;
|
brightness.Set(Controllers::BrightnessController::Levels::Low);
|
||||||
case 2: brightness.Set(Controllers::BrightnessController::Levels::High); break;
|
break;
|
||||||
|
case 1:
|
||||||
|
brightness.Set(Controllers::BrightnessController::Levels::Medium);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
brightness.Set(Controllers::BrightnessController::Levels::High);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
lv_label_set_text(slider_label, LevelToString(brightness.Level()));
|
lv_label_set_text(slider_label, LevelToString(brightness.Level()));
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t Brightness::LevelToInt(Pinetime::Controllers::BrightnessController::Levels level) {
|
uint8_t Brightness::LevelToInt(Pinetime::Controllers::BrightnessController::Levels level) {
|
||||||
switch(level) {
|
switch (level) {
|
||||||
case Pinetime::Controllers::BrightnessController::Levels::Off: return 0;
|
case Pinetime::Controllers::BrightnessController::Levels::Off:
|
||||||
case Pinetime::Controllers::BrightnessController::Levels::Low: return 0;
|
return 0;
|
||||||
case Pinetime::Controllers::BrightnessController::Levels::Medium: return 1;
|
case Pinetime::Controllers::BrightnessController::Levels::Low:
|
||||||
case Pinetime::Controllers::BrightnessController::Levels::High: return 2;
|
return 0;
|
||||||
default : return 0;
|
case Pinetime::Controllers::BrightnessController::Levels::Medium:
|
||||||
|
return 1;
|
||||||
|
case Pinetime::Controllers::BrightnessController::Levels::High:
|
||||||
|
return 2;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Brightness::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
bool Brightness::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
||||||
switch(event) {
|
switch (event) {
|
||||||
case TouchEvents::SwipeLeft:
|
case TouchEvents::SwipeLeft:
|
||||||
brightness.Lower();
|
brightness.Lower();
|
||||||
if ( brightness.Level() == Pinetime::Controllers::BrightnessController::Levels::Off) {
|
if (brightness.Level() == Pinetime::Controllers::BrightnessController::Levels::Off) {
|
||||||
brightness.Set(Controllers::BrightnessController::Levels::Low);
|
brightness.Set(Controllers::BrightnessController::Levels::Low);
|
||||||
}
|
}
|
||||||
SetValue();
|
SetValue();
|
||||||
|
|
|
@ -9,25 +9,25 @@ namespace Pinetime {
|
||||||
namespace Applications {
|
namespace Applications {
|
||||||
namespace Screens {
|
namespace Screens {
|
||||||
class Brightness : public Screen {
|
class Brightness : public Screen {
|
||||||
public:
|
public:
|
||||||
Brightness(DisplayApp* app, Controllers::BrightnessController& brightness);
|
Brightness(DisplayApp* app, Controllers::BrightnessController& brightness);
|
||||||
~Brightness() override;
|
~Brightness() override;
|
||||||
bool Refresh() override;
|
bool Refresh() override;
|
||||||
|
|
||||||
bool OnTouchEvent(TouchEvents event) override;
|
bool OnTouchEvent(TouchEvents event) override;
|
||||||
|
|
||||||
void OnValueChanged();
|
void OnValueChanged();
|
||||||
private:
|
|
||||||
|
|
||||||
Controllers::BrightnessController& brightness;
|
private:
|
||||||
|
Controllers::BrightnessController& brightness;
|
||||||
|
|
||||||
lv_obj_t * slider_label;
|
lv_obj_t* slider_label;
|
||||||
lv_obj_t * slider;
|
lv_obj_t* slider;
|
||||||
|
|
||||||
const char* LevelToString(Controllers::BrightnessController::Levels level);
|
const char* LevelToString(Controllers::BrightnessController::Levels level);
|
||||||
uint8_t LevelToInt(Controllers::BrightnessController::Levels level);
|
uint8_t LevelToInt(Controllers::BrightnessController::Levels level);
|
||||||
void SetValue(uint8_t value);
|
void SetValue(uint8_t value);
|
||||||
void SetValue();
|
void SetValue();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,43 +15,46 @@
|
||||||
#include "WatchFaceDigital.h"
|
#include "WatchFaceDigital.h"
|
||||||
#include "WatchFaceAnalog.h"
|
#include "WatchFaceAnalog.h"
|
||||||
|
|
||||||
|
|
||||||
using namespace Pinetime::Applications::Screens;
|
using namespace Pinetime::Applications::Screens;
|
||||||
|
|
||||||
Clock::Clock(DisplayApp* app,
|
Clock::Clock(DisplayApp* app,
|
||||||
Controllers::DateTime& dateTimeController,
|
Controllers::DateTime& dateTimeController,
|
||||||
Controllers::Battery& batteryController,
|
Controllers::Battery& batteryController,
|
||||||
Controllers::Ble& bleController,
|
Controllers::Ble& bleController,
|
||||||
Controllers::NotificationManager& notificatioManager,
|
Controllers::NotificationManager& notificatioManager,
|
||||||
Controllers::Settings &settingsController,
|
Controllers::Settings& settingsController,
|
||||||
Controllers::HeartRateController& heartRateController,
|
Controllers::HeartRateController& heartRateController,
|
||||||
Controllers::MotionController& motionController) : Screen(app),
|
Controllers::MotionController& motionController)
|
||||||
dateTimeController{dateTimeController}, batteryController{batteryController},
|
: Screen(app),
|
||||||
bleController{bleController}, notificatioManager{notificatioManager},
|
dateTimeController {dateTimeController},
|
||||||
settingsController{settingsController},
|
batteryController {batteryController},
|
||||||
heartRateController{heartRateController},
|
bleController {bleController},
|
||||||
motionController{motionController},
|
notificatioManager {notificatioManager},
|
||||||
screens{app,
|
settingsController {settingsController},
|
||||||
settingsController.GetClockFace(),
|
heartRateController {heartRateController},
|
||||||
{
|
motionController {motionController},
|
||||||
[this]() -> std::unique_ptr<Screen> { return WatchFaceDigitalScreen(); },
|
screens {app,
|
||||||
[this]() -> std::unique_ptr<Screen> { return WatchFaceAnalogScreen(); },
|
settingsController.GetClockFace(),
|
||||||
// Examples for more watch faces
|
{
|
||||||
//[this]() -> std::unique_ptr<Screen> { return WatchFaceMinimalScreen(); },
|
[this]() -> std::unique_ptr<Screen> {
|
||||||
//[this]() -> std::unique_ptr<Screen> { return WatchFaceCustomScreen(); }
|
return WatchFaceDigitalScreen();
|
||||||
},
|
},
|
||||||
Screens::ScreenListModes::LongPress
|
[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() {
|
Clock::~Clock() {
|
||||||
lv_obj_clean(lv_scr_act());
|
lv_obj_clean(lv_scr_act());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Clock::Refresh() {
|
bool Clock::Refresh() {
|
||||||
screens.Refresh();
|
screens.Refresh();
|
||||||
return running;
|
return running;
|
||||||
|
@ -62,20 +65,30 @@ bool Clock::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Screen> Clock::WatchFaceDigitalScreen() {
|
std::unique_ptr<Screen> Clock::WatchFaceDigitalScreen() {
|
||||||
return std::make_unique<Screens::WatchFaceDigital>(app, dateTimeController, batteryController, bleController, notificatioManager, settingsController, heartRateController, motionController);
|
return std::make_unique<Screens::WatchFaceDigital>(app,
|
||||||
|
dateTimeController,
|
||||||
|
batteryController,
|
||||||
|
bleController,
|
||||||
|
notificatioManager,
|
||||||
|
settingsController,
|
||||||
|
heartRateController,
|
||||||
|
motionController);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Screen> Clock::WatchFaceAnalogScreen() {
|
std::unique_ptr<Screen> Clock::WatchFaceAnalogScreen() {
|
||||||
return std::make_unique<Screens::WatchFaceAnalog>(app, dateTimeController, batteryController, bleController, notificatioManager, settingsController);
|
return std::make_unique<Screens::WatchFaceAnalog>(
|
||||||
|
app, dateTimeController, batteryController, bleController, notificatioManager, settingsController);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// Examples for more watch faces
|
// Examples for more watch faces
|
||||||
std::unique_ptr<Screen> Clock::WatchFaceMinimalScreen() {
|
std::unique_ptr<Screen> Clock::WatchFaceMinimalScreen() {
|
||||||
return std::make_unique<Screens::WatchFaceMinimal>(app, dateTimeController, batteryController, bleController, notificatioManager, settingsController);
|
return std::make_unique<Screens::WatchFaceMinimal>(app, dateTimeController, batteryController, bleController, notificatioManager,
|
||||||
|
settingsController);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Screen> Clock::WatchFaceCustomScreen() {
|
std::unique_ptr<Screen> Clock::WatchFaceCustomScreen() {
|
||||||
return std::make_unique<Screens::WatchFaceCustom>(app, dateTimeController, batteryController, bleController, notificatioManager, settingsController);
|
return std::make_unique<Screens::WatchFaceCustom>(app, dateTimeController, batteryController, bleController, notificatioManager,
|
||||||
|
settingsController);
|
||||||
}
|
}
|
||||||
*/
|
*/
|
|
@ -23,42 +23,37 @@ namespace Pinetime {
|
||||||
namespace Applications {
|
namespace Applications {
|
||||||
namespace Screens {
|
namespace Screens {
|
||||||
class Clock : public Screen {
|
class Clock : public Screen {
|
||||||
public:
|
public:
|
||||||
Clock(DisplayApp* app,
|
Clock(DisplayApp* app,
|
||||||
Controllers::DateTime& dateTimeController,
|
Controllers::DateTime& dateTimeController,
|
||||||
Controllers::Battery& batteryController,
|
Controllers::Battery& batteryController,
|
||||||
Controllers::Ble& bleController,
|
Controllers::Ble& bleController,
|
||||||
Controllers::NotificationManager& notificatioManager,
|
Controllers::NotificationManager& notificatioManager,
|
||||||
Controllers::Settings &settingsController,
|
Controllers::Settings& settingsController,
|
||||||
Controllers::HeartRateController& heartRateController,
|
Controllers::HeartRateController& heartRateController,
|
||||||
Controllers::MotionController& motionController);
|
Controllers::MotionController& motionController);
|
||||||
~Clock() override;
|
~Clock() override;
|
||||||
|
|
||||||
bool Refresh() override;
|
bool Refresh() override;
|
||||||
|
|
||||||
bool OnTouchEvent(TouchEvents event) 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();
|
|
||||||
|
|
||||||
|
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();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,20 +5,21 @@
|
||||||
|
|
||||||
using namespace Pinetime::Applications::Screens;
|
using namespace Pinetime::Applications::Screens;
|
||||||
|
|
||||||
DropDownDemo::DropDownDemo(Pinetime::Applications::DisplayApp *app) : Screen(app) {
|
DropDownDemo::DropDownDemo(Pinetime::Applications::DisplayApp* app) : Screen(app) {
|
||||||
// Create the dropdown object, with many item, and fix its height
|
// Create the dropdown object, with many item, and fix its height
|
||||||
ddlist = lv_ddlist_create(lv_scr_act(), nullptr);
|
ddlist = lv_ddlist_create(lv_scr_act(), nullptr);
|
||||||
lv_ddlist_set_options(ddlist, "Apple\n"
|
lv_ddlist_set_options(ddlist,
|
||||||
"Banana\n"
|
"Apple\n"
|
||||||
"Orange\n"
|
"Banana\n"
|
||||||
"Melon\n"
|
"Orange\n"
|
||||||
"Grape\n"
|
"Melon\n"
|
||||||
"Raspberry\n"
|
"Grape\n"
|
||||||
"A\n"
|
"Raspberry\n"
|
||||||
"B\n"
|
"A\n"
|
||||||
"C\n"
|
"B\n"
|
||||||
"D\n"
|
"C\n"
|
||||||
"E");
|
"D\n"
|
||||||
|
"E");
|
||||||
lv_ddlist_set_fix_width(ddlist, 150);
|
lv_ddlist_set_fix_width(ddlist, 150);
|
||||||
lv_ddlist_set_draw_arrow(ddlist, true);
|
lv_ddlist_set_draw_arrow(ddlist, true);
|
||||||
lv_ddlist_set_fix_height(ddlist, 150);
|
lv_ddlist_set_fix_height(ddlist, 150);
|
||||||
|
@ -32,12 +33,12 @@ DropDownDemo::~DropDownDemo() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DropDownDemo::Refresh() {
|
bool DropDownDemo::Refresh() {
|
||||||
auto* list = static_cast<lv_ddlist_ext_t *>(ddlist->ext_attr);
|
auto* list = static_cast<lv_ddlist_ext_t*>(ddlist->ext_attr);
|
||||||
|
|
||||||
// Switch touchmode to Polling if the dropdown is opened. This will allow to scroll inside the
|
// Switch touchmode to Polling if the dropdown is opened. This will allow to scroll inside the
|
||||||
// dropdown while it is opened.
|
// dropdown while it is opened.
|
||||||
// Disable the polling mode when the dropdown is closed to be able to handle the gestures.
|
// Disable the polling mode when the dropdown is closed to be able to handle the gestures.
|
||||||
if(list->opened)
|
if (list->opened)
|
||||||
app->SetTouchMode(DisplayApp::TouchModes::Polling);
|
app->SetTouchMode(DisplayApp::TouchModes::Polling);
|
||||||
else
|
else
|
||||||
app->SetTouchMode(DisplayApp::TouchModes::Gestures);
|
app->SetTouchMode(DisplayApp::TouchModes::Gestures);
|
||||||
|
@ -47,11 +48,10 @@ bool DropDownDemo::Refresh() {
|
||||||
bool DropDownDemo::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
bool DropDownDemo::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
||||||
// If the dropdown is opened, notify Display app that it doesn't need to handle the event
|
// If the dropdown is opened, notify Display app that it doesn't need to handle the event
|
||||||
// (this will prevent displayApp from going back to the menu or clock scree).
|
// (this will prevent displayApp from going back to the menu or clock scree).
|
||||||
auto* list = static_cast<lv_ddlist_ext_t *>(ddlist->ext_attr);
|
auto* list = static_cast<lv_ddlist_ext_t*>(ddlist->ext_attr);
|
||||||
if(list->opened) {
|
if (list->opened) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,18 +9,18 @@ namespace Pinetime {
|
||||||
namespace Screens {
|
namespace Screens {
|
||||||
|
|
||||||
class DropDownDemo : public Screen {
|
class DropDownDemo : public Screen {
|
||||||
public:
|
public:
|
||||||
DropDownDemo(DisplayApp* app);
|
DropDownDemo(DisplayApp* app);
|
||||||
~DropDownDemo() override;
|
~DropDownDemo() override;
|
||||||
|
|
||||||
bool Refresh() override;
|
bool Refresh() override;
|
||||||
|
|
||||||
bool OnTouchEvent(TouchEvents event) override;
|
bool OnTouchEvent(TouchEvents event) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
lv_obj_t * ddlist;
|
lv_obj_t* ddlist;
|
||||||
|
|
||||||
bool isDropDownOpened = false;
|
bool isDropDownOpened = false;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,11 +5,10 @@
|
||||||
|
|
||||||
using namespace Pinetime::Applications::Screens;
|
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) :
|
lv_obj_t* backgroundLabel = lv_label_create(lv_scr_act(), nullptr);
|
||||||
Screen(app), bleController{bleController} {
|
|
||||||
|
|
||||||
lv_obj_t * backgroundLabel = lv_label_create(lv_scr_act(), nullptr);
|
|
||||||
lv_label_set_long_mode(backgroundLabel, LV_LABEL_LONG_CROP);
|
lv_label_set_long_mode(backgroundLabel, LV_LABEL_LONG_CROP);
|
||||||
lv_obj_set_size(backgroundLabel, 240, 240);
|
lv_obj_set_size(backgroundLabel, 240, 240);
|
||||||
lv_obj_set_pos(backgroundLabel, 0, 0);
|
lv_obj_set_pos(backgroundLabel, 0, 0);
|
||||||
|
@ -38,21 +37,21 @@ FirmwareUpdate::~FirmwareUpdate() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FirmwareUpdate::Refresh() {
|
bool FirmwareUpdate::Refresh() {
|
||||||
switch(bleController.State()) {
|
switch (bleController.State()) {
|
||||||
default:
|
default:
|
||||||
case Pinetime::Controllers::Ble::FirmwareUpdateStates::Idle:
|
case Pinetime::Controllers::Ble::FirmwareUpdateStates::Idle:
|
||||||
case Pinetime::Controllers::Ble::FirmwareUpdateStates::Running:
|
case Pinetime::Controllers::Ble::FirmwareUpdateStates::Running:
|
||||||
if(state != States::Running)
|
if (state != States::Running)
|
||||||
state = States::Running;
|
state = States::Running;
|
||||||
return DisplayProgression();
|
return DisplayProgression();
|
||||||
case Pinetime::Controllers::Ble::FirmwareUpdateStates::Validated:
|
case Pinetime::Controllers::Ble::FirmwareUpdateStates::Validated:
|
||||||
if(state != States::Validated) {
|
if (state != States::Validated) {
|
||||||
UpdateValidated();
|
UpdateValidated();
|
||||||
state = States::Validated;
|
state = States::Validated;
|
||||||
}
|
}
|
||||||
return running;
|
return running;
|
||||||
case Pinetime::Controllers::Ble::FirmwareUpdateStates::Error:
|
case Pinetime::Controllers::Ble::FirmwareUpdateStates::Error:
|
||||||
if(state != States::Error) {
|
if (state != States::Error) {
|
||||||
UpdateError();
|
UpdateError();
|
||||||
state = States::Error;
|
state = States::Error;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,29 +10,28 @@ namespace Pinetime {
|
||||||
namespace Applications {
|
namespace Applications {
|
||||||
namespace Screens {
|
namespace Screens {
|
||||||
|
|
||||||
class FirmwareUpdate : public Screen{
|
class FirmwareUpdate : public Screen {
|
||||||
public:
|
public:
|
||||||
FirmwareUpdate(DisplayApp* app, Pinetime::Controllers::Ble& bleController);
|
FirmwareUpdate(DisplayApp* app, Pinetime::Controllers::Ble& bleController);
|
||||||
~FirmwareUpdate() override;
|
~FirmwareUpdate() override;
|
||||||
|
|
||||||
bool Refresh() override;
|
bool Refresh() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
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:
|
States state;
|
||||||
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;
|
bool DisplayProgression() const;
|
||||||
|
|
||||||
bool DisplayProgression() const;
|
void UpdateValidated();
|
||||||
|
|
||||||
void UpdateValidated();
|
void UpdateError();
|
||||||
|
|
||||||
void UpdateError();
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,23 +7,20 @@
|
||||||
using namespace Pinetime::Applications::Screens;
|
using namespace Pinetime::Applications::Screens;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
static void ButtonEventHandler(lv_obj_t * obj, lv_event_t event)
|
static void ButtonEventHandler(lv_obj_t* obj, lv_event_t event) {
|
||||||
{
|
FirmwareValidation* screen = static_cast<FirmwareValidation*>(obj->user_data);
|
||||||
FirmwareValidation* screen = static_cast<FirmwareValidation *>(obj->user_data);
|
|
||||||
screen->OnButtonEvent(obj, event);
|
screen->OnButtonEvent(obj, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FirmwareValidation::FirmwareValidation(Pinetime::Applications::DisplayApp *app,
|
FirmwareValidation::FirmwareValidation(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::FirmwareValidator& validator)
|
||||||
Pinetime::Controllers::FirmwareValidator &validator)
|
: Screen {app}, validator {validator} {
|
||||||
: Screen{app}, validator{validator} {
|
|
||||||
labelVersionInfo = lv_label_create(lv_scr_act(), nullptr);
|
labelVersionInfo = lv_label_create(lv_scr_act(), nullptr);
|
||||||
lv_obj_align(labelVersionInfo, nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0);
|
lv_obj_align(labelVersionInfo, nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0);
|
||||||
lv_label_set_text(labelVersionInfo, "Version : ");
|
lv_label_set_text(labelVersionInfo, "Version : ");
|
||||||
lv_label_set_align(labelVersionInfo, LV_LABEL_ALIGN_LEFT);
|
lv_label_set_align(labelVersionInfo, LV_LABEL_ALIGN_LEFT);
|
||||||
|
|
||||||
|
|
||||||
labelVersionValue = lv_label_create(lv_scr_act(), nullptr);
|
labelVersionValue = lv_label_create(lv_scr_act(), nullptr);
|
||||||
lv_obj_align(labelVersionValue, labelVersionInfo, LV_ALIGN_OUT_RIGHT_MID, 0, 0);
|
lv_obj_align(labelVersionValue, labelVersionInfo, LV_ALIGN_OUT_RIGHT_MID, 0, 0);
|
||||||
lv_label_set_recolor(labelVersionValue, true);
|
lv_label_set_recolor(labelVersionValue, true);
|
||||||
|
@ -36,11 +33,10 @@ FirmwareValidation::FirmwareValidation(Pinetime::Applications::DisplayApp *app,
|
||||||
lv_label_set_long_mode(labelIsValidated, LV_LABEL_LONG_BREAK);
|
lv_label_set_long_mode(labelIsValidated, LV_LABEL_LONG_BREAK);
|
||||||
lv_obj_set_width(labelIsValidated, 240);
|
lv_obj_set_width(labelIsValidated, 240);
|
||||||
|
|
||||||
if(validator.IsValidated())
|
if (validator.IsValidated())
|
||||||
lv_label_set_text(labelIsValidated, "You have already\n#00ff00 validated# this firmware#");
|
lv_label_set_text(labelIsValidated, "You have already\n#00ff00 validated# this firmware#");
|
||||||
else {
|
else {
|
||||||
lv_label_set_text(labelIsValidated,
|
lv_label_set_text(labelIsValidated, "Please #00ff00 Validate# this version or\n#ff0000 Reset# to rollback to the previous version.");
|
||||||
"Please #00ff00 Validate# this version or\n#ff0000 Reset# to rollback to the previous version.");
|
|
||||||
|
|
||||||
buttonValidate = lv_btn_create(lv_scr_act(), nullptr);
|
buttonValidate = lv_btn_create(lv_scr_act(), nullptr);
|
||||||
lv_obj_align(buttonValidate, NULL, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0);
|
lv_obj_align(buttonValidate, NULL, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0);
|
||||||
|
@ -62,7 +58,6 @@ FirmwareValidation::FirmwareValidation(Pinetime::Applications::DisplayApp *app,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
FirmwareValidation::~FirmwareValidation() {
|
FirmwareValidation::~FirmwareValidation() {
|
||||||
lv_obj_clean(lv_scr_act());
|
lv_obj_clean(lv_scr_act());
|
||||||
}
|
}
|
||||||
|
@ -71,12 +66,11 @@ bool FirmwareValidation::Refresh() {
|
||||||
return running;
|
return running;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FirmwareValidation::OnButtonEvent(lv_obj_t *object, lv_event_t event) {
|
void FirmwareValidation::OnButtonEvent(lv_obj_t* object, lv_event_t event) {
|
||||||
if(object == buttonValidate && event == LV_EVENT_PRESSED) {
|
if (object == buttonValidate && event == LV_EVENT_PRESSED) {
|
||||||
validator.Validate();
|
validator.Validate();
|
||||||
running = false;
|
running = false;
|
||||||
} else if(object == buttonReset && event == LV_EVENT_PRESSED) {
|
} else if (object == buttonReset && event == LV_EVENT_PRESSED) {
|
||||||
validator.Reset();
|
validator.Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,28 +11,26 @@ namespace Pinetime {
|
||||||
namespace Applications {
|
namespace Applications {
|
||||||
namespace Screens {
|
namespace Screens {
|
||||||
|
|
||||||
class FirmwareValidation : public Screen{
|
class FirmwareValidation : public Screen {
|
||||||
public:
|
public:
|
||||||
FirmwareValidation(DisplayApp* app, Pinetime::Controllers::FirmwareValidator& validator);
|
FirmwareValidation(DisplayApp* app, Pinetime::Controllers::FirmwareValidator& validator);
|
||||||
~FirmwareValidation() override;
|
~FirmwareValidation() override;
|
||||||
|
|
||||||
bool Refresh() override;
|
bool Refresh() override;
|
||||||
|
|
||||||
|
void OnButtonEvent(lv_obj_t* object, lv_event_t event);
|
||||||
|
|
||||||
void OnButtonEvent(lv_obj_t *object, lv_event_t event);
|
private:
|
||||||
|
Pinetime::Controllers::FirmwareValidator& validator;
|
||||||
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;
|
|
||||||
|
|
||||||
|
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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,19 +5,18 @@
|
||||||
using namespace Pinetime::Applications::Screens;
|
using namespace Pinetime::Applications::Screens;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
static void event_handler(lv_obj_t * obj, lv_event_t event) {
|
static void event_handler(lv_obj_t* obj, lv_event_t event) {
|
||||||
FlashLight* screen = static_cast<FlashLight *>(obj->user_data);
|
FlashLight* screen = static_cast<FlashLight*>(obj->user_data);
|
||||||
screen->OnClickEvent(obj, event);
|
screen->OnClickEvent(obj, event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FlashLight::FlashLight(
|
FlashLight::FlashLight(Pinetime::Applications::DisplayApp* app,
|
||||||
Pinetime::Applications::DisplayApp *app,
|
System::SystemTask& systemTask,
|
||||||
System::SystemTask &systemTask,
|
Controllers::BrightnessController& brightness)
|
||||||
Controllers::BrightnessController& brightness) :
|
: Screen(app),
|
||||||
Screen(app),
|
systemTask {systemTask},
|
||||||
systemTask{systemTask},
|
brightness {brightness}
|
||||||
brightness{brightness}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
brightness.Backup();
|
brightness.Backup();
|
||||||
|
@ -41,10 +40,8 @@ FlashLight::FlashLight(
|
||||||
lv_obj_set_event_cb(backgroundAction, event_handler);
|
lv_obj_set_event_cb(backgroundAction, event_handler);
|
||||||
|
|
||||||
systemTask.PushMessage(Pinetime::System::SystemTask::Messages::DisableSleeping);
|
systemTask.PushMessage(Pinetime::System::SystemTask::Messages::DisableSleeping);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
FlashLight::~FlashLight() {
|
FlashLight::~FlashLight() {
|
||||||
lv_obj_clean(lv_scr_act());
|
lv_obj_clean(lv_scr_act());
|
||||||
lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
|
lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
|
||||||
|
@ -52,19 +49,18 @@ FlashLight::~FlashLight() {
|
||||||
systemTask.PushMessage(Pinetime::System::SystemTask::Messages::EnableSleeping);
|
systemTask.PushMessage(Pinetime::System::SystemTask::Messages::EnableSleeping);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FlashLight::OnClickEvent(lv_obj_t *obj, lv_event_t event) {
|
void FlashLight::OnClickEvent(lv_obj_t* obj, lv_event_t event) {
|
||||||
if(obj == backgroundAction) {
|
if (obj == backgroundAction) {
|
||||||
if (event == LV_EVENT_CLICKED) {
|
if (event == LV_EVENT_CLICKED) {
|
||||||
isOn = !isOn;
|
isOn = !isOn;
|
||||||
|
|
||||||
if ( isOn ) {
|
if (isOn) {
|
||||||
lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xFFFFFF));
|
lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xFFFFFF));
|
||||||
lv_obj_set_style_local_text_color(flashLight, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
|
lv_obj_set_style_local_text_color(flashLight, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
|
||||||
} else {
|
} else {
|
||||||
lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
|
lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
|
||||||
lv_obj_set_style_local_text_color(flashLight, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xFFFFFF));
|
lv_obj_set_style_local_text_color(flashLight, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xFFFFFF));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,4 +72,3 @@ bool FlashLight::Refresh() {
|
||||||
bool FlashLight::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
bool FlashLight::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,30 +6,28 @@
|
||||||
#include "systemtask/SystemTask.h"
|
#include "systemtask/SystemTask.h"
|
||||||
#include "components/brightness/BrightnessController.h"
|
#include "components/brightness/BrightnessController.h"
|
||||||
|
|
||||||
|
|
||||||
namespace Pinetime {
|
namespace Pinetime {
|
||||||
|
|
||||||
namespace Applications {
|
namespace Applications {
|
||||||
namespace Screens {
|
namespace Screens {
|
||||||
|
|
||||||
class FlashLight : public Screen{
|
class FlashLight : public Screen {
|
||||||
public:
|
public:
|
||||||
FlashLight(DisplayApp* app, System::SystemTask &systemTask, Controllers::BrightnessController& brightness);
|
FlashLight(DisplayApp* app, System::SystemTask& systemTask, Controllers::BrightnessController& brightness);
|
||||||
~FlashLight() override;
|
~FlashLight() override;
|
||||||
|
|
||||||
bool Refresh() override;
|
bool Refresh() override;
|
||||||
|
|
||||||
bool OnTouchEvent(Pinetime::Applications::TouchEvents event) override;
|
bool OnTouchEvent(Pinetime::Applications::TouchEvents event) override;
|
||||||
void OnClickEvent(lv_obj_t *obj, lv_event_t event);
|
void OnClickEvent(lv_obj_t* obj, lv_event_t event);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Pinetime::System::SystemTask& systemTask;
|
Pinetime::System::SystemTask& systemTask;
|
||||||
Controllers::BrightnessController& brightness;
|
Controllers::BrightnessController& brightness;
|
||||||
|
|
||||||
lv_obj_t* flashLight;
|
|
||||||
lv_obj_t* backgroundAction;
|
|
||||||
bool isOn = true;
|
|
||||||
|
|
||||||
|
lv_obj_t* flashLight;
|
||||||
|
lv_obj_t* backgroundAction;
|
||||||
|
bool isOn = true;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
using namespace Pinetime::Applications::Screens;
|
using namespace Pinetime::Applications::Screens;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
const char *ToString(Pinetime::Controllers::HeartRateController::States s) {
|
const char* ToString(Pinetime::Controllers::HeartRateController::States s) {
|
||||||
switch (s) {
|
switch (s) {
|
||||||
case Pinetime::Controllers::HeartRateController::States::NotEnoughData:
|
case Pinetime::Controllers::HeartRateController::States::NotEnoughData:
|
||||||
return "Not enough data,\nplease wait...";
|
return "Not enough data,\nplease wait...";
|
||||||
|
@ -21,20 +21,22 @@ namespace {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
static void btnStartStopEventHandler(lv_obj_t *obj, lv_event_t event) {
|
static void btnStartStopEventHandler(lv_obj_t* obj, lv_event_t event) {
|
||||||
HeartRate *screen = static_cast<HeartRate *>(obj->user_data);
|
HeartRate* screen = static_cast<HeartRate*>(obj->user_data);
|
||||||
screen->OnStartStopEvent(event);
|
screen->OnStartStopEvent(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HeartRate::HeartRate(Pinetime::Applications::DisplayApp *app, Controllers::HeartRateController& heartRateController, System::SystemTask &systemTask) :
|
HeartRate::HeartRate(Pinetime::Applications::DisplayApp* app,
|
||||||
Screen(app), heartRateController{heartRateController}, systemTask{systemTask} {
|
Controllers::HeartRateController& heartRateController,
|
||||||
|
System::SystemTask& systemTask)
|
||||||
|
: Screen(app), heartRateController {heartRateController}, systemTask {systemTask} {
|
||||||
bool isHrRunning = heartRateController.State() != Controllers::HeartRateController::States::Stopped;
|
bool isHrRunning = heartRateController.State() != Controllers::HeartRateController::States::Stopped;
|
||||||
label_hr = lv_label_create(lv_scr_act(), nullptr);
|
label_hr = lv_label_create(lv_scr_act(), nullptr);
|
||||||
|
|
||||||
lv_obj_set_style_local_text_font(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76);
|
lv_obj_set_style_local_text_font(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76);
|
||||||
|
|
||||||
if(isHrRunning)
|
if (isHrRunning)
|
||||||
lv_obj_set_style_local_text_color(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GREEN);
|
lv_obj_set_style_local_text_color(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GREEN);
|
||||||
else
|
else
|
||||||
lv_obj_set_style_local_text_color(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
|
lv_obj_set_style_local_text_color(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
|
||||||
|
@ -60,7 +62,7 @@ HeartRate::HeartRate(Pinetime::Applications::DisplayApp *app, Controllers::Heart
|
||||||
|
|
||||||
label_startStop = lv_label_create(btn_startStop, nullptr);
|
label_startStop = lv_label_create(btn_startStop, nullptr);
|
||||||
UpdateStartStopButton(isHrRunning);
|
UpdateStartStopButton(isHrRunning);
|
||||||
if(isHrRunning)
|
if (isHrRunning)
|
||||||
systemTask.PushMessage(Pinetime::System::SystemTask::Messages::DisableSleeping);
|
systemTask.PushMessage(Pinetime::System::SystemTask::Messages::DisableSleeping);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,10 +74,10 @@ HeartRate::~HeartRate() {
|
||||||
bool HeartRate::Refresh() {
|
bool HeartRate::Refresh() {
|
||||||
|
|
||||||
auto state = heartRateController.State();
|
auto state = heartRateController.State();
|
||||||
switch(state) {
|
switch (state) {
|
||||||
case Controllers::HeartRateController::States::NoTouch:
|
case Controllers::HeartRateController::States::NoTouch:
|
||||||
case Controllers::HeartRateController::States::NotEnoughData:
|
case Controllers::HeartRateController::States::NotEnoughData:
|
||||||
//case Controllers::HeartRateController::States::Stopped:
|
// case Controllers::HeartRateController::States::Stopped:
|
||||||
lv_label_set_text(label_hr, "000");
|
lv_label_set_text(label_hr, "000");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -90,13 +92,12 @@ bool HeartRate::Refresh() {
|
||||||
|
|
||||||
void HeartRate::OnStartStopEvent(lv_event_t event) {
|
void HeartRate::OnStartStopEvent(lv_event_t event) {
|
||||||
if (event == LV_EVENT_CLICKED) {
|
if (event == LV_EVENT_CLICKED) {
|
||||||
if(heartRateController.State() == Controllers::HeartRateController::States::Stopped) {
|
if (heartRateController.State() == Controllers::HeartRateController::States::Stopped) {
|
||||||
heartRateController.Start();
|
heartRateController.Start();
|
||||||
UpdateStartStopButton(heartRateController.State() != Controllers::HeartRateController::States::Stopped);
|
UpdateStartStopButton(heartRateController.State() != Controllers::HeartRateController::States::Stopped);
|
||||||
systemTask.PushMessage(Pinetime::System::SystemTask::Messages::DisableSleeping);
|
systemTask.PushMessage(Pinetime::System::SystemTask::Messages::DisableSleeping);
|
||||||
lv_obj_set_style_local_text_color(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GREEN);
|
lv_obj_set_style_local_text_color(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GREEN);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
heartRateController.Stop();
|
heartRateController.Stop();
|
||||||
UpdateStartStopButton(heartRateController.State() != Controllers::HeartRateController::States::Stopped);
|
UpdateStartStopButton(heartRateController.State() != Controllers::HeartRateController::States::Stopped);
|
||||||
systemTask.PushMessage(Pinetime::System::SystemTask::Messages::EnableSleeping);
|
systemTask.PushMessage(Pinetime::System::SystemTask::Messages::EnableSleeping);
|
||||||
|
@ -106,7 +107,7 @@ void HeartRate::OnStartStopEvent(lv_event_t event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void HeartRate::UpdateStartStopButton(bool isRunning) {
|
void HeartRate::UpdateStartStopButton(bool isRunning) {
|
||||||
if(isRunning)
|
if (isRunning)
|
||||||
lv_label_set_text(label_startStop, "Stop");
|
lv_label_set_text(label_startStop, "Stop");
|
||||||
else
|
else
|
||||||
lv_label_set_text(label_startStop, "Start");
|
lv_label_set_text(label_startStop, "Start");
|
||||||
|
|
|
@ -15,9 +15,9 @@ namespace Pinetime {
|
||||||
namespace Applications {
|
namespace Applications {
|
||||||
namespace Screens {
|
namespace Screens {
|
||||||
|
|
||||||
class HeartRate : public Screen{
|
class HeartRate : public Screen {
|
||||||
public:
|
public:
|
||||||
HeartRate(DisplayApp* app, Controllers::HeartRateController& HeartRateController, System::SystemTask &systemTask);
|
HeartRate(DisplayApp* app, Controllers::HeartRateController& HeartRateController, System::SystemTask& systemTask);
|
||||||
~HeartRate() override;
|
~HeartRate() override;
|
||||||
|
|
||||||
bool Refresh() override;
|
bool Refresh() override;
|
||||||
|
@ -33,9 +33,6 @@ namespace Pinetime {
|
||||||
lv_obj_t* label_status;
|
lv_obj_t* label_status;
|
||||||
lv_obj_t* btn_startStop;
|
lv_obj_t* btn_startStop;
|
||||||
lv_obj_t* label_startStop;
|
lv_obj_t* label_startStop;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
using namespace Pinetime::Applications::Screens;
|
using namespace Pinetime::Applications::Screens;
|
||||||
|
|
||||||
InfiniPaint::InfiniPaint(Pinetime::Applications::DisplayApp* app, Pinetime::Components::LittleVgl& lvgl) : Screen(app), lvgl{lvgl} {
|
InfiniPaint::InfiniPaint(Pinetime::Applications::DisplayApp* app, Pinetime::Components::LittleVgl& lvgl) : Screen(app), lvgl {lvgl} {
|
||||||
app->SetTouchMode(DisplayApp::TouchModes::Polling);
|
app->SetTouchMode(DisplayApp::TouchModes::Polling);
|
||||||
std::fill(b, b + bufferSize, selectColor);
|
std::fill(b, b + bufferSize, selectColor);
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ bool InfiniPaint::Refresh() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InfiniPaint::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
bool InfiniPaint::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
||||||
switch(event) {
|
switch (event) {
|
||||||
case Pinetime::Applications::TouchEvents::LongTap:
|
case Pinetime::Applications::TouchEvents::LongTap:
|
||||||
switch (color) {
|
switch (color) {
|
||||||
case 0:
|
case 0:
|
||||||
|
@ -72,4 +72,3 @@ bool InfiniPaint::OnTouchEvent(uint16_t x, uint16_t y) {
|
||||||
lvgl.FlushDisplay(&area, b);
|
lvgl.FlushDisplay(&area, b);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,6 @@ namespace Pinetime {
|
||||||
lv_color_t b[bufferSize];
|
lv_color_t b[bufferSize];
|
||||||
lv_color_t selectColor = LV_COLOR_WHITE;
|
lv_color_t selectColor = LV_COLOR_WHITE;
|
||||||
uint8_t color = 2;
|
uint8_t color = 2;
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,12 +2,10 @@
|
||||||
|
|
||||||
using namespace Pinetime::Applications::Screens;
|
using namespace Pinetime::Applications::Screens;
|
||||||
|
|
||||||
Label::Label(uint8_t screenID, uint8_t numScreens,
|
Label::Label(uint8_t screenID, uint8_t numScreens, Pinetime::Applications::DisplayApp* app, lv_obj_t* labelText)
|
||||||
Pinetime::Applications::DisplayApp *app, lv_obj_t* labelText) :
|
: Screen(app), labelText {labelText} {
|
||||||
Screen(app),
|
|
||||||
labelText{labelText} {
|
|
||||||
|
|
||||||
if ( numScreens > 1 ) {
|
if (numScreens > 1) {
|
||||||
pageIndicatorBasePoints[0].x = 240 - 1;
|
pageIndicatorBasePoints[0].x = 240 - 1;
|
||||||
pageIndicatorBasePoints[0].y = 6;
|
pageIndicatorBasePoints[0].y = 6;
|
||||||
pageIndicatorBasePoints[1].x = 240 - 1;
|
pageIndicatorBasePoints[1].x = 240 - 1;
|
||||||
|
@ -19,7 +17,6 @@ Label::Label(uint8_t screenID, uint8_t numScreens,
|
||||||
lv_obj_set_style_local_line_rounded(pageIndicatorBase, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, true);
|
lv_obj_set_style_local_line_rounded(pageIndicatorBase, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, true);
|
||||||
lv_line_set_points(pageIndicatorBase, pageIndicatorBasePoints, 2);
|
lv_line_set_points(pageIndicatorBase, pageIndicatorBasePoints, 2);
|
||||||
|
|
||||||
|
|
||||||
uint16_t indicatorSize = 228 / numScreens;
|
uint16_t indicatorSize = 228 / numScreens;
|
||||||
uint16_t indicatorPos = indicatorSize * screenID;
|
uint16_t indicatorPos = indicatorSize * screenID;
|
||||||
|
|
||||||
|
@ -34,7 +31,6 @@ Label::Label(uint8_t screenID, uint8_t numScreens,
|
||||||
lv_obj_set_style_local_line_rounded(pageIndicator, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, true);
|
lv_obj_set_style_local_line_rounded(pageIndicator, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, true);
|
||||||
lv_line_set_points(pageIndicator, pageIndicatorPoints, 2);
|
lv_line_set_points(pageIndicator, pageIndicatorPoints, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Label::~Label() {
|
Label::~Label() {
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue