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
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: MultiLine
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: false
|
||||
AfterClass: false
|
||||
|
@ -52,14 +52,14 @@ BreakStringLiterals: true
|
|||
ColumnLimit: 140
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
ConstructorInitializerIndentWidth: 2
|
||||
ContinuationIndentWidth: 2
|
||||
Cpp11BracedListStyle: true
|
||||
DeriveLineEnding: false
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
ExperimentalAutoDetectBinPacking: true
|
||||
FixNamespaceComments: false
|
||||
ForEachMacros:
|
||||
- foreach
|
||||
|
@ -90,10 +90,6 @@ MacroBlockBegin: ''
|
|||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: All
|
||||
ObjCBinPackProtocolList: Auto
|
||||
ObjCBlockIndentWidth: 2
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PenaltyBreakAssignment: 2
|
||||
PenaltyBreakBeforeFirstCallParameter: 19
|
||||
PenaltyBreakComment: 300
|
||||
|
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,4 +1,7 @@
|
|||
.idea/
|
||||
# Python virtual environment for DFU images
|
||||
.venv/
|
||||
|
||||
# CMake
|
||||
cmake-build-*
|
||||
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
|
||||
|
||||
![Pinetime screens](images/0.14.0/collage1.png "PinetimeScreens")
|
||||
![Pinetime screens](images/0.14.0/collage2.png "PinetimeScreens")
|
||||
![Pinetime screens](images/1.0.0/collage.png "PinetimeScreens")
|
||||
|
||||
As of now, here is the list of achievements of this project:
|
||||
|
||||
|
@ -37,10 +36,15 @@ As of now, here is the list of achievements of this project:
|
|||
- Heart rate measurements
|
||||
- Step counting
|
||||
- Wake-up on wrist rotation
|
||||
- Quick actions
|
||||
* Disable vibration on notification
|
||||
* Brightness settings
|
||||
* Flashlight
|
||||
* Settings
|
||||
- 2 watch faces:
|
||||
* Digital
|
||||
* Analog
|
||||
- Multiple 'apps' :
|
||||
* Clock (displays the date, time, battery level, ble connection status, heart rate)
|
||||
* System info (displays various info : BLE MAC, build date/time, uptime, version,...)
|
||||
* Brightess (allows the user to configure the brightness of the display)
|
||||
* Music (control the playback of the music on your phone)
|
||||
* Heart rate (controls the heart rate sensor and display current heartbeat)
|
||||
* Navigation (displays navigation instructions coming from the companion app)
|
||||
|
@ -48,13 +52,22 @@ As of now, here is the list of achievements of this project:
|
|||
* Paddle (single player pong-like game)
|
||||
* Two (2048 clone game)
|
||||
* Stopwatch (with all the necessary functions such as play, pause, lap, stop)
|
||||
* Motion sensor and step counter (displays the number of steps and the state of the motion sensor in real-time)
|
||||
- User settings:
|
||||
* Display timeout
|
||||
* Wake-up condition
|
||||
* Time format (12/24h)
|
||||
* Default watch face
|
||||
* Battery status
|
||||
* Firmware validation
|
||||
* System information
|
||||
- Supported by 3 companion apps (development is in progress):
|
||||
* [Gadgetbridge](https://codeberg.org/Freeyourgadget/Gadgetbridge/) (on Android)
|
||||
* [Amazfish](https://openrepos.net/content/piggz/amazfish) (on SailfishOS and Linux)
|
||||
* [Siglo](https://github.com/alexr4535/siglo) (on Linux)
|
||||
* **[Experimental]** [WebBLEWatch](https://hubmartin.github.io/WebBLEWatch/) Synchronize time directly from your web browser. [video](https://youtu.be/IakiuhVDdrY)
|
||||
- **[Experimental]** OTA (Over-the-air) update via BLE
|
||||
- **[Experimental]** Bootloader based on [MCUBoot](https://juullabs-oss.github.io/mcuboot/)
|
||||
- OTA (Over-the-air) update via BLE
|
||||
- [Bootloader](https://github.com/JF002/pinetime-mcuboot-bootloader) based on [MCUBoot](https://juullabs-oss.github.io/mcuboot/)
|
||||
|
||||
## Documentation
|
||||
|
||||
|
@ -62,7 +75,7 @@ As of now, here is the list of achievements of this project:
|
|||
- [Flash, upgrade (OTA), time synchronization,...](doc/gettingStarted/gettingStarted.md)
|
||||
|
||||
### Develop
|
||||
- [Generate the fonts and symbols](src/displayapp/fonts/Readme.md)
|
||||
- [Generate the fonts and symbols](src/displayapp/fonts/README.md)
|
||||
- [Creating a stopwatch in Pinetime(article)](https://pankajraghav.com/2021/04/03/PINETIME-STOPCLOCK.html)
|
||||
|
||||
### Build, flash and debug
|
||||
|
|
BIN
images/1.0.0/collage.png
Normal file
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;
|
||||
}
|
||||
|
||||
const char *BootloaderVersion::VersionString() {
|
||||
const char* BootloaderVersion::VersionString() {
|
||||
return "0.0.0";
|
||||
}
|
||||
|
||||
|
|
|
@ -26,12 +26,11 @@
|
|||
* 1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
|
||||
#ifndef FREERTOS_CONFIG_H
|
||||
#define FREERTOS_CONFIG_H
|
||||
|
||||
#ifdef SOFTDEVICE_PRESENT
|
||||
#include "nrf_soc.h"
|
||||
#include "nrf_soc.h"
|
||||
#endif
|
||||
#include "app_util_platform.h"
|
||||
|
||||
|
@ -59,12 +58,12 @@
|
|||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
||||
#define configUSE_TICKLESS_IDLE 1
|
||||
#define configUSE_TICKLESS_IDLE_SIMPLE_DEBUG 0 /* See into vPortSuppressTicksAndSleep source code for explanation */
|
||||
#define configCPU_CLOCK_HZ ( SystemCoreClock )
|
||||
#define configCPU_CLOCK_HZ (SystemCoreClock)
|
||||
#define configTICK_RATE_HZ 1024
|
||||
#define configMAX_PRIORITIES ( 3 )
|
||||
#define configMINIMAL_STACK_SIZE ( 120 )
|
||||
#define configTOTAL_HEAP_SIZE ( 1024*16 )
|
||||
#define configMAX_TASK_NAME_LEN ( 4 )
|
||||
#define configMAX_PRIORITIES (3)
|
||||
#define configMINIMAL_STACK_SIZE (120)
|
||||
#define configTOTAL_HEAP_SIZE (1024 * 16)
|
||||
#define configMAX_TASK_NAME_LEN (4)
|
||||
#define configUSE_16_BIT_TICKS 0
|
||||
#define configIDLE_SHOULD_YIELD 1
|
||||
#define configUSE_MUTEXES 1
|
||||
|
@ -90,23 +89,22 @@
|
|||
|
||||
/* Co-routine definitions. */
|
||||
#define configUSE_CO_ROUTINES 0
|
||||
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
|
||||
#define configMAX_CO_ROUTINE_PRIORITIES (2)
|
||||
|
||||
/* Software timer definitions. */
|
||||
#define configUSE_TIMERS 1
|
||||
#define configTIMER_TASK_PRIORITY ( 0 )
|
||||
#define configTIMER_TASK_PRIORITY (0)
|
||||
#define configTIMER_QUEUE_LENGTH 32
|
||||
#define configTIMER_TASK_STACK_DEPTH ( 300 )
|
||||
#define configTIMER_TASK_STACK_DEPTH (300)
|
||||
|
||||
/* Tickless Idle configuration. */
|
||||
#define configEXPECTED_IDLE_TIME_BEFORE_SLEEP 2
|
||||
|
||||
/* Tickless idle/low power functionality. */
|
||||
|
||||
|
||||
/* Define to trap errors during development. */
|
||||
#if defined(DEBUG_NRF) || defined(DEBUG_NRF_USER)
|
||||
#define configASSERT( x ) ASSERT(x)
|
||||
#define configASSERT(x) ASSERT(x)
|
||||
#endif
|
||||
|
||||
/* FreeRTOS MPU specific definitions. */
|
||||
|
@ -140,7 +138,6 @@ INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
|
|||
PRIORITY THAN THIS! (higher priorities are lower numeric values. */
|
||||
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY _PRIO_APP_HIGH
|
||||
|
||||
|
||||
/* Interrupt priorities used by the kernel port layer itself. These are generic
|
||||
to all Cortex-M ports, and do not rely on any particular library functions. */
|
||||
#define configKERNEL_INTERRUPT_PRIORITY configLIBRARY_LOWEST_INTERRUPT_PRIORITY
|
||||
|
@ -154,7 +151,6 @@ standard names - or at least those used in the unmodified vector table. */
|
|||
#define vPortSVCHandler SVC_Handler
|
||||
#define xPortPendSVHandler PendSV_Handler
|
||||
|
||||
|
||||
/*-----------------------------------------------------------
|
||||
* Settings that are generated automatically
|
||||
* basing on the settings above
|
||||
|
@ -164,7 +160,7 @@ standard names - or at least those used in the unmodified vector table. */
|
|||
// to CPU clock source
|
||||
#define xPortSysTickHandler SysTick_Handler
|
||||
#elif (configTICK_SOURCE == FREERTOS_USE_RTC)
|
||||
#define configSYSTICK_CLOCK_HZ ( 32768UL )
|
||||
#define configSYSTICK_CLOCK_HZ (32768UL)
|
||||
#define xPortSysTickHandler RTC1_IRQHandler
|
||||
#else
|
||||
#error Unsupported configTICK_SOURCE value
|
||||
|
@ -187,7 +183,7 @@ standard names - or at least those used in the unmodified vector table. */
|
|||
/* Access to current system core clock is required only if we are ticking the system by systimer */
|
||||
#if (configTICK_SOURCE == FREERTOS_USE_SYSTICK)
|
||||
#include <stdint.h>
|
||||
extern uint32_t SystemCoreClock;
|
||||
extern uint32_t SystemCoreClock;
|
||||
#endif
|
||||
#endif /* !assembler */
|
||||
|
||||
|
@ -198,9 +194,9 @@ standard names - or at least those used in the unmodified vector table. */
|
|||
* one or more RTC ticks are lost. The tick interrupt inside RTOS will detect this and make a correction needed. This is needed
|
||||
* for the RTOS internal timers to be more accurate.
|
||||
* 1. The auto correction for RTOS tick is disabled even though few RTC tick interrupts were lost. This feature is desirable when debugging
|
||||
* the RTOS application and stepping though the code. After stepping when the application is continued in debug mode, the auto-corrections of
|
||||
* RTOS tick might cause asserts. Setting configUSE_DISABLE_TICK_AUTO_CORRECTION_DEBUG to 1 will make RTC and RTOS go out of sync but could be
|
||||
* convenient for debugging.
|
||||
* the RTOS application and stepping though the code. After stepping when the application is continued in debug mode, the
|
||||
* auto-corrections of RTOS tick might cause asserts. Setting configUSE_DISABLE_TICK_AUTO_CORRECTION_DEBUG to 1 will make RTC and RTOS go
|
||||
* out of sync but could be convenient for debugging.
|
||||
*/
|
||||
#define configUSE_DISABLE_TICK_AUTO_CORRECTION_DEBUG 0
|
||||
|
||||
|
|
|
@ -7,15 +7,15 @@
|
|||
|
||||
using namespace Pinetime::Controllers;
|
||||
|
||||
Battery *Battery::instance = nullptr;
|
||||
Battery* Battery::instance = nullptr;
|
||||
|
||||
Battery::Battery() {
|
||||
instance = this;
|
||||
}
|
||||
|
||||
void Battery::Init() {
|
||||
nrf_gpio_cfg_input(chargingPin, (nrf_gpio_pin_pull_t)GPIO_PIN_CNF_PULL_Pullup);
|
||||
nrf_gpio_cfg_input(powerPresentPin, (nrf_gpio_pin_pull_t)GPIO_PIN_CNF_PULL_Pullup);
|
||||
nrf_gpio_cfg_input(chargingPin, (nrf_gpio_pin_pull_t) GPIO_PIN_CNF_PULL_Pullup);
|
||||
nrf_gpio_cfg_input(powerPresentPin, (nrf_gpio_pin_pull_t) GPIO_PIN_CNF_PULL_Pullup);
|
||||
}
|
||||
|
||||
void Battery::Update() {
|
||||
|
@ -23,17 +23,17 @@ void Battery::Update() {
|
|||
isCharging = !nrf_gpio_pin_read(chargingPin);
|
||||
isPowerPresent = !nrf_gpio_pin_read(powerPresentPin);
|
||||
|
||||
if ( isReading ) return;
|
||||
if (isReading)
|
||||
return;
|
||||
// Non blocking read
|
||||
samples = 0;
|
||||
isReading = true;
|
||||
SaadcInit();
|
||||
|
||||
nrfx_saadc_sample();
|
||||
|
||||
}
|
||||
|
||||
void Battery::adcCallbackStatic(nrfx_saadc_evt_t const *event) {
|
||||
void Battery::adcCallbackStatic(nrfx_saadc_evt_t const* event) {
|
||||
instance->SaadcEventHandler(event);
|
||||
}
|
||||
|
||||
|
@ -41,8 +41,7 @@ void Battery::SaadcInit() {
|
|||
nrfx_saadc_config_t adcConfig = NRFX_SAADC_DEFAULT_CONFIG;
|
||||
APP_ERROR_CHECK(nrfx_saadc_init(&adcConfig, adcCallbackStatic));
|
||||
|
||||
nrf_saadc_channel_config_t adcChannelConfig = {
|
||||
.resistor_p = NRF_SAADC_RESISTOR_DISABLED,
|
||||
nrf_saadc_channel_config_t adcChannelConfig = {.resistor_p = NRF_SAADC_RESISTOR_DISABLED,
|
||||
.resistor_n = NRF_SAADC_RESISTOR_DISABLED,
|
||||
.gain = NRF_SAADC_GAIN1_5,
|
||||
.reference = NRF_SAADC_REFERENCE_INTERNAL,
|
||||
|
@ -50,14 +49,12 @@ void Battery::SaadcInit() {
|
|||
.mode = NRF_SAADC_MODE_SINGLE_ENDED,
|
||||
.burst = NRF_SAADC_BURST_ENABLED,
|
||||
.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_buffer_convert(&saadc_value, 1));
|
||||
|
||||
}
|
||||
|
||||
void Battery::SaadcEventHandler(nrfx_saadc_evt_t const * p_event) {
|
||||
void Battery::SaadcEventHandler(nrfx_saadc_evt_t const* p_event) {
|
||||
|
||||
const float battery_max = 4.18; // maximum voltage of battery ( max charging voltage is 4.21 )
|
||||
const float battery_min = 3.20; // minimum voltage of battery before shutdown ( depends on the battery )
|
||||
|
@ -77,12 +74,11 @@ void Battery::SaadcEventHandler(nrfx_saadc_evt_t const * p_event) {
|
|||
percentRemainingBuffer.insert(percentRemaining);
|
||||
|
||||
samples++;
|
||||
if ( samples > percentRemainingSamples ) {
|
||||
if (samples > percentRemainingSamples) {
|
||||
nrfx_saadc_uninit();
|
||||
isReading = false;
|
||||
} else {
|
||||
nrfx_saadc_sample();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -11,10 +11,10 @@ namespace Pinetime {
|
|||
out the sensor values. The total capacity of the CircBuffer
|
||||
is given as the template parameter N.
|
||||
*/
|
||||
template <int N>
|
||||
class CircBuffer {
|
||||
template <int N> class CircBuffer {
|
||||
public:
|
||||
CircBuffer() : arr{}, sz{}, cap{N}, head{} {}
|
||||
CircBuffer() : arr {}, sz {}, cap {N}, head {} {
|
||||
}
|
||||
/**
|
||||
insert member function overwrites the next data to the current
|
||||
HEAD and moves the HEAD to the newly inserted value.
|
||||
|
@ -41,21 +41,28 @@ namespace Pinetime {
|
|||
|
||||
class Battery {
|
||||
public:
|
||||
|
||||
Battery();
|
||||
|
||||
void Init();
|
||||
void Update();
|
||||
|
||||
int PercentRemaining() const { return percentRemainingBuffer.GetAverage(); }
|
||||
int PercentRemaining() const {
|
||||
return percentRemainingBuffer.GetAverage();
|
||||
}
|
||||
|
||||
float Voltage() const { return voltage; }
|
||||
float Voltage() const {
|
||||
return voltage;
|
||||
}
|
||||
|
||||
bool IsCharging() const { return isCharging; }
|
||||
bool IsPowerPresent() const { return isPowerPresent; }
|
||||
bool IsCharging() const {
|
||||
return isCharging;
|
||||
}
|
||||
bool IsPowerPresent() const {
|
||||
return isPowerPresent;
|
||||
}
|
||||
|
||||
private:
|
||||
static Battery *instance;
|
||||
static Battery* instance;
|
||||
nrf_saadc_value_t saadc_value;
|
||||
|
||||
static constexpr uint8_t percentRemainingSamples = 5;
|
||||
|
@ -72,8 +79,8 @@ namespace Pinetime {
|
|||
|
||||
void SaadcInit();
|
||||
|
||||
void SaadcEventHandler(nrfx_saadc_evt_t const * p_event);
|
||||
static void adcCallbackStatic(nrfx_saadc_evt_t const *event);
|
||||
void SaadcEventHandler(nrfx_saadc_evt_t const* p_event);
|
||||
static void adcCallbackStatic(nrfx_saadc_evt_t const* event);
|
||||
|
||||
bool isReading = false;
|
||||
uint8_t samples = 0;
|
||||
|
|
|
@ -12,50 +12,42 @@ constexpr ble_uuid16_t AlertNotificationClient::unreadAlertStatusUuid;
|
|||
constexpr ble_uuid16_t AlertNotificationClient::controlPointUuid;
|
||||
|
||||
namespace {
|
||||
int
|
||||
OnDiscoveryEventCallback(uint16_t conn_handle, const struct ble_gatt_error *error, const struct ble_gatt_svc *service,
|
||||
void *arg) {
|
||||
auto client = static_cast<AlertNotificationClient *>(arg);
|
||||
int OnDiscoveryEventCallback(uint16_t conn_handle, const struct ble_gatt_error* error, const struct ble_gatt_svc* service, void* arg) {
|
||||
auto client = static_cast<AlertNotificationClient*>(arg);
|
||||
return client->OnDiscoveryEvent(conn_handle, error, service);
|
||||
}
|
||||
|
||||
int OnAlertNotificationCharacteristicDiscoveredCallback(uint16_t conn_handle, const struct ble_gatt_error *error,
|
||||
const struct ble_gatt_chr *chr, void *arg) {
|
||||
auto client = static_cast<AlertNotificationClient *>(arg);
|
||||
int OnAlertNotificationCharacteristicDiscoveredCallback(uint16_t conn_handle,
|
||||
const struct ble_gatt_error* error,
|
||||
const struct ble_gatt_chr* chr,
|
||||
void* arg) {
|
||||
auto client = static_cast<AlertNotificationClient*>(arg);
|
||||
return client->OnCharacteristicsDiscoveryEvent(conn_handle, error, chr);
|
||||
}
|
||||
|
||||
int OnAlertNotificationDescriptorDiscoveryEventCallback(uint16_t conn_handle,
|
||||
const struct ble_gatt_error *error,
|
||||
uint16_t chr_val_handle,
|
||||
const struct ble_gatt_dsc *dsc,
|
||||
void *arg) {
|
||||
auto client = static_cast<AlertNotificationClient *>(arg);
|
||||
int OnAlertNotificationDescriptorDiscoveryEventCallback(
|
||||
uint16_t conn_handle, const struct ble_gatt_error* error, uint16_t chr_val_handle, const struct ble_gatt_dsc* dsc, void* arg) {
|
||||
auto client = static_cast<AlertNotificationClient*>(arg);
|
||||
return client->OnDescriptorDiscoveryEventCallback(conn_handle, error, chr_val_handle, dsc);
|
||||
}
|
||||
|
||||
int NewAlertSubcribeCallback(uint16_t conn_handle,
|
||||
const struct ble_gatt_error *error,
|
||||
struct ble_gatt_attr *attr,
|
||||
void *arg) {
|
||||
auto client = static_cast<AlertNotificationClient *>(arg);
|
||||
int NewAlertSubcribeCallback(uint16_t conn_handle, const struct ble_gatt_error* error, struct ble_gatt_attr* attr, void* arg) {
|
||||
auto client = static_cast<AlertNotificationClient*>(arg);
|
||||
return client->OnNewAlertSubcribe(conn_handle, error, attr);
|
||||
}
|
||||
}
|
||||
|
||||
AlertNotificationClient::AlertNotificationClient(Pinetime::System::SystemTask &systemTask,
|
||||
Pinetime::Controllers::NotificationManager ¬ificationManager) :
|
||||
systemTask{systemTask}, notificationManager{notificationManager} {
|
||||
AlertNotificationClient::AlertNotificationClient(Pinetime::System::SystemTask& systemTask,
|
||||
Pinetime::Controllers::NotificationManager& notificationManager)
|
||||
: systemTask {systemTask}, notificationManager {notificationManager} {
|
||||
}
|
||||
|
||||
bool AlertNotificationClient::OnDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error *error,
|
||||
const ble_gatt_svc *service) {
|
||||
bool AlertNotificationClient::OnDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error* error, const ble_gatt_svc* service) {
|
||||
if (service == nullptr && error->status == BLE_HS_EDONE) {
|
||||
if (isDiscovered) {
|
||||
NRF_LOG_INFO("ANS Discovery found, starting characteristics discovery");
|
||||
|
||||
ble_gattc_disc_all_chrs(connectionHandle, ansStartHandle, ansEndHandle,
|
||||
OnAlertNotificationCharacteristicDiscoveredCallback, this);
|
||||
ble_gattc_disc_all_chrs(connectionHandle, ansStartHandle, ansEndHandle, OnAlertNotificationCharacteristicDiscoveredCallback, this);
|
||||
} else {
|
||||
NRF_LOG_INFO("ANS not found");
|
||||
onServiceDiscovered(connectionHandle);
|
||||
|
@ -63,7 +55,7 @@ bool AlertNotificationClient::OnDiscoveryEvent(uint16_t connectionHandle, const
|
|||
return true;
|
||||
}
|
||||
|
||||
if (service != nullptr && ble_uuid_cmp(((ble_uuid_t *) &ansServiceUuid), &service->uuid.u) == 0) {
|
||||
if (service != nullptr && ble_uuid_cmp(((ble_uuid_t*) &ansServiceUuid), &service->uuid.u) == 0) {
|
||||
NRF_LOG_INFO("ANS discovered : 0x%x - 0x%x", service->start_handle, service->end_handle);
|
||||
ansStartHandle = service->start_handle;
|
||||
ansEndHandle = service->end_handle;
|
||||
|
@ -72,8 +64,9 @@ bool AlertNotificationClient::OnDiscoveryEvent(uint16_t connectionHandle, const
|
|||
return false;
|
||||
}
|
||||
|
||||
int AlertNotificationClient::OnCharacteristicsDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error *error,
|
||||
const ble_gatt_chr *characteristic) {
|
||||
int AlertNotificationClient::OnCharacteristicsDiscoveryEvent(uint16_t connectionHandle,
|
||||
const ble_gatt_error* error,
|
||||
const ble_gatt_chr* characteristic) {
|
||||
if (error->status != 0 && error->status != BLE_HS_EDONE) {
|
||||
NRF_LOG_INFO("ANS Characteristic discovery ERROR");
|
||||
onServiceDiscovered(connectionHandle);
|
||||
|
@ -83,41 +76,34 @@ int AlertNotificationClient::OnCharacteristicsDiscoveryEvent(uint16_t connection
|
|||
if (characteristic == nullptr && error->status == BLE_HS_EDONE) {
|
||||
NRF_LOG_INFO("ANS Characteristic discovery complete");
|
||||
if (isCharacteristicDiscovered) {
|
||||
ble_gattc_disc_all_dscs(connectionHandle,
|
||||
newAlertHandle, ansEndHandle,
|
||||
OnAlertNotificationDescriptorDiscoveryEventCallback, this);
|
||||
ble_gattc_disc_all_dscs(connectionHandle, newAlertHandle, ansEndHandle, OnAlertNotificationDescriptorDiscoveryEventCallback, this);
|
||||
} else
|
||||
onServiceDiscovered(connectionHandle);
|
||||
} else {
|
||||
if (characteristic != nullptr &&
|
||||
ble_uuid_cmp(((ble_uuid_t *) &supportedNewAlertCategoryUuid), &characteristic->uuid.u) == 0) {
|
||||
if (characteristic != nullptr && ble_uuid_cmp(((ble_uuid_t*) &supportedNewAlertCategoryUuid), &characteristic->uuid.u) == 0) {
|
||||
NRF_LOG_INFO("ANS Characteristic discovered : supportedNewAlertCategoryUuid");
|
||||
supportedNewAlertCategoryHandle = characteristic->val_handle;
|
||||
} else if (characteristic != nullptr &&
|
||||
ble_uuid_cmp(((ble_uuid_t *) &supportedUnreadAlertCategoryUuid), &characteristic->uuid.u) == 0) {
|
||||
} else if (characteristic != nullptr && ble_uuid_cmp(((ble_uuid_t*) &supportedUnreadAlertCategoryUuid), &characteristic->uuid.u) == 0) {
|
||||
NRF_LOG_INFO("ANS Characteristic discovered : supportedUnreadAlertCategoryUuid");
|
||||
supportedUnreadAlertCategoryHandle = characteristic->val_handle;
|
||||
} else if (characteristic != nullptr &&
|
||||
ble_uuid_cmp(((ble_uuid_t *) &newAlertUuid), &characteristic->uuid.u) == 0) {
|
||||
} else if (characteristic != nullptr && ble_uuid_cmp(((ble_uuid_t*) &newAlertUuid), &characteristic->uuid.u) == 0) {
|
||||
NRF_LOG_INFO("ANS Characteristic discovered : newAlertUuid");
|
||||
newAlertHandle = characteristic->val_handle;
|
||||
newAlertDefHandle = characteristic->def_handle;
|
||||
isCharacteristicDiscovered = true;
|
||||
} else if (characteristic != nullptr &&
|
||||
ble_uuid_cmp(((ble_uuid_t *) &unreadAlertStatusUuid), &characteristic->uuid.u) == 0) {
|
||||
} else if (characteristic != nullptr && ble_uuid_cmp(((ble_uuid_t*) &unreadAlertStatusUuid), &characteristic->uuid.u) == 0) {
|
||||
NRF_LOG_INFO("ANS Characteristic discovered : unreadAlertStatusUuid");
|
||||
unreadAlertStatusHandle = characteristic->val_handle;
|
||||
} else if (characteristic != nullptr &&
|
||||
ble_uuid_cmp(((ble_uuid_t *) &controlPointUuid), &characteristic->uuid.u) == 0) {
|
||||
} else if (characteristic != nullptr && ble_uuid_cmp(((ble_uuid_t*) &controlPointUuid), &characteristic->uuid.u) == 0) {
|
||||
NRF_LOG_INFO("ANS Characteristic discovered : controlPointUuid");
|
||||
controlPointHandle = characteristic->val_handle;
|
||||
} else NRF_LOG_INFO("ANS Characteristic discovered : 0x%x", characteristic->val_handle);
|
||||
} else
|
||||
NRF_LOG_INFO("ANS Characteristic discovered : 0x%x", characteristic->val_handle);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AlertNotificationClient::OnNewAlertSubcribe(uint16_t connectionHandle, const ble_gatt_error *error,
|
||||
ble_gatt_attr *attribute) {
|
||||
int AlertNotificationClient::OnNewAlertSubcribe(uint16_t connectionHandle, const ble_gatt_error* error, ble_gatt_attr* attribute) {
|
||||
if (error->status == 0) {
|
||||
NRF_LOG_INFO("ANS New alert subscribe OK");
|
||||
} else {
|
||||
|
@ -128,12 +114,12 @@ int AlertNotificationClient::OnNewAlertSubcribe(uint16_t connectionHandle, const
|
|||
return 0;
|
||||
}
|
||||
|
||||
int AlertNotificationClient::OnDescriptorDiscoveryEventCallback(uint16_t connectionHandle, const ble_gatt_error *error,
|
||||
int AlertNotificationClient::OnDescriptorDiscoveryEventCallback(uint16_t connectionHandle,
|
||||
const ble_gatt_error* error,
|
||||
uint16_t characteristicValueHandle,
|
||||
const ble_gatt_dsc *descriptor) {
|
||||
const ble_gatt_dsc* descriptor) {
|
||||
if (error->status == 0) {
|
||||
if (characteristicValueHandle == newAlertHandle &&
|
||||
ble_uuid_cmp(((ble_uuid_t *) &newAlertUuid), &descriptor->uuid.u)) {
|
||||
if (characteristicValueHandle == newAlertHandle && ble_uuid_cmp(((ble_uuid_t*) &newAlertUuid), &descriptor->uuid.u)) {
|
||||
if (newAlertDescriptorHandle == 0) {
|
||||
NRF_LOG_INFO("ANS Descriptor discovered : %d", descriptor->handle);
|
||||
newAlertDescriptorHandle = descriptor->handle;
|
||||
|
@ -151,16 +137,17 @@ int AlertNotificationClient::OnDescriptorDiscoveryEventCallback(uint16_t connect
|
|||
return 0;
|
||||
}
|
||||
|
||||
void AlertNotificationClient::OnNotification(ble_gap_event *event) {
|
||||
void AlertNotificationClient::OnNotification(ble_gap_event* event) {
|
||||
if (event->notify_rx.attr_handle == newAlertHandle) {
|
||||
constexpr size_t stringTerminatorSize = 1; // end of string '\0'
|
||||
constexpr size_t headerSize = 3;
|
||||
const auto maxMessageSize{NotificationManager::MaximumMessageSize()};
|
||||
const auto maxBufferSize{maxMessageSize + headerSize};
|
||||
const auto maxMessageSize {NotificationManager::MaximumMessageSize()};
|
||||
const auto maxBufferSize {maxMessageSize + headerSize};
|
||||
|
||||
// Ignore notifications with empty message
|
||||
const auto packetLen = OS_MBUF_PKTLEN(event->notify_rx.om);
|
||||
if(packetLen <= headerSize) return;
|
||||
if (packetLen <= headerSize)
|
||||
return;
|
||||
|
||||
size_t bufferSize = std::min(packetLen + stringTerminatorSize, maxBufferSize);
|
||||
auto messageSize = std::min(maxMessageSize, (bufferSize - headerSize));
|
||||
|
|
|
@ -20,51 +20,35 @@ namespace Pinetime {
|
|||
|
||||
class AlertNotificationClient : public BleClient {
|
||||
public:
|
||||
explicit AlertNotificationClient(Pinetime::System::SystemTask &systemTask,
|
||||
Pinetime::Controllers::NotificationManager ¬ificationManager);
|
||||
explicit AlertNotificationClient(Pinetime::System::SystemTask& systemTask,
|
||||
Pinetime::Controllers::NotificationManager& notificationManager);
|
||||
|
||||
bool OnDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error *error, const ble_gatt_svc *service);
|
||||
int OnCharacteristicsDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error *error,
|
||||
const ble_gatt_chr *characteristic);
|
||||
int OnNewAlertSubcribe(uint16_t connectionHandle, const ble_gatt_error *error, ble_gatt_attr *attribute);
|
||||
int OnDescriptorDiscoveryEventCallback(uint16_t connectionHandle, const ble_gatt_error *error,
|
||||
uint16_t characteristicValueHandle, const ble_gatt_dsc *descriptor);
|
||||
void OnNotification(ble_gap_event *event);
|
||||
bool OnDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error* error, const ble_gatt_svc* service);
|
||||
int OnCharacteristicsDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error* error, const ble_gatt_chr* characteristic);
|
||||
int OnNewAlertSubcribe(uint16_t connectionHandle, const ble_gatt_error* error, ble_gatt_attr* attribute);
|
||||
int OnDescriptorDiscoveryEventCallback(uint16_t connectionHandle,
|
||||
const ble_gatt_error* error,
|
||||
uint16_t characteristicValueHandle,
|
||||
const ble_gatt_dsc* descriptor);
|
||||
void OnNotification(ble_gap_event* event);
|
||||
void Reset();
|
||||
void Discover(uint16_t connectionHandle, std::function<void(uint16_t)> lambda) override;
|
||||
|
||||
private:
|
||||
static constexpr uint16_t ansServiceId{0x1811};
|
||||
static constexpr uint16_t ansServiceId {0x1811};
|
||||
static constexpr uint16_t supportedNewAlertCategoryId = 0x2a47;
|
||||
static constexpr uint16_t supportedUnreadAlertCategoryId = 0x2a48;
|
||||
static constexpr uint16_t newAlertId = 0x2a46;
|
||||
static constexpr uint16_t unreadAlertStatusId = 0x2a45;
|
||||
static constexpr uint16_t controlPointId = 0x2a44;
|
||||
|
||||
static constexpr ble_uuid16_t ansServiceUuid{
|
||||
.u {.type = BLE_UUID_TYPE_16},
|
||||
.value = ansServiceId
|
||||
};
|
||||
static constexpr ble_uuid16_t supportedNewAlertCategoryUuid{
|
||||
.u {.type = BLE_UUID_TYPE_16},
|
||||
.value = supportedNewAlertCategoryId
|
||||
};
|
||||
static constexpr ble_uuid16_t supportedUnreadAlertCategoryUuid{
|
||||
.u {.type = BLE_UUID_TYPE_16},
|
||||
.value = supportedUnreadAlertCategoryId
|
||||
};
|
||||
static constexpr ble_uuid16_t newAlertUuid{
|
||||
.u {.type = BLE_UUID_TYPE_16},
|
||||
.value = newAlertId
|
||||
};
|
||||
static constexpr ble_uuid16_t unreadAlertStatusUuid{
|
||||
.u {.type = BLE_UUID_TYPE_16},
|
||||
.value = unreadAlertStatusId
|
||||
};
|
||||
static constexpr ble_uuid16_t controlPointUuid{
|
||||
.u {.type = BLE_UUID_TYPE_16},
|
||||
.value = controlPointId
|
||||
};
|
||||
static constexpr ble_uuid16_t ansServiceUuid {.u {.type = BLE_UUID_TYPE_16}, .value = ansServiceId};
|
||||
static constexpr ble_uuid16_t supportedNewAlertCategoryUuid {.u {.type = BLE_UUID_TYPE_16}, .value = supportedNewAlertCategoryId};
|
||||
static constexpr ble_uuid16_t supportedUnreadAlertCategoryUuid {.u {.type = BLE_UUID_TYPE_16},
|
||||
.value = supportedUnreadAlertCategoryId};
|
||||
static constexpr ble_uuid16_t newAlertUuid {.u {.type = BLE_UUID_TYPE_16}, .value = newAlertId};
|
||||
static constexpr ble_uuid16_t unreadAlertStatusUuid {.u {.type = BLE_UUID_TYPE_16}, .value = unreadAlertStatusId};
|
||||
static constexpr ble_uuid16_t controlPointUuid {.u {.type = BLE_UUID_TYPE_16}, .value = controlPointId};
|
||||
|
||||
uint16_t ansStartHandle = 0;
|
||||
uint16_t ansEndHandle = 0;
|
||||
|
@ -76,8 +60,8 @@ namespace Pinetime {
|
|||
uint16_t unreadAlertStatusHandle = 0;
|
||||
uint16_t controlPointHandle = 0;
|
||||
bool isDiscovered = false;
|
||||
Pinetime::System::SystemTask &systemTask;
|
||||
Pinetime::Controllers::NotificationManager ¬ificationManager;
|
||||
Pinetime::System::SystemTask& systemTask;
|
||||
Pinetime::Controllers::NotificationManager& notificationManager;
|
||||
std::function<void(uint16_t)> onServiceDiscovered;
|
||||
bool isCharacteristicDiscovered = false;
|
||||
bool isDescriptorFound = false;
|
||||
|
|
|
@ -11,8 +11,7 @@ constexpr ble_uuid16_t AlertNotificationService::ansUuid;
|
|||
constexpr ble_uuid16_t AlertNotificationService::ansCharUuid;
|
||||
constexpr ble_uuid128_t AlertNotificationService::notificationEventUuid;
|
||||
|
||||
|
||||
int AlertNotificationCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) {
|
||||
int AlertNotificationCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
|
||||
auto anService = static_cast<AlertNotificationService*>(arg);
|
||||
return anService->OnAlert(conn_handle, attr_handle, ctxt);
|
||||
}
|
||||
|
@ -26,62 +25,52 @@ void AlertNotificationService::Init() {
|
|||
ASSERT(res == 0);
|
||||
}
|
||||
|
||||
AlertNotificationService::AlertNotificationService ( System::SystemTask& systemTask, NotificationManager& notificationManager )
|
||||
: characteristicDefinition{
|
||||
{
|
||||
.uuid = (ble_uuid_t *) &ansCharUuid,
|
||||
AlertNotificationService::AlertNotificationService(System::SystemTask& systemTask, NotificationManager& notificationManager)
|
||||
: characteristicDefinition {{.uuid = (ble_uuid_t*) &ansCharUuid,
|
||||
.access_cb = AlertNotificationCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE
|
||||
},
|
||||
{
|
||||
.uuid = (ble_uuid_t *) ¬ificationEventUuid,
|
||||
.flags = BLE_GATT_CHR_F_WRITE},
|
||||
{.uuid = (ble_uuid_t*) ¬ificationEventUuid,
|
||||
.access_cb = AlertNotificationCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_NOTIFY,
|
||||
.val_handle = &eventHandle
|
||||
},
|
||||
{
|
||||
0
|
||||
}
|
||||
},
|
||||
serviceDefinition{
|
||||
{
|
||||
/* Device Information Service */
|
||||
.val_handle = &eventHandle},
|
||||
{0}},
|
||||
serviceDefinition {
|
||||
{/* Device Information Service */
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = (ble_uuid_t *) &ansUuid,
|
||||
.characteristics = characteristicDefinition
|
||||
.uuid = (ble_uuid_t*) &ansUuid,
|
||||
.characteristics = characteristicDefinition},
|
||||
{0},
|
||||
},
|
||||
{
|
||||
0
|
||||
},
|
||||
}, systemTask{systemTask}, notificationManager{notificationManager} {
|
||||
systemTask {systemTask},
|
||||
notificationManager {notificationManager} {
|
||||
}
|
||||
|
||||
int AlertNotificationService::OnAlert(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt) {
|
||||
int AlertNotificationService::OnAlert(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) {
|
||||
if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
|
||||
constexpr size_t stringTerminatorSize = 1; // end of string '\0'
|
||||
constexpr size_t headerSize = 3;
|
||||
const auto maxMessageSize {NotificationManager::MaximumMessageSize()};
|
||||
const auto maxBufferSize{maxMessageSize + headerSize};
|
||||
const auto maxBufferSize {maxMessageSize + headerSize};
|
||||
|
||||
// Ignore notifications with empty message
|
||||
const auto packetLen = OS_MBUF_PKTLEN(ctxt->om);
|
||||
if(packetLen <= headerSize) return 0;
|
||||
if (packetLen <= headerSize)
|
||||
return 0;
|
||||
|
||||
size_t bufferSize = std::min(packetLen + stringTerminatorSize, maxBufferSize);
|
||||
auto messageSize = std::min(maxMessageSize, (bufferSize-headerSize));
|
||||
auto messageSize = std::min(maxMessageSize, (bufferSize - headerSize));
|
||||
Categories category;
|
||||
|
||||
NotificationManager::Notification notif;
|
||||
os_mbuf_copydata(ctxt->om, headerSize, messageSize-1, notif.message.data());
|
||||
os_mbuf_copydata(ctxt->om, headerSize, messageSize - 1, notif.message.data());
|
||||
os_mbuf_copydata(ctxt->om, 0, 1, &category);
|
||||
notif.message[messageSize-1] = '\0';
|
||||
notif.message[messageSize - 1] = '\0';
|
||||
notif.size = messageSize;
|
||||
|
||||
// TODO convert all ANS categories to NotificationController categories
|
||||
switch(category) {
|
||||
switch (category) {
|
||||
case Categories::Call:
|
||||
notif.category = Pinetime::Controllers::NotificationManager::Categories::IncomingCall;
|
||||
break;
|
||||
|
@ -99,7 +88,7 @@ int AlertNotificationService::OnAlert(uint16_t conn_handle, uint16_t attr_handle
|
|||
|
||||
void AlertNotificationService::AcceptIncomingCall() {
|
||||
auto response = IncomingCallResponses::Answer;
|
||||
auto *om = ble_hs_mbuf_from_flat(&response, 1);
|
||||
auto* om = ble_hs_mbuf_from_flat(&response, 1);
|
||||
|
||||
uint16_t connectionHandle = systemTask.nimble().connHandle();
|
||||
|
||||
|
@ -112,7 +101,7 @@ void AlertNotificationService::AcceptIncomingCall() {
|
|||
|
||||
void AlertNotificationService::RejectIncomingCall() {
|
||||
auto response = IncomingCallResponses::Reject;
|
||||
auto *om = ble_hs_mbuf_from_flat(&response, 1);
|
||||
auto* om = ble_hs_mbuf_from_flat(&response, 1);
|
||||
|
||||
uint16_t connectionHandle = systemTask.nimble().connHandle();
|
||||
|
||||
|
@ -125,7 +114,7 @@ void AlertNotificationService::RejectIncomingCall() {
|
|||
|
||||
void AlertNotificationService::MuteIncomingCall() {
|
||||
auto response = IncomingCallResponses::Mute;
|
||||
auto *om = ble_hs_mbuf_from_flat(&response, 1);
|
||||
auto* om = ble_hs_mbuf_from_flat(&response, 1);
|
||||
|
||||
uint16_t connectionHandle = systemTask.nimble().connHandle();
|
||||
|
||||
|
|
|
@ -7,8 +7,9 @@
|
|||
#undef max
|
||||
#undef min
|
||||
|
||||
//00020001-78fc-48fe-8e23-433b3a1942d0
|
||||
#define NOTIFICATION_EVENT_SERVICE_UUID_BASE {0xd0, 0x42, 0x19, 0x3a, 0x3b, 0x43, 0x23, 0x8e, 0xfe, 0x48, 0xfc, 0x78, 0x01, 0x00, 0x02, 0x00}
|
||||
// 00020001-78fc-48fe-8e23-433b3a1942d0
|
||||
#define NOTIFICATION_EVENT_SERVICE_UUID_BASE \
|
||||
{ 0xd0, 0x42, 0x19, 0x3a, 0x3b, 0x43, 0x23, 0x8e, 0xfe, 0x48, 0xfc, 0x78, 0x01, 0x00, 0x02, 0x00 }
|
||||
|
||||
namespace Pinetime {
|
||||
|
||||
|
@ -20,22 +21,16 @@ namespace Pinetime {
|
|||
|
||||
class AlertNotificationService {
|
||||
public:
|
||||
AlertNotificationService(Pinetime::System::SystemTask &systemTask,
|
||||
Pinetime::Controllers::NotificationManager ¬ificationManager);
|
||||
AlertNotificationService(Pinetime::System::SystemTask& systemTask, Pinetime::Controllers::NotificationManager& notificationManager);
|
||||
void Init();
|
||||
|
||||
int OnAlert(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt);
|
||||
int OnAlert(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt);
|
||||
|
||||
void AcceptIncomingCall();
|
||||
void RejectIncomingCall();
|
||||
void MuteIncomingCall();
|
||||
|
||||
enum class IncomingCallResponses : uint8_t {
|
||||
Reject = 0x00,
|
||||
Answer = 0x01,
|
||||
Mute = 0x02
|
||||
};
|
||||
enum class IncomingCallResponses : uint8_t { Reject = 0x00, Answer = 0x01, Mute = 0x02 };
|
||||
|
||||
private:
|
||||
enum class Categories : uint8_t {
|
||||
|
@ -55,26 +50,17 @@ namespace Pinetime {
|
|||
static constexpr uint16_t ansId {0x1811};
|
||||
static constexpr uint16_t ansCharId {0x2a46};
|
||||
|
||||
static constexpr ble_uuid16_t ansUuid {
|
||||
.u { .type = BLE_UUID_TYPE_16 },
|
||||
.value = ansId
|
||||
};
|
||||
static constexpr ble_uuid16_t ansUuid {.u {.type = BLE_UUID_TYPE_16}, .value = ansId};
|
||||
|
||||
static constexpr ble_uuid16_t ansCharUuid {
|
||||
.u { .type = BLE_UUID_TYPE_16 },
|
||||
.value = ansCharId
|
||||
};
|
||||
static constexpr ble_uuid16_t ansCharUuid {.u {.type = BLE_UUID_TYPE_16}, .value = ansCharId};
|
||||
|
||||
static constexpr ble_uuid128_t notificationEventUuid {
|
||||
.u { .type = BLE_UUID_TYPE_128 },
|
||||
.value = NOTIFICATION_EVENT_SERVICE_UUID_BASE
|
||||
};
|
||||
static constexpr ble_uuid128_t notificationEventUuid {.u {.type = BLE_UUID_TYPE_128}, .value = NOTIFICATION_EVENT_SERVICE_UUID_BASE};
|
||||
|
||||
struct ble_gatt_chr_def characteristicDefinition[3];
|
||||
struct ble_gatt_svc_def serviceDefinition[2];
|
||||
|
||||
Pinetime::System::SystemTask &systemTask;
|
||||
NotificationManager ¬ificationManager;
|
||||
Pinetime::System::SystemTask& systemTask;
|
||||
NotificationManager& notificationManager;
|
||||
|
||||
uint16_t eventHandle;
|
||||
};
|
||||
|
|
|
@ -7,39 +7,26 @@ using namespace Pinetime::Controllers;
|
|||
constexpr ble_uuid16_t BatteryInformationService::batteryInformationServiceUuid;
|
||||
constexpr ble_uuid16_t BatteryInformationService::batteryLevelUuid;
|
||||
|
||||
|
||||
|
||||
int BatteryInformationServiceCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) {
|
||||
int BatteryInformationServiceCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
|
||||
auto* batteryInformationService = static_cast<BatteryInformationService*>(arg);
|
||||
return batteryInformationService->OnBatteryServiceRequested(conn_handle, attr_handle, ctxt);
|
||||
}
|
||||
|
||||
BatteryInformationService::BatteryInformationService(Controllers::Battery& batteryController) :
|
||||
batteryController{batteryController},
|
||||
characteristicDefinition{
|
||||
{
|
||||
.uuid = (ble_uuid_t *) &batteryLevelUuid,
|
||||
BatteryInformationService::BatteryInformationService(Controllers::Battery& batteryController)
|
||||
: batteryController {batteryController},
|
||||
characteristicDefinition {{.uuid = (ble_uuid_t*) &batteryLevelUuid,
|
||||
.access_cb = BatteryInformationServiceCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_READ,
|
||||
.val_handle = &batteryLevelHandle
|
||||
},
|
||||
{
|
||||
0
|
||||
}
|
||||
},
|
||||
serviceDefinition{
|
||||
{
|
||||
/* Device Information Service */
|
||||
.val_handle = &batteryLevelHandle},
|
||||
{0}},
|
||||
serviceDefinition {
|
||||
{/* Device Information Service */
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = (ble_uuid_t *) &batteryInformationServiceUuid,
|
||||
.characteristics = characteristicDefinition
|
||||
},
|
||||
{
|
||||
0
|
||||
},
|
||||
}{
|
||||
|
||||
.uuid = (ble_uuid_t*) &batteryInformationServiceUuid,
|
||||
.characteristics = characteristicDefinition},
|
||||
{0},
|
||||
} {
|
||||
}
|
||||
|
||||
void BatteryInformationService::Init() {
|
||||
|
@ -51,9 +38,10 @@ void BatteryInformationService::Init() {
|
|||
ASSERT(res == 0);
|
||||
}
|
||||
|
||||
int BatteryInformationService::OnBatteryServiceRequested(uint16_t connectionHandle, uint16_t attributeHandle,
|
||||
ble_gatt_access_ctxt *context) {
|
||||
if(attributeHandle == batteryLevelHandle) {
|
||||
int BatteryInformationService::OnBatteryServiceRequested(uint16_t connectionHandle,
|
||||
uint16_t attributeHandle,
|
||||
ble_gatt_access_ctxt* context) {
|
||||
if (attributeHandle == batteryLevelHandle) {
|
||||
NRF_LOG_INFO("BATTERY : handle = %d", batteryLevelHandle);
|
||||
static uint8_t batteryValue = batteryController.PercentRemaining();
|
||||
int res = os_mbuf_append(context->om, &batteryValue, 1);
|
||||
|
|
|
@ -16,29 +16,21 @@ namespace Pinetime {
|
|||
BatteryInformationService(Controllers::Battery& batteryController);
|
||||
void Init();
|
||||
|
||||
int
|
||||
OnBatteryServiceRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt *context);
|
||||
int OnBatteryServiceRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context);
|
||||
|
||||
private:
|
||||
Controllers::Battery& batteryController;
|
||||
static constexpr uint16_t batteryInformationServiceId {0x180F};
|
||||
static constexpr uint16_t batteryLevelId {0x2A19};
|
||||
|
||||
static constexpr ble_uuid16_t batteryInformationServiceUuid {
|
||||
.u {.type = BLE_UUID_TYPE_16},
|
||||
.value = batteryInformationServiceId
|
||||
};
|
||||
static constexpr ble_uuid16_t batteryInformationServiceUuid {.u {.type = BLE_UUID_TYPE_16}, .value = batteryInformationServiceId};
|
||||
|
||||
static constexpr ble_uuid16_t batteryLevelUuid {
|
||||
.u {.type = BLE_UUID_TYPE_16},
|
||||
.value = batteryLevelId
|
||||
};
|
||||
static constexpr ble_uuid16_t batteryLevelUuid {.u {.type = BLE_UUID_TYPE_16}, .value = batteryLevelId};
|
||||
|
||||
struct ble_gatt_chr_def characteristicDefinition[3];
|
||||
struct ble_gatt_svc_def serviceDefinition[2];
|
||||
|
||||
uint16_t batteryLevelHandle;
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#include <functional>
|
||||
|
||||
namespace Pinetime {
|
||||
namespace Controllers{
|
||||
namespace Controllers {
|
||||
class BleClient {
|
||||
public:
|
||||
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) {
|
||||
firmwareUpdateCurrentBytes = currentBytes;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -8,11 +8,13 @@ namespace Pinetime {
|
|||
class Ble {
|
||||
public:
|
||||
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 };
|
||||
|
||||
Ble() = default;
|
||||
bool IsConnected() const {return isConnected;}
|
||||
bool IsConnected() const {
|
||||
return isConnected;
|
||||
}
|
||||
void Connect();
|
||||
void Disconnect();
|
||||
|
||||
|
@ -20,16 +22,33 @@ namespace Pinetime {
|
|||
void StopFirmwareUpdate();
|
||||
void FirmwareUpdateTotalBytes(uint32_t totalBytes);
|
||||
void FirmwareUpdateCurrentBytes(uint32_t currentBytes);
|
||||
void State(FirmwareUpdateStates state) { firmwareUpdateState = state; }
|
||||
void State(FirmwareUpdateStates state) {
|
||||
firmwareUpdateState = state;
|
||||
}
|
||||
|
||||
bool IsFirmwareUpdating() const { return isFirmwareUpdating; }
|
||||
uint32_t FirmwareUpdateTotalBytes() const { return firmwareUpdateTotalBytes; }
|
||||
uint32_t FirmwareUpdateCurrentBytes() const { return firmwareUpdateCurrentBytes; }
|
||||
FirmwareUpdateStates State() const { return firmwareUpdateState; }
|
||||
bool IsFirmwareUpdating() const {
|
||||
return isFirmwareUpdating;
|
||||
}
|
||||
uint32_t FirmwareUpdateTotalBytes() const {
|
||||
return firmwareUpdateTotalBytes;
|
||||
}
|
||||
uint32_t FirmwareUpdateCurrentBytes() const {
|
||||
return firmwareUpdateCurrentBytes;
|
||||
}
|
||||
FirmwareUpdateStates State() const {
|
||||
return firmwareUpdateState;
|
||||
}
|
||||
|
||||
void Address(BleAddress&& addr) {
|
||||
address = addr;
|
||||
}
|
||||
const BleAddress& Address() const {
|
||||
return address;
|
||||
}
|
||||
void AddressType(AddressTypes t) {
|
||||
addressType = t;
|
||||
}
|
||||
|
||||
void Address(BleAddress&& addr) { address = addr; }
|
||||
const BleAddress& Address() const { return address; }
|
||||
void AddressType(AddressTypes t) { addressType = t;}
|
||||
private:
|
||||
bool isConnected = false;
|
||||
bool isFirmwareUpdating = false;
|
||||
|
@ -38,7 +57,6 @@ namespace Pinetime {
|
|||
FirmwareUpdateStates firmwareUpdateState = FirmwareUpdateStates::Idle;
|
||||
BleAddress address;
|
||||
AddressTypes addressType;
|
||||
|
||||
};
|
||||
}
|
||||
}
|
|
@ -9,39 +9,37 @@ constexpr ble_uuid16_t CurrentTimeClient::ctsServiceUuid;
|
|||
constexpr ble_uuid16_t CurrentTimeClient::currentTimeCharacteristicUuid;
|
||||
|
||||
namespace {
|
||||
int OnDiscoveryEventCallback(uint16_t conn_handle, const struct ble_gatt_error *error, const struct ble_gatt_svc *service, void *arg) {
|
||||
auto client = static_cast<CurrentTimeClient *>(arg);
|
||||
int OnDiscoveryEventCallback(uint16_t conn_handle, const struct ble_gatt_error* error, const struct ble_gatt_svc* service, void* arg) {
|
||||
auto client = static_cast<CurrentTimeClient*>(arg);
|
||||
return client->OnDiscoveryEvent(conn_handle, error, service);
|
||||
}
|
||||
|
||||
int OnCurrentTimeCharacteristicDiscoveredCallback(uint16_t conn_handle, const struct ble_gatt_error *error,
|
||||
const struct ble_gatt_chr *chr, void *arg) {
|
||||
auto client = static_cast<CurrentTimeClient *>(arg);
|
||||
int OnCurrentTimeCharacteristicDiscoveredCallback(uint16_t conn_handle,
|
||||
const struct ble_gatt_error* error,
|
||||
const struct ble_gatt_chr* chr,
|
||||
void* arg) {
|
||||
auto client = static_cast<CurrentTimeClient*>(arg);
|
||||
return client->OnCharacteristicDiscoveryEvent(conn_handle, error, chr);
|
||||
}
|
||||
|
||||
int CurrentTimeReadCallback(uint16_t conn_handle, const struct ble_gatt_error *error, struct ble_gatt_attr *attr, void *arg) {
|
||||
auto client = static_cast<CurrentTimeClient *>(arg);
|
||||
int CurrentTimeReadCallback(uint16_t conn_handle, const struct ble_gatt_error* error, struct ble_gatt_attr* attr, void* arg) {
|
||||
auto client = static_cast<CurrentTimeClient*>(arg);
|
||||
return client->OnCurrentTimeReadResult(conn_handle, error, attr);
|
||||
}
|
||||
}
|
||||
|
||||
CurrentTimeClient::CurrentTimeClient(DateTime &dateTimeController) : dateTimeController{dateTimeController} {
|
||||
|
||||
CurrentTimeClient::CurrentTimeClient(DateTime& dateTimeController) : dateTimeController {dateTimeController} {
|
||||
}
|
||||
|
||||
void CurrentTimeClient::Init() {
|
||||
|
||||
}
|
||||
|
||||
bool CurrentTimeClient::OnDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error *error,
|
||||
const ble_gatt_svc *service) {
|
||||
bool CurrentTimeClient::OnDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error* error, const ble_gatt_svc* service) {
|
||||
if (service == nullptr && error->status == BLE_HS_EDONE) {
|
||||
if (isDiscovered) {
|
||||
NRF_LOG_INFO("CTS found, starting characteristics discovery");
|
||||
|
||||
ble_gattc_disc_all_chrs(connectionHandle, ctsStartHandle, ctsEndHandle,
|
||||
OnCurrentTimeCharacteristicDiscoveredCallback, this);
|
||||
ble_gattc_disc_all_chrs(connectionHandle, ctsStartHandle, ctsEndHandle, OnCurrentTimeCharacteristicDiscoveredCallback, this);
|
||||
} else {
|
||||
NRF_LOG_INFO("CTS not found");
|
||||
onServiceDiscovered(connectionHandle);
|
||||
|
@ -49,7 +47,7 @@ bool CurrentTimeClient::OnDiscoveryEvent(uint16_t connectionHandle, const ble_ga
|
|||
return true;
|
||||
}
|
||||
|
||||
if (service != nullptr && ble_uuid_cmp(((ble_uuid_t *) &ctsServiceUuid), &service->uuid.u) == 0) {
|
||||
if (service != nullptr && ble_uuid_cmp(((ble_uuid_t*) &ctsServiceUuid), &service->uuid.u) == 0) {
|
||||
NRF_LOG_INFO("CTS discovered : 0x%x - 0x%x", service->start_handle, service->end_handle);
|
||||
isDiscovered = true;
|
||||
ctsStartHandle = service->start_handle;
|
||||
|
@ -59,8 +57,9 @@ bool CurrentTimeClient::OnDiscoveryEvent(uint16_t connectionHandle, const ble_ga
|
|||
return false;
|
||||
}
|
||||
|
||||
int CurrentTimeClient::OnCharacteristicDiscoveryEvent(uint16_t conn_handle, const ble_gatt_error *error,
|
||||
const ble_gatt_chr *characteristic) {
|
||||
int CurrentTimeClient::OnCharacteristicDiscoveryEvent(uint16_t conn_handle,
|
||||
const ble_gatt_error* error,
|
||||
const ble_gatt_chr* characteristic) {
|
||||
if (characteristic == nullptr && error->status == BLE_HS_EDONE) {
|
||||
if (isCharacteristicDiscovered) {
|
||||
NRF_LOG_INFO("CTS Characteristic discovery complete, fetching time");
|
||||
|
@ -73,8 +72,7 @@ int CurrentTimeClient::OnCharacteristicDiscoveryEvent(uint16_t conn_handle, cons
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (characteristic != nullptr &&
|
||||
ble_uuid_cmp(((ble_uuid_t *) ¤tTimeCharacteristicUuid), &characteristic->uuid.u) == 0) {
|
||||
if (characteristic != nullptr && ble_uuid_cmp(((ble_uuid_t*) ¤tTimeCharacteristicUuid), &characteristic->uuid.u) == 0) {
|
||||
NRF_LOG_INFO("CTS Characteristic discovered : 0x%x", characteristic->val_handle);
|
||||
isCharacteristicDiscovered = true;
|
||||
currentTimeHandle = characteristic->val_handle;
|
||||
|
@ -82,17 +80,15 @@ int CurrentTimeClient::OnCharacteristicDiscoveryEvent(uint16_t conn_handle, cons
|
|||
return 0;
|
||||
}
|
||||
|
||||
int CurrentTimeClient::OnCurrentTimeReadResult(uint16_t conn_handle, const ble_gatt_error *error,
|
||||
const ble_gatt_attr *attribute) {
|
||||
int CurrentTimeClient::OnCurrentTimeReadResult(uint16_t conn_handle, const ble_gatt_error* error, const ble_gatt_attr* attribute) {
|
||||
if (error->status == 0) {
|
||||
// TODO check that attribute->handle equals the handle discovered in OnCharacteristicDiscoveryEvent
|
||||
CtsData result;
|
||||
os_mbuf_copydata(attribute->om, 0, sizeof(CtsData), &result);
|
||||
NRF_LOG_INFO("Received data: %d-%d-%d %d:%d:%d", result.year,
|
||||
result.month, result.dayofmonth,
|
||||
result.hour, result.minute, result.second);
|
||||
dateTimeController.SetTime(result.year, result.month, result.dayofmonth,
|
||||
0, result.hour, result.minute, result.second, nrf_rtc_counter_get(portNRF_RTC_REG));
|
||||
NRF_LOG_INFO(
|
||||
"Received data: %d-%d-%d %d:%d:%d", result.year, result.month, result.dayofmonth, result.hour, result.minute, result.second);
|
||||
dateTimeController.SetTime(
|
||||
result.year, result.month, result.dayofmonth, 0, result.hour, result.minute, result.second, nrf_rtc_counter_get(portNRF_RTC_REG));
|
||||
} else {
|
||||
NRF_LOG_INFO("Error retrieving current time: %d", error->status);
|
||||
}
|
||||
|
|
|
@ -16,12 +16,15 @@ namespace Pinetime {
|
|||
explicit CurrentTimeClient(DateTime& dateTimeController);
|
||||
void Init();
|
||||
void Reset();
|
||||
bool OnDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error *error, const ble_gatt_svc *service);
|
||||
int OnCharacteristicDiscoveryEvent(uint16_t conn_handle, const ble_gatt_error *error,
|
||||
const ble_gatt_chr *characteristic);
|
||||
int OnCurrentTimeReadResult(uint16_t conn_handle, const ble_gatt_error *error, const ble_gatt_attr *attribute);
|
||||
static constexpr const ble_uuid16_t* Uuid() { return &CurrentTimeClient::ctsServiceUuid; }
|
||||
static constexpr const ble_uuid16_t* CurrentTimeCharacteristicUuid() { return &CurrentTimeClient::currentTimeCharacteristicUuid; }
|
||||
bool OnDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error* error, const ble_gatt_svc* service);
|
||||
int OnCharacteristicDiscoveryEvent(uint16_t conn_handle, const ble_gatt_error* error, const ble_gatt_chr* characteristic);
|
||||
int OnCurrentTimeReadResult(uint16_t conn_handle, const ble_gatt_error* error, const ble_gatt_attr* attribute);
|
||||
static constexpr const ble_uuid16_t* Uuid() {
|
||||
return &CurrentTimeClient::ctsServiceUuid;
|
||||
}
|
||||
static constexpr const ble_uuid16_t* CurrentTimeCharacteristicUuid() {
|
||||
return &CurrentTimeClient::currentTimeCharacteristicUuid;
|
||||
}
|
||||
void Discover(uint16_t connectionHandle, std::function<void(uint16_t)> lambda) override;
|
||||
|
||||
private:
|
||||
|
@ -39,14 +42,8 @@ namespace Pinetime {
|
|||
static constexpr uint16_t ctsServiceId {0x1805};
|
||||
static constexpr uint16_t currentTimeCharacteristicId {0x2a2b};
|
||||
|
||||
static constexpr ble_uuid16_t ctsServiceUuid {
|
||||
.u { .type = BLE_UUID_TYPE_16 },
|
||||
.value = ctsServiceId
|
||||
};
|
||||
static constexpr ble_uuid16_t currentTimeCharacteristicUuid {
|
||||
.u { .type = BLE_UUID_TYPE_16 },
|
||||
.value = currentTimeCharacteristicId
|
||||
};
|
||||
static constexpr ble_uuid16_t ctsServiceUuid {.u {.type = BLE_UUID_TYPE_16}, .value = ctsServiceId};
|
||||
static constexpr ble_uuid16_t currentTimeCharacteristicUuid {.u {.type = BLE_UUID_TYPE_16}, .value = currentTimeCharacteristicId};
|
||||
|
||||
DateTime& dateTimeController;
|
||||
bool isDiscovered = false;
|
||||
|
|
|
@ -7,8 +7,7 @@ using namespace Pinetime::Controllers;
|
|||
constexpr ble_uuid16_t CurrentTimeService::ctsUuid;
|
||||
constexpr ble_uuid16_t CurrentTimeService::ctChrUuid;
|
||||
|
||||
|
||||
int CTSCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) {
|
||||
int CTSCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
|
||||
auto cts = static_cast<CurrentTimeService*>(arg);
|
||||
return cts->OnTimeAccessed(conn_handle, attr_handle, ctxt);
|
||||
}
|
||||
|
@ -22,9 +21,7 @@ void CurrentTimeService::Init() {
|
|||
ASSERT(res == 0);
|
||||
}
|
||||
|
||||
|
||||
int CurrentTimeService::OnTimeAccessed(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt) {
|
||||
int CurrentTimeService::OnTimeAccessed(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) {
|
||||
|
||||
NRF_LOG_INFO("Setting time...");
|
||||
|
||||
|
@ -32,12 +29,11 @@ int CurrentTimeService::OnTimeAccessed(uint16_t conn_handle, uint16_t attr_handl
|
|||
CtsData result;
|
||||
os_mbuf_copydata(ctxt->om, 0, sizeof(CtsData), &result);
|
||||
|
||||
NRF_LOG_INFO("Received data: %d-%d-%d %d:%d:%d", result.year,
|
||||
result.month, result.dayofmonth,
|
||||
result.hour, result.minute, result.second);
|
||||
NRF_LOG_INFO(
|
||||
"Received data: %d-%d-%d %d:%d:%d", result.year, result.month, result.dayofmonth, result.hour, result.minute, result.second);
|
||||
|
||||
m_dateTimeController.SetTime(result.year, result.month, result.dayofmonth,
|
||||
0, result.hour, result.minute, result.second, nrf_rtc_counter_get(portNRF_RTC_REG));
|
||||
m_dateTimeController.SetTime(
|
||||
result.year, result.month, result.dayofmonth, 0, result.hour, result.minute, result.second, nrf_rtc_counter_get(portNRF_RTC_REG));
|
||||
|
||||
} else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
|
||||
CtsData currentDateTime;
|
||||
|
@ -49,39 +45,26 @@ int CurrentTimeService::OnTimeAccessed(uint16_t conn_handle, uint16_t attr_handl
|
|||
currentDateTime.second = m_dateTimeController.Seconds();
|
||||
currentDateTime.millis = 0;
|
||||
|
||||
|
||||
int res = os_mbuf_append(ctxt->om, ¤tDateTime, sizeof(CtsData));
|
||||
return (res == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
CurrentTimeService::CurrentTimeService(DateTime &dateTimeController) :
|
||||
characteristicDefinition{
|
||||
{
|
||||
.uuid = (ble_uuid_t *) &ctChrUuid,
|
||||
CurrentTimeService::CurrentTimeService(DateTime& dateTimeController)
|
||||
: characteristicDefinition {{.uuid = (ble_uuid_t*) &ctChrUuid,
|
||||
.access_cb = CTSCallback,
|
||||
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
|
||||
},
|
||||
{
|
||||
0
|
||||
}
|
||||
},
|
||||
serviceDefinition{
|
||||
{
|
||||
/* Device Information Service */
|
||||
.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
|
||||
.uuid = (ble_uuid_t*) &ctsUuid,
|
||||
.characteristics = characteristicDefinition},
|
||||
{0},
|
||||
},
|
||||
{
|
||||
0
|
||||
},
|
||||
}, m_dateTimeController{dateTimeController} {
|
||||
|
||||
m_dateTimeController {dateTimeController} {
|
||||
}
|
||||
|
||||
|
|
|
@ -13,25 +13,18 @@ namespace Pinetime {
|
|||
namespace Controllers {
|
||||
class CurrentTimeService {
|
||||
public:
|
||||
CurrentTimeService(DateTime &dateTimeController);
|
||||
CurrentTimeService(DateTime& dateTimeController);
|
||||
void Init();
|
||||
|
||||
int OnTimeAccessed(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt);
|
||||
int OnTimeAccessed(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt);
|
||||
|
||||
private:
|
||||
static constexpr uint16_t ctsId {0x1805};
|
||||
static constexpr uint16_t ctsCharId {0x2a2b};
|
||||
|
||||
static constexpr ble_uuid16_t ctsUuid {
|
||||
.u { .type = BLE_UUID_TYPE_16 },
|
||||
.value = ctsId
|
||||
};
|
||||
static constexpr ble_uuid16_t ctsUuid {.u {.type = BLE_UUID_TYPE_16}, .value = ctsId};
|
||||
|
||||
static constexpr ble_uuid16_t ctChrUuid {
|
||||
.u { .type = BLE_UUID_TYPE_16 },
|
||||
.value = ctsCharId
|
||||
};
|
||||
static constexpr ble_uuid16_t ctChrUuid {.u {.type = BLE_UUID_TYPE_16}, .value = ctsCharId};
|
||||
|
||||
struct ble_gatt_chr_def characteristicDefinition[2];
|
||||
struct ble_gatt_svc_def serviceDefinition[2];
|
||||
|
@ -47,7 +40,7 @@ namespace Pinetime {
|
|||
uint8_t reason;
|
||||
} 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::swRevisionUuid;
|
||||
|
||||
|
||||
int DeviceInformationCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) {
|
||||
int DeviceInformationCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
|
||||
auto deviceInformationService = static_cast<DeviceInformationService*>(arg);
|
||||
return deviceInformationService->OnDeviceInfoRequested(conn_handle, attr_handle, ctxt);
|
||||
}
|
||||
|
@ -25,10 +24,8 @@ void DeviceInformationService::Init() {
|
|||
ASSERT(res == 0);
|
||||
}
|
||||
|
||||
|
||||
int DeviceInformationService::OnDeviceInfoRequested(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt) {
|
||||
const char *str;
|
||||
int DeviceInformationService::OnDeviceInfoRequested(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) {
|
||||
const char* str;
|
||||
|
||||
switch (ble_uuid_u16(ctxt->chr->uuid)) {
|
||||
case manufacturerNameId:
|
||||
|
@ -57,60 +54,49 @@ int DeviceInformationService::OnDeviceInfoRequested(uint16_t conn_handle, uint16
|
|||
return (res == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
|
||||
DeviceInformationService::DeviceInformationService() :
|
||||
characteristicDefinition{
|
||||
{
|
||||
.uuid = (ble_uuid_t *) &manufacturerNameUuid,
|
||||
DeviceInformationService::DeviceInformationService()
|
||||
: characteristicDefinition {{
|
||||
.uuid = (ble_uuid_t*) &manufacturerNameUuid,
|
||||
.access_cb = DeviceInformationCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_READ,
|
||||
},
|
||||
{
|
||||
.uuid = (ble_uuid_t *) &modelNumberUuid,
|
||||
.uuid = (ble_uuid_t*) &modelNumberUuid,
|
||||
.access_cb = DeviceInformationCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_READ,
|
||||
},
|
||||
{
|
||||
.uuid = (ble_uuid_t *) &serialNumberUuid,
|
||||
.uuid = (ble_uuid_t*) &serialNumberUuid,
|
||||
.access_cb = DeviceInformationCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_READ,
|
||||
},
|
||||
{
|
||||
.uuid = (ble_uuid_t *) &fwRevisionUuid,
|
||||
.uuid = (ble_uuid_t*) &fwRevisionUuid,
|
||||
.access_cb = DeviceInformationCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_READ,
|
||||
},
|
||||
{
|
||||
.uuid = (ble_uuid_t *) &hwRevisionUuid,
|
||||
.uuid = (ble_uuid_t*) &hwRevisionUuid,
|
||||
.access_cb = DeviceInformationCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_READ,
|
||||
},
|
||||
{
|
||||
.uuid = (ble_uuid_t *) &swRevisionUuid,
|
||||
.uuid = (ble_uuid_t*) &swRevisionUuid,
|
||||
.access_cb = DeviceInformationCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_READ,
|
||||
},
|
||||
{
|
||||
0
|
||||
}
|
||||
},
|
||||
serviceDefinition{
|
||||
{
|
||||
/* Device Information Service */
|
||||
{0}},
|
||||
serviceDefinition {
|
||||
{/* Device Information Service */
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = (ble_uuid_t *) &deviceInfoUuid,
|
||||
.characteristics = characteristicDefinition
|
||||
},
|
||||
{
|
||||
0
|
||||
},
|
||||
}
|
||||
{
|
||||
|
||||
.uuid = (ble_uuid_t*) &deviceInfoUuid,
|
||||
.characteristics = characteristicDefinition},
|
||||
{0},
|
||||
} {
|
||||
}
|
||||
|
||||
|
|
|
@ -13,8 +13,7 @@ namespace Pinetime {
|
|||
DeviceInformationService();
|
||||
void Init();
|
||||
|
||||
int OnDeviceInfoRequested(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt);
|
||||
int OnDeviceInfoRequested(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt);
|
||||
|
||||
private:
|
||||
static constexpr uint16_t deviceInfoId {0x180a};
|
||||
|
@ -32,46 +31,22 @@ namespace Pinetime {
|
|||
static constexpr const char* fwRevision = Version::VersionString();
|
||||
static constexpr const char* swRevision = "InfiniTime";
|
||||
|
||||
static constexpr ble_uuid16_t deviceInfoUuid {.u {.type = BLE_UUID_TYPE_16}, .value = deviceInfoId};
|
||||
|
||||
static constexpr ble_uuid16_t deviceInfoUuid {
|
||||
.u { .type = BLE_UUID_TYPE_16 },
|
||||
.value = deviceInfoId
|
||||
};
|
||||
static constexpr ble_uuid16_t manufacturerNameUuid {.u {.type = BLE_UUID_TYPE_16}, .value = manufacturerNameId};
|
||||
|
||||
static constexpr ble_uuid16_t manufacturerNameUuid {
|
||||
.u { .type = BLE_UUID_TYPE_16 },
|
||||
.value = manufacturerNameId
|
||||
};
|
||||
static constexpr ble_uuid16_t modelNumberUuid {.u {.type = BLE_UUID_TYPE_16}, .value = modelNumberId};
|
||||
|
||||
static constexpr ble_uuid16_t modelNumberUuid {
|
||||
.u { .type = BLE_UUID_TYPE_16 },
|
||||
.value = modelNumberId
|
||||
};
|
||||
static constexpr ble_uuid16_t serialNumberUuid {.u {.type = BLE_UUID_TYPE_16}, .value = serialNumberId};
|
||||
|
||||
static constexpr ble_uuid16_t serialNumberUuid {
|
||||
.u { .type = BLE_UUID_TYPE_16 },
|
||||
.value = serialNumberId
|
||||
};
|
||||
static constexpr ble_uuid16_t fwRevisionUuid {.u {.type = BLE_UUID_TYPE_16}, .value = fwRevisionId};
|
||||
|
||||
static constexpr ble_uuid16_t fwRevisionUuid {
|
||||
.u { .type = BLE_UUID_TYPE_16 },
|
||||
.value = fwRevisionId
|
||||
};
|
||||
static constexpr ble_uuid16_t hwRevisionUuid {.u {.type = BLE_UUID_TYPE_16}, .value = hwRevisionId};
|
||||
|
||||
static constexpr ble_uuid16_t hwRevisionUuid {
|
||||
.u {.type = BLE_UUID_TYPE_16},
|
||||
.value = hwRevisionId
|
||||
};
|
||||
|
||||
static constexpr ble_uuid16_t swRevisionUuid {
|
||||
.u {.type = BLE_UUID_TYPE_16},
|
||||
.value = swRevisionId
|
||||
};
|
||||
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::packetCharacteristicUuid;
|
||||
|
||||
int DfuServiceCallback(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg) {
|
||||
auto dfuService = static_cast<DfuService *>(arg);
|
||||
int DfuServiceCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
|
||||
auto dfuService = static_cast<DfuService*>(arg);
|
||||
return dfuService->OnServiceData(conn_handle, attr_handle, ctxt);
|
||||
}
|
||||
|
||||
void NotificationTimerCallback(TimerHandle_t xTimer) {
|
||||
auto notificationManager = static_cast<DfuService::NotificationManager *>(pvTimerGetTimerID(xTimer));
|
||||
auto notificationManager = static_cast<DfuService::NotificationManager*>(pvTimerGetTimerID(xTimer));
|
||||
notificationManager->OnNotificationTimer();
|
||||
}
|
||||
|
||||
void TimeoutTimerCallback(TimerHandle_t xTimer) {
|
||||
auto dfuService = static_cast<DfuService *>(pvTimerGetTimerID(xTimer));
|
||||
auto dfuService = static_cast<DfuService*>(pvTimerGetTimerID(xTimer));
|
||||
dfuService->OnTimeout();
|
||||
}
|
||||
|
||||
DfuService::DfuService(Pinetime::System::SystemTask &systemTask, Pinetime::Controllers::Ble &bleController,
|
||||
Pinetime::Drivers::SpiNorFlash &spiNorFlash) :
|
||||
systemTask{systemTask},
|
||||
bleController{bleController},
|
||||
dfuImage{spiNorFlash},
|
||||
characteristicDefinition{
|
||||
{
|
||||
.uuid = (ble_uuid_t *) &packetCharacteristicUuid,
|
||||
DfuService::DfuService(Pinetime::System::SystemTask& systemTask,
|
||||
Pinetime::Controllers::Ble& bleController,
|
||||
Pinetime::Drivers::SpiNorFlash& spiNorFlash)
|
||||
: systemTask {systemTask},
|
||||
bleController {bleController},
|
||||
dfuImage {spiNorFlash},
|
||||
characteristicDefinition {{
|
||||
.uuid = (ble_uuid_t*) &packetCharacteristicUuid,
|
||||
.access_cb = DfuServiceCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE_NO_RSP,
|
||||
.val_handle = nullptr,
|
||||
},
|
||||
{
|
||||
.uuid = (ble_uuid_t *) &controlPointCharacteristicUuid,
|
||||
.uuid = (ble_uuid_t*) &controlPointCharacteristicUuid,
|
||||
.access_cb = DfuServiceCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_NOTIFY,
|
||||
.val_handle = nullptr,
|
||||
},
|
||||
{
|
||||
.uuid = (ble_uuid_t *) &revisionCharacteristicUuid,
|
||||
.uuid = (ble_uuid_t*) &revisionCharacteristicUuid,
|
||||
.access_cb = DfuServiceCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_READ,
|
||||
.val_handle = &revision,
|
||||
|
||||
},
|
||||
{
|
||||
0
|
||||
}
|
||||
{0}
|
||||
|
||||
},
|
||||
serviceDefinition{
|
||||
{
|
||||
/* Device Information Service */
|
||||
serviceDefinition {
|
||||
{/* Device Information Service */
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = (ble_uuid_t *) &serviceUuid,
|
||||
.characteristics = characteristicDefinition
|
||||
},
|
||||
{
|
||||
0
|
||||
},
|
||||
.uuid = (ble_uuid_t*) &serviceUuid,
|
||||
.characteristics = characteristicDefinition},
|
||||
{0},
|
||||
} {
|
||||
timeoutTimer = xTimerCreate ("notificationTimer", 10000, pdFALSE, this, TimeoutTimerCallback);
|
||||
timeoutTimer = xTimerCreate("notificationTimer", 10000, pdFALSE, this, TimeoutTimerCallback);
|
||||
}
|
||||
|
||||
void DfuService::Init() {
|
||||
|
@ -83,55 +76,54 @@ void DfuService::Init() {
|
|||
ASSERT(res == 0);
|
||||
}
|
||||
|
||||
int DfuService::OnServiceData(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt *context) {
|
||||
if(bleController.IsFirmwareUpdating()){
|
||||
int DfuService::OnServiceData(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context) {
|
||||
if (bleController.IsFirmwareUpdating()) {
|
||||
xTimerStart(timeoutTimer, 0);
|
||||
}
|
||||
|
||||
|
||||
ble_gatts_find_chr((ble_uuid_t *) &serviceUuid, (ble_uuid_t *) &packetCharacteristicUuid, nullptr,
|
||||
&packetCharacteristicHandle);
|
||||
ble_gatts_find_chr((ble_uuid_t *) &serviceUuid, (ble_uuid_t *) &controlPointCharacteristicUuid, nullptr,
|
||||
&controlPointCharacteristicHandle);
|
||||
ble_gatts_find_chr((ble_uuid_t *) &serviceUuid, (ble_uuid_t *) &revisionCharacteristicUuid, nullptr,
|
||||
&revisionCharacteristicHandle);
|
||||
ble_gatts_find_chr((ble_uuid_t*) &serviceUuid, (ble_uuid_t*) &packetCharacteristicUuid, nullptr, &packetCharacteristicHandle);
|
||||
ble_gatts_find_chr((ble_uuid_t*) &serviceUuid, (ble_uuid_t*) &controlPointCharacteristicUuid, nullptr, &controlPointCharacteristicHandle);
|
||||
ble_gatts_find_chr((ble_uuid_t*) &serviceUuid, (ble_uuid_t*) &revisionCharacteristicUuid, nullptr, &revisionCharacteristicHandle);
|
||||
|
||||
if (attributeHandle == packetCharacteristicHandle) {
|
||||
if (context->op == BLE_GATT_ACCESS_OP_WRITE_CHR)
|
||||
return WritePacketHandler(connectionHandle, context->om);
|
||||
else return 0;
|
||||
else
|
||||
return 0;
|
||||
} else if (attributeHandle == controlPointCharacteristicHandle) {
|
||||
if (context->op == BLE_GATT_ACCESS_OP_WRITE_CHR)
|
||||
return ControlPointHandler(connectionHandle, context->om);
|
||||
else return 0;
|
||||
else
|
||||
return 0;
|
||||
} else if (attributeHandle == revisionCharacteristicHandle) {
|
||||
if (context->op == BLE_GATT_ACCESS_OP_READ_CHR)
|
||||
return SendDfuRevision(context->om);
|
||||
else return 0;
|
||||
else
|
||||
return 0;
|
||||
} else {
|
||||
NRF_LOG_INFO("[DFU] Unknown Characteristic : %d", attributeHandle);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int DfuService::SendDfuRevision(os_mbuf *om) const {
|
||||
int DfuService::SendDfuRevision(os_mbuf* om) const {
|
||||
int res = os_mbuf_append(om, &revision, sizeof(revision));
|
||||
return (res == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
|
||||
int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf *om) {
|
||||
int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf* om) {
|
||||
switch (state) {
|
||||
case States::Start: {
|
||||
softdeviceSize = om->om_data[0] + (om->om_data[1] << 8) + (om->om_data[2] << 16) + (om->om_data[3] << 24);
|
||||
bootloaderSize = om->om_data[4] + (om->om_data[5] << 8) + (om->om_data[6] << 16) + (om->om_data[7] << 24);
|
||||
applicationSize = om->om_data[8] + (om->om_data[9] << 8) + (om->om_data[10] << 16) + (om->om_data[11] << 24);
|
||||
bleController.FirmwareUpdateTotalBytes(applicationSize);
|
||||
NRF_LOG_INFO("[DFU] -> Start data received : SD size : %d, BT size : %d, app size : %d", softdeviceSize,
|
||||
bootloaderSize, applicationSize);
|
||||
NRF_LOG_INFO(
|
||||
"[DFU] -> Start data received : SD size : %d, BT size : %d, app size : %d", softdeviceSize, bootloaderSize, applicationSize);
|
||||
|
||||
dfuImage.Erase();
|
||||
|
||||
uint8_t data[]{16, 1, 1};
|
||||
uint8_t data[] {16, 1, 1};
|
||||
notificationManager.Send(connectionHandle, controlPointCharacteristicHandle, data, 3);
|
||||
state = States::Init;
|
||||
}
|
||||
|
@ -139,19 +131,22 @@ int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf *om) {
|
|||
case States::Init: {
|
||||
uint16_t deviceType = om->om_data[0] + (om->om_data[1] << 8);
|
||||
uint16_t deviceRevision = om->om_data[2] + (om->om_data[3] << 8);
|
||||
uint32_t applicationVersion =
|
||||
om->om_data[4] + (om->om_data[5] << 8) + (om->om_data[6] << 16) + (om->om_data[7] << 24);
|
||||
uint32_t applicationVersion = om->om_data[4] + (om->om_data[5] << 8) + (om->om_data[6] << 16) + (om->om_data[7] << 24);
|
||||
uint16_t softdeviceArrayLength = om->om_data[8] + (om->om_data[9] << 8);
|
||||
uint16_t sd[softdeviceArrayLength];
|
||||
for (int i = 0; i < softdeviceArrayLength; i++) {
|
||||
sd[i] = om->om_data[10 + (i * 2)] + (om->om_data[10 + (i * 2) + 1] << 8);
|
||||
}
|
||||
expectedCrc =
|
||||
om->om_data[10 + (softdeviceArrayLength * 2)] + (om->om_data[10 + (softdeviceArrayLength * 2) + 1] << 8);
|
||||
expectedCrc = om->om_data[10 + (softdeviceArrayLength * 2)] + (om->om_data[10 + (softdeviceArrayLength * 2) + 1] << 8);
|
||||
|
||||
NRF_LOG_INFO(
|
||||
"[DFU] -> Init data received : deviceType = %d, deviceRevision = %d, applicationVersion = %d, nb SD = %d, First SD = %d, CRC = %u",
|
||||
deviceType, deviceRevision, applicationVersion, softdeviceArrayLength, sd[0], expectedCrc);
|
||||
deviceType,
|
||||
deviceRevision,
|
||||
applicationVersion,
|
||||
softdeviceArrayLength,
|
||||
sd[0],
|
||||
expectedCrc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -163,14 +158,16 @@ int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf *om) {
|
|||
bleController.FirmwareUpdateCurrentBytes(bytesReceived);
|
||||
|
||||
if ((nbPacketReceived % nbPacketsToNotify) == 0 && bytesReceived != applicationSize) {
|
||||
uint8_t data[5]{static_cast<uint8_t>(Opcodes::PacketReceiptNotification),
|
||||
(uint8_t) (bytesReceived & 0x000000FFu), (uint8_t) (bytesReceived >> 8u),
|
||||
(uint8_t) (bytesReceived >> 16u), (uint8_t) (bytesReceived >> 24u)};
|
||||
uint8_t data[5] {static_cast<uint8_t>(Opcodes::PacketReceiptNotification),
|
||||
(uint8_t) (bytesReceived & 0x000000FFu),
|
||||
(uint8_t) (bytesReceived >> 8u),
|
||||
(uint8_t) (bytesReceived >> 16u),
|
||||
(uint8_t) (bytesReceived >> 24u)};
|
||||
NRF_LOG_INFO("[DFU] -> Send packet notification: %d bytes received", bytesReceived);
|
||||
notificationManager.Send(connectionHandle, controlPointCharacteristicHandle, data, 5);
|
||||
}
|
||||
if (dfuImage.IsComplete()) {
|
||||
uint8_t data[3]{static_cast<uint8_t>(Opcodes::Response),
|
||||
uint8_t data[3] {static_cast<uint8_t>(Opcodes::Response),
|
||||
static_cast<uint8_t>(Opcodes::ReceiveFirmwareImage),
|
||||
static_cast<uint8_t>(ErrorCodes::NoError)};
|
||||
NRF_LOG_INFO("[DFU] -> Send packet notification : all bytes received!");
|
||||
|
@ -186,7 +183,7 @@ int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf *om) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int DfuService::ControlPointHandler(uint16_t connectionHandle, os_mbuf *om) {
|
||||
int DfuService::ControlPointHandler(uint16_t connectionHandle, os_mbuf* om) {
|
||||
auto opcode = static_cast<Opcodes>(om->om_data[0]);
|
||||
NRF_LOG_INFO("[DFU] -> ControlPointHandler");
|
||||
|
||||
|
@ -214,8 +211,7 @@ int DfuService::ControlPointHandler(uint16_t connectionHandle, os_mbuf *om) {
|
|||
NRF_LOG_INFO("[DFU] -> Start DFU, mode %d not supported!", imageType);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
case Opcodes::InitDFUParameters: {
|
||||
if (state != States::Init) {
|
||||
NRF_LOG_INFO("[DFU] -> Init DFU requested, but we are not in Init state");
|
||||
|
@ -225,11 +221,9 @@ int DfuService::ControlPointHandler(uint16_t connectionHandle, os_mbuf *om) {
|
|||
NRF_LOG_INFO("[DFU] -> Init DFU parameters %s", isInitComplete ? " complete" : " not complete");
|
||||
|
||||
if (isInitComplete) {
|
||||
uint8_t data[3] {
|
||||
static_cast<uint8_t>(Opcodes::Response),
|
||||
uint8_t data[3] {static_cast<uint8_t>(Opcodes::Response),
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
|
@ -257,26 +251,22 @@ int DfuService::ControlPointHandler(uint16_t connectionHandle, os_mbuf *om) {
|
|||
|
||||
NRF_LOG_INFO("[DFU] -> Validate firmware image requested -- %d", connectionHandle);
|
||||
|
||||
if(dfuImage.Validate()){
|
||||
if (dfuImage.Validate()) {
|
||||
state = States::Validated;
|
||||
bleController.State(Pinetime::Controllers::Ble::FirmwareUpdateStates::Validated);
|
||||
NRF_LOG_INFO("Image OK");
|
||||
|
||||
uint8_t data[3] {
|
||||
static_cast<uint8_t>(Opcodes::Response),
|
||||
uint8_t data[3] {static_cast<uint8_t>(Opcodes::Response),
|
||||
static_cast<uint8_t>(Opcodes::ValidateFirmware),
|
||||
static_cast<uint8_t>(ErrorCodes::NoError)
|
||||
};
|
||||
static_cast<uint8_t>(ErrorCodes::NoError)};
|
||||
notificationManager.AsyncSend(connectionHandle, controlPointCharacteristicHandle, data, 3);
|
||||
} else {
|
||||
bleController.State(Pinetime::Controllers::Ble::FirmwareUpdateStates::Error);
|
||||
NRF_LOG_INFO("Image Error : bad CRC");
|
||||
|
||||
uint8_t data[3] {
|
||||
static_cast<uint8_t>(Opcodes::Response),
|
||||
uint8_t data[3] {static_cast<uint8_t>(Opcodes::Response),
|
||||
static_cast<uint8_t>(Opcodes::ValidateFirmware),
|
||||
static_cast<uint8_t>(ErrorCodes::CrcError)
|
||||
};
|
||||
static_cast<uint8_t>(ErrorCodes::CrcError)};
|
||||
notificationManager.AsyncSend(connectionHandle, controlPointCharacteristicHandle, data, 3);
|
||||
}
|
||||
|
||||
|
@ -318,11 +308,11 @@ void DfuService::Reset() {
|
|||
}
|
||||
|
||||
DfuService::NotificationManager::NotificationManager() {
|
||||
timer = xTimerCreate ("notificationTimer", 1000, pdFALSE, this, NotificationTimerCallback);
|
||||
timer = xTimerCreate("notificationTimer", 1000, pdFALSE, this, NotificationTimerCallback);
|
||||
}
|
||||
|
||||
bool DfuService::NotificationManager::AsyncSend(uint16_t connection, uint16_t charactHandle, uint8_t *data, size_t s) {
|
||||
if(size != 0 || s > 10)
|
||||
bool DfuService::NotificationManager::AsyncSend(uint16_t connection, uint16_t charactHandle, uint8_t* data, size_t s) {
|
||||
if (size != 0 || s > 10)
|
||||
return false;
|
||||
|
||||
connectionHandle = connection;
|
||||
|
@ -334,14 +324,14 @@ bool DfuService::NotificationManager::AsyncSend(uint16_t connection, uint16_t ch
|
|||
}
|
||||
|
||||
void DfuService::NotificationManager::OnNotificationTimer() {
|
||||
if(size > 0) {
|
||||
if (size > 0) {
|
||||
Send(connectionHandle, characteristicHandle, buffer, size);
|
||||
size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void DfuService::NotificationManager::Send(uint16_t connection, uint16_t charactHandle, const uint8_t *data, const size_t s) {
|
||||
auto *om = ble_hs_mbuf_from_flat(data, s);
|
||||
void DfuService::NotificationManager::Send(uint16_t connection, uint16_t charactHandle, const uint8_t* data, const size_t s) {
|
||||
auto* om = ble_hs_mbuf_from_flat(data, s);
|
||||
auto ret = ble_gattc_notify_custom(connection, charactHandle, om);
|
||||
ASSERT(ret == 0);
|
||||
}
|
||||
|
@ -354,27 +344,29 @@ void DfuService::NotificationManager::Reset() {
|
|||
}
|
||||
|
||||
void DfuService::DfuImage::Init(size_t chunkSize, size_t totalSize, uint16_t expectedCrc) {
|
||||
if(chunkSize != 20) return;
|
||||
if (chunkSize != 20)
|
||||
return;
|
||||
this->chunkSize = chunkSize;
|
||||
this->totalSize = totalSize;
|
||||
this->expectedCrc = expectedCrc;
|
||||
this->ready = true;
|
||||
}
|
||||
|
||||
void DfuService::DfuImage::Append(uint8_t *data, size_t size) {
|
||||
if(!ready) return;
|
||||
void DfuService::DfuImage::Append(uint8_t* data, size_t size) {
|
||||
if (!ready)
|
||||
return;
|
||||
ASSERT(size <= 20);
|
||||
|
||||
std::memcpy(tempBuffer + bufferWriteIndex, data, size);
|
||||
bufferWriteIndex += size;
|
||||
|
||||
if(bufferWriteIndex == bufferSize) {
|
||||
if (bufferWriteIndex == bufferSize) {
|
||||
spiNorFlash.Write(writeOffset + totalWriteIndex, tempBuffer, bufferWriteIndex);
|
||||
totalWriteIndex += bufferWriteIndex;
|
||||
bufferWriteIndex = 0;
|
||||
}
|
||||
|
||||
if(bufferWriteIndex > 0 && totalWriteIndex + bufferWriteIndex == totalSize) {
|
||||
if (bufferWriteIndex > 0 && totalWriteIndex + bufferWriteIndex == totalSize) {
|
||||
spiNorFlash.Write(writeOffset + totalWriteIndex, tempBuffer, bufferWriteIndex);
|
||||
totalWriteIndex += bufferWriteIndex;
|
||||
if (totalSize < maxSize)
|
||||
|
@ -383,7 +375,8 @@ void DfuService::DfuImage::Append(uint8_t *data, size_t size) {
|
|||
}
|
||||
|
||||
void DfuService::DfuImage::WriteMagicNumber() {
|
||||
uint32_t magic[4] = { // TODO When this variable is a static constexpr, the values written to the memory are not correct. Why?
|
||||
uint32_t magic[4] = {
|
||||
// TODO When this variable is a static constexpr, the values written to the memory are not correct. Why?
|
||||
0xf395c277,
|
||||
0x7fefd260,
|
||||
0x0f505235,
|
||||
|
@ -391,7 +384,7 @@ void DfuService::DfuImage::WriteMagicNumber() {
|
|||
};
|
||||
|
||||
uint32_t offset = writeOffset + (maxSize - (4 * sizeof(uint32_t)));
|
||||
spiNorFlash.Write(offset, reinterpret_cast<const uint8_t *>(magic), 4 * sizeof(uint32_t));
|
||||
spiNorFlash.Write(offset, reinterpret_cast<const uint8_t*>(magic), 4 * sizeof(uint32_t));
|
||||
}
|
||||
|
||||
void DfuService::DfuImage::Erase() {
|
||||
|
@ -421,7 +414,7 @@ bool DfuService::DfuImage::Validate() {
|
|||
return (crc == expectedCrc);
|
||||
}
|
||||
|
||||
uint16_t DfuService::DfuImage::ComputeCrc(uint8_t const *p_data, uint32_t size, uint16_t const *p_crc) {
|
||||
uint16_t DfuService::DfuImage::ComputeCrc(uint8_t const* p_data, uint32_t size, uint16_t const* p_crc) {
|
||||
uint16_t crc = (p_crc == NULL) ? 0xFFFF : *p_crc;
|
||||
|
||||
for (uint32_t i = 0; i < size; i++) {
|
||||
|
@ -436,6 +429,7 @@ uint16_t DfuService::DfuImage::ComputeCrc(uint8_t const *p_data, uint32_t size,
|
|||
}
|
||||
|
||||
bool DfuService::DfuImage::IsComplete() {
|
||||
if(!ready) return false;
|
||||
if (!ready)
|
||||
return false;
|
||||
return totalWriteIndex == totalSize;
|
||||
}
|
||||
|
|
|
@ -21,31 +21,35 @@ namespace Pinetime {
|
|||
|
||||
class DfuService {
|
||||
public:
|
||||
DfuService(Pinetime::System::SystemTask &systemTask, Pinetime::Controllers::Ble &bleController,
|
||||
Pinetime::Drivers::SpiNorFlash &spiNorFlash);
|
||||
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);
|
||||
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);
|
||||
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} {}
|
||||
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);
|
||||
|
@ -66,46 +70,37 @@ namespace Pinetime {
|
|||
uint16_t expectedCrc = 0;
|
||||
|
||||
void WriteMagicNumber();
|
||||
uint16_t ComputeCrc(uint8_t const *p_data, uint32_t size, uint16_t const *p_crc);
|
||||
|
||||
uint16_t ComputeCrc(uint8_t const* p_data, uint32_t size, uint16_t const* p_crc);
|
||||
};
|
||||
|
||||
private:
|
||||
Pinetime::System::SystemTask &systemTask;
|
||||
Pinetime::Controllers::Ble &bleController;
|
||||
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};
|
||||
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};
|
||||
uint16_t revision {0x0008};
|
||||
|
||||
static constexpr ble_uuid128_t serviceUuid{
|
||||
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}
|
||||
};
|
||||
.value = {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15, 0xDE, 0xEF, 0x12, 0x12, 0x30, 0x15, 0x00, 0x00}};
|
||||
|
||||
static constexpr ble_uuid128_t packetCharacteristicUuid{
|
||||
static constexpr ble_uuid128_t packetCharacteristicUuid {
|
||||
.u {.type = BLE_UUID_TYPE_128},
|
||||
.value = {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15,
|
||||
0xDE, 0xEF, 0x12, 0x12, 0x32, 0x15, 0x00, 0x00}
|
||||
};
|
||||
.value = {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15, 0xDE, 0xEF, 0x12, 0x12, 0x32, 0x15, 0x00, 0x00}};
|
||||
|
||||
static constexpr ble_uuid128_t controlPointCharacteristicUuid{
|
||||
static constexpr ble_uuid128_t controlPointCharacteristicUuid {
|
||||
.u {.type = BLE_UUID_TYPE_128},
|
||||
.value = {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15,
|
||||
0xDE, 0xEF, 0x12, 0x12, 0x31, 0x15, 0x00, 0x00}
|
||||
};
|
||||
.value = {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15, 0xDE, 0xEF, 0x12, 0x12, 0x31, 0x15, 0x00, 0x00}};
|
||||
|
||||
static constexpr ble_uuid128_t revisionCharacteristicUuid{
|
||||
static constexpr ble_uuid128_t revisionCharacteristicUuid {
|
||||
.u {.type = BLE_UUID_TYPE_128},
|
||||
.value = {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15,
|
||||
0xDE, 0xEF, 0x12, 0x12, 0x34, 0x15, 0x00, 0x00}
|
||||
};
|
||||
.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];
|
||||
|
@ -113,9 +108,7 @@ namespace Pinetime {
|
|||
uint16_t controlPointCharacteristicHandle;
|
||||
uint16_t revisionCharacteristicHandle;
|
||||
|
||||
enum class States : uint8_t {
|
||||
Idle, Init, Start, Data, Validate, Validated
|
||||
};
|
||||
enum class States : uint8_t { Idle, Init, Start, Data, Validate, Validated };
|
||||
States state = States::Idle;
|
||||
|
||||
enum class ImageTypes : uint8_t {
|
||||
|
@ -155,9 +148,9 @@ namespace Pinetime {
|
|||
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);
|
||||
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;
|
||||
|
||||
namespace {
|
||||
int HeartRateServiceServiceCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) {
|
||||
int HeartRateServiceServiceCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
|
||||
auto* heartRateService = static_cast<HeartRateService*>(arg);
|
||||
return heartRateService->OnHeartRateRequested(conn_handle, attr_handle, ctxt);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Refactoring - remove dependency to SystemTask
|
||||
HeartRateService::HeartRateService(Pinetime::System::SystemTask &system, Controllers::HeartRateController& heartRateController) :
|
||||
system{system},
|
||||
heartRateController{heartRateController},
|
||||
characteristicDefinition{
|
||||
{
|
||||
.uuid = (ble_uuid_t *) &heartRateMeasurementUuid,
|
||||
HeartRateService::HeartRateService(Pinetime::System::SystemTask& system, Controllers::HeartRateController& heartRateController)
|
||||
: system {system},
|
||||
heartRateController {heartRateController},
|
||||
characteristicDefinition {{.uuid = (ble_uuid_t*) &heartRateMeasurementUuid,
|
||||
.access_cb = HeartRateServiceServiceCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY,
|
||||
.val_handle = &heartRateMeasurementHandle
|
||||
},
|
||||
{
|
||||
0
|
||||
}
|
||||
},
|
||||
serviceDefinition{
|
||||
{
|
||||
/* Device Information Service */
|
||||
.val_handle = &heartRateMeasurementHandle},
|
||||
{0}},
|
||||
serviceDefinition {
|
||||
{/* Device Information Service */
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = (ble_uuid_t *) &heartRateServiceUuid,
|
||||
.characteristics = characteristicDefinition
|
||||
},
|
||||
{
|
||||
0
|
||||
},
|
||||
}{
|
||||
.uuid = (ble_uuid_t*) &heartRateServiceUuid,
|
||||
.characteristics = characteristicDefinition},
|
||||
{0},
|
||||
} {
|
||||
// TODO refactor to prevent this loop dependency (service depends on controller and controller depends on service)
|
||||
heartRateController.SetService(this);
|
||||
}
|
||||
|
@ -54,9 +44,8 @@ void HeartRateService::Init() {
|
|||
ASSERT(res == 0);
|
||||
}
|
||||
|
||||
int HeartRateService::OnHeartRateRequested(uint16_t connectionHandle, uint16_t attributeHandle,
|
||||
ble_gatt_access_ctxt *context) {
|
||||
if(attributeHandle == heartRateMeasurementHandle) {
|
||||
int HeartRateService::OnHeartRateRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context) {
|
||||
if (attributeHandle == heartRateMeasurementHandle) {
|
||||
NRF_LOG_INFO("HEARTRATE : handle = %d", heartRateMeasurementHandle);
|
||||
uint8_t buffer[2] = {0, heartRateController.HeartRate()}; // [0] = flags, [1] = hr value
|
||||
|
||||
|
@ -68,7 +57,7 @@ int HeartRateService::OnHeartRateRequested(uint16_t connectionHandle, uint16_t a
|
|||
|
||||
void HeartRateService::OnNewHeartRateValue(uint8_t heartRateValue) {
|
||||
uint8_t buffer[2] = {0, heartRateController.HeartRate()}; // [0] = flags, [1] = hr value
|
||||
auto *om = ble_hs_mbuf_from_flat(buffer, 2);
|
||||
auto* om = ble_hs_mbuf_from_flat(buffer, 2);
|
||||
|
||||
uint16_t connectionHandle = system.nimble().connHandle();
|
||||
|
||||
|
|
|
@ -13,32 +13,25 @@ namespace Pinetime {
|
|||
class HeartRateController;
|
||||
class HeartRateService {
|
||||
public:
|
||||
HeartRateService(Pinetime::System::SystemTask &system, Controllers::HeartRateController& heartRateController);
|
||||
HeartRateService(Pinetime::System::SystemTask& system, Controllers::HeartRateController& heartRateController);
|
||||
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);
|
||||
|
||||
private:
|
||||
Pinetime::System::SystemTask &system;
|
||||
Pinetime::System::SystemTask& system;
|
||||
Controllers::HeartRateController& heartRateController;
|
||||
static constexpr uint16_t heartRateServiceId {0x180D};
|
||||
static constexpr uint16_t heartRateMeasurementId {0x2A37};
|
||||
|
||||
static constexpr ble_uuid16_t heartRateServiceUuid {
|
||||
.u {.type = BLE_UUID_TYPE_16},
|
||||
.value = heartRateServiceId
|
||||
};
|
||||
static constexpr ble_uuid16_t heartRateServiceUuid {.u {.type = BLE_UUID_TYPE_16}, .value = heartRateServiceId};
|
||||
|
||||
static constexpr ble_uuid16_t heartRateMeasurementUuid {
|
||||
.u {.type = BLE_UUID_TYPE_16},
|
||||
.value = heartRateMeasurementId
|
||||
};
|
||||
static constexpr ble_uuid16_t heartRateMeasurementUuid {.u {.type = BLE_UUID_TYPE_16}, .value = heartRateMeasurementId};
|
||||
|
||||
struct ble_gatt_chr_def characteristicDefinition[3];
|
||||
struct ble_gatt_svc_def serviceDefinition[2];
|
||||
|
||||
uint16_t heartRateMeasurementHandle;
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,49 +9,42 @@ constexpr ble_uuid16_t ImmediateAlertService::immediateAlertServiceUuid;
|
|||
constexpr ble_uuid16_t ImmediateAlertService::alertLevelUuid;
|
||||
|
||||
namespace {
|
||||
int AlertLevelCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) {
|
||||
auto *immediateAlertService = static_cast<ImmediateAlertService *>(arg);
|
||||
int AlertLevelCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
|
||||
auto* immediateAlertService = static_cast<ImmediateAlertService*>(arg);
|
||||
return immediateAlertService->OnAlertLevelChanged(conn_handle, attr_handle, ctxt);
|
||||
}
|
||||
|
||||
const char* ToString(ImmediateAlertService::Levels level) {
|
||||
switch (level) {
|
||||
case ImmediateAlertService::Levels::NoAlert: return "Alert : None";
|
||||
case ImmediateAlertService::Levels::HighAlert: return "Alert : High";
|
||||
case ImmediateAlertService::Levels::MildAlert: return "Alert : Mild";
|
||||
default: return "";
|
||||
case ImmediateAlertService::Levels::NoAlert:
|
||||
return "Alert : None";
|
||||
case ImmediateAlertService::Levels::HighAlert:
|
||||
return "Alert : High";
|
||||
case ImmediateAlertService::Levels::MildAlert:
|
||||
return "Alert : Mild";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImmediateAlertService::ImmediateAlertService(Pinetime::System::SystemTask &systemTask,
|
||||
Pinetime::Controllers::NotificationManager ¬ificationManager) :
|
||||
systemTask{systemTask},
|
||||
notificationManager{notificationManager},
|
||||
characteristicDefinition{
|
||||
{
|
||||
.uuid = (ble_uuid_t *) &alertLevelUuid,
|
||||
ImmediateAlertService::ImmediateAlertService(Pinetime::System::SystemTask& systemTask,
|
||||
Pinetime::Controllers::NotificationManager& notificationManager)
|
||||
: systemTask {systemTask},
|
||||
notificationManager {notificationManager},
|
||||
characteristicDefinition {{.uuid = (ble_uuid_t*) &alertLevelUuid,
|
||||
.access_cb = AlertLevelCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE_NO_RSP,
|
||||
.val_handle = &alertLevelHandle
|
||||
},
|
||||
{
|
||||
0
|
||||
}
|
||||
},
|
||||
serviceDefinition{
|
||||
{
|
||||
/* Device Information Service */
|
||||
.val_handle = &alertLevelHandle},
|
||||
{0}},
|
||||
serviceDefinition {
|
||||
{/* Device Information Service */
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = (ble_uuid_t *) &immediateAlertServiceUuid,
|
||||
.characteristics = characteristicDefinition
|
||||
},
|
||||
{
|
||||
0
|
||||
},
|
||||
}{
|
||||
|
||||
.uuid = (ble_uuid_t*) &immediateAlertServiceUuid,
|
||||
.characteristics = characteristicDefinition},
|
||||
{0},
|
||||
} {
|
||||
}
|
||||
|
||||
void ImmediateAlertService::Init() {
|
||||
|
@ -63,9 +56,9 @@ void ImmediateAlertService::Init() {
|
|||
ASSERT(res == 0);
|
||||
}
|
||||
|
||||
int ImmediateAlertService::OnAlertLevelChanged(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt *context) {
|
||||
if(attributeHandle == alertLevelHandle) {
|
||||
if(context->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
|
||||
int ImmediateAlertService::OnAlertLevelChanged(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context) {
|
||||
if (attributeHandle == alertLevelHandle) {
|
||||
if (context->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
|
||||
auto alertLevel = static_cast<Levels>(context->om->om_data[0]);
|
||||
auto* alertString = ToString(alertLevel);
|
||||
|
||||
|
|
|
@ -13,16 +13,11 @@ namespace Pinetime {
|
|||
class NotificationManager;
|
||||
class ImmediateAlertService {
|
||||
public:
|
||||
enum class Levels : uint8_t {
|
||||
NoAlert = 0,
|
||||
MildAlert = 1,
|
||||
HighAlert = 2
|
||||
};
|
||||
enum class Levels : uint8_t { NoAlert = 0, MildAlert = 1, HighAlert = 2 };
|
||||
|
||||
ImmediateAlertService(Pinetime::System::SystemTask &systemTask,
|
||||
Pinetime::Controllers::NotificationManager ¬ificationManager);
|
||||
ImmediateAlertService(Pinetime::System::SystemTask& systemTask, Pinetime::Controllers::NotificationManager& notificationManager);
|
||||
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:
|
||||
Pinetime::System::SystemTask& systemTask;
|
||||
|
@ -31,15 +26,9 @@ namespace Pinetime {
|
|||
static constexpr uint16_t immediateAlertServiceId {0x1802};
|
||||
static constexpr uint16_t alertLevelId {0x2A06};
|
||||
|
||||
static constexpr ble_uuid16_t immediateAlertServiceUuid {
|
||||
.u {.type = BLE_UUID_TYPE_16},
|
||||
.value = immediateAlertServiceId
|
||||
};
|
||||
static constexpr ble_uuid16_t immediateAlertServiceUuid {.u {.type = BLE_UUID_TYPE_16}, .value = immediateAlertServiceId};
|
||||
|
||||
static constexpr ble_uuid16_t alertLevelUuid {
|
||||
.u {.type = BLE_UUID_TYPE_16},
|
||||
.value = alertLevelId
|
||||
};
|
||||
static constexpr ble_uuid16_t alertLevelUuid {.u {.type = BLE_UUID_TYPE_16}, .value = alertLevelId};
|
||||
|
||||
struct ble_gatt_chr_def characteristicDefinition[3];
|
||||
struct ble_gatt_svc_def serviceDefinition[2];
|
||||
|
|
|
@ -18,12 +18,12 @@
|
|||
#include "MusicService.h"
|
||||
#include "systemtask/SystemTask.h"
|
||||
|
||||
int MSCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) {
|
||||
auto musicService = static_cast<Pinetime::Controllers::MusicService *>(arg);
|
||||
int MSCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
|
||||
auto musicService = static_cast<Pinetime::Controllers::MusicService*>(arg);
|
||||
return musicService->OnCommand(conn_handle, attr_handle, ctxt);
|
||||
}
|
||||
|
||||
Pinetime::Controllers::MusicService::MusicService(Pinetime::System::SystemTask &system) : m_system(system) {
|
||||
Pinetime::Controllers::MusicService::MusicService(Pinetime::System::SystemTask& system) : m_system(system) {
|
||||
msUuid.value[14] = msId[0];
|
||||
msUuid.value[15] = msId[1];
|
||||
|
||||
|
@ -87,79 +87,48 @@ Pinetime::Controllers::MusicService::MusicService(Pinetime::System::SystemTask &
|
|||
msShuffleCharUuid.value[14] = msId[0];
|
||||
msShuffleCharUuid.value[15] = msId[1];
|
||||
|
||||
characteristicDefinition[0] = {.uuid = (ble_uuid_t *) (&msEventCharUuid),
|
||||
characteristicDefinition[0] = {.uuid = (ble_uuid_t*) (&msEventCharUuid),
|
||||
.access_cb = MSCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_NOTIFY,
|
||||
.val_handle = &eventHandle
|
||||
};
|
||||
characteristicDefinition[1] = {.uuid = (ble_uuid_t *) (&msStatusCharUuid),
|
||||
.val_handle = &eventHandle};
|
||||
characteristicDefinition[1] = {
|
||||
.uuid = (ble_uuid_t*) (&msStatusCharUuid), .access_cb = MSCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||
characteristicDefinition[2] = {
|
||||
.uuid = (ble_uuid_t*) (&msTrackCharUuid), .access_cb = MSCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||
characteristicDefinition[3] = {
|
||||
.uuid = (ble_uuid_t*) (&msArtistCharUuid), .access_cb = MSCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||
characteristicDefinition[4] = {
|
||||
.uuid = (ble_uuid_t*) (&msAlbumCharUuid), .access_cb = MSCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||
characteristicDefinition[5] = {
|
||||
.uuid = (ble_uuid_t*) (&msPositionCharUuid), .access_cb = MSCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||
characteristicDefinition[6] = {.uuid = (ble_uuid_t*) (&msTotalLengthCharUuid),
|
||||
.access_cb = MSCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
|
||||
};
|
||||
characteristicDefinition[2] = {.uuid = (ble_uuid_t *) (&msTrackCharUuid),
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||
characteristicDefinition[7] = {.uuid = (ble_uuid_t*) (&msTotalLengthCharUuid),
|
||||
.access_cb = MSCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
|
||||
};
|
||||
characteristicDefinition[3] = {.uuid = (ble_uuid_t *) (&msArtistCharUuid),
|
||||
.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[4] = {.uuid = (ble_uuid_t *) (&msAlbumCharUuid),
|
||||
.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[5] = {.uuid = (ble_uuid_t *) (&msPositionCharUuid),
|
||||
.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[6] = {.uuid = (ble_uuid_t *) (&msTotalLengthCharUuid),
|
||||
.access_cb = MSCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
|
||||
};
|
||||
characteristicDefinition[7] = {.uuid = (ble_uuid_t *) (&msTotalLengthCharUuid),
|
||||
.access_cb = MSCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
|
||||
};
|
||||
characteristicDefinition[8] = {.uuid = (ble_uuid_t *) (&msTrackNumberCharUuid),
|
||||
.access_cb = MSCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
|
||||
};
|
||||
characteristicDefinition[9] = {.uuid = (ble_uuid_t *) (&msTrackTotalCharUuid),
|
||||
.access_cb = MSCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
|
||||
};
|
||||
characteristicDefinition[10] = {.uuid = (ble_uuid_t *) (&msPlaybackSpeedCharUuid),
|
||||
.access_cb = MSCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
|
||||
};
|
||||
characteristicDefinition[11] = {.uuid = (ble_uuid_t *) (&msRepeatCharUuid),
|
||||
.access_cb = MSCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
|
||||
};
|
||||
characteristicDefinition[12] = {.uuid = (ble_uuid_t *) (&msShuffleCharUuid),
|
||||
.access_cb = MSCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
|
||||
};
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||
characteristicDefinition[11] = {
|
||||
.uuid = (ble_uuid_t*) (&msRepeatCharUuid), .access_cb = MSCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||
characteristicDefinition[12] = {
|
||||
.uuid = (ble_uuid_t*) (&msShuffleCharUuid), .access_cb = MSCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||
characteristicDefinition[13] = {0};
|
||||
|
||||
serviceDefinition[0] = {
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = (ble_uuid_t *) &msUuid,
|
||||
.characteristics = characteristicDefinition
|
||||
};
|
||||
serviceDefinition[0] = {.type = BLE_GATT_SVC_TYPE_PRIMARY, .uuid = (ble_uuid_t*) &msUuid, .characteristics = characteristicDefinition};
|
||||
serviceDefinition[1] = {0};
|
||||
|
||||
artistName = "Waiting for";
|
||||
|
@ -182,36 +151,35 @@ void Pinetime::Controllers::MusicService::Init() {
|
|||
ASSERT(res == 0);
|
||||
}
|
||||
|
||||
int Pinetime::Controllers::MusicService::OnCommand(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt) {
|
||||
int Pinetime::Controllers::MusicService::OnCommand(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) {
|
||||
|
||||
if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
|
||||
size_t notifSize = OS_MBUF_PKTLEN(ctxt->om);
|
||||
uint8_t data[notifSize + 1];
|
||||
data[notifSize] = '\0';
|
||||
os_mbuf_copydata(ctxt->om, 0, notifSize, data);
|
||||
char *s = (char *) &data[0];
|
||||
if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msArtistCharUuid) == 0) {
|
||||
char* s = (char*) &data[0];
|
||||
if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msArtistCharUuid) == 0) {
|
||||
artistName = s;
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msTrackCharUuid) == 0) {
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msTrackCharUuid) == 0) {
|
||||
trackName = s;
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msAlbumCharUuid) == 0) {
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msAlbumCharUuid) == 0) {
|
||||
albumName = s;
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msStatusCharUuid) == 0) {
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msStatusCharUuid) == 0) {
|
||||
playing = s[0];
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msRepeatCharUuid) == 0) {
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msRepeatCharUuid) == 0) {
|
||||
repeat = s[0];
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msShuffleCharUuid) == 0) {
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msShuffleCharUuid) == 0) {
|
||||
shuffle = s[0];
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msPositionCharUuid) == 0) {
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msPositionCharUuid) == 0) {
|
||||
trackProgress = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msTotalLengthCharUuid) == 0) {
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msTotalLengthCharUuid) == 0) {
|
||||
trackLength = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msTrackNumberCharUuid) == 0) {
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msTrackNumberCharUuid) == 0) {
|
||||
trackNumber = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msTrackTotalCharUuid) == 0) {
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msTrackTotalCharUuid) == 0) {
|
||||
tracksTotal = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msPlaybackSpeedCharUuid) == 0) {
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msPlaybackSpeedCharUuid) == 0) {
|
||||
playbackSpeed = static_cast<float>(((s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3])) / 100.0f;
|
||||
}
|
||||
}
|
||||
|
@ -239,7 +207,7 @@ float Pinetime::Controllers::MusicService::getPlaybackSpeed() {
|
|||
}
|
||||
|
||||
void Pinetime::Controllers::MusicService::event(char event) {
|
||||
auto *om = ble_hs_mbuf_from_flat(&event, 1);
|
||||
auto* om = ble_hs_mbuf_from_flat(&event, 1);
|
||||
|
||||
uint16_t connectionHandle = m_system.nimble().connHandle();
|
||||
|
||||
|
@ -257,4 +225,3 @@ int Pinetime::Controllers::MusicService::getProgress() {
|
|||
int Pinetime::Controllers::MusicService::getTrackLength() {
|
||||
return trackLength;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,8 +26,9 @@
|
|||
#undef max
|
||||
#undef min
|
||||
|
||||
//00000000-78fc-48fe-8e23-433b3a1942d0
|
||||
#define MUSIC_SERVICE_UUID_BASE {0xd0, 0x42, 0x19, 0x3a, 0x3b, 0x43, 0x23, 0x8e, 0xfe, 0x48, 0xfc, 0x78, 0x00, 0x00, 0x00, 0x00}
|
||||
// 00000000-78fc-48fe-8e23-433b3a1942d0
|
||||
#define MUSIC_SERVICE_UUID_BASE \
|
||||
{ 0xd0, 0x42, 0x19, 0x3a, 0x3b, 0x43, 0x23, 0x8e, 0xfe, 0x48, 0xfc, 0x78, 0x00, 0x00, 0x00, 0x00 }
|
||||
|
||||
namespace Pinetime {
|
||||
namespace System {
|
||||
|
@ -37,12 +38,11 @@ namespace Pinetime {
|
|||
|
||||
class MusicService {
|
||||
public:
|
||||
explicit MusicService(Pinetime::System::SystemTask &system);
|
||||
explicit MusicService(Pinetime::System::SystemTask& system);
|
||||
|
||||
void Init();
|
||||
|
||||
int OnCommand(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt);
|
||||
int OnCommand(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt);
|
||||
|
||||
void event(char event);
|
||||
|
||||
|
@ -68,10 +68,8 @@ namespace Pinetime {
|
|||
static const char EVENT_MUSIC_VOLUP = 0x05;
|
||||
static const char EVENT_MUSIC_VOLDOWN = 0x06;
|
||||
|
||||
enum MusicStatus {
|
||||
NotPlaying = 0x00,
|
||||
Playing = 0x01
|
||||
};
|
||||
enum MusicStatus { NotPlaying = 0x00, Playing = 0x01 };
|
||||
|
||||
private:
|
||||
static constexpr uint8_t msId[2] = {0x00, 0x00};
|
||||
static constexpr uint8_t msEventCharId[2] = {0x01, 0x00};
|
||||
|
@ -87,59 +85,20 @@ namespace Pinetime {
|
|||
static constexpr uint8_t msRepeatCharId[2] = {0x0b, 0x00};
|
||||
static constexpr uint8_t msShuffleCharId[2] = {0x0c, 0x00};
|
||||
|
||||
ble_uuid128_t msUuid{
|
||||
.u = {.type = BLE_UUID_TYPE_128},
|
||||
.value = MUSIC_SERVICE_UUID_BASE
|
||||
};
|
||||
ble_uuid128_t msUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||
|
||||
ble_uuid128_t msEventCharUuid{
|
||||
.u = {.type = BLE_UUID_TYPE_128},
|
||||
.value = MUSIC_SERVICE_UUID_BASE
|
||||
};
|
||||
ble_uuid128_t msStatusCharUuid{
|
||||
.u = {.type = BLE_UUID_TYPE_128},
|
||||
.value = MUSIC_SERVICE_UUID_BASE
|
||||
};
|
||||
ble_uuid128_t msArtistCharUuid{
|
||||
.u = {.type = BLE_UUID_TYPE_128},
|
||||
.value = MUSIC_SERVICE_UUID_BASE
|
||||
};
|
||||
ble_uuid128_t msTrackCharUuid{
|
||||
.u = {.type = BLE_UUID_TYPE_128},
|
||||
.value = MUSIC_SERVICE_UUID_BASE
|
||||
};
|
||||
ble_uuid128_t msAlbumCharUuid{
|
||||
.u = {.type = BLE_UUID_TYPE_128},
|
||||
.value = MUSIC_SERVICE_UUID_BASE
|
||||
};
|
||||
ble_uuid128_t msPositionCharUuid{
|
||||
.u = {.type = BLE_UUID_TYPE_128},
|
||||
.value = MUSIC_SERVICE_UUID_BASE
|
||||
};
|
||||
ble_uuid128_t msTotalLengthCharUuid{
|
||||
.u = {.type = BLE_UUID_TYPE_128},
|
||||
.value = MUSIC_SERVICE_UUID_BASE
|
||||
};
|
||||
ble_uuid128_t msTrackNumberCharUuid{
|
||||
.u = {.type = BLE_UUID_TYPE_128},
|
||||
.value = MUSIC_SERVICE_UUID_BASE
|
||||
};
|
||||
ble_uuid128_t msTrackTotalCharUuid{
|
||||
.u = {.type = BLE_UUID_TYPE_128},
|
||||
.value = MUSIC_SERVICE_UUID_BASE
|
||||
};
|
||||
ble_uuid128_t msPlaybackSpeedCharUuid{
|
||||
.u = {.type = BLE_UUID_TYPE_128},
|
||||
.value = MUSIC_SERVICE_UUID_BASE
|
||||
};
|
||||
ble_uuid128_t msRepeatCharUuid{
|
||||
.u = {.type = BLE_UUID_TYPE_128},
|
||||
.value = MUSIC_SERVICE_UUID_BASE
|
||||
};
|
||||
ble_uuid128_t msShuffleCharUuid{
|
||||
.u = {.type = BLE_UUID_TYPE_128},
|
||||
.value = MUSIC_SERVICE_UUID_BASE
|
||||
};
|
||||
ble_uuid128_t msEventCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||
ble_uuid128_t msStatusCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||
ble_uuid128_t msArtistCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||
ble_uuid128_t msTrackCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||
ble_uuid128_t msAlbumCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||
ble_uuid128_t msPositionCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||
ble_uuid128_t msTotalLengthCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||
ble_uuid128_t msTrackNumberCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||
ble_uuid128_t msTrackTotalCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||
ble_uuid128_t msPlaybackSpeedCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||
ble_uuid128_t msRepeatCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||
ble_uuid128_t msShuffleCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||
|
||||
struct ble_gatt_chr_def characteristicDefinition[14];
|
||||
struct ble_gatt_svc_def serviceDefinition[2];
|
||||
|
@ -162,8 +121,7 @@ namespace Pinetime {
|
|||
bool repeat;
|
||||
bool shuffle;
|
||||
|
||||
Pinetime::System::SystemTask &m_system;
|
||||
Pinetime::System::SystemTask& m_system;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,12 +20,12 @@
|
|||
|
||||
#include "systemtask/SystemTask.h"
|
||||
|
||||
int NAVCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) {
|
||||
auto navService = static_cast<Pinetime::Controllers::NavigationService *>(arg);
|
||||
int NAVCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
|
||||
auto navService = static_cast<Pinetime::Controllers::NavigationService*>(arg);
|
||||
return navService->OnCommand(conn_handle, attr_handle, ctxt);
|
||||
}
|
||||
|
||||
Pinetime::Controllers::NavigationService::NavigationService(Pinetime::System::SystemTask &system) : m_system(system) {
|
||||
Pinetime::Controllers::NavigationService::NavigationService(Pinetime::System::SystemTask& system) : m_system(system) {
|
||||
navUuid.value[14] = navId[0];
|
||||
navUuid.value[15] = navId[1];
|
||||
|
||||
|
@ -49,35 +49,25 @@ Pinetime::Controllers::NavigationService::NavigationService(Pinetime::System::Sy
|
|||
navProgressCharUuid.value[14] = navId[0];
|
||||
navProgressCharUuid.value[15] = navId[1];
|
||||
|
||||
characteristicDefinition[0] = {.uuid = (ble_uuid_t *) (&navFlagCharUuid),
|
||||
.access_cb = NAVCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
|
||||
};
|
||||
characteristicDefinition[0] = {
|
||||
.uuid = (ble_uuid_t*) (&navFlagCharUuid), .access_cb = NAVCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||
|
||||
characteristicDefinition[1] = {.uuid = (ble_uuid_t *) (&navNarrativeCharUuid),
|
||||
characteristicDefinition[1] = {.uuid = (ble_uuid_t*) (&navNarrativeCharUuid),
|
||||
.access_cb = NAVCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
|
||||
};
|
||||
characteristicDefinition[2] = {.uuid = (ble_uuid_t *) (&navManDistCharUuid),
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||
characteristicDefinition[2] = {.uuid = (ble_uuid_t*) (&navManDistCharUuid),
|
||||
.access_cb = NAVCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
|
||||
};
|
||||
characteristicDefinition[3] = {.uuid = (ble_uuid_t *) (&navProgressCharUuid),
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||
characteristicDefinition[3] = {.uuid = (ble_uuid_t*) (&navProgressCharUuid),
|
||||
.access_cb = NAVCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
|
||||
};
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||
|
||||
characteristicDefinition[4] = {0};
|
||||
|
||||
serviceDefinition[0] = {
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = (ble_uuid_t *) &navUuid,
|
||||
.characteristics = characteristicDefinition
|
||||
};
|
||||
serviceDefinition[0] = {.type = BLE_GATT_SVC_TYPE_PRIMARY, .uuid = (ble_uuid_t*) &navUuid, .characteristics = characteristicDefinition};
|
||||
serviceDefinition[1] = {0};
|
||||
|
||||
m_progress = 0;
|
||||
|
@ -92,45 +82,39 @@ void Pinetime::Controllers::NavigationService::Init() {
|
|||
ASSERT(res == 0);
|
||||
}
|
||||
|
||||
int Pinetime::Controllers::NavigationService::OnCommand(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt) {
|
||||
int Pinetime::Controllers::NavigationService::OnCommand(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) {
|
||||
|
||||
if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
|
||||
size_t notifSize = OS_MBUF_PKTLEN(ctxt->om);
|
||||
uint8_t data[notifSize + 1];
|
||||
data[notifSize] = '\0';
|
||||
os_mbuf_copydata(ctxt->om, 0, notifSize, data);
|
||||
char *s = (char *) &data[0];
|
||||
if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &navFlagCharUuid) == 0) {
|
||||
char* s = (char*) &data[0];
|
||||
if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &navFlagCharUuid) == 0) {
|
||||
m_flag = s;
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &navNarrativeCharUuid) == 0) {
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &navNarrativeCharUuid) == 0) {
|
||||
m_narrative = s;
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &navManDistCharUuid) == 0) {
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &navManDistCharUuid) == 0) {
|
||||
m_manDist = s;
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &navProgressCharUuid) == 0) {
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &navProgressCharUuid) == 0) {
|
||||
m_progress = data[0];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string Pinetime::Controllers::NavigationService::getFlag()
|
||||
{
|
||||
std::string Pinetime::Controllers::NavigationService::getFlag() {
|
||||
return m_flag;
|
||||
}
|
||||
|
||||
std::string Pinetime::Controllers::NavigationService::getNarrative()
|
||||
{
|
||||
std::string Pinetime::Controllers::NavigationService::getNarrative() {
|
||||
return m_narrative;
|
||||
}
|
||||
|
||||
std::string Pinetime::Controllers::NavigationService::getManDist()
|
||||
{
|
||||
std::string Pinetime::Controllers::NavigationService::getManDist() {
|
||||
return m_manDist;
|
||||
}
|
||||
|
||||
int Pinetime::Controllers::NavigationService::getProgress()
|
||||
{
|
||||
int Pinetime::Controllers::NavigationService::getProgress() {
|
||||
return m_progress;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,8 +26,9 @@
|
|||
#undef max
|
||||
#undef min
|
||||
|
||||
//c7e60000-78fc-48fe-8e23-433b3a1942d0
|
||||
#define NAVIGATION_SERVICE_UUID_BASE {0xd0, 0x42, 0x19, 0x3a, 0x3b, 0x43, 0x23, 0x8e, 0xfe, 0x48, 0xfc, 0x78, 0x00, 0x00, 0x00, 0x00}
|
||||
// c7e60000-78fc-48fe-8e23-433b3a1942d0
|
||||
#define NAVIGATION_SERVICE_UUID_BASE \
|
||||
{ 0xd0, 0x42, 0x19, 0x3a, 0x3b, 0x43, 0x23, 0x8e, 0xfe, 0x48, 0xfc, 0x78, 0x00, 0x00, 0x00, 0x00 }
|
||||
|
||||
namespace Pinetime {
|
||||
namespace System {
|
||||
|
@ -37,12 +38,11 @@ namespace Pinetime {
|
|||
|
||||
class NavigationService {
|
||||
public:
|
||||
explicit NavigationService(Pinetime::System::SystemTask &system);
|
||||
explicit NavigationService(Pinetime::System::SystemTask& system);
|
||||
|
||||
void Init();
|
||||
|
||||
int OnCommand(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt);
|
||||
int OnCommand(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt);
|
||||
|
||||
std::string getFlag();
|
||||
|
||||
|
@ -59,27 +59,12 @@ namespace Pinetime {
|
|||
static constexpr uint8_t navManDistCharId[2] = {0x03, 0x00};
|
||||
static constexpr uint8_t navProgressCharId[2] = {0x04, 0x00};
|
||||
|
||||
ble_uuid128_t navUuid{
|
||||
.u = {.type = BLE_UUID_TYPE_128},
|
||||
.value = NAVIGATION_SERVICE_UUID_BASE
|
||||
};
|
||||
ble_uuid128_t navUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = NAVIGATION_SERVICE_UUID_BASE};
|
||||
|
||||
ble_uuid128_t navFlagCharUuid{
|
||||
.u = {.type = BLE_UUID_TYPE_128},
|
||||
.value = NAVIGATION_SERVICE_UUID_BASE
|
||||
};
|
||||
ble_uuid128_t navNarrativeCharUuid{
|
||||
.u = {.type = BLE_UUID_TYPE_128},
|
||||
.value = NAVIGATION_SERVICE_UUID_BASE
|
||||
};
|
||||
ble_uuid128_t navManDistCharUuid{
|
||||
.u = {.type = BLE_UUID_TYPE_128},
|
||||
.value = NAVIGATION_SERVICE_UUID_BASE
|
||||
};
|
||||
ble_uuid128_t navProgressCharUuid{
|
||||
.u = {.type = BLE_UUID_TYPE_128},
|
||||
.value = NAVIGATION_SERVICE_UUID_BASE
|
||||
};
|
||||
ble_uuid128_t navFlagCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = NAVIGATION_SERVICE_UUID_BASE};
|
||||
ble_uuid128_t navNarrativeCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = NAVIGATION_SERVICE_UUID_BASE};
|
||||
ble_uuid128_t navManDistCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = NAVIGATION_SERVICE_UUID_BASE};
|
||||
ble_uuid128_t navProgressCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = NAVIGATION_SERVICE_UUID_BASE};
|
||||
|
||||
struct ble_gatt_chr_def characteristicDefinition[5];
|
||||
struct ble_gatt_svc_def serviceDefinition[2];
|
||||
|
@ -89,8 +74,7 @@ namespace Pinetime {
|
|||
std::string m_manDist;
|
||||
int m_progress;
|
||||
|
||||
Pinetime::System::SystemTask &m_system;
|
||||
Pinetime::System::SystemTask& m_system;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,32 +23,33 @@ NimbleController::NimbleController(Pinetime::System::SystemTask& systemTask,
|
|||
Pinetime::Controllers::NotificationManager& notificationManager,
|
||||
Controllers::Battery& batteryController,
|
||||
Pinetime::Drivers::SpiNorFlash& spiNorFlash,
|
||||
Controllers::HeartRateController& heartRateController) :
|
||||
systemTask{systemTask},
|
||||
bleController{bleController},
|
||||
dateTimeController{dateTimeController},
|
||||
notificationManager{notificationManager},
|
||||
spiNorFlash{spiNorFlash},
|
||||
dfuService{systemTask, bleController, spiNorFlash},
|
||||
currentTimeClient{dateTimeController},
|
||||
anService{systemTask, notificationManager},
|
||||
alertNotificationClient{systemTask, notificationManager},
|
||||
currentTimeService{dateTimeController},
|
||||
musicService{systemTask},
|
||||
navService{systemTask},
|
||||
batteryInformationService{batteryController},
|
||||
immediateAlertService{systemTask, notificationManager},
|
||||
heartRateService{systemTask, heartRateController},
|
||||
Controllers::HeartRateController& heartRateController)
|
||||
: systemTask {systemTask},
|
||||
bleController {bleController},
|
||||
dateTimeController {dateTimeController},
|
||||
notificationManager {notificationManager},
|
||||
spiNorFlash {spiNorFlash},
|
||||
dfuService {systemTask, bleController, spiNorFlash},
|
||||
currentTimeClient {dateTimeController},
|
||||
anService {systemTask, notificationManager},
|
||||
alertNotificationClient {systemTask, notificationManager},
|
||||
currentTimeService {dateTimeController},
|
||||
musicService {systemTask},
|
||||
navService {systemTask},
|
||||
batteryInformationService {batteryController},
|
||||
immediateAlertService {systemTask, notificationManager},
|
||||
heartRateService {systemTask, heartRateController},
|
||||
serviceDiscovery({¤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);
|
||||
return nimbleController->OnGAPEvent(event);
|
||||
}
|
||||
|
||||
void NimbleController::Init() {
|
||||
while (!ble_hs_synced()) {}
|
||||
while (!ble_hs_synced()) {
|
||||
}
|
||||
|
||||
ble_svc_gap_init();
|
||||
ble_svc_gatt_init();
|
||||
|
@ -81,7 +82,8 @@ void NimbleController::Init() {
|
|||
}
|
||||
|
||||
void NimbleController::StartAdvertising() {
|
||||
if(bleController.IsConnected() || ble_gap_conn_active() || ble_gap_adv_active()) return;
|
||||
if (bleController.IsConnected() || ble_gap_conn_active() || ble_gap_adv_active())
|
||||
return;
|
||||
|
||||
ble_svc_gap_device_name_set(deviceName);
|
||||
|
||||
|
@ -101,29 +103,27 @@ void NimbleController::StartAdvertising() {
|
|||
adv_params.conn_mode = BLE_GAP_CONN_MODE_UND;
|
||||
adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN;
|
||||
|
||||
fields.flags = BLE_HS_ADV_F_DISC_GEN |
|
||||
BLE_HS_ADV_F_BREDR_UNSUP;
|
||||
// fields.uuids128 = BLE_UUID128(BLE_UUID128_DECLARE(
|
||||
// 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
|
||||
// 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff));
|
||||
fields.flags = BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP;
|
||||
// fields.uuids128 = BLE_UUID128(BLE_UUID128_DECLARE(
|
||||
// 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
|
||||
// 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff));
|
||||
fields.uuids128 = &dfuServiceUuid;
|
||||
fields.num_uuids128 = 1;
|
||||
fields.uuids128_is_complete = 1;
|
||||
fields.tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO;
|
||||
|
||||
rsp_fields.name = (uint8_t *)deviceName;
|
||||
rsp_fields.name = (uint8_t*) deviceName;
|
||||
rsp_fields.name_len = strlen(deviceName);
|
||||
rsp_fields.name_is_complete = 1;
|
||||
|
||||
ble_gap_adv_set_fields(&fields);
|
||||
// ASSERT(res == 0); // TODO this one sometimes fails with error 22 (notsync)
|
||||
// ASSERT(res == 0); // TODO this one sometimes fails with error 22 (notsync)
|
||||
|
||||
ble_gap_adv_rsp_set_fields(&rsp_fields);
|
||||
// ASSERT(res == 0);
|
||||
// ASSERT(res == 0);
|
||||
|
||||
ble_gap_adv_start(addrType, NULL, 180000,
|
||||
&adv_params, GAPEventCallback, this);
|
||||
// ASSERT(res == 0);// TODO I've disabled these ASSERT as they sometime asserts and reset the mcu.
|
||||
ble_gap_adv_start(addrType, NULL, 180000, &adv_params, GAPEventCallback, this);
|
||||
// ASSERT(res == 0);// TODO I've disabled these ASSERT as they sometime asserts and reset the mcu.
|
||||
// For now, the advertising is restarted as soon as it ends. There may be a race condition
|
||||
// that prevent the advertising from restarting reliably.
|
||||
// I remove the assert to prevent this uncesseray crash, but in the long term, the management of
|
||||
|
@ -131,7 +131,7 @@ void NimbleController::StartAdvertising() {
|
|||
// the application has been woken up, for example.
|
||||
}
|
||||
|
||||
int NimbleController::OnGAPEvent(ble_gap_event *event) {
|
||||
int NimbleController::OnGAPEvent(ble_gap_event* event) {
|
||||
switch (event->type) {
|
||||
case BLE_GAP_EVENT_ADV_COMPLETE:
|
||||
NRF_LOG_INFO("Advertising event : BLE_GAP_EVENT_ADV_COMPLETE");
|
||||
|
@ -141,8 +141,7 @@ int NimbleController::OnGAPEvent(ble_gap_event *event) {
|
|||
NRF_LOG_INFO("Advertising event : BLE_GAP_EVENT_CONNECT");
|
||||
|
||||
/* A new connection was established or a connection attempt failed. */
|
||||
NRF_LOG_INFO("connection %s; status=%d ", event->connect.status == 0 ? "established" : "failed",
|
||||
event->connect.status);
|
||||
NRF_LOG_INFO("connection %s; status=%d ", event->connect.status == 0 ? "established" : "failed", event->connect.status);
|
||||
|
||||
if (event->connect.status != 0) {
|
||||
/* Connection failed; resume advertising. */
|
||||
|
@ -154,8 +153,7 @@ int NimbleController::OnGAPEvent(ble_gap_event *event) {
|
|||
connectionHandle = event->connect.conn_handle;
|
||||
// Service discovery is deffered via systemtask
|
||||
}
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
case BLE_GAP_EVENT_DISCONNECT:
|
||||
NRF_LOG_INFO("Advertising event : BLE_GAP_EVENT_DISCONNECT");
|
||||
NRF_LOG_INFO("disconnect; reason=%d", event->disconnect.reason);
|
||||
|
@ -187,10 +185,7 @@ int NimbleController::OnGAPEvent(ble_gap_event *event) {
|
|||
event->subscribe.prev_indicate);
|
||||
return 0;
|
||||
case BLE_GAP_EVENT_MTU:
|
||||
NRF_LOG_INFO("mtu update event; conn_handle=%d cid=%d mtu=%d\n",
|
||||
event->mtu.conn_handle,
|
||||
event->mtu.channel_id,
|
||||
event->mtu.value);
|
||||
NRF_LOG_INFO("mtu update event; conn_handle=%d cid=%d mtu=%d\n", event->mtu.conn_handle, event->mtu.channel_id, event->mtu.value);
|
||||
return 0;
|
||||
|
||||
case BLE_GAP_EVENT_REPEAT_PAIRING: {
|
||||
|
@ -216,9 +211,7 @@ int NimbleController::OnGAPEvent(ble_gap_event *event) {
|
|||
|
||||
NRF_LOG_INFO("received %s; conn_handle=%d attr_handle=%d "
|
||||
"attr_len=%d",
|
||||
event->notify_rx.indication ?
|
||||
"indication" :
|
||||
"notification",
|
||||
event->notify_rx.indication ? "indication" : "notification",
|
||||
event->notify_rx.conn_handle,
|
||||
event->notify_rx.attr_handle,
|
||||
notifSize);
|
||||
|
@ -229,7 +222,7 @@ int NimbleController::OnGAPEvent(ble_gap_event *event) {
|
|||
/* Attribute data is contained in event->notify_rx.attr_data. */
|
||||
|
||||
default:
|
||||
// NRF_LOG_INFO("Advertising event : %d", event->type);
|
||||
// NRF_LOG_INFO("Advertising event : %d", event->type);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
|
@ -239,8 +232,6 @@ void NimbleController::StartDiscovery() {
|
|||
serviceDiscovery.StartDiscovery(connectionHandle);
|
||||
}
|
||||
|
||||
|
||||
uint16_t NimbleController::connHandle() {
|
||||
return connectionHandle;
|
||||
}
|
||||
|
||||
|
|
|
@ -37,28 +37,37 @@ namespace Pinetime {
|
|||
class NimbleController {
|
||||
|
||||
public:
|
||||
NimbleController(Pinetime::System::SystemTask& systemTask, Pinetime::Controllers::Ble& bleController,
|
||||
DateTime& dateTimeController, Pinetime::Controllers::NotificationManager& notificationManager,
|
||||
Controllers::Battery& batteryController, Pinetime::Drivers::SpiNorFlash& spiNorFlash,
|
||||
NimbleController(Pinetime::System::SystemTask& systemTask,
|
||||
Pinetime::Controllers::Ble& bleController,
|
||||
DateTime& dateTimeController,
|
||||
Pinetime::Controllers::NotificationManager& notificationManager,
|
||||
Controllers::Battery& batteryController,
|
||||
Pinetime::Drivers::SpiNorFlash& spiNorFlash,
|
||||
Controllers::HeartRateController& heartRateController);
|
||||
void Init();
|
||||
void StartAdvertising();
|
||||
int OnGAPEvent(ble_gap_event *event);
|
||||
int OnGAPEvent(ble_gap_event* event);
|
||||
|
||||
int OnDiscoveryEvent(uint16_t i, const ble_gatt_error *pError, const ble_gatt_svc *pSvc);
|
||||
int OnCTSCharacteristicDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error *error,
|
||||
const ble_gatt_chr *characteristic);
|
||||
int OnANSCharacteristicDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error *error,
|
||||
const ble_gatt_chr *characteristic);
|
||||
int OnCurrentTimeReadResult(uint16_t connectionHandle, const ble_gatt_error *error, ble_gatt_attr *attribute);
|
||||
int OnANSDescriptorDiscoveryEventCallback(uint16_t connectionHandle, const ble_gatt_error *error,
|
||||
uint16_t characteristicValueHandle, const ble_gatt_dsc *descriptor);
|
||||
int OnDiscoveryEvent(uint16_t i, const ble_gatt_error* pError, const ble_gatt_svc* pSvc);
|
||||
int OnCTSCharacteristicDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error* error, const ble_gatt_chr* characteristic);
|
||||
int OnANSCharacteristicDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error* error, const ble_gatt_chr* characteristic);
|
||||
int OnCurrentTimeReadResult(uint16_t connectionHandle, const ble_gatt_error* error, ble_gatt_attr* attribute);
|
||||
int OnANSDescriptorDiscoveryEventCallback(uint16_t connectionHandle,
|
||||
const ble_gatt_error* error,
|
||||
uint16_t characteristicValueHandle,
|
||||
const ble_gatt_dsc* descriptor);
|
||||
|
||||
void StartDiscovery();
|
||||
|
||||
Pinetime::Controllers::MusicService& music() {return musicService;};
|
||||
Pinetime::Controllers::NavigationService& navigation() {return navService;};
|
||||
Pinetime::Controllers::AlertNotificationService& alertService() {return anService;};
|
||||
Pinetime::Controllers::MusicService& music() {
|
||||
return musicService;
|
||||
};
|
||||
Pinetime::Controllers::NavigationService& navigation() {
|
||||
return navService;
|
||||
};
|
||||
Pinetime::Controllers::AlertNotificationService& alertService() {
|
||||
return anService;
|
||||
};
|
||||
|
||||
uint16_t connHandle();
|
||||
|
||||
|
@ -86,10 +95,8 @@ namespace Pinetime {
|
|||
uint16_t connectionHandle = 0;
|
||||
|
||||
ble_uuid128_t dfuServiceUuid {
|
||||
.u { .type = BLE_UUID_TYPE_128},
|
||||
.value = {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15,
|
||||
0xDE, 0xEF, 0x12, 0x12, 0x30, 0x15, 0x00, 0x00}
|
||||
};
|
||||
.u {.type = BLE_UUID_TYPE_128},
|
||||
.value = {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15, 0xDE, 0xEF, 0x12, 0x12, 0x30, 0x15, 0x00, 0x00}};
|
||||
|
||||
ServiceDiscovery serviceDiscovery;
|
||||
};
|
||||
|
|
|
@ -6,15 +6,15 @@ using namespace Pinetime::Controllers;
|
|||
|
||||
constexpr uint8_t NotificationManager::MessageSize;
|
||||
|
||||
|
||||
void NotificationManager::Push(NotificationManager::Notification &¬if) {
|
||||
void NotificationManager::Push(NotificationManager::Notification&& notif) {
|
||||
notif.id = GetNextId();
|
||||
notif.valid = true;
|
||||
notifications[writeIndex] = std::move(notif);
|
||||
writeIndex = (writeIndex + 1 < TotalNbNotifications) ? writeIndex + 1 : 0;
|
||||
if(!empty)
|
||||
if (!empty)
|
||||
readIndex = (readIndex + 1 < TotalNbNotifications) ? readIndex + 1 : 0;
|
||||
else empty = false;
|
||||
else
|
||||
empty = false;
|
||||
|
||||
newNotification = true;
|
||||
}
|
||||
|
@ -30,40 +30,48 @@ NotificationManager::Notification::Id NotificationManager::GetNextId() {
|
|||
}
|
||||
|
||||
NotificationManager::Notification NotificationManager::GetNext(NotificationManager::Notification::Id id) {
|
||||
auto currentIterator = std::find_if(notifications.begin(), notifications.end(), [id](const Notification& n){return n.valid && n.id == id;});
|
||||
if(currentIterator == notifications.end() || currentIterator->id != id) return Notification{};
|
||||
auto currentIterator = std::find_if(notifications.begin(), notifications.end(), [id](const Notification& n) {
|
||||
return n.valid && n.id == id;
|
||||
});
|
||||
if (currentIterator == notifications.end() || currentIterator->id != id)
|
||||
return Notification {};
|
||||
|
||||
auto& lastNotification = notifications[readIndex];
|
||||
|
||||
NotificationManager::Notification result;
|
||||
|
||||
if(currentIterator == (notifications.end()-1))
|
||||
if (currentIterator == (notifications.end() - 1))
|
||||
result = *(notifications.begin());
|
||||
else
|
||||
result = *(currentIterator+1);
|
||||
result = *(currentIterator + 1);
|
||||
|
||||
if(result.id <= id) return {};
|
||||
if (result.id <= id)
|
||||
return {};
|
||||
|
||||
result.index = (lastNotification.id - result.id)+1;
|
||||
result.index = (lastNotification.id - result.id) + 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
NotificationManager::Notification NotificationManager::GetPrevious(NotificationManager::Notification::Id id) {
|
||||
auto currentIterator = std::find_if(notifications.begin(), notifications.end(), [id](const Notification& n){return n.valid && n.id == id;});
|
||||
if(currentIterator == notifications.end() || currentIterator->id != id) return Notification{};
|
||||
auto currentIterator = std::find_if(notifications.begin(), notifications.end(), [id](const Notification& n) {
|
||||
return n.valid && n.id == id;
|
||||
});
|
||||
if (currentIterator == notifications.end() || currentIterator->id != id)
|
||||
return Notification {};
|
||||
|
||||
auto& lastNotification = notifications[readIndex];
|
||||
|
||||
NotificationManager::Notification result;
|
||||
|
||||
if(currentIterator == notifications.begin())
|
||||
result = *(notifications.end()-1);
|
||||
if (currentIterator == notifications.begin())
|
||||
result = *(notifications.end() - 1);
|
||||
else
|
||||
result = *(currentIterator-1);
|
||||
result = *(currentIterator - 1);
|
||||
|
||||
if(result.id >= id) return {};
|
||||
if (result.id >= id)
|
||||
return {};
|
||||
|
||||
result.index = (lastNotification.id - result.id)+1;
|
||||
result.index = (lastNotification.id - result.id) + 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -84,21 +92,23 @@ bool NotificationManager::ClearNewNotificationFlag() {
|
|||
}
|
||||
|
||||
size_t NotificationManager::NbNotifications() const {
|
||||
return std::count_if(notifications.begin(), notifications.end(), [](const Notification& n){ return n.valid;});
|
||||
return std::count_if(notifications.begin(), notifications.end(), [](const Notification& n) {
|
||||
return n.valid;
|
||||
});
|
||||
}
|
||||
|
||||
const char* NotificationManager::Notification::Message() const {
|
||||
const char* itField = std::find(message.begin(), message.begin()+size-1, '\0');
|
||||
if(itField != message.begin()+size-1) {
|
||||
const char* ptr = (itField)+1;
|
||||
const char* itField = std::find(message.begin(), message.begin() + size - 1, '\0');
|
||||
if (itField != message.begin() + size - 1) {
|
||||
const char* ptr = (itField) + 1;
|
||||
return ptr;
|
||||
}
|
||||
return const_cast<char*>(message.data());
|
||||
}
|
||||
|
||||
const char* NotificationManager::Notification::Title() const {
|
||||
const char * itField = std::find(message.begin(), message.begin()+size-1, '\0');
|
||||
if(itField != message.begin()+size-1) {
|
||||
const char* itField = std::find(message.begin(), message.begin() + size - 1, '\0');
|
||||
if (itField != message.begin() + size - 1) {
|
||||
return message.data();
|
||||
}
|
||||
return {};
|
||||
|
|
|
@ -9,8 +9,20 @@ namespace Pinetime {
|
|||
namespace Controllers {
|
||||
class NotificationManager {
|
||||
public:
|
||||
enum class Categories {Unknown, SimpleAlert, Email, News, IncomingCall, MissedCall, Sms, VoiceMail, Schedule, HighProriotyAlert, InstantMessage };
|
||||
static constexpr uint8_t MessageSize{100};
|
||||
enum class Categories {
|
||||
Unknown,
|
||||
SimpleAlert,
|
||||
Email,
|
||||
News,
|
||||
IncomingCall,
|
||||
MissedCall,
|
||||
Sms,
|
||||
VoiceMail,
|
||||
Schedule,
|
||||
HighProriotyAlert,
|
||||
InstantMessage
|
||||
};
|
||||
static constexpr uint8_t MessageSize {100};
|
||||
|
||||
struct Notification {
|
||||
using Id = uint8_t;
|
||||
|
@ -18,7 +30,7 @@ namespace Pinetime {
|
|||
bool valid = false;
|
||||
uint8_t index;
|
||||
uint8_t size;
|
||||
std::array<char, MessageSize+1> message;
|
||||
std::array<char, MessageSize + 1> message;
|
||||
Categories category = Categories::Unknown;
|
||||
|
||||
const char* Message() const;
|
||||
|
@ -35,7 +47,9 @@ namespace Pinetime {
|
|||
bool IsVibrationEnabled();
|
||||
void ToggleVibrations();
|
||||
|
||||
static constexpr size_t MaximumMessageSize() { return MessageSize; };
|
||||
static constexpr size_t MaximumMessageSize() {
|
||||
return MessageSize;
|
||||
};
|
||||
size_t NbNotifications() const;
|
||||
|
||||
private:
|
||||
|
@ -45,7 +59,7 @@ namespace Pinetime {
|
|||
uint8_t readIndex = 0;
|
||||
uint8_t writeIndex = 0;
|
||||
bool empty = true;
|
||||
std::atomic<bool> newNotification{false};
|
||||
std::atomic<bool> newNotification {false};
|
||||
bool vibrationEnabled = true;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -4,8 +4,7 @@
|
|||
|
||||
using namespace Pinetime::Controllers;
|
||||
|
||||
ServiceDiscovery::ServiceDiscovery(std::array<BleClient*, 2>&& clients) : clients{clients} {
|
||||
|
||||
ServiceDiscovery::ServiceDiscovery(std::array<BleClient*, 2>&& clients) : clients {clients} {
|
||||
}
|
||||
|
||||
void ServiceDiscovery::StartDiscovery(uint16_t connectionHandle) {
|
||||
|
@ -16,7 +15,7 @@ void ServiceDiscovery::StartDiscovery(uint16_t connectionHandle) {
|
|||
|
||||
void ServiceDiscovery::OnServiceDiscovered(uint16_t connectionHandle) {
|
||||
clientIterator++;
|
||||
if(clientIterator != clients.end()) {
|
||||
if (clientIterator != clients.end()) {
|
||||
DiscoverNextService(connectionHandle);
|
||||
} else {
|
||||
NRF_LOG_INFO("End of service discovery");
|
||||
|
@ -26,7 +25,7 @@ void ServiceDiscovery::OnServiceDiscovered(uint16_t connectionHandle) {
|
|||
void ServiceDiscovery::DiscoverNextService(uint16_t connectionHandle) {
|
||||
NRF_LOG_INFO("[Discovery] Discover next service");
|
||||
|
||||
auto discoverNextService = [this](uint16_t connectionHandle){
|
||||
auto discoverNextService = [this](uint16_t connectionHandle) {
|
||||
this->OnServiceDiscovered(connectionHandle);
|
||||
};
|
||||
(*clientIterator)->Discover(connectionHandle, discoverNextService);
|
||||
|
|
|
@ -13,7 +13,6 @@ namespace Pinetime {
|
|||
|
||||
void StartDiscovery(uint16_t connectionHandle);
|
||||
|
||||
|
||||
private:
|
||||
BleClient** clientIterator;
|
||||
std::array<BleClient*, 2> clients;
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
using namespace Pinetime::Controllers;
|
||||
|
||||
|
||||
void BrightnessController::Init() {
|
||||
nrf_gpio_cfg_output(pinLcdBacklight1);
|
||||
nrf_gpio_cfg_output(pinLcdBacklight2);
|
||||
|
@ -14,7 +13,7 @@ void BrightnessController::Init() {
|
|||
|
||||
void BrightnessController::Set(BrightnessController::Levels level) {
|
||||
this->level = level;
|
||||
switch(level) {
|
||||
switch (level) {
|
||||
default:
|
||||
case Levels::High:
|
||||
nrf_gpio_pin_clear(pinLcdBacklight1);
|
||||
|
@ -40,20 +39,34 @@ void BrightnessController::Set(BrightnessController::Levels level) {
|
|||
}
|
||||
|
||||
void BrightnessController::Lower() {
|
||||
switch(level) {
|
||||
case Levels::High: Set(Levels::Medium); break;
|
||||
case Levels::Medium: Set(Levels::Low); break;
|
||||
case Levels::Low: Set(Levels::Off); break;
|
||||
default: break;
|
||||
switch (level) {
|
||||
case Levels::High:
|
||||
Set(Levels::Medium);
|
||||
break;
|
||||
case Levels::Medium:
|
||||
Set(Levels::Low);
|
||||
break;
|
||||
case Levels::Low:
|
||||
Set(Levels::Off);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void BrightnessController::Higher() {
|
||||
switch(level) {
|
||||
case Levels::Off: Set(Levels::Low); break;
|
||||
case Levels::Low: Set(Levels::Medium); break;
|
||||
case Levels::Medium: Set(Levels::High); break;
|
||||
default: break;
|
||||
switch (level) {
|
||||
case Levels::Off:
|
||||
Set(Levels::Low);
|
||||
break;
|
||||
case Levels::Low:
|
||||
Set(Levels::Medium);
|
||||
break;
|
||||
case Levels::Medium:
|
||||
Set(Levels::High);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -70,29 +83,44 @@ void BrightnessController::Restore() {
|
|||
}
|
||||
|
||||
void BrightnessController::Step() {
|
||||
switch(level) {
|
||||
case Levels::Low: Set(Levels::Medium); break;
|
||||
case Levels::Medium: Set(Levels::High); break;
|
||||
case Levels::High: Set(Levels::Low); break;
|
||||
default: break;
|
||||
switch (level) {
|
||||
case Levels::Low:
|
||||
Set(Levels::Medium);
|
||||
break;
|
||||
case Levels::Medium:
|
||||
Set(Levels::High);
|
||||
break;
|
||||
case Levels::High:
|
||||
Set(Levels::Low);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const char* BrightnessController::GetIcon() {
|
||||
switch(level) {
|
||||
case Levels::Medium: return Applications::Screens::Symbols::brightnessMedium;
|
||||
case Levels::High: return Applications::Screens::Symbols::brightnessHigh;
|
||||
default: break;
|
||||
switch (level) {
|
||||
case Levels::Medium:
|
||||
return Applications::Screens::Symbols::brightnessMedium;
|
||||
case Levels::High:
|
||||
return Applications::Screens::Symbols::brightnessHigh;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return Applications::Screens::Symbols::brightnessLow;
|
||||
}
|
||||
|
||||
const char* BrightnessController::ToString() {
|
||||
switch(level) {
|
||||
case Levels::Off: return "Off";
|
||||
case Levels::Low: return "Low";
|
||||
case Levels::Medium: return "Medium";
|
||||
case Levels::High: return "High";
|
||||
default : return "???";
|
||||
switch (level) {
|
||||
case Levels::Off:
|
||||
return "Off";
|
||||
case Levels::Low:
|
||||
return "Low";
|
||||
case Levels::Medium:
|
||||
return "Medium";
|
||||
case Levels::High:
|
||||
return "High";
|
||||
default:
|
||||
return "???";
|
||||
}
|
||||
}
|
|
@ -6,7 +6,7 @@ namespace Pinetime {
|
|||
namespace Controllers {
|
||||
class BrightnessController {
|
||||
public:
|
||||
enum class Levels {Off, Low, Medium, High};
|
||||
enum class Levels { Off, Low, Medium, High };
|
||||
void Init();
|
||||
|
||||
void Set(Levels level);
|
||||
|
|
|
@ -5,14 +5,13 @@
|
|||
|
||||
using namespace Pinetime::Controllers;
|
||||
|
||||
DateTime::DateTime(System::SystemTask& systemTask) : systemTask{systemTask} {
|
||||
|
||||
DateTime::DateTime(System::SystemTask& systemTask) : systemTask {systemTask} {
|
||||
}
|
||||
|
||||
|
||||
void DateTime::SetTime(uint16_t year, uint8_t month, uint8_t day, uint8_t dayOfWeek, uint8_t hour, uint8_t minute,
|
||||
uint8_t second, uint32_t systickCounter) {
|
||||
std::tm tm = { /* .tm_sec = */ second,
|
||||
void DateTime::SetTime(
|
||||
uint16_t year, uint8_t month, uint8_t day, uint8_t dayOfWeek, uint8_t hour, uint8_t minute, uint8_t second, uint32_t systickCounter) {
|
||||
std::tm tm = {
|
||||
/* .tm_sec = */ second,
|
||||
/* .tm_min = */ minute,
|
||||
/* .tm_hour = */ hour,
|
||||
/* .tm_mday = */ day,
|
||||
|
@ -34,7 +33,7 @@ void DateTime::SetTime(uint16_t year, uint8_t month, uint8_t day, uint8_t dayOfW
|
|||
void DateTime::UpdateTime(uint32_t systickCounter) {
|
||||
// Handle systick counter overflow
|
||||
uint32_t systickDelta = 0;
|
||||
if(systickCounter < previousSystickCounter) {
|
||||
if (systickCounter < previousSystickCounter) {
|
||||
systickDelta = 0xffffff - previousSystickCounter;
|
||||
systickDelta += systickCounter + 1;
|
||||
} else {
|
||||
|
@ -45,8 +44,8 @@ void DateTime::UpdateTime(uint32_t systickCounter) {
|
|||
* 1000 ms = 1024 ticks
|
||||
*/
|
||||
auto correctedDelta = systickDelta / 1024;
|
||||
auto rest = (systickDelta - (correctedDelta*1024));
|
||||
if(systickCounter >= rest) {
|
||||
auto rest = (systickDelta - (correctedDelta * 1024));
|
||||
if (systickCounter >= rest) {
|
||||
previousSystickCounter = systickCounter - rest;
|
||||
} else {
|
||||
previousSystickCounter = 0xffffff - (rest - systickCounter);
|
||||
|
@ -56,12 +55,12 @@ void DateTime::UpdateTime(uint32_t systickCounter) {
|
|||
uptime += std::chrono::seconds(correctedDelta);
|
||||
|
||||
auto dp = date::floor<date::days>(currentDateTime);
|
||||
auto time = date::make_time(currentDateTime-dp);
|
||||
auto time = date::make_time(currentDateTime - dp);
|
||||
auto yearMonthDay = date::year_month_day(dp);
|
||||
|
||||
year = (int)yearMonthDay.year();
|
||||
month = static_cast<Months>((unsigned)yearMonthDay.month());
|
||||
day = (unsigned)yearMonthDay.day();
|
||||
year = (int) yearMonthDay.year();
|
||||
month = static_cast<Months>((unsigned) yearMonthDay.month());
|
||||
day = (unsigned) yearMonthDay.day();
|
||||
dayOfWeek = static_cast<Days>(date::weekday(yearMonthDay).iso_encoding());
|
||||
|
||||
hour = time.hours().count();
|
||||
|
@ -69,7 +68,7 @@ void DateTime::UpdateTime(uint32_t systickCounter) {
|
|||
second = time.seconds().count();
|
||||
|
||||
// Notify new day to SystemTask
|
||||
if(hour == 0 and not isMidnightAlreadyNotified) {
|
||||
if (hour == 0 and not isMidnightAlreadyNotified) {
|
||||
isMidnightAlreadyNotified = true;
|
||||
systemTask.PushMessage(System::SystemTask::Messages::OnNewDay);
|
||||
} else if (hour != 0) {
|
||||
|
@ -77,123 +76,45 @@ void DateTime::UpdateTime(uint32_t systickCounter) {
|
|||
}
|
||||
}
|
||||
|
||||
const char *DateTime::MonthShortToString() {
|
||||
return DateTime::MonthsString[(uint8_t)month];
|
||||
const char* DateTime::MonthShortToString() {
|
||||
return DateTime::MonthsString[(uint8_t) month];
|
||||
}
|
||||
|
||||
const char *DateTime::MonthShortToStringLow() {
|
||||
return DateTime::MonthsStringLow[(uint8_t)month];
|
||||
const char* DateTime::MonthShortToStringLow() {
|
||||
return DateTime::MonthsStringLow[(uint8_t) month];
|
||||
}
|
||||
|
||||
const char *DateTime::MonthsToStringLow() {
|
||||
return DateTime::MonthsLow[(uint8_t)month];
|
||||
const char* DateTime::MonthsToStringLow() {
|
||||
return DateTime::MonthsLow[(uint8_t) month];
|
||||
}
|
||||
|
||||
const char *DateTime::DayOfWeekToString() {
|
||||
return DateTime::DaysString[(uint8_t)dayOfWeek];
|
||||
const char* DateTime::DayOfWeekToString() {
|
||||
return DateTime::DaysString[(uint8_t) dayOfWeek];
|
||||
}
|
||||
|
||||
const char *DateTime::DayOfWeekShortToString() {
|
||||
return DateTime::DaysStringShort[(uint8_t)dayOfWeek];
|
||||
const char* DateTime::DayOfWeekShortToString() {
|
||||
return DateTime::DaysStringShort[(uint8_t) dayOfWeek];
|
||||
}
|
||||
|
||||
const char *DateTime::DayOfWeekToStringLow() {
|
||||
return DateTime::DaysStringLow[(uint8_t)dayOfWeek];
|
||||
const char* DateTime::DayOfWeekToStringLow() {
|
||||
return DateTime::DaysStringLow[(uint8_t) dayOfWeek];
|
||||
}
|
||||
|
||||
const char *DateTime::DayOfWeekShortToStringLow() {
|
||||
return DateTime::DaysStringShortLow[(uint8_t)dayOfWeek];
|
||||
const char* DateTime::DayOfWeekShortToStringLow() {
|
||||
return DateTime::DaysStringShortLow[(uint8_t) dayOfWeek];
|
||||
}
|
||||
|
||||
char const* DateTime::DaysStringLow[] = {"--", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"};
|
||||
|
||||
char const *DateTime::DaysStringLow[] = {
|
||||
"--",
|
||||
"Monday",
|
||||
"Tuesday",
|
||||
"Wednesday",
|
||||
"Thursday",
|
||||
"Friday",
|
||||
"Saturday",
|
||||
"Sunday"
|
||||
};
|
||||
char const* DateTime::DaysStringShortLow[] = {"--", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
|
||||
|
||||
char const *DateTime::DaysStringShortLow[] = {
|
||||
"--",
|
||||
"Mon",
|
||||
"Tue",
|
||||
"Wed",
|
||||
"Thu",
|
||||
"Fri",
|
||||
"Sat",
|
||||
"Sun"
|
||||
};
|
||||
char const* DateTime::DaysStringShort[] = {"--", "MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"};
|
||||
|
||||
char const *DateTime::DaysStringShort[] = {
|
||||
"--",
|
||||
"MON",
|
||||
"TUE",
|
||||
"WED",
|
||||
"THU",
|
||||
"FRI",
|
||||
"SAT",
|
||||
"SUN"
|
||||
};
|
||||
char const* DateTime::DaysString[] = {"--", "MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY", "SUNDAY"};
|
||||
|
||||
char const *DateTime::DaysString[] = {
|
||||
"--",
|
||||
"MONDAY",
|
||||
"TUESDAY",
|
||||
"WEDNESDAY",
|
||||
"THURSDAY",
|
||||
"FRIDAY",
|
||||
"SATURDAY",
|
||||
"SUNDAY"
|
||||
};
|
||||
char const* DateTime::MonthsString[] = {"--", "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
|
||||
|
||||
char const *DateTime::MonthsString[] = {
|
||||
"--",
|
||||
"JAN",
|
||||
"FEB",
|
||||
"MAR",
|
||||
"APR",
|
||||
"MAY",
|
||||
"JUN",
|
||||
"JUL",
|
||||
"AUG",
|
||||
"SEP",
|
||||
"OCT",
|
||||
"NOV",
|
||||
"DEC"
|
||||
};
|
||||
char const* DateTime::MonthsStringLow[] = {"--", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
|
||||
|
||||
char const *DateTime::MonthsStringLow[] = {
|
||||
"--",
|
||||
"Jan",
|
||||
"Feb",
|
||||
"Mar",
|
||||
"Apr",
|
||||
"May",
|
||||
"Jun",
|
||||
"Jul",
|
||||
"Aug",
|
||||
"Sep",
|
||||
"Oct",
|
||||
"Nov",
|
||||
"Dec"
|
||||
};
|
||||
|
||||
char const *DateTime::MonthsLow[] = {
|
||||
"--",
|
||||
"January",
|
||||
"February",
|
||||
"March",
|
||||
"April",
|
||||
"May",
|
||||
"June",
|
||||
"July",
|
||||
"August",
|
||||
"September",
|
||||
"October",
|
||||
"November",
|
||||
"December"
|
||||
};
|
||||
char const* DateTime::MonthsLow[] = {
|
||||
"--", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"};
|
|
@ -10,31 +10,71 @@ namespace Pinetime {
|
|||
namespace Controllers {
|
||||
class DateTime {
|
||||
public:
|
||||
enum class Days : uint8_t {Unknown, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday};
|
||||
enum class Months : uint8_t {Unknown, January, February, March, April, May, June, July, August, September, October, November, December};
|
||||
enum class Days : uint8_t { Unknown, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday };
|
||||
enum class Months : uint8_t {
|
||||
Unknown,
|
||||
January,
|
||||
February,
|
||||
March,
|
||||
April,
|
||||
May,
|
||||
June,
|
||||
July,
|
||||
August,
|
||||
September,
|
||||
October,
|
||||
November,
|
||||
December
|
||||
};
|
||||
|
||||
DateTime(System::SystemTask& systemTask);
|
||||
|
||||
void SetTime(uint16_t year, uint8_t month, uint8_t day, uint8_t dayOfWeek, uint8_t hour, uint8_t minute, uint8_t second, uint32_t systickCounter);
|
||||
void SetTime(uint16_t year,
|
||||
uint8_t month,
|
||||
uint8_t day,
|
||||
uint8_t dayOfWeek,
|
||||
uint8_t hour,
|
||||
uint8_t minute,
|
||||
uint8_t second,
|
||||
uint32_t systickCounter);
|
||||
void UpdateTime(uint32_t systickCounter);
|
||||
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; }
|
||||
uint16_t Year() const {
|
||||
return year;
|
||||
}
|
||||
Months Month() const {
|
||||
return month;
|
||||
}
|
||||
uint8_t Day() const {
|
||||
return day;
|
||||
}
|
||||
Days DayOfWeek() const {
|
||||
return dayOfWeek;
|
||||
}
|
||||
uint8_t Hours() const {
|
||||
return hour;
|
||||
}
|
||||
uint8_t Minutes() const {
|
||||
return minute;
|
||||
}
|
||||
uint8_t Seconds() const {
|
||||
return second;
|
||||
}
|
||||
|
||||
const char *MonthShortToString();
|
||||
const char *MonthShortToStringLow();
|
||||
const char *MonthsToStringLow();
|
||||
const char *DayOfWeekToString();
|
||||
const char *DayOfWeekShortToString();
|
||||
const char *DayOfWeekToStringLow();
|
||||
const char *DayOfWeekShortToStringLow();
|
||||
const char* MonthShortToString();
|
||||
const char* MonthShortToStringLow();
|
||||
const char* MonthsToStringLow();
|
||||
const char* DayOfWeekToString();
|
||||
const char* DayOfWeekShortToString();
|
||||
const char* DayOfWeekToStringLow();
|
||||
const char* DayOfWeekShortToStringLow();
|
||||
|
||||
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> CurrentDateTime() const {
|
||||
return currentDateTime;
|
||||
}
|
||||
std::chrono::seconds Uptime() const {
|
||||
return uptime;
|
||||
}
|
||||
|
||||
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> CurrentDateTime() const { return currentDateTime; }
|
||||
std::chrono::seconds Uptime() const { return uptime; }
|
||||
private:
|
||||
System::SystemTask& systemTask;
|
||||
uint16_t year = 0;
|
||||
|
@ -51,14 +91,13 @@ namespace Pinetime {
|
|||
|
||||
bool isMidnightAlreadyNotified = false;
|
||||
|
||||
static char const *DaysString[];
|
||||
static char const *DaysStringShort[];
|
||||
static char const *DaysStringLow[];
|
||||
static char const *DaysStringShortLow[];
|
||||
static char const *MonthsString[];
|
||||
static char const *MonthsStringLow[];
|
||||
static char const *MonthsLow[];
|
||||
|
||||
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;
|
||||
|
||||
bool FirmwareValidator::IsValidated() const {
|
||||
auto* imageOkPtr = reinterpret_cast<uint32_t *>(validBitAdress);
|
||||
auto* imageOkPtr = reinterpret_cast<uint32_t*>(validBitAdress);
|
||||
return (*imageOkPtr) == validBitValue;
|
||||
}
|
||||
|
||||
void FirmwareValidator::Validate() {
|
||||
if(!IsValidated())
|
||||
if (!IsValidated())
|
||||
Pinetime::Drivers::InternalFlash::WriteWord(validBitAdress, validBitValue);
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ namespace Pinetime {
|
|||
bool IsValidated() const;
|
||||
|
||||
void Reset();
|
||||
|
||||
private:
|
||||
static constexpr uint32_t validBitAdress {0x7BFE8};
|
||||
static constexpr uint32_t validBitValue {1};
|
||||
|
|
|
@ -2,11 +2,10 @@
|
|||
#include "drivers/St7789.h"
|
||||
using namespace Pinetime::Components;
|
||||
|
||||
Gfx::Gfx(Pinetime::Drivers::St7789 &lcd) : lcd{lcd} {
|
||||
Gfx::Gfx(Pinetime::Drivers::St7789& lcd) : lcd {lcd} {
|
||||
}
|
||||
|
||||
void Gfx::Init() {
|
||||
|
||||
}
|
||||
|
||||
void Gfx::ClearScreen() {
|
||||
|
@ -18,9 +17,8 @@ void Gfx::ClearScreen() {
|
|||
state.action = Action::FillRectangle;
|
||||
state.taskToNotify = xTaskGetCurrentTaskHandle();
|
||||
|
||||
lcd.DrawBuffer(0, 0, width, height, reinterpret_cast<const uint8_t *>(buffer), width * 2);
|
||||
lcd.DrawBuffer(0, 0, width, height, reinterpret_cast<const uint8_t*>(buffer), width * 2);
|
||||
WaitTransferFinished();
|
||||
|
||||
}
|
||||
|
||||
void Gfx::FillRectangle(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint16_t color) {
|
||||
|
@ -33,7 +31,7 @@ void Gfx::FillRectangle(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint16_t col
|
|||
state.color = color;
|
||||
state.taskToNotify = xTaskGetCurrentTaskHandle();
|
||||
|
||||
lcd.DrawBuffer(x, y, w, h, reinterpret_cast<const uint8_t *>(buffer), width * 2);
|
||||
lcd.DrawBuffer(x, y, w, h, reinterpret_cast<const uint8_t*>(buffer), width * 2);
|
||||
|
||||
WaitTransferFinished();
|
||||
}
|
||||
|
@ -46,12 +44,12 @@ void Gfx::FillRectangle(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t* b)
|
|||
state.color = 0x00;
|
||||
state.taskToNotify = xTaskGetCurrentTaskHandle();
|
||||
|
||||
lcd.DrawBuffer(x, y, w, h, reinterpret_cast<const uint8_t *>(b), width * 2);
|
||||
lcd.DrawBuffer(x, y, w, h, reinterpret_cast<const uint8_t*>(b), width * 2);
|
||||
|
||||
WaitTransferFinished();
|
||||
}
|
||||
|
||||
void Gfx::DrawString(uint8_t x, uint8_t y, uint16_t color, const char *text, const FONT_INFO *p_font, bool wrap) {
|
||||
void Gfx::DrawString(uint8_t x, uint8_t y, uint16_t color, const char* text, const FONT_INFO* p_font, bool wrap) {
|
||||
if (y > (height - p_font->height)) {
|
||||
// Not enough space to write even single char.
|
||||
return;
|
||||
|
@ -86,7 +84,7 @@ void Gfx::DrawString(uint8_t x, uint8_t y, uint16_t color, const char *text, con
|
|||
}
|
||||
}
|
||||
|
||||
void Gfx::DrawChar(const FONT_INFO *font, uint8_t c, uint8_t *x, uint8_t y, uint16_t color) {
|
||||
void Gfx::DrawChar(const FONT_INFO* font, uint8_t c, uint8_t* x, uint8_t y, uint16_t color) {
|
||||
uint8_t char_idx = c - font->startChar;
|
||||
uint16_t bytes_in_line = CEIL_DIV(font->charInfo[char_idx].widthBits, 8);
|
||||
uint16_t bg = 0x0000;
|
||||
|
@ -100,10 +98,9 @@ void Gfx::DrawChar(const FONT_INFO *font, uint8_t c, uint8_t *x, uint8_t y, uint
|
|||
for (uint16_t j = 0; j < bytes_in_line; j++) {
|
||||
for (uint8_t k = 0; k < 8; k++) {
|
||||
if ((1 << (7 - k)) & font->data[font->charInfo[char_idx].offset + j]) {
|
||||
buffer[(j*8)+k] = color;
|
||||
}
|
||||
else {
|
||||
buffer[(j*8)+k] = bg;
|
||||
buffer[(j * 8) + k] = color;
|
||||
} else {
|
||||
buffer[(j * 8) + k] = bg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -112,12 +109,12 @@ void Gfx::DrawChar(const FONT_INFO *font, uint8_t c, uint8_t *x, uint8_t y, uint
|
|||
state.currentIteration = 0;
|
||||
state.busy = true;
|
||||
state.action = Action::DrawChar;
|
||||
state.font = const_cast<FONT_INFO *>(font);
|
||||
state.font = const_cast<FONT_INFO*>(font);
|
||||
state.character = c;
|
||||
state.color = color;
|
||||
state.taskToNotify = xTaskGetCurrentTaskHandle();
|
||||
|
||||
lcd.DrawBuffer(*x, y, bytes_in_line*8, font->height, reinterpret_cast<const uint8_t *>(&buffer), bytes_in_line*8*2);
|
||||
lcd.DrawBuffer(*x, y, bytes_in_line * 8, font->height, reinterpret_cast<const uint8_t*>(&buffer), bytes_in_line * 8 * 2);
|
||||
WaitTransferFinished();
|
||||
|
||||
*x += font->charInfo[char_idx].widthBits + font->spacePixels;
|
||||
|
@ -136,13 +133,14 @@ void Gfx::Wakeup() {
|
|||
}
|
||||
|
||||
void Gfx::SetBackgroundColor(uint16_t color) {
|
||||
for(int i = 0; i < width; i++) {
|
||||
for (int i = 0; i < width; i++) {
|
||||
buffer[i] = color;
|
||||
}
|
||||
}
|
||||
|
||||
bool Gfx::GetNextBuffer(uint8_t **data, size_t &size) {
|
||||
if(!state.busy) return false;
|
||||
bool Gfx::GetNextBuffer(uint8_t** data, size_t& size) {
|
||||
if (!state.busy)
|
||||
return false;
|
||||
state.remainingIterations--;
|
||||
if (state.remainingIterations == 0) {
|
||||
state.busy = false;
|
||||
|
@ -150,27 +148,26 @@ bool Gfx::GetNextBuffer(uint8_t **data, size_t &size) {
|
|||
return false;
|
||||
}
|
||||
|
||||
if(state.action == Action::FillRectangle) {
|
||||
*data = reinterpret_cast<uint8_t *>(buffer);
|
||||
if (state.action == Action::FillRectangle) {
|
||||
*data = reinterpret_cast<uint8_t*>(buffer);
|
||||
size = width * 2;
|
||||
} else if(state.action == Action::DrawChar) {
|
||||
} else if (state.action == Action::DrawChar) {
|
||||
uint16_t bg = 0x0000;
|
||||
uint8_t char_idx = state.character - state.font->startChar;
|
||||
uint16_t bytes_in_line = CEIL_DIV(state.font->charInfo[char_idx].widthBits, 8);
|
||||
|
||||
for (uint16_t j = 0; j < bytes_in_line; j++) {
|
||||
for (uint8_t k = 0; k < 8; k++) {
|
||||
if ((1 << (7 - k)) & state.font->data[state.font->charInfo[char_idx].offset + ((state.currentIteration+1) * bytes_in_line) + j]) {
|
||||
buffer[(j*8)+k] = state.color;
|
||||
}
|
||||
else {
|
||||
buffer[(j*8)+k] = bg;
|
||||
if ((1 << (7 - k)) & state.font->data[state.font->charInfo[char_idx].offset + ((state.currentIteration + 1) * bytes_in_line) + j]) {
|
||||
buffer[(j * 8) + k] = state.color;
|
||||
} else {
|
||||
buffer[(j * 8) + k] = bg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*data = reinterpret_cast<uint8_t *>(buffer);
|
||||
size = bytes_in_line*8*2;
|
||||
*data = reinterpret_cast<uint8_t*>(buffer);
|
||||
size = bytes_in_line * 8 * 2;
|
||||
}
|
||||
|
||||
state.currentIteration++;
|
||||
|
@ -179,7 +176,7 @@ bool Gfx::GetNextBuffer(uint8_t **data, size_t &size) {
|
|||
}
|
||||
|
||||
void Gfx::NotifyEndOfTransfer(TaskHandle_t task) {
|
||||
if(task != nullptr) {
|
||||
if (task != nullptr) {
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
vTaskNotifyGiveFromISR(task, &xHigherPriorityTaskWoken);
|
||||
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
||||
|
|
|
@ -16,32 +16,31 @@ namespace Pinetime {
|
|||
explicit Gfx(Drivers::St7789& lcd);
|
||||
void Init();
|
||||
void ClearScreen();
|
||||
void DrawString(uint8_t x, uint8_t y, uint16_t color, const char* text, const FONT_INFO *p_font, bool wrap);
|
||||
void DrawChar(const FONT_INFO *font, uint8_t c, uint8_t *x, uint8_t y, uint16_t color);
|
||||
void DrawString(uint8_t x, uint8_t y, uint16_t color, const char* text, const FONT_INFO* p_font, bool wrap);
|
||||
void DrawChar(const FONT_INFO* font, uint8_t c, uint8_t* x, uint8_t y, uint16_t color);
|
||||
void FillRectangle(uint8_t x, uint8_t y, uint8_t width, uint8_t height, uint16_t color);
|
||||
void FillRectangle(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t* b);
|
||||
void SetScrollArea(uint16_t topFixedLines, uint16_t scrollLines, uint16_t bottomFixedLines);
|
||||
void SetScrollStartLine(uint16_t line);
|
||||
|
||||
|
||||
void Sleep();
|
||||
void Wakeup();
|
||||
bool GetNextBuffer(uint8_t **buffer, size_t &size) override;
|
||||
bool GetNextBuffer(uint8_t** buffer, size_t& size) override;
|
||||
void pixel_draw(uint8_t x, uint8_t y, uint16_t color);
|
||||
|
||||
|
||||
private:
|
||||
static constexpr uint8_t width = 240;
|
||||
static constexpr uint8_t height = 240;
|
||||
|
||||
enum class Action { None, FillRectangle, DrawChar};
|
||||
enum class Action { None, FillRectangle, DrawChar };
|
||||
struct State {
|
||||
State() : busy{false}, action{Action::None}, remainingIterations{0}, currentIteration{0} {}
|
||||
State() : busy {false}, action {Action::None}, remainingIterations {0}, currentIteration {0} {
|
||||
}
|
||||
volatile bool busy;
|
||||
volatile Action action;
|
||||
volatile uint16_t remainingIterations;
|
||||
volatile uint16_t currentIteration;
|
||||
volatile FONT_INFO *font;
|
||||
volatile FONT_INFO* font;
|
||||
volatile uint16_t color;
|
||||
volatile uint8_t character;
|
||||
volatile TaskHandle_t taskToNotify = nullptr;
|
||||
|
|
|
@ -9,8 +9,7 @@
|
|||
using namespace Pinetime::Controllers;
|
||||
|
||||
/** Original implementation from wasp-os : https://github.com/daniel-thompson/wasp-os/blob/master/wasp/ppg.py */
|
||||
Biquad::Biquad(float b0, float b1, float b2, float a1, float a2) : b0{b0}, b1{b1}, b2{b2}, a1{a1}, a2{a2} {
|
||||
|
||||
Biquad::Biquad(float b0, float b1, float b2, float a1, float a2) : b0 {b0}, b1 {b1}, b2 {b2}, a1 {a1}, a2 {a2} {
|
||||
}
|
||||
|
||||
float Biquad::Step(float x) {
|
||||
|
|
|
@ -4,38 +4,35 @@
|
|||
|
||||
using namespace Pinetime::Controllers;
|
||||
|
||||
HeartRateController::HeartRateController(Pinetime::System::SystemTask &systemTask) : systemTask{systemTask} {
|
||||
|
||||
HeartRateController::HeartRateController(Pinetime::System::SystemTask& systemTask) : systemTask {systemTask} {
|
||||
}
|
||||
|
||||
|
||||
void HeartRateController::Update(HeartRateController::States newState, uint8_t heartRate) {
|
||||
this->state = newState;
|
||||
if(this->heartRate != heartRate) {
|
||||
if (this->heartRate != heartRate) {
|
||||
this->heartRate = heartRate;
|
||||
service->OnNewHeartRateValue(heartRate);
|
||||
}
|
||||
}
|
||||
|
||||
void HeartRateController::Start() {
|
||||
if(task != nullptr) {
|
||||
if (task != nullptr) {
|
||||
state = States::NotEnoughData;
|
||||
task->PushMessage(Pinetime::Applications::HeartRateTask::Messages::StartMeasurement);
|
||||
}
|
||||
}
|
||||
|
||||
void HeartRateController::Stop() {
|
||||
if(task != nullptr) {
|
||||
if (task != nullptr) {
|
||||
state = States::Stopped;
|
||||
task->PushMessage(Pinetime::Applications::HeartRateTask::Messages::StopMeasurement);
|
||||
}
|
||||
}
|
||||
|
||||
void HeartRateController::SetHeartRateTask(Pinetime::Applications::HeartRateTask *task) {
|
||||
void HeartRateController::SetHeartRateTask(Pinetime::Applications::HeartRateTask* task) {
|
||||
this->task = task;
|
||||
}
|
||||
|
||||
void HeartRateController::SetService(Pinetime::Controllers::HeartRateService *service) {
|
||||
void HeartRateController::SetService(Pinetime::Controllers::HeartRateService* service) {
|
||||
this->service = service;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace Pinetime {
|
|||
namespace Controllers {
|
||||
class HeartRateController {
|
||||
public:
|
||||
enum class States { Stopped, NotEnoughData, NoTouch, Running};
|
||||
enum class States { Stopped, NotEnoughData, NoTouch, Running };
|
||||
|
||||
explicit HeartRateController(System::SystemTask& systemTask);
|
||||
|
||||
|
@ -22,10 +22,14 @@ namespace Pinetime {
|
|||
void Update(States newState, uint8_t heartRate);
|
||||
|
||||
void SetHeartRateTask(Applications::HeartRateTask* task);
|
||||
States State() const { return state; }
|
||||
uint8_t HeartRate() const { return heartRate; }
|
||||
States State() const {
|
||||
return state;
|
||||
}
|
||||
uint8_t HeartRate() const {
|
||||
return heartRate;
|
||||
}
|
||||
|
||||
void SetService(Pinetime::Controllers::HeartRateService *service);
|
||||
void SetService(Pinetime::Controllers::HeartRateService* service);
|
||||
|
||||
private:
|
||||
System::SystemTask& systemTask;
|
||||
|
|
|
@ -13,7 +13,7 @@ using namespace Pinetime::Controllers;
|
|||
namespace {
|
||||
int Compare(int* d1, int* d2, size_t count) {
|
||||
int e = 0;
|
||||
for(size_t i = 0; i < count; i++) {
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
auto d = d1[i] - d2[i];
|
||||
e += d * d;
|
||||
}
|
||||
|
@ -21,15 +21,15 @@ namespace {
|
|||
}
|
||||
|
||||
int CompareShift(int* d, int shift, size_t count) {
|
||||
return Compare(d +shift, d, count - shift);
|
||||
return Compare(d + shift, d, count - shift);
|
||||
}
|
||||
|
||||
int Trough(int* d, size_t size, float mn, float mx) {
|
||||
auto z2 = CompareShift(d, mn-2, size);
|
||||
auto z1 = CompareShift(d, mn-1, size);
|
||||
for(int i = mn; i < mx + 1; i++) {
|
||||
auto z2 = CompareShift(d, mn - 2, size);
|
||||
auto z1 = CompareShift(d, mn - 1, size);
|
||||
for (int i = mn; i < mx + 1; i++) {
|
||||
auto z = CompareShift(d, i, size);
|
||||
if(z2 > z1 && z1 < z)
|
||||
if (z2 > z1 && z1 < z)
|
||||
return i;
|
||||
z2 = z1;
|
||||
z1 = z;
|
||||
|
@ -38,11 +38,11 @@ namespace {
|
|||
}
|
||||
}
|
||||
|
||||
Ppg::Ppg(float spl) : offset{spl},
|
||||
hpf{0.87033078, -1.74066156, 0.87033078,-1.72377617, 0.75754694},
|
||||
agc{20, 0.971, 2},
|
||||
lpf{0.11595249, 0.23190498, 0.11595249,-0.72168143, 0.18549138} {
|
||||
|
||||
Ppg::Ppg(float spl)
|
||||
: offset {spl},
|
||||
hpf {0.87033078, -1.74066156, 0.87033078, -1.72377617, 0.75754694},
|
||||
agc {20, 0.971, 2},
|
||||
lpf {0.11595249, 0.23190498, 0.11595249, -0.72168143, 0.18549138} {
|
||||
}
|
||||
|
||||
int Ppg::Preprocess(float spl) {
|
||||
|
@ -53,13 +53,13 @@ int Ppg::Preprocess(float spl) {
|
|||
|
||||
auto spl_int = static_cast<int>(spl);
|
||||
|
||||
if(dataIndex < 200)
|
||||
if (dataIndex < 200)
|
||||
data[dataIndex++] = spl_int;
|
||||
return spl_int;
|
||||
}
|
||||
|
||||
float Ppg::HeartRate() {
|
||||
if(dataIndex < 200)
|
||||
if (dataIndex < 200)
|
||||
return 0;
|
||||
|
||||
NRF_LOG_INFO("PREPROCESS, offset = %d", offset);
|
||||
|
@ -71,26 +71,26 @@ float Ppg::HeartRate() {
|
|||
int cccount = 0;
|
||||
float Ppg::ProcessHeartRate() {
|
||||
|
||||
if(cccount > 2)
|
||||
if (cccount > 2)
|
||||
asm("nop");
|
||||
cccount ++;
|
||||
cccount++;
|
||||
auto t0 = Trough(data.data(), dataIndex, 7, 48);
|
||||
if(t0 < 0)
|
||||
if (t0 < 0)
|
||||
return 0;
|
||||
|
||||
float t1 = t0 * 2;
|
||||
t1 = Trough(data.data(), dataIndex, t1-5, t1+5);
|
||||
if(t1 < 0)
|
||||
t1 = Trough(data.data(), dataIndex, t1 - 5, t1 + 5);
|
||||
if (t1 < 0)
|
||||
return 0;
|
||||
|
||||
float t2 = static_cast<int>(t1 * 3) / 2;
|
||||
t2 = Trough(data.data(), dataIndex, t2 - 5, t2 + 5);
|
||||
if(t2 < 0)
|
||||
if (t2 < 0)
|
||||
return 0;
|
||||
|
||||
float t3 = static_cast<int>(t2 * 4) / 3;
|
||||
t3 = Trough(data.data(), dataIndex, t3 - 4, t3 + 4);
|
||||
if(t3 < 0)
|
||||
if (t3 < 0)
|
||||
return static_cast<int>(60 * 24 * 3) / static_cast<int>(t2);
|
||||
|
||||
return static_cast<int>(60 * 24 * 4) / static_cast<int>(t3);
|
||||
|
|
|
@ -24,7 +24,6 @@ namespace Pinetime {
|
|||
Ptagc agc;
|
||||
Biquad lpf;
|
||||
|
||||
|
||||
float ProcessHeartRate();
|
||||
};
|
||||
}
|
||||
|
|
|
@ -10,17 +10,16 @@
|
|||
using namespace Pinetime::Controllers;
|
||||
|
||||
/** Original implementation from wasp-os : https://github.com/daniel-thompson/wasp-os/blob/master/wasp/ppg.py */
|
||||
Ptagc::Ptagc(float start, float decay, float threshold) : peak{start}, decay{decay}, boost{1.0f/decay}, threshold{threshold} {
|
||||
|
||||
Ptagc::Ptagc(float start, float decay, float threshold) : peak {start}, decay {decay}, boost {1.0f / decay}, threshold {threshold} {
|
||||
}
|
||||
|
||||
float Ptagc::Step(float spl) {
|
||||
if(std::abs(spl) > peak)
|
||||
if (std::abs(spl) > peak)
|
||||
peak *= boost;
|
||||
else
|
||||
peak *= decay;
|
||||
|
||||
if((spl > (peak * threshold)) || (spl < (peak * -threshold)))
|
||||
if ((spl > (peak * threshold)) || (spl < (peak * -threshold)))
|
||||
return 0.0f;
|
||||
|
||||
spl = 100.0f * spl / (2.0f * peak);
|
||||
|
|
|
@ -12,7 +12,6 @@ namespace Pinetime {
|
|||
float decay;
|
||||
float boost;
|
||||
float threshold;
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,14 +8,24 @@ namespace Pinetime {
|
|||
public:
|
||||
void Update(int16_t x, int16_t y, int16_t z, uint32_t nbSteps);
|
||||
|
||||
int16_t X() const { return x; }
|
||||
int16_t Y() const { return y; }
|
||||
int16_t Z() const { return z; }
|
||||
uint32_t NbSteps() const { return nbSteps; }
|
||||
int16_t X() const {
|
||||
return x;
|
||||
}
|
||||
int16_t Y() const {
|
||||
return y;
|
||||
}
|
||||
int16_t Z() const {
|
||||
return z;
|
||||
}
|
||||
uint32_t NbSteps() const {
|
||||
return nbSteps;
|
||||
}
|
||||
bool ShouldWakeUp(bool isSleeping);
|
||||
|
||||
void IsSensorOk(bool isOk);
|
||||
bool IsSensorOk() const { return isSensorOk; }
|
||||
bool IsSensorOk() const {
|
||||
return isSensorOk;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t nbSteps;
|
||||
|
|
|
@ -7,7 +7,8 @@ APP_TIMER_DEF(vibTimer);
|
|||
|
||||
using namespace Pinetime::Controllers;
|
||||
|
||||
MotorController::MotorController( Controllers::Settings &settingsController ) : settingsController{settingsController} {}
|
||||
MotorController::MotorController(Controllers::Settings& settingsController) : settingsController {settingsController} {
|
||||
}
|
||||
|
||||
void MotorController::Init() {
|
||||
nrf_gpio_cfg_output(pinMotor);
|
||||
|
@ -18,13 +19,14 @@ void MotorController::Init() {
|
|||
|
||||
void MotorController::SetDuration(uint8_t motorDuration) {
|
||||
|
||||
if ( settingsController.GetVibrationStatus() == Controllers::Settings::Vibration::OFF ) return;
|
||||
if (settingsController.GetVibrationStatus() == Controllers::Settings::Vibration::OFF)
|
||||
return;
|
||||
|
||||
nrf_gpio_pin_clear(pinMotor);
|
||||
/* Start timer for motorDuration miliseconds and timer triggers vibrate() when it finishes*/
|
||||
app_timer_start(vibTimer, APP_TIMER_TICKS(motorDuration), NULL);
|
||||
}
|
||||
|
||||
void MotorController::vibrate(void * p_context) {
|
||||
void MotorController::vibrate(void* p_context) {
|
||||
nrf_gpio_pin_set(pinMotor);
|
||||
}
|
|
@ -10,13 +10,13 @@ namespace Pinetime {
|
|||
|
||||
class MotorController {
|
||||
public:
|
||||
MotorController( Controllers::Settings &settingsController );
|
||||
MotorController(Controllers::Settings& settingsController);
|
||||
void Init();
|
||||
void SetDuration(uint8_t motorDuration);
|
||||
|
||||
private:
|
||||
Controllers::Settings& settingsController;
|
||||
static void vibrate(void * p_context);
|
||||
static void vibrate(void* p_context);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,18 +2,16 @@
|
|||
|
||||
using namespace Pinetime::Tools;
|
||||
|
||||
RleDecoder::RleDecoder(const uint8_t *buffer, size_t size) : buffer{buffer}, size{size} {
|
||||
|
||||
RleDecoder::RleDecoder(const uint8_t* buffer, size_t size) : buffer {buffer}, size {size} {
|
||||
}
|
||||
|
||||
RleDecoder::RleDecoder(const uint8_t *buffer, size_t size, uint16_t foregroundColor, uint16_t backgroundColor) : RleDecoder{buffer, size} {
|
||||
RleDecoder::RleDecoder(const uint8_t* buffer, size_t size, uint16_t foregroundColor, uint16_t backgroundColor) : RleDecoder {buffer, size} {
|
||||
this->foregroundColor = foregroundColor;
|
||||
this->backgroundColor = backgroundColor;
|
||||
}
|
||||
|
||||
|
||||
void RleDecoder::DecodeNext(uint8_t *output, size_t maxBytes) {
|
||||
for (;encodedBufferIndex<size; encodedBufferIndex++) {
|
||||
void RleDecoder::DecodeNext(uint8_t* output, size_t maxBytes) {
|
||||
for (; encodedBufferIndex < size; encodedBufferIndex++) {
|
||||
uint8_t rl = buffer[encodedBufferIndex] - processedCount;
|
||||
while (rl) {
|
||||
output[bp] = color >> 8;
|
||||
|
@ -36,4 +34,3 @@ void RleDecoder::DecodeNext(uint8_t *output, size_t maxBytes) {
|
|||
color = backgroundColor;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,35 +11,33 @@ struct 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() {
|
||||
|
||||
// Load default settings from Flash
|
||||
LoadSettingsFromFlash();
|
||||
|
||||
}
|
||||
|
||||
void Settings::SaveSettings() {
|
||||
|
||||
// verify if is necessary to save
|
||||
if ( settingsChanged ) {
|
||||
if (settingsChanged) {
|
||||
SaveSettingsToFlash();
|
||||
}
|
||||
settingsChanged = false;
|
||||
}
|
||||
|
||||
|
||||
bool Settings::FindHeader() {
|
||||
SettingsHeader settingsHeader;
|
||||
uint8_t bufferHead[sizeof(settingsHeader)];
|
||||
|
||||
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));
|
||||
if ( settingsHeader.isActive == 0xF1 && settingsHeader.version == settingsVersion ) {
|
||||
if (settingsHeader.isActive == 0xF1 && settingsHeader.version == settingsVersion) {
|
||||
settingsFlashBlock = block;
|
||||
return true;
|
||||
}
|
||||
|
@ -49,7 +47,7 @@ bool Settings::FindHeader() {
|
|||
|
||||
void Settings::ReadSettingsData() {
|
||||
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));
|
||||
}
|
||||
|
||||
|
@ -58,7 +56,7 @@ void Settings::EraseBlock() {
|
|||
spiNorFlash.SectorErase(settingsBaseAddr + (settingsFlashBlock * 0x1000));
|
||||
}
|
||||
|
||||
void Settings::SetHeader( bool state ) {
|
||||
void Settings::SetHeader(bool state) {
|
||||
SettingsHeader settingsHeader;
|
||||
uint8_t bufferHead[sizeof(settingsHeader)];
|
||||
settingsHeader.isActive = state ? 0xF1 : 0xF0;
|
||||
|
@ -66,7 +64,6 @@ void Settings::SetHeader( bool state ) {
|
|||
|
||||
std::memcpy(bufferHead, &settingsHeader, sizeof(settingsHeader));
|
||||
spiNorFlash.Write(settingsBaseAddr + (settingsFlashBlock * 0x1000), bufferHead, sizeof(settingsHeader));
|
||||
|
||||
}
|
||||
|
||||
void Settings::SaveSettingsData() {
|
||||
|
@ -77,9 +74,9 @@ void Settings::SaveSettingsData() {
|
|||
|
||||
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 !
|
||||
if ( FindHeader() ) {
|
||||
if (FindHeader()) {
|
||||
ReadSettingsData();
|
||||
} else {
|
||||
SaveSettingsToFlash();
|
||||
|
@ -89,7 +86,6 @@ void Settings::LoadSettingsFromFlash() {
|
|||
// never used :)
|
||||
ReadSettingsData();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Settings::SaveSettingsToFlash() {
|
||||
|
@ -101,14 +97,15 @@ void Settings::SaveSettingsToFlash() {
|
|||
|
||||
// if first time hever, only saves to block 0 and set settingsFlashBlock
|
||||
|
||||
if ( settingsFlashBlock != 99 ) {
|
||||
SetHeader( false );
|
||||
if (settingsFlashBlock != 99) {
|
||||
SetHeader(false);
|
||||
}
|
||||
|
||||
settingsFlashBlock++;
|
||||
if ( settingsFlashBlock > 9 ) settingsFlashBlock = 0;
|
||||
if (settingsFlashBlock > 9)
|
||||
settingsFlashBlock = 0;
|
||||
|
||||
EraseBlock();
|
||||
SetHeader( true );
|
||||
SetHeader(true);
|
||||
SaveSettingsData();
|
||||
}
|
||||
|
|
|
@ -9,65 +9,92 @@ namespace Pinetime {
|
|||
namespace Controllers {
|
||||
class Settings {
|
||||
public:
|
||||
enum class ClockType {H24, H12};
|
||||
enum class Vibration {ON, OFF};
|
||||
enum class WakeUpMode {None, SingleTap, DoubleTap, RaiseWrist};
|
||||
enum class ClockType { H24, H12 };
|
||||
enum class Vibration { ON, OFF };
|
||||
enum class WakeUpMode { None, SingleTap, DoubleTap, RaiseWrist };
|
||||
|
||||
Settings( Pinetime::Drivers::SpiNorFlash &spiNorFlash );
|
||||
Settings(Pinetime::Drivers::SpiNorFlash& spiNorFlash);
|
||||
|
||||
void Init();
|
||||
void SaveSettings();
|
||||
|
||||
void SetClockFace( uint8_t face ) {
|
||||
if ( face != settings.clockFace ) settingsChanged = true;
|
||||
void SetClockFace(uint8_t face) {
|
||||
if (face != settings.clockFace)
|
||||
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; };
|
||||
uint8_t GetAppMenu() { return appMenu; };
|
||||
void SetAppMenu(uint8_t menu) {
|
||||
appMenu = menu;
|
||||
};
|
||||
uint8_t GetAppMenu() {
|
||||
return appMenu;
|
||||
};
|
||||
|
||||
void SetSettingsMenu( uint8_t menu ) { settingsMenu = menu; };
|
||||
uint8_t GetSettingsMenu() const { return settingsMenu; };
|
||||
void SetSettingsMenu(uint8_t menu) {
|
||||
settingsMenu = menu;
|
||||
};
|
||||
uint8_t GetSettingsMenu() const {
|
||||
return settingsMenu;
|
||||
};
|
||||
|
||||
void SetClockType( ClockType clocktype ) {
|
||||
if ( clocktype != settings.clockType ) settingsChanged = true;
|
||||
void SetClockType(ClockType clocktype) {
|
||||
if (clocktype != settings.clockType)
|
||||
settingsChanged = true;
|
||||
settings.clockType = clocktype;
|
||||
};
|
||||
ClockType GetClockType() const { return settings.clockType; };
|
||||
ClockType GetClockType() const {
|
||||
return settings.clockType;
|
||||
};
|
||||
|
||||
void SetVibrationStatus( Vibration status ) {
|
||||
if ( status != settings.vibrationStatus ) settingsChanged = true;
|
||||
void SetVibrationStatus(Vibration status) {
|
||||
if (status != settings.vibrationStatus)
|
||||
settingsChanged = true;
|
||||
settings.vibrationStatus = status;
|
||||
};
|
||||
Vibration GetVibrationStatus() const { return settings.vibrationStatus; };
|
||||
Vibration GetVibrationStatus() const {
|
||||
return settings.vibrationStatus;
|
||||
};
|
||||
|
||||
void SetScreenTimeOut( uint32_t timeout ) {
|
||||
if ( timeout != settings.screenTimeOut ) settingsChanged = true;
|
||||
void SetScreenTimeOut(uint32_t timeout) {
|
||||
if (timeout != settings.screenTimeOut)
|
||||
settingsChanged = true;
|
||||
settings.screenTimeOut = timeout;
|
||||
};
|
||||
uint32_t GetScreenTimeOut() const { return settings.screenTimeOut; };
|
||||
uint32_t GetScreenTimeOut() const {
|
||||
return settings.screenTimeOut;
|
||||
};
|
||||
|
||||
void setWakeUpMode( WakeUpMode wakeUp ) {
|
||||
if ( wakeUp != settings.wakeUpMode ) settingsChanged = true;
|
||||
void setWakeUpMode(WakeUpMode wakeUp) {
|
||||
if (wakeUp != settings.wakeUpMode)
|
||||
settingsChanged = true;
|
||||
settings.wakeUpMode = wakeUp;
|
||||
};
|
||||
WakeUpMode getWakeUpMode() const { return settings.wakeUpMode; };
|
||||
WakeUpMode getWakeUpMode() const {
|
||||
return settings.wakeUpMode;
|
||||
};
|
||||
|
||||
void SetBrightness( Controllers::BrightnessController::Levels level ) {
|
||||
if ( level != settings.brightLevel ) settingsChanged = true;
|
||||
void SetBrightness(Controllers::BrightnessController::Levels level) {
|
||||
if (level != settings.brightLevel)
|
||||
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 ) {
|
||||
if ( goal != settings.stepsGoal ) settingsChanged = true;
|
||||
if ( goal != settings.stepsGoal )
|
||||
settingsChanged = true;
|
||||
settings.stepsGoal = goal;
|
||||
};
|
||||
|
||||
uint32_t GetStepsGoal() const { return settings.stepsGoal; };
|
||||
|
||||
private:
|
||||
|
||||
Pinetime::Drivers::SpiNorFlash& spiNorFlash;
|
||||
struct SettingsData {
|
||||
|
||||
|
@ -82,7 +109,6 @@ namespace Pinetime {
|
|||
WakeUpMode wakeUpMode = WakeUpMode::None;
|
||||
|
||||
Controllers::BrightnessController::Levels brightLevel = Controllers::BrightnessController::Levels::Medium;
|
||||
|
||||
};
|
||||
|
||||
SettingsData settings;
|
||||
|
@ -101,11 +127,10 @@ namespace Pinetime {
|
|||
bool FindHeader();
|
||||
void ReadSettingsData();
|
||||
void EraseBlock();
|
||||
void SetHeader( bool state );
|
||||
void SetHeader(bool state);
|
||||
void SaveSettingsData();
|
||||
void LoadSettingsFromFlash();
|
||||
void SaveSettingsToFlash();
|
||||
|
||||
};
|
||||
}
|
||||
}
|
|
@ -3,9 +3,32 @@
|
|||
namespace Pinetime {
|
||||
namespace Applications {
|
||||
enum class Apps {
|
||||
None, Launcher, Clock, SysInfo, FirmwareUpdate, FirmwareValidation, NotificationsPreview, Notifications, FlashLight, BatteryInfo,
|
||||
Music, Paint, Paddle, Twos, HeartRate, Navigation, StopWatch, Motion, Steps,
|
||||
QuickSettings, Settings, SettingWatchFace, SettingTimeFormat, SettingDisplay, SettingWakeUp, SettingSteps
|
||||
None,
|
||||
Launcher,
|
||||
Clock,
|
||||
SysInfo,
|
||||
FirmwareUpdate,
|
||||
FirmwareValidation,
|
||||
NotificationsPreview,
|
||||
Notifications,
|
||||
FlashLight,
|
||||
BatteryInfo,
|
||||
Music,
|
||||
Paint,
|
||||
Paddle,
|
||||
Twos,
|
||||
HeartRate,
|
||||
Navigation,
|
||||
StopWatch,
|
||||
Motion,
|
||||
Steps,
|
||||
QuickSettings,
|
||||
Settings,
|
||||
SettingWatchFace,
|
||||
SettingTimeFormat,
|
||||
SettingDisplay,
|
||||
SettingWakeUp,
|
||||
SettingSteps
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,29 +42,33 @@
|
|||
using namespace Pinetime::Applications;
|
||||
using namespace Pinetime::Applications::Display;
|
||||
|
||||
DisplayApp::DisplayApp(Drivers::St7789 &lcd, Components::LittleVgl &lvgl, Drivers::Cst816S &touchPanel,
|
||||
Controllers::Battery &batteryController, Controllers::Ble &bleController,
|
||||
Controllers::DateTime &dateTimeController, Drivers::WatchdogView &watchdog,
|
||||
System::SystemTask &systemTask,
|
||||
DisplayApp::DisplayApp(Drivers::St7789& lcd,
|
||||
Components::LittleVgl& lvgl,
|
||||
Drivers::Cst816S& touchPanel,
|
||||
Controllers::Battery& batteryController,
|
||||
Controllers::Ble& bleController,
|
||||
Controllers::DateTime& dateTimeController,
|
||||
Drivers::WatchdogView& watchdog,
|
||||
System::SystemTask& systemTask,
|
||||
Pinetime::Controllers::NotificationManager& notificationManager,
|
||||
Pinetime::Controllers::HeartRateController& heartRateController,
|
||||
Controllers::Settings &settingsController,
|
||||
Pinetime::Controllers::MotionController& motionController) :
|
||||
lcd{lcd},
|
||||
lvgl{lvgl},
|
||||
touchPanel{touchPanel},
|
||||
batteryController{batteryController},
|
||||
bleController{bleController},
|
||||
dateTimeController{dateTimeController},
|
||||
watchdog{watchdog},
|
||||
systemTask{systemTask},
|
||||
notificationManager{notificationManager},
|
||||
heartRateController{heartRateController},
|
||||
settingsController{settingsController},
|
||||
motionController{motionController} {
|
||||
Controllers::Settings& settingsController,
|
||||
Pinetime::Controllers::MotionController& motionController)
|
||||
: lcd {lcd},
|
||||
lvgl {lvgl},
|
||||
touchPanel {touchPanel},
|
||||
batteryController {batteryController},
|
||||
bleController {bleController},
|
||||
dateTimeController {dateTimeController},
|
||||
watchdog {watchdog},
|
||||
systemTask {systemTask},
|
||||
notificationManager {notificationManager},
|
||||
heartRateController {heartRateController},
|
||||
settingsController {settingsController},
|
||||
motionController {motionController} {
|
||||
msgQueue = xQueueCreate(queueSize, itemSize);
|
||||
// Start clock when smartwatch boots
|
||||
LoadApp( Apps::Clock, DisplayApp::FullRefreshDirections::None );
|
||||
LoadApp(Apps::Clock, DisplayApp::FullRefreshDirections::None);
|
||||
}
|
||||
|
||||
void DisplayApp::Start() {
|
||||
|
@ -72,8 +76,8 @@ void DisplayApp::Start() {
|
|||
APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);
|
||||
}
|
||||
|
||||
void DisplayApp::Process(void *instance) {
|
||||
auto *app = static_cast<DisplayApp *>(instance);
|
||||
void DisplayApp::Process(void* instance) {
|
||||
auto* app = static_cast<DisplayApp*>(instance);
|
||||
NRF_LOG_INFO("displayapp task started!");
|
||||
app->InitHw();
|
||||
|
||||
|
@ -114,7 +118,7 @@ void DisplayApp::Refresh() {
|
|||
switch (msg) {
|
||||
case Messages::GoToSleep:
|
||||
brightnessController.Backup();
|
||||
while(brightnessController.Level() != Controllers::BrightnessController::Levels::Off) {
|
||||
while (brightnessController.Level() != Controllers::BrightnessController::Levels::Off) {
|
||||
brightnessController.Lower();
|
||||
vTaskDelay(100);
|
||||
}
|
||||
|
@ -131,28 +135,30 @@ void DisplayApp::Refresh() {
|
|||
systemTask.PushMessage(System::SystemTask::Messages::UpdateTimeOut);
|
||||
break;
|
||||
case Messages::UpdateBleConnection:
|
||||
// clockScreen.SetBleConnectionState(bleController.IsConnected() ? Screens::Clock::BleConnectionStates::Connected : Screens::Clock::BleConnectionStates::NotConnected);
|
||||
// clockScreen.SetBleConnectionState(bleController.IsConnected() ? Screens::Clock::BleConnectionStates::Connected :
|
||||
// Screens::Clock::BleConnectionStates::NotConnected);
|
||||
break;
|
||||
case Messages::UpdateBatteryLevel:
|
||||
batteryController.Update();
|
||||
break;
|
||||
case Messages::NewNotification:
|
||||
LoadApp( Apps::NotificationsPreview, DisplayApp::FullRefreshDirections::Down );
|
||||
LoadApp(Apps::NotificationsPreview, DisplayApp::FullRefreshDirections::Down);
|
||||
break;
|
||||
case Messages::TouchEvent: {
|
||||
if (state != States::Running) break;
|
||||
if (state != States::Running)
|
||||
break;
|
||||
auto gesture = OnTouchEvent();
|
||||
if(!currentScreen->OnTouchEvent(gesture)) {
|
||||
if ( currentApp == Apps::Clock ) {
|
||||
if (!currentScreen->OnTouchEvent(gesture)) {
|
||||
if (currentApp == Apps::Clock) {
|
||||
switch (gesture) {
|
||||
case TouchEvents::SwipeUp:
|
||||
LoadApp( Apps::Launcher, DisplayApp::FullRefreshDirections::Up );
|
||||
LoadApp(Apps::Launcher, DisplayApp::FullRefreshDirections::Up);
|
||||
break;
|
||||
case TouchEvents::SwipeDown:
|
||||
LoadApp( Apps::Notifications, DisplayApp::FullRefreshDirections::Down );
|
||||
LoadApp(Apps::Notifications, DisplayApp::FullRefreshDirections::Down);
|
||||
break;
|
||||
case TouchEvents::SwipeRight:
|
||||
LoadApp( Apps::QuickSettings, DisplayApp::FullRefreshDirections::RightAnim );
|
||||
LoadApp(Apps::QuickSettings, DisplayApp::FullRefreshDirections::RightAnim);
|
||||
break;
|
||||
case TouchEvents::DoubleTap:
|
||||
systemTask.PushMessage(System::SystemTask::Messages::GoToSleep);
|
||||
|
@ -160,24 +166,23 @@ void DisplayApp::Refresh() {
|
|||
default:
|
||||
break;
|
||||
}
|
||||
} else if ( returnTouchEvent == gesture ) {
|
||||
LoadApp( returnToApp, returnDirection );
|
||||
} else if (returnTouchEvent == gesture) {
|
||||
LoadApp(returnToApp, returnDirection);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
case Messages::ButtonPushed:
|
||||
if( currentApp == Apps::Clock ) {
|
||||
if (currentApp == Apps::Clock) {
|
||||
systemTask.PushMessage(System::SystemTask::Messages::GoToSleep);
|
||||
} else {
|
||||
if ( !currentScreen->OnButtonPushed() ) {
|
||||
LoadApp( returnToApp, returnDirection );
|
||||
if (!currentScreen->OnButtonPushed()) {
|
||||
LoadApp(returnToApp, returnDirection);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Messages::BleFirmwareUpdateStarted:
|
||||
LoadApp( Apps::FirmwareUpdate, DisplayApp::FullRefreshDirections::Down );
|
||||
LoadApp(Apps::FirmwareUpdate, DisplayApp::FullRefreshDirections::Down);
|
||||
break;
|
||||
case Messages::UpdateDateTime:
|
||||
// Added to remove warning
|
||||
|
@ -186,10 +191,10 @@ void DisplayApp::Refresh() {
|
|||
}
|
||||
}
|
||||
|
||||
if(state != States::Idle && touchMode == TouchModes::Polling) {
|
||||
if (state != States::Idle && touchMode == TouchModes::Polling) {
|
||||
auto info = touchPanel.GetTouchInfo();
|
||||
if(info.action == 2) {// 2 = contact
|
||||
if(!currentScreen->OnTouchEvent(info.x, info.y)) {
|
||||
if (info.action == 2) { // 2 = contact
|
||||
if (!currentScreen->OnTouchEvent(info.x, info.y)) {
|
||||
lvgl.SetNewTapEvent(info.x, info.y);
|
||||
}
|
||||
}
|
||||
|
@ -197,14 +202,14 @@ void DisplayApp::Refresh() {
|
|||
}
|
||||
|
||||
void DisplayApp::RunningState() {
|
||||
if(!currentScreen->Refresh()) {
|
||||
LoadApp( returnToApp, returnDirection );
|
||||
if (!currentScreen->Refresh()) {
|
||||
LoadApp(returnToApp, returnDirection);
|
||||
}
|
||||
lv_task_handler();
|
||||
}
|
||||
|
||||
void DisplayApp::StartApp(Apps app, DisplayApp::FullRefreshDirections direction) {
|
||||
LoadApp( app, direction );
|
||||
LoadApp(app, direction);
|
||||
}
|
||||
|
||||
void DisplayApp::returnApp(Apps app, DisplayApp::FullRefreshDirections direction, TouchEvents touchEvent) {
|
||||
|
@ -215,19 +220,26 @@ void DisplayApp::returnApp(Apps app, DisplayApp::FullRefreshDirections direction
|
|||
|
||||
void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction) {
|
||||
currentScreen.reset(nullptr);
|
||||
SetFullRefresh( direction );
|
||||
SetFullRefresh(direction);
|
||||
|
||||
// default return to launcher
|
||||
returnApp(Apps::Launcher, FullRefreshDirections::Down, TouchEvents::SwipeDown);
|
||||
|
||||
switch(app) {
|
||||
switch (app) {
|
||||
case Apps::Launcher:
|
||||
currentScreen = std::make_unique<Screens::ApplicationList>(this, settingsController, batteryController, dateTimeController);
|
||||
returnApp(Apps::Clock, FullRefreshDirections::Down, TouchEvents::SwipeDown);
|
||||
break;
|
||||
case Apps::None:
|
||||
case Apps::Clock:
|
||||
currentScreen = std::make_unique<Screens::Clock>(this, dateTimeController, batteryController, bleController, notificationManager, settingsController, heartRateController, motionController);
|
||||
currentScreen = std::make_unique<Screens::Clock>(this,
|
||||
dateTimeController,
|
||||
batteryController,
|
||||
bleController,
|
||||
notificationManager,
|
||||
settingsController,
|
||||
heartRateController,
|
||||
motionController);
|
||||
break;
|
||||
|
||||
case Apps::FirmwareValidation:
|
||||
|
@ -239,17 +251,20 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction)
|
|||
break;
|
||||
|
||||
case Apps::Notifications:
|
||||
currentScreen = std::make_unique<Screens::Notifications>(this, notificationManager, systemTask.nimble().alertService(), Screens::Notifications::Modes::Normal);
|
||||
currentScreen = std::make_unique<Screens::Notifications>(
|
||||
this, notificationManager, systemTask.nimble().alertService(), Screens::Notifications::Modes::Normal);
|
||||
returnApp(Apps::Clock, FullRefreshDirections::Up, TouchEvents::SwipeUp);
|
||||
break;
|
||||
case Apps::NotificationsPreview:
|
||||
currentScreen = std::make_unique<Screens::Notifications>(this, notificationManager, systemTask.nimble().alertService(), Screens::Notifications::Modes::Preview);
|
||||
currentScreen = std::make_unique<Screens::Notifications>(
|
||||
this, notificationManager, systemTask.nimble().alertService(), Screens::Notifications::Modes::Preview);
|
||||
returnApp(Apps::Clock, FullRefreshDirections::Up, TouchEvents::SwipeUp);
|
||||
break;
|
||||
|
||||
// Settings
|
||||
case Apps::QuickSettings:
|
||||
currentScreen = std::make_unique<Screens::QuickSettings>(this, batteryController, dateTimeController, brightnessController, settingsController);
|
||||
currentScreen =
|
||||
std::make_unique<Screens::QuickSettings>(this, batteryController, dateTimeController, brightnessController, settingsController);
|
||||
returnApp(Apps::Clock, FullRefreshDirections::LeftAnim, TouchEvents::SwipeLeft);
|
||||
break;
|
||||
case Apps::Settings:
|
||||
|
@ -281,7 +296,8 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction)
|
|||
returnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
|
||||
break;
|
||||
case Apps::SysInfo:
|
||||
currentScreen = std::make_unique<Screens::SystemInfo>(this, dateTimeController, batteryController, brightnessController, bleController, watchdog);
|
||||
currentScreen =
|
||||
std::make_unique<Screens::SystemInfo>(this, dateTimeController, batteryController, brightnessController, bleController, watchdog);
|
||||
returnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
|
||||
break;
|
||||
//
|
||||
|
@ -322,7 +338,6 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction)
|
|||
}
|
||||
|
||||
void DisplayApp::IdleState() {
|
||||
|
||||
}
|
||||
|
||||
void DisplayApp::PushMessage(Messages msg) {
|
||||
|
@ -337,10 +352,10 @@ void DisplayApp::PushMessage(Messages msg) {
|
|||
|
||||
TouchEvents DisplayApp::OnTouchEvent() {
|
||||
auto info = touchPanel.GetTouchInfo();
|
||||
if(info.isTouch) {
|
||||
switch(info.gesture) {
|
||||
if (info.isTouch) {
|
||||
switch (info.gesture) {
|
||||
case Pinetime::Drivers::Cst816S::Gestures::SingleTap:
|
||||
if(touchMode == TouchModes::Gestures)
|
||||
if (touchMode == TouchModes::Gestures)
|
||||
lvgl.SetNewTapEvent(info.x, info.y);
|
||||
return TouchEvents::Tap;
|
||||
case Pinetime::Drivers::Cst816S::Gestures::LongPress:
|
||||
|
@ -364,7 +379,7 @@ TouchEvents DisplayApp::OnTouchEvent() {
|
|||
}
|
||||
|
||||
void DisplayApp::SetFullRefresh(DisplayApp::FullRefreshDirections direction) {
|
||||
switch(direction){
|
||||
switch (direction) {
|
||||
case DisplayApp::FullRefreshDirections::Down:
|
||||
lvgl.SetFullRefresh(Components::LittleVgl::FullRefreshDirections::Down);
|
||||
break;
|
||||
|
@ -383,11 +398,11 @@ void DisplayApp::SetFullRefresh(DisplayApp::FullRefreshDirections direction) {
|
|||
case DisplayApp::FullRefreshDirections::RightAnim:
|
||||
lvgl.SetFullRefresh(Components::LittleVgl::FullRefreshDirections::RightAnim);
|
||||
break;
|
||||
default: break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void DisplayApp::SetTouchMode(DisplayApp::TouchModes mode) {
|
||||
touchMode = mode;
|
||||
}
|
||||
|
||||
|
|
|
@ -36,19 +36,22 @@ namespace Pinetime {
|
|||
namespace Applications {
|
||||
class DisplayApp {
|
||||
public:
|
||||
enum class States {Idle, Running};
|
||||
enum class States { Idle, Running };
|
||||
enum class FullRefreshDirections { None, Up, Down, Left, Right, LeftAnim, RightAnim };
|
||||
enum class TouchModes { Gestures, Polling };
|
||||
|
||||
DisplayApp(Drivers::St7789 &lcd, Components::LittleVgl &lvgl, Drivers::Cst816S &,
|
||||
Controllers::Battery &batteryController, Controllers::Ble &bleController,
|
||||
Controllers::DateTime &dateTimeController, Drivers::WatchdogView &watchdog,
|
||||
System::SystemTask &systemTask,
|
||||
DisplayApp(Drivers::St7789& lcd,
|
||||
Components::LittleVgl& lvgl,
|
||||
Drivers::Cst816S&,
|
||||
Controllers::Battery& batteryController,
|
||||
Controllers::Ble& bleController,
|
||||
Controllers::DateTime& dateTimeController,
|
||||
Drivers::WatchdogView& watchdog,
|
||||
System::SystemTask& systemTask,
|
||||
Pinetime::Controllers::NotificationManager& notificationManager,
|
||||
Pinetime::Controllers::HeartRateController& heartRateController,
|
||||
Controllers::Settings &settingsController,
|
||||
Pinetime::Controllers::MotionController& motionController
|
||||
);
|
||||
Controllers::Settings& settingsController,
|
||||
Pinetime::Controllers::MotionController& motionController);
|
||||
void Start();
|
||||
void PushMessage(Display::Messages msg);
|
||||
|
||||
|
@ -58,12 +61,11 @@ namespace Pinetime {
|
|||
void SetTouchMode(TouchModes mode);
|
||||
|
||||
private:
|
||||
|
||||
Pinetime::Drivers::St7789& lcd;
|
||||
Pinetime::Components::LittleVgl& lvgl;
|
||||
Pinetime::Drivers::Cst816S& touchPanel;
|
||||
Pinetime::Controllers::Battery &batteryController;
|
||||
Pinetime::Controllers::Ble &bleController;
|
||||
Pinetime::Controllers::Battery& batteryController;
|
||||
Pinetime::Controllers::Ble& bleController;
|
||||
Pinetime::Controllers::DateTime& dateTimeController;
|
||||
Pinetime::Drivers::WatchdogView& watchdog;
|
||||
Pinetime::System::SystemTask& systemTask;
|
||||
|
@ -100,9 +102,6 @@ namespace Pinetime {
|
|||
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;
|
||||
|
||||
DisplayApp::DisplayApp(Drivers::St7789 &lcd, Components::LittleVgl &lvgl, Drivers::Cst816S &touchPanel,
|
||||
Controllers::Battery &batteryController, Controllers::Ble &bleController,
|
||||
Controllers::DateTime &dateTimeController, Drivers::WatchdogView &watchdog,
|
||||
System::SystemTask &systemTask,
|
||||
DisplayApp::DisplayApp(Drivers::St7789& lcd,
|
||||
Components::LittleVgl& lvgl,
|
||||
Drivers::Cst816S& touchPanel,
|
||||
Controllers::Battery& batteryController,
|
||||
Controllers::Ble& bleController,
|
||||
Controllers::DateTime& dateTimeController,
|
||||
Drivers::WatchdogView& watchdog,
|
||||
System::SystemTask& systemTask,
|
||||
Pinetime::Controllers::NotificationManager& notificationManager,
|
||||
Pinetime::Controllers::HeartRateController& heartRateController,
|
||||
Pinetime::Controllers::Settings& settingsController,
|
||||
Pinetime::Controllers::MotionController& motionController):
|
||||
lcd{lcd}, bleController{bleController} {
|
||||
Pinetime::Controllers::MotionController& motionController)
|
||||
: lcd {lcd}, bleController {bleController} {
|
||||
msgQueue = xQueueCreate(queueSize, itemSize);
|
||||
|
||||
}
|
||||
|
||||
void DisplayApp::Start() {
|
||||
|
@ -25,8 +28,8 @@ void DisplayApp::Start() {
|
|||
APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);
|
||||
}
|
||||
|
||||
void DisplayApp::Process(void *instance) {
|
||||
auto *app = static_cast<DisplayApp *>(instance);
|
||||
void DisplayApp::Process(void* instance) {
|
||||
auto* app = static_cast<DisplayApp*>(instance);
|
||||
NRF_LOG_INFO("displayapp task started!");
|
||||
|
||||
// Send a dummy notification to unlock the lvgl display driver for the first iteration
|
||||
|
@ -61,8 +64,9 @@ void DisplayApp::Refresh() {
|
|||
}
|
||||
|
||||
if (bleController.IsFirmwareUpdating()) {
|
||||
uint8_t percent = (static_cast<float>(bleController.FirmwareUpdateCurrentBytes()) /
|
||||
static_cast<float>(bleController.FirmwareUpdateTotalBytes())) * 100.0f;
|
||||
uint8_t percent =
|
||||
(static_cast<float>(bleController.FirmwareUpdateCurrentBytes()) / static_cast<float>(bleController.FirmwareUpdateTotalBytes())) *
|
||||
100.0f;
|
||||
switch (bleController.State()) {
|
||||
case Controllers::Ble::FirmwareUpdateStates::Running:
|
||||
DisplayOtaProgress(percent, colorWhite);
|
||||
|
@ -81,20 +85,20 @@ void DisplayApp::Refresh() {
|
|||
|
||||
void DisplayApp::DisplayLogo(uint16_t color) {
|
||||
Pinetime::Tools::RleDecoder rleDecoder(infinitime_nb, sizeof(infinitime_nb), color, colorBlack);
|
||||
for(int i = 0; i < displayWidth; i++) {
|
||||
for (int i = 0; i < displayWidth; i++) {
|
||||
rleDecoder.DecodeNext(displayBuffer, displayWidth * bytesPerPixel);
|
||||
ulTaskNotifyTake(pdTRUE, 500);
|
||||
lcd.DrawBuffer(0, i, displayWidth, 1, reinterpret_cast<const uint8_t *>(displayBuffer), displayWidth * bytesPerPixel);
|
||||
lcd.DrawBuffer(0, i, displayWidth, 1, reinterpret_cast<const uint8_t*>(displayBuffer), displayWidth * bytesPerPixel);
|
||||
}
|
||||
}
|
||||
|
||||
void DisplayApp::DisplayOtaProgress(uint8_t percent, uint16_t color) {
|
||||
const uint8_t barHeight = 20;
|
||||
std::fill(displayBuffer, displayBuffer+(displayWidth * bytesPerPixel), color);
|
||||
for(int i = 0; i < barHeight; i++) {
|
||||
std::fill(displayBuffer, displayBuffer + (displayWidth * bytesPerPixel), color);
|
||||
for (int i = 0; i < barHeight; i++) {
|
||||
ulTaskNotifyTake(pdTRUE, 500);
|
||||
uint16_t barWidth = std::min(static_cast<float>(percent) * 2.4f, static_cast<float>(displayWidth));
|
||||
lcd.DrawBuffer(0, displayWidth - barHeight + i, barWidth, 1, reinterpret_cast<const uint8_t *>(displayBuffer), barWidth * bytesPerPixel);
|
||||
lcd.DrawBuffer(0, displayWidth - barHeight + i, barWidth, 1, reinterpret_cast<const uint8_t*>(displayBuffer), barWidth * bytesPerPixel);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,10 +30,14 @@ namespace Pinetime {
|
|||
namespace Applications {
|
||||
class DisplayApp {
|
||||
public:
|
||||
DisplayApp(Drivers::St7789 &lcd, Components::LittleVgl &lvgl, Drivers::Cst816S &,
|
||||
Controllers::Battery &batteryController, Controllers::Ble &bleController,
|
||||
Controllers::DateTime &dateTimeController, Drivers::WatchdogView &watchdog,
|
||||
System::SystemTask &systemTask,
|
||||
DisplayApp(Drivers::St7789& lcd,
|
||||
Components::LittleVgl& lvgl,
|
||||
Drivers::Cst816S&,
|
||||
Controllers::Battery& batteryController,
|
||||
Controllers::Ble& bleController,
|
||||
Controllers::DateTime& dateTimeController,
|
||||
Drivers::WatchdogView& watchdog,
|
||||
System::SystemTask& systemTask,
|
||||
Pinetime::Controllers::NotificationManager& notificationManager,
|
||||
Pinetime::Controllers::HeartRateController& heartRateController,
|
||||
Pinetime::Controllers::Settings& settingsController,
|
||||
|
@ -49,7 +53,7 @@ namespace Pinetime {
|
|||
void InitHw();
|
||||
void Refresh();
|
||||
Pinetime::Drivers::St7789& lcd;
|
||||
Controllers::Ble &bleController;
|
||||
Controllers::Ble& bleController;
|
||||
|
||||
static constexpr uint8_t queueSize = 10;
|
||||
static constexpr uint8_t itemSize = 1;
|
||||
|
@ -66,10 +70,6 @@ namespace Pinetime {
|
|||
static constexpr uint16_t colorRedSwapped = 0x00ff;
|
||||
static constexpr uint16_t colorBlack = 0x0000;
|
||||
uint8_t displayBuffer[displayWidth * bytesPerPixel];
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -11,20 +11,23 @@ namespace Pinetime {
|
|||
class LittleVgl {
|
||||
public:
|
||||
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) {}
|
||||
|
||||
|
||||
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;
|
||||
|
||||
static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p) {
|
||||
static void disp_flush(lv_disp_drv_t* disp_drv, const lv_area_t* area, lv_color_t* color_p) {
|
||||
auto* lvgl = static_cast<LittleVgl*>(disp_drv->user_data);
|
||||
lvgl->FlushDisplay(area, color_p);
|
||||
}
|
||||
|
||||
bool touchpad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data) {
|
||||
bool touchpad_read(lv_indev_drv_t* indev_drv, lv_indev_data_t* data) {
|
||||
auto* lvgl = static_cast<LittleVgl*>(indev_drv->user_data);
|
||||
return lvgl->GetTouchPadInfo(data);
|
||||
}
|
||||
|
||||
LittleVgl::LittleVgl(Pinetime::Drivers::St7789& lcd, Pinetime::Drivers::Cst816S& touchPanel) : lcd{lcd}, touchPanel{touchPanel}, previousClick{0,0} {
|
||||
LittleVgl::LittleVgl(Pinetime::Drivers::St7789& lcd, Pinetime::Drivers::Cst816S& touchPanel)
|
||||
: lcd {lcd}, touchPanel {touchPanel}, previousClick {0, 0} {
|
||||
lv_init();
|
||||
InitTheme();
|
||||
InitDisplay();
|
||||
|
@ -59,7 +60,7 @@ void LittleVgl::InitTouchpad() {
|
|||
}
|
||||
|
||||
void LittleVgl::SetFullRefresh(FullRefreshDirections direction) {
|
||||
if(scrollDirection == FullRefreshDirections::None) {
|
||||
if (scrollDirection == FullRefreshDirections::None) {
|
||||
scrollDirection = direction;
|
||||
if (scrollDirection == FullRefreshDirections::Down) {
|
||||
lv_disp_set_direction(lv_disp_get_default(), 1);
|
||||
|
@ -75,16 +76,16 @@ void LittleVgl::SetFullRefresh(FullRefreshDirections direction) {
|
|||
}
|
||||
}
|
||||
|
||||
void LittleVgl::FlushDisplay(const lv_area_t *area, lv_color_t *color_p) {
|
||||
void LittleVgl::FlushDisplay(const lv_area_t* area, lv_color_t* color_p) {
|
||||
uint16_t y1, y2, width, height = 0;
|
||||
|
||||
ulTaskNotifyTake(pdTRUE, 200);
|
||||
// NOtification is still needed (even if there is a mutex on SPI) because of the DataCommand pin
|
||||
// which cannot be set/clear during a transfert.
|
||||
|
||||
if( (scrollDirection == LittleVgl::FullRefreshDirections::Down) && (area->y2 == visibleNbLines - 1)) {
|
||||
if ((scrollDirection == LittleVgl::FullRefreshDirections::Down) && (area->y2 == visibleNbLines - 1)) {
|
||||
writeOffset = ((writeOffset + totalNbLines) - visibleNbLines) % totalNbLines;
|
||||
} else if( (scrollDirection == FullRefreshDirections::Up) && (area->y1 == 0) ) {
|
||||
} else if ((scrollDirection == FullRefreshDirections::Up) && (area->y1 == 0)) {
|
||||
writeOffset = (writeOffset + visibleNbLines) % totalNbLines;
|
||||
}
|
||||
|
||||
|
@ -94,11 +95,11 @@ void LittleVgl::FlushDisplay(const lv_area_t *area, lv_color_t *color_p) {
|
|||
width = (area->x2 - area->x1) + 1;
|
||||
height = (area->y2 - area->y1) + 1;
|
||||
|
||||
if(scrollDirection == LittleVgl::FullRefreshDirections::Down) {
|
||||
if (scrollDirection == LittleVgl::FullRefreshDirections::Down) {
|
||||
|
||||
if(area->y2 < visibleNbLines - 1) {
|
||||
if (area->y2 < visibleNbLines - 1) {
|
||||
uint16_t toScroll = 0;
|
||||
if(area->y1 == 0) {
|
||||
if (area->y1 == 0) {
|
||||
toScroll = height * 2;
|
||||
scrollDirection = FullRefreshDirections::None;
|
||||
lv_disp_set_direction(lv_disp_get_default(), 0);
|
||||
|
@ -106,19 +107,19 @@ void LittleVgl::FlushDisplay(const lv_area_t *area, lv_color_t *color_p) {
|
|||
toScroll = height;
|
||||
}
|
||||
|
||||
if(scrollOffset >= toScroll)
|
||||
if (scrollOffset >= toScroll)
|
||||
scrollOffset -= toScroll;
|
||||
else {
|
||||
toScroll -= scrollOffset;
|
||||
scrollOffset = (totalNbLines) - toScroll;
|
||||
scrollOffset = (totalNbLines) -toScroll;
|
||||
}
|
||||
lcd.VerticalScrollStartAddress(scrollOffset);
|
||||
}
|
||||
|
||||
} else if(scrollDirection == FullRefreshDirections::Up) {
|
||||
} else if (scrollDirection == FullRefreshDirections::Up) {
|
||||
|
||||
if(area->y1 > 0) {
|
||||
if(area->y2 == visibleNbLines - 1) {
|
||||
if (area->y1 > 0) {
|
||||
if (area->y2 == visibleNbLines - 1) {
|
||||
scrollOffset += (height * 2);
|
||||
scrollDirection = FullRefreshDirections::None;
|
||||
lv_disp_set_direction(lv_disp_get_default(), 0);
|
||||
|
@ -128,13 +129,13 @@ void LittleVgl::FlushDisplay(const lv_area_t *area, lv_color_t *color_p) {
|
|||
scrollOffset = scrollOffset % totalNbLines;
|
||||
lcd.VerticalScrollStartAddress(scrollOffset);
|
||||
}
|
||||
} else if(scrollDirection == FullRefreshDirections::Left or scrollDirection == FullRefreshDirections::LeftAnim) {
|
||||
if(area->x2 == visibleNbLines - 1) {
|
||||
} else if (scrollDirection == FullRefreshDirections::Left or scrollDirection == FullRefreshDirections::LeftAnim) {
|
||||
if (area->x2 == visibleNbLines - 1) {
|
||||
scrollDirection = FullRefreshDirections::None;
|
||||
lv_disp_set_direction(lv_disp_get_default(), 0);
|
||||
}
|
||||
} else if(scrollDirection == FullRefreshDirections::Right or scrollDirection == FullRefreshDirections::RightAnim) {
|
||||
if(area->x1 == 0) {
|
||||
} else if (scrollDirection == FullRefreshDirections::Right or scrollDirection == FullRefreshDirections::RightAnim) {
|
||||
if (area->x1 == 0) {
|
||||
scrollDirection = FullRefreshDirections::None;
|
||||
lv_disp_set_direction(lv_disp_get_default(), 0);
|
||||
}
|
||||
|
@ -143,17 +144,17 @@ void LittleVgl::FlushDisplay(const lv_area_t *area, lv_color_t *color_p) {
|
|||
if (y2 < y1) {
|
||||
height = totalNbLines - y1;
|
||||
|
||||
if ( height > 0 ) {
|
||||
lcd.DrawBuffer(area->x1, y1, width, height, reinterpret_cast<const uint8_t *>(color_p), width * height * 2);
|
||||
if (height > 0) {
|
||||
lcd.DrawBuffer(area->x1, y1, width, height, reinterpret_cast<const uint8_t*>(color_p), width * height * 2);
|
||||
ulTaskNotifyTake(pdTRUE, 100);
|
||||
}
|
||||
|
||||
uint16_t pixOffset = width * height;
|
||||
height = y2 + 1;
|
||||
lcd.DrawBuffer(area->x1, 0, width, height, reinterpret_cast<const uint8_t *>(color_p + pixOffset), width * height * 2);
|
||||
lcd.DrawBuffer(area->x1, 0, width, height, reinterpret_cast<const uint8_t*>(color_p + pixOffset), width * height * 2);
|
||||
|
||||
} else {
|
||||
lcd.DrawBuffer(area->x1, y1, width, height, reinterpret_cast<const uint8_t *>(color_p), width * height * 2);
|
||||
lcd.DrawBuffer(area->x1, y1, width, height, reinterpret_cast<const uint8_t*>(color_p), width * height * 2);
|
||||
}
|
||||
|
||||
// IMPORTANT!!!
|
||||
|
@ -167,8 +168,8 @@ void LittleVgl::SetNewTapEvent(uint16_t x, uint16_t y) {
|
|||
tapped = true;
|
||||
}
|
||||
|
||||
bool LittleVgl::GetTouchPadInfo(lv_indev_data_t *ptr) {
|
||||
if(tapped) {
|
||||
bool LittleVgl::GetTouchPadInfo(lv_indev_data_t* ptr) {
|
||||
if (tapped) {
|
||||
ptr->point.x = tap_x;
|
||||
ptr->point.y = tap_y;
|
||||
ptr->state = LV_INDEV_STATE_PR;
|
||||
|
@ -202,14 +203,8 @@ bool LittleVgl::GetTouchPadInfo(lv_indev_data_t *ptr) {
|
|||
|
||||
void LittleVgl::InitTheme() {
|
||||
|
||||
lv_theme_t * th = lv_pinetime_theme_init(
|
||||
LV_COLOR_WHITE, LV_COLOR_SILVER,
|
||||
0,
|
||||
&jetbrains_mono_bold_20,
|
||||
&jetbrains_mono_bold_20,
|
||||
&jetbrains_mono_bold_20,
|
||||
&jetbrains_mono_bold_20);
|
||||
lv_theme_t* th = lv_pinetime_theme_init(
|
||||
LV_COLOR_WHITE, LV_COLOR_SILVER, 0, &jetbrains_mono_bold_20, &jetbrains_mono_bold_20, &jetbrains_mono_bold_20, &jetbrains_mono_bold_20);
|
||||
|
||||
lv_theme_set_act(th);
|
||||
|
||||
}
|
||||
|
|
|
@ -19,8 +19,8 @@ namespace Pinetime {
|
|||
LittleVgl(LittleVgl&&) = delete;
|
||||
LittleVgl& operator=(LittleVgl&&) = delete;
|
||||
|
||||
void FlushDisplay(const lv_area_t * area, lv_color_t * color_p);
|
||||
bool GetTouchPadInfo(lv_indev_data_t *ptr);
|
||||
void FlushDisplay(const lv_area_t* area, lv_color_t* color_p);
|
||||
bool GetTouchPadInfo(lv_indev_data_t* ptr);
|
||||
void SetFullRefresh(FullRefreshDirections direction);
|
||||
void SetNewTapEvent(uint16_t x, uint16_t y);
|
||||
|
||||
|
@ -29,11 +29,9 @@ namespace Pinetime {
|
|||
void InitTouchpad();
|
||||
void InitTheme();
|
||||
|
||||
|
||||
Pinetime::Drivers::St7789& lcd;
|
||||
Pinetime::Drivers::Cst816S& touchPanel;
|
||||
|
||||
|
||||
lv_disp_buf_t disp_buf_2;
|
||||
lv_color_t buf2_1[LV_HOR_RES_MAX * 4];
|
||||
lv_color_t buf2_2[LV_HOR_RES_MAX * 4];
|
||||
|
@ -45,7 +43,9 @@ namespace Pinetime {
|
|||
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; }
|
||||
static constexpr uint8_t MaxScrollOffset() {
|
||||
return LV_VER_RES_MAX - nbWriteLines;
|
||||
}
|
||||
FullRefreshDirections scrollDirection = FullRefreshDirections::None;
|
||||
uint16_t writeOffset = 0;
|
||||
uint16_t scrollOffset = 0;
|
||||
|
@ -56,4 +56,3 @@ namespace Pinetime {
|
|||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,8 +3,16 @@ namespace Pinetime {
|
|||
namespace Applications {
|
||||
namespace Display {
|
||||
enum class Messages : uint8_t {
|
||||
GoToSleep, GoToRunning, UpdateDateTime, UpdateBleConnection, UpdateBatteryLevel, TouchEvent, ButtonPushed,
|
||||
NewNotification, BleFirmwareUpdateStarted, UpdateTimeOut
|
||||
GoToSleep,
|
||||
GoToRunning,
|
||||
UpdateDateTime,
|
||||
UpdateBleConnection,
|
||||
UpdateBatteryLevel,
|
||||
TouchEvent,
|
||||
ButtonPushed,
|
||||
NewNotification,
|
||||
BleFirmwareUpdateStarted,
|
||||
UpdateTimeOut
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,6 @@
|
|||
namespace Pinetime {
|
||||
namespace Applications {
|
||||
|
||||
enum class TouchEvents { None, Tap, SwipeLeft, SwipeRight, SwipeUp, SwipeDown, LongTap, DoubleTap};
|
||||
enum class TouchEvents { None, Tap, SwipeLeft, SwipeRight, SwipeUp, SwipeDown, LongTap, DoubleTap };
|
||||
}
|
||||
}
|
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 void theme_apply(lv_obj_t * obj, lv_theme_style_t name);
|
||||
static void theme_apply(lv_obj_t* obj, lv_theme_style_t name);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
|
@ -67,15 +67,14 @@ static bool inited;
|
|||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void style_init_reset(lv_style_t * style)
|
||||
{
|
||||
if(inited) lv_style_reset(style);
|
||||
else lv_style_init(style);
|
||||
static void style_init_reset(lv_style_t* style) {
|
||||
if (inited)
|
||||
lv_style_reset(style);
|
||||
else
|
||||
lv_style_init(style);
|
||||
}
|
||||
|
||||
|
||||
static void basic_init(void)
|
||||
{
|
||||
static void basic_init(void) {
|
||||
|
||||
style_init_reset(&style_pad);
|
||||
lv_style_set_pad_top(&style_pad, LV_STATE_DEFAULT, LV_VER_RES / 30);
|
||||
|
@ -103,7 +102,6 @@ static void basic_init(void)
|
|||
lv_style_set_border_color(&style_box_border, LV_STATE_DEFAULT, LV_PINETIME_GRAY);
|
||||
lv_style_set_text_color(&style_box, LV_STATE_DEFAULT, LV_PINETIME_BLUE);
|
||||
|
||||
|
||||
style_init_reset(&style_title);
|
||||
lv_style_set_text_color(&style_title, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
|
||||
lv_style_set_text_font(&style_title, LV_STATE_DEFAULT, theme.font_subtitle);
|
||||
|
@ -212,10 +210,10 @@ static void basic_init(void)
|
|||
lv_style_set_bg_opa(&style_sw_knob, LV_STATE_DEFAULT, LV_OPA_COVER);
|
||||
lv_style_set_bg_color(&style_sw_knob, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
|
||||
lv_style_set_radius(&style_sw_knob, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
|
||||
lv_style_set_pad_top(&style_sw_knob, LV_STATE_DEFAULT, - 4);
|
||||
lv_style_set_pad_bottom(&style_sw_knob, LV_STATE_DEFAULT, - 4);
|
||||
lv_style_set_pad_left(&style_sw_knob, LV_STATE_DEFAULT, - 4);
|
||||
lv_style_set_pad_right(&style_sw_knob, LV_STATE_DEFAULT, - 4);
|
||||
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);
|
||||
lv_style_set_bg_opa(&style_slider_knob, LV_STATE_DEFAULT, LV_OPA_COVER);
|
||||
|
@ -301,10 +299,8 @@ static void basic_init(void)
|
|||
lv_style_set_pad_right(&style_cb_bullet, LV_STATE_DEFAULT, LV_DPX(8));
|
||||
lv_style_set_pad_top(&style_cb_bullet, LV_STATE_DEFAULT, LV_DPX(8));
|
||||
lv_style_set_pad_bottom(&style_cb_bullet, LV_STATE_DEFAULT, LV_DPX(8));
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
@ -320,10 +316,13 @@ static void basic_init(void)
|
|||
* @param font_title pointer to a extra large font
|
||||
* @return a pointer to reference this theme later
|
||||
*/
|
||||
lv_theme_t * lv_pinetime_theme_init(lv_color_t color_primary, lv_color_t color_secondary, uint32_t flags,
|
||||
const lv_font_t * font_small, const lv_font_t * font_normal, const lv_font_t * font_subtitle,
|
||||
const lv_font_t * font_title)
|
||||
{
|
||||
lv_theme_t* lv_pinetime_theme_init(lv_color_t color_primary,
|
||||
lv_color_t color_secondary,
|
||||
uint32_t flags,
|
||||
const lv_font_t* font_small,
|
||||
const lv_font_t* font_normal,
|
||||
const lv_font_t* font_subtitle,
|
||||
const lv_font_t* font_title) {
|
||||
theme.color_primary = color_primary;
|
||||
theme.color_secondary = color_secondary;
|
||||
theme.font_small = font_small;
|
||||
|
@ -341,14 +340,12 @@ lv_theme_t * lv_pinetime_theme_init(lv_color_t color_primary, lv_color_t color_s
|
|||
return &theme;
|
||||
}
|
||||
|
||||
|
||||
static void theme_apply(lv_obj_t * obj, lv_theme_style_t name)
|
||||
{
|
||||
lv_style_list_t * list;
|
||||
static void theme_apply(lv_obj_t* obj, lv_theme_style_t name) {
|
||||
lv_style_list_t* list;
|
||||
|
||||
/*To avoid warnings*/
|
||||
uint32_t name_int = (uint32_t) name;
|
||||
switch(name_int) {
|
||||
switch (name_int) {
|
||||
case LV_THEME_NONE:
|
||||
break;
|
||||
|
||||
|
@ -442,7 +439,6 @@ static void theme_apply(lv_obj_t * obj, lv_theme_style_t name)
|
|||
_lv_style_list_add_style(list, &style_list_btn);
|
||||
break;
|
||||
|
||||
|
||||
case LV_THEME_ARC:
|
||||
lv_obj_clean_style_list(obj, LV_ARC_PART_BG);
|
||||
list = lv_obj_get_style_list(obj, LV_ARC_PART_BG);
|
||||
|
@ -453,7 +449,6 @@ static void theme_apply(lv_obj_t * obj, lv_theme_style_t name)
|
|||
_lv_style_list_add_style(list, &style_arc_indic);
|
||||
break;
|
||||
|
||||
|
||||
case LV_THEME_SWITCH:
|
||||
lv_obj_clean_style_list(obj, LV_SWITCH_PART_BG);
|
||||
list = lv_obj_get_style_list(obj, LV_SWITCH_PART_BG);
|
||||
|
@ -497,7 +492,7 @@ static void theme_apply(lv_obj_t * obj, lv_theme_style_t name)
|
|||
start at 1 due to presence of LV_TABLE_PART_BG=0
|
||||
in the enum (lv_table.h) */
|
||||
/* declaring idx outside loop to work with older compilers */
|
||||
for(; idx <= LV_TABLE_CELL_STYLE_CNT; idx ++) {
|
||||
for (; idx <= LV_TABLE_CELL_STYLE_CNT; idx++) {
|
||||
list = lv_obj_get_style_list(obj, idx);
|
||||
_lv_style_list_add_style(list, &style_table_cell);
|
||||
_lv_style_list_add_style(list, &style_label_white);
|
||||
|
@ -526,15 +521,11 @@ static void theme_apply(lv_obj_t * obj, lv_theme_style_t name)
|
|||
_lv_style_list_add_style(list, &style_cb_bullet);
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
lv_obj_refresh_style(obj, LV_OBJ_PART_ALL, LV_STYLE_PROP_ALL);
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**********************
|
||||
|
|
|
@ -23,7 +23,7 @@ extern "C" {
|
|||
#define LV_PINETIME_LIGHT lv_color_hex(0xf3f8fe)
|
||||
#define LV_PINETIME_GRAY lv_color_hex(0x8a8a8a)
|
||||
#define LV_PINETIME_LIGHT_GRAY lv_color_hex(0xc4c4c4)
|
||||
#define LV_PINETIME_BLUE lv_color_hex(0x2f3243) //006fb6
|
||||
#define LV_PINETIME_BLUE lv_color_hex(0x2f3243) // 006fb6
|
||||
#define LV_PINETIME_GREEN lv_color_hex(0x4cb242)
|
||||
#define LV_PINETIME_RED lv_color_hex(0xd51732)
|
||||
|
||||
|
@ -31,12 +31,10 @@ extern "C" {
|
|||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
|
||||
/**
|
||||
* Initialize the default
|
||||
* @param color_primary the primary color of the theme
|
||||
|
@ -48,9 +46,13 @@ extern "C" {
|
|||
* @param font_title pointer to a extra large font
|
||||
* @return a pointer to reference this theme later
|
||||
*/
|
||||
lv_theme_t * lv_pinetime_theme_init(lv_color_t color_primary, lv_color_t color_secondary, uint32_t flags,
|
||||
const lv_font_t * font_small, const lv_font_t * font_normal, const lv_font_t * font_subtitle,
|
||||
const lv_font_t * font_title);
|
||||
lv_theme_t* lv_pinetime_theme_init(lv_color_t color_primary,
|
||||
lv_color_t color_secondary,
|
||||
uint32_t flags,
|
||||
const lv_font_t* font_small,
|
||||
const lv_font_t* font_normal,
|
||||
const lv_font_t* font_subtitle,
|
||||
const lv_font_t* font_title);
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
|
|
@ -8,31 +8,34 @@
|
|||
|
||||
using namespace Pinetime::Applications::Screens;
|
||||
|
||||
ApplicationList::ApplicationList(Pinetime::Applications::DisplayApp *app,
|
||||
Pinetime::Controllers::Settings &settingsController,
|
||||
ApplicationList::ApplicationList(Pinetime::Applications::DisplayApp* app,
|
||||
Pinetime::Controllers::Settings& settingsController,
|
||||
Pinetime::Controllers::Battery& batteryController,
|
||||
Controllers::DateTime& dateTimeController) :
|
||||
Screen(app),
|
||||
settingsController{settingsController},
|
||||
batteryController{batteryController},
|
||||
dateTimeController{dateTimeController},
|
||||
screens{app,
|
||||
Controllers::DateTime& dateTimeController)
|
||||
: Screen(app),
|
||||
settingsController {settingsController},
|
||||
batteryController {batteryController},
|
||||
dateTimeController {dateTimeController},
|
||||
screens {app,
|
||||
settingsController.GetAppMenu(),
|
||||
{
|
||||
[this]() -> std::unique_ptr<Screen> { return CreateScreen1(); },
|
||||
[this]() -> std::unique_ptr<Screen> { return CreateScreen2(); },
|
||||
[this]() -> std::unique_ptr<Screen> {
|
||||
return CreateScreen1();
|
||||
},
|
||||
[this]() -> std::unique_ptr<Screen> {
|
||||
return CreateScreen2();
|
||||
},
|
||||
//[this]() -> std::unique_ptr<Screen> { return CreateScreen3(); }
|
||||
},
|
||||
Screens::ScreenListModes::UpDown
|
||||
} {}
|
||||
|
||||
Screens::ScreenListModes::UpDown} {
|
||||
}
|
||||
|
||||
ApplicationList::~ApplicationList() {
|
||||
lv_obj_clean(lv_scr_act());
|
||||
}
|
||||
|
||||
bool ApplicationList::Refresh() {
|
||||
if(running)
|
||||
if (running)
|
||||
running = screens.Refresh();
|
||||
return running;
|
||||
}
|
||||
|
@ -42,31 +45,27 @@ bool ApplicationList::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
|||
}
|
||||
|
||||
std::unique_ptr<Screen> ApplicationList::CreateScreen1() {
|
||||
std::array<Screens::Tile::Applications, 6> applications {
|
||||
{
|
||||
std::array<Screens::Tile::Applications, 6> applications {{
|
||||
{Symbols::stopWatch, Apps::StopWatch},
|
||||
{Symbols::music, Apps::Music},
|
||||
{Symbols::map, Apps::Navigation},
|
||||
{Symbols::shoe, Apps::Steps},
|
||||
{Symbols::heartBeat, Apps::HeartRate},
|
||||
{"", Apps::None},
|
||||
}
|
||||
};
|
||||
}};
|
||||
|
||||
return std::make_unique<Screens::Tile>(0, 2, app, settingsController, batteryController, dateTimeController, applications);
|
||||
}
|
||||
|
||||
std::unique_ptr<Screen> ApplicationList::CreateScreen2() {
|
||||
std::array<Screens::Tile::Applications, 6> applications {
|
||||
{
|
||||
std::array<Screens::Tile::Applications, 6> applications {{
|
||||
{Symbols::paintbrush, Apps::Paint},
|
||||
{Symbols::paddle, Apps::Paddle},
|
||||
{"2", Apps::Twos},
|
||||
{"M", Apps::Motion},
|
||||
{"", Apps::None},
|
||||
{"", Apps::None},
|
||||
}
|
||||
};
|
||||
}};
|
||||
|
||||
return std::make_unique<Screens::Tile>(1, 2, app, settingsController, batteryController, dateTimeController, applications);
|
||||
}
|
||||
|
@ -84,4 +83,3 @@ std::unique_ptr<Screen> ApplicationList::CreateScreen2() {
|
|||
|
||||
return std::make_unique<Screens::Tile>(2, 3, app, settingsController, batteryController, dateTimeController, applications);
|
||||
}*/
|
||||
|
||||
|
|
|
@ -14,14 +14,14 @@ namespace Pinetime {
|
|||
class ApplicationList : public Screen {
|
||||
public:
|
||||
explicit ApplicationList(DisplayApp* app,
|
||||
Pinetime::Controllers::Settings &settingsController,
|
||||
Pinetime::Controllers::Settings& settingsController,
|
||||
Pinetime::Controllers::Battery& batteryController,
|
||||
Controllers::DateTime& dateTimeController);
|
||||
~ApplicationList() override;
|
||||
bool Refresh() override;
|
||||
bool OnTouchEvent(TouchEvents event) override;
|
||||
private:
|
||||
|
||||
private:
|
||||
Controllers::Settings& settingsController;
|
||||
Pinetime::Controllers::Battery& batteryController;
|
||||
Controllers::DateTime& dateTimeController;
|
||||
|
@ -29,7 +29,7 @@ namespace Pinetime {
|
|||
ScreenList<2> screens;
|
||||
std::unique_ptr<Screen> CreateScreen1();
|
||||
std::unique_ptr<Screen> CreateScreen2();
|
||||
//std::unique_ptr<Screen> CreateScreen3();
|
||||
// std::unique_ptr<Screen> CreateScreen3();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,10 +4,14 @@
|
|||
using namespace Pinetime::Applications::Screens;
|
||||
|
||||
const char* BatteryIcon::GetBatteryIcon(int batteryPercent) {
|
||||
if(batteryPercent > 90) return Symbols::batteryFull;
|
||||
if(batteryPercent > 75) return Symbols::batteryThreeQuarter;
|
||||
if(batteryPercent > 50) return Symbols::batteryHalf;
|
||||
if(batteryPercent > 25) return Symbols::batteryOneQuarter;
|
||||
if (batteryPercent > 90)
|
||||
return Symbols::batteryFull;
|
||||
if (batteryPercent > 75)
|
||||
return Symbols::batteryThreeQuarter;
|
||||
if (batteryPercent > 50)
|
||||
return Symbols::batteryHalf;
|
||||
if (batteryPercent > 25)
|
||||
return Symbols::batteryOneQuarter;
|
||||
return Symbols::batteryEmpty;
|
||||
}
|
||||
|
||||
|
@ -15,8 +19,9 @@ const char* BatteryIcon::GetUnknownIcon() {
|
|||
return Symbols::batteryEmpty;
|
||||
}
|
||||
|
||||
const char *BatteryIcon::GetPlugIcon(bool isCharging) {
|
||||
if(isCharging)
|
||||
const char* BatteryIcon::GetPlugIcon(bool isCharging) {
|
||||
if (isCharging)
|
||||
return Symbols::plug;
|
||||
else return "";
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
|
|
@ -4,22 +4,18 @@
|
|||
|
||||
using namespace Pinetime::Applications::Screens;
|
||||
|
||||
static void lv_update_task(struct _lv_task_t *task) {
|
||||
auto user_data = static_cast<BatteryInfo *>(task->user_data);
|
||||
static void lv_update_task(struct _lv_task_t* task) {
|
||||
auto user_data = static_cast<BatteryInfo*>(task->user_data);
|
||||
user_data->UpdateScreen();
|
||||
}
|
||||
|
||||
static void lv_anim_task(struct _lv_task_t *task) {
|
||||
auto user_data = static_cast<BatteryInfo *>(task->user_data);
|
||||
static void lv_anim_task(struct _lv_task_t* task) {
|
||||
auto user_data = static_cast<BatteryInfo*>(task->user_data);
|
||||
user_data->UpdateAnim();
|
||||
}
|
||||
|
||||
BatteryInfo::BatteryInfo(
|
||||
Pinetime::Applications::DisplayApp *app,
|
||||
Pinetime::Controllers::Battery& batteryController) :
|
||||
Screen(app),
|
||||
batteryController{batteryController}
|
||||
{
|
||||
BatteryInfo::BatteryInfo(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Battery& batteryController)
|
||||
: Screen(app), batteryController {batteryController} {
|
||||
|
||||
batteryPercent = batteryController.PercentRemaining();
|
||||
batteryVoltage = batteryController.Voltage();
|
||||
|
@ -32,37 +28,38 @@ BatteryInfo::BatteryInfo(
|
|||
lv_obj_set_style_local_radius(charging_bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
|
||||
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, lv_color_hex(0x222222));
|
||||
lv_obj_set_style_local_bg_opa(charging_bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, LV_OPA_100);
|
||||
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC , LV_STATE_DEFAULT, lv_color_hex(0xFF0000));
|
||||
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, lv_color_hex(0xFF0000));
|
||||
lv_bar_set_value(charging_bar, batteryPercent, LV_ANIM_OFF);
|
||||
|
||||
status = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_label_set_text_static(status,"Reading Battery status");
|
||||
lv_label_set_text_static(status, "Reading Battery status");
|
||||
lv_label_set_align(status, LV_LABEL_ALIGN_CENTER);
|
||||
lv_obj_align(status, charging_bar, LV_ALIGN_OUT_BOTTOM_MID, 0, 20);
|
||||
|
||||
percent = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_set_style_local_text_font(percent, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76);
|
||||
if ( batteryPercent >= 0) {
|
||||
lv_label_set_text_fmt(percent,"%02i%%", batteryPercent);
|
||||
if (batteryPercent >= 0) {
|
||||
lv_label_set_text_fmt(percent, "%02i%%", batteryPercent);
|
||||
} else {
|
||||
lv_label_set_text(percent,"--%");
|
||||
lv_label_set_text(percent, "--%");
|
||||
}
|
||||
lv_label_set_align(percent, LV_LABEL_ALIGN_LEFT);
|
||||
lv_obj_align(percent, nullptr, LV_ALIGN_CENTER, 0, -60);
|
||||
|
||||
// hack to not use the flot functions from printf
|
||||
uint8_t batteryVoltageBytes[2];
|
||||
batteryVoltageBytes[1] = static_cast<uint8_t>(batteryVoltage); //truncate whole numbers
|
||||
batteryVoltageBytes[0] = static_cast<uint8_t>((batteryVoltage - batteryVoltageBytes[1]) * 100); //remove whole part of flt and shift 2 places over
|
||||
batteryVoltageBytes[1] = static_cast<uint8_t>(batteryVoltage); // truncate whole numbers
|
||||
batteryVoltageBytes[0] =
|
||||
static_cast<uint8_t>((batteryVoltage - batteryVoltageBytes[1]) * 100); // remove whole part of flt and shift 2 places over
|
||||
//
|
||||
|
||||
voltage = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_set_style_local_text_color(voltage, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xC6A600));
|
||||
lv_label_set_text_fmt(voltage,"%1i.%02i volts", batteryVoltageBytes[1], batteryVoltageBytes[0]);
|
||||
lv_label_set_text_fmt(voltage, "%1i.%02i volts", batteryVoltageBytes[1], batteryVoltageBytes[0]);
|
||||
lv_label_set_align(voltage, LV_LABEL_ALIGN_CENTER);
|
||||
lv_obj_align(voltage, nullptr, LV_ALIGN_CENTER, 0, 95);
|
||||
|
||||
lv_obj_t * backgroundLabel = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_t* backgroundLabel = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_label_set_long_mode(backgroundLabel, LV_LABEL_LONG_CROP);
|
||||
lv_obj_set_size(backgroundLabel, 240, 240);
|
||||
lv_obj_set_pos(backgroundLabel, 0, 0);
|
||||
|
@ -73,7 +70,6 @@ BatteryInfo::BatteryInfo(
|
|||
UpdateScreen();
|
||||
}
|
||||
|
||||
|
||||
BatteryInfo::~BatteryInfo() {
|
||||
lv_task_del(taskUpdate);
|
||||
lv_task_del(taskAnim);
|
||||
|
@ -83,9 +79,9 @@ BatteryInfo::~BatteryInfo() {
|
|||
void BatteryInfo::UpdateAnim() {
|
||||
batteryPercent = batteryController.PercentRemaining();
|
||||
|
||||
if ( batteryPercent >= 0 ) {
|
||||
if ( batteryController.IsCharging() and batteryPercent < 100 ) {
|
||||
animation +=1;
|
||||
if (batteryPercent >= 0) {
|
||||
if (batteryController.IsCharging() and batteryPercent < 100) {
|
||||
animation += 1;
|
||||
if (animation >= 100) {
|
||||
animation = 0;
|
||||
}
|
||||
|
@ -110,40 +106,39 @@ void BatteryInfo::UpdateScreen() {
|
|||
batteryPercent = batteryController.PercentRemaining();
|
||||
batteryVoltage = batteryController.Voltage();
|
||||
|
||||
if ( batteryPercent >= 0 ) {
|
||||
if ( batteryController.IsCharging() and batteryPercent < 100 ) {
|
||||
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC , LV_STATE_DEFAULT, LV_COLOR_RED);
|
||||
lv_label_set_text_static(status,"Battery charging");
|
||||
} else if ( batteryPercent == 100 ) {
|
||||
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC , LV_STATE_DEFAULT, LV_COLOR_BLUE);
|
||||
lv_label_set_text_static(status,"Battery is fully charged");
|
||||
} else if ( batteryPercent < 10 ) {
|
||||
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC , LV_STATE_DEFAULT, LV_COLOR_YELLOW);
|
||||
lv_label_set_text_static(status,"Battery is low");
|
||||
if (batteryPercent >= 0) {
|
||||
if (batteryController.IsCharging() and batteryPercent < 100) {
|
||||
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_RED);
|
||||
lv_label_set_text_static(status, "Battery charging");
|
||||
} else if (batteryPercent == 100) {
|
||||
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_BLUE);
|
||||
lv_label_set_text_static(status, "Battery is fully charged");
|
||||
} else if (batteryPercent < 10) {
|
||||
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_YELLOW);
|
||||
lv_label_set_text_static(status, "Battery is low");
|
||||
} else {
|
||||
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC , LV_STATE_DEFAULT, LV_COLOR_GREEN);
|
||||
lv_label_set_text_static(status,"Battery discharging");
|
||||
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_GREEN);
|
||||
lv_label_set_text_static(status, "Battery discharging");
|
||||
}
|
||||
|
||||
lv_label_set_text_fmt(percent,"%02i%%", batteryPercent);
|
||||
lv_label_set_text_fmt(percent, "%02i%%", batteryPercent);
|
||||
|
||||
} else {
|
||||
lv_label_set_text_static(status,"Reading Battery status");
|
||||
lv_label_set_text(percent,"--%");
|
||||
lv_label_set_text_static(status, "Reading Battery status");
|
||||
lv_label_set_text(percent, "--%");
|
||||
}
|
||||
|
||||
lv_obj_align(status, charging_bar, LV_ALIGN_OUT_BOTTOM_MID, 0, 20);
|
||||
// hack to not use the flot functions from printf
|
||||
uint8_t batteryVoltageBytes[2];
|
||||
batteryVoltageBytes[1] = static_cast<uint8_t>(batteryVoltage); //truncate whole numbers
|
||||
batteryVoltageBytes[0] = static_cast<uint8_t>((batteryVoltage - batteryVoltageBytes[1]) * 100); //remove whole part of flt and shift 2 places over
|
||||
batteryVoltageBytes[1] = static_cast<uint8_t>(batteryVoltage); // truncate whole numbers
|
||||
batteryVoltageBytes[0] =
|
||||
static_cast<uint8_t>((batteryVoltage - batteryVoltageBytes[1]) * 100); // remove whole part of flt and shift 2 places over
|
||||
//
|
||||
lv_label_set_text_fmt(voltage,"%1i.%02i volts", batteryVoltageBytes[1], batteryVoltageBytes[0]);
|
||||
|
||||
lv_label_set_text_fmt(voltage, "%1i.%02i volts", batteryVoltageBytes[1], batteryVoltageBytes[0]);
|
||||
}
|
||||
|
||||
bool BatteryInfo::Refresh() {
|
||||
|
||||
return running;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
#include "Screen.h"
|
||||
#include <lvgl/lvgl.h>
|
||||
|
||||
|
||||
namespace Pinetime {
|
||||
namespace Controllers {
|
||||
class Battery;
|
||||
|
@ -15,20 +14,17 @@ namespace Pinetime {
|
|||
namespace Applications {
|
||||
namespace Screens {
|
||||
|
||||
class BatteryInfo : public Screen{
|
||||
class BatteryInfo : public Screen {
|
||||
public:
|
||||
BatteryInfo(DisplayApp* app,
|
||||
Pinetime::Controllers::Battery& batteryController);
|
||||
BatteryInfo(DisplayApp* app, Pinetime::Controllers::Battery& batteryController);
|
||||
~BatteryInfo() override;
|
||||
|
||||
bool Refresh() override;
|
||||
|
||||
|
||||
void UpdateScreen();
|
||||
void UpdateAnim();
|
||||
|
||||
private:
|
||||
|
||||
Pinetime::Controllers::Battery& batteryController;
|
||||
|
||||
lv_obj_t* voltage;
|
||||
|
@ -42,7 +38,6 @@ namespace Pinetime {
|
|||
int8_t animation = 0;
|
||||
int8_t batteryPercent = -1;
|
||||
float batteryVoltage = 0.0f;
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
using namespace Pinetime::Applications::Screens;
|
||||
|
||||
const char* BleIcon::GetIcon(bool isConnected) {
|
||||
if(isConnected) return Symbols::bluetooth;
|
||||
else return "";
|
||||
if (isConnected)
|
||||
return Symbols::bluetooth;
|
||||
else
|
||||
return "";
|
||||
}
|
|
@ -3,14 +3,15 @@
|
|||
|
||||
using namespace Pinetime::Applications::Screens;
|
||||
|
||||
void slider_event_cb(lv_obj_t * slider, lv_event_t event) {
|
||||
if(event == LV_EVENT_VALUE_CHANGED) {
|
||||
void slider_event_cb(lv_obj_t* slider, lv_event_t event) {
|
||||
if (event == LV_EVENT_VALUE_CHANGED) {
|
||||
auto* brightnessSlider = static_cast<Brightness*>(slider->user_data);
|
||||
brightnessSlider->OnValueChanged();
|
||||
}
|
||||
}
|
||||
|
||||
Brightness::Brightness(Pinetime::Applications::DisplayApp *app, Controllers::BrightnessController& brightness) : Screen(app), brightness{brightness} {
|
||||
Brightness::Brightness(Pinetime::Applications::DisplayApp* app, Controllers::BrightnessController& brightness)
|
||||
: Screen(app), brightness {brightness} {
|
||||
slider = lv_slider_create(lv_scr_act(), nullptr);
|
||||
lv_obj_set_user_data(slider, this);
|
||||
lv_obj_set_width(slider, LV_DPI * 2);
|
||||
|
@ -33,13 +34,18 @@ bool Brightness::Refresh() {
|
|||
return running;
|
||||
}
|
||||
|
||||
const char *Brightness::LevelToString(Pinetime::Controllers::BrightnessController::Levels level) {
|
||||
switch(level) {
|
||||
case Pinetime::Controllers::BrightnessController::Levels::Off: return "Off";
|
||||
case Pinetime::Controllers::BrightnessController::Levels::Low: return "Low";
|
||||
case Pinetime::Controllers::BrightnessController::Levels::Medium: return "Medium";
|
||||
case Pinetime::Controllers::BrightnessController::Levels::High: return "High";
|
||||
default : return "???";
|
||||
const char* Brightness::LevelToString(Pinetime::Controllers::BrightnessController::Levels level) {
|
||||
switch (level) {
|
||||
case Pinetime::Controllers::BrightnessController::Levels::Off:
|
||||
return "Off";
|
||||
case Pinetime::Controllers::BrightnessController::Levels::Low:
|
||||
return "Low";
|
||||
case Pinetime::Controllers::BrightnessController::Levels::Medium:
|
||||
return "Medium";
|
||||
case Pinetime::Controllers::BrightnessController::Levels::High:
|
||||
return "High";
|
||||
default:
|
||||
return "???";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -48,29 +54,40 @@ void Brightness::OnValueChanged() {
|
|||
}
|
||||
|
||||
void Brightness::SetValue(uint8_t value) {
|
||||
switch(value) {
|
||||
case 0: brightness.Set(Controllers::BrightnessController::Levels::Low); break;
|
||||
case 1: brightness.Set(Controllers::BrightnessController::Levels::Medium); break;
|
||||
case 2: brightness.Set(Controllers::BrightnessController::Levels::High); break;
|
||||
switch (value) {
|
||||
case 0:
|
||||
brightness.Set(Controllers::BrightnessController::Levels::Low);
|
||||
break;
|
||||
case 1:
|
||||
brightness.Set(Controllers::BrightnessController::Levels::Medium);
|
||||
break;
|
||||
case 2:
|
||||
brightness.Set(Controllers::BrightnessController::Levels::High);
|
||||
break;
|
||||
}
|
||||
lv_label_set_text(slider_label, LevelToString(brightness.Level()));
|
||||
}
|
||||
|
||||
uint8_t Brightness::LevelToInt(Pinetime::Controllers::BrightnessController::Levels level) {
|
||||
switch(level) {
|
||||
case Pinetime::Controllers::BrightnessController::Levels::Off: return 0;
|
||||
case Pinetime::Controllers::BrightnessController::Levels::Low: return 0;
|
||||
case Pinetime::Controllers::BrightnessController::Levels::Medium: return 1;
|
||||
case Pinetime::Controllers::BrightnessController::Levels::High: return 2;
|
||||
default : return 0;
|
||||
switch (level) {
|
||||
case Pinetime::Controllers::BrightnessController::Levels::Off:
|
||||
return 0;
|
||||
case Pinetime::Controllers::BrightnessController::Levels::Low:
|
||||
return 0;
|
||||
case Pinetime::Controllers::BrightnessController::Levels::Medium:
|
||||
return 1;
|
||||
case Pinetime::Controllers::BrightnessController::Levels::High:
|
||||
return 2;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool Brightness::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
||||
switch(event) {
|
||||
switch (event) {
|
||||
case TouchEvents::SwipeLeft:
|
||||
brightness.Lower();
|
||||
if ( brightness.Level() == Pinetime::Controllers::BrightnessController::Levels::Off) {
|
||||
if (brightness.Level() == Pinetime::Controllers::BrightnessController::Levels::Off) {
|
||||
brightness.Set(Controllers::BrightnessController::Levels::Low);
|
||||
}
|
||||
SetValue();
|
||||
|
|
|
@ -17,12 +17,12 @@ namespace Pinetime {
|
|||
bool OnTouchEvent(TouchEvents event) override;
|
||||
|
||||
void OnValueChanged();
|
||||
private:
|
||||
|
||||
private:
|
||||
Controllers::BrightnessController& brightness;
|
||||
|
||||
lv_obj_t * slider_label;
|
||||
lv_obj_t * slider;
|
||||
lv_obj_t* slider_label;
|
||||
lv_obj_t* slider;
|
||||
|
||||
const char* LevelToString(Controllers::BrightnessController::Levels level);
|
||||
uint8_t LevelToInt(Controllers::BrightnessController::Levels level);
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
#include "WatchFaceDigital.h"
|
||||
#include "WatchFaceAnalog.h"
|
||||
|
||||
|
||||
using namespace Pinetime::Applications::Screens;
|
||||
|
||||
Clock::Clock(DisplayApp* app,
|
||||
|
@ -23,35 +22,39 @@ Clock::Clock(DisplayApp* app,
|
|||
Controllers::Battery& batteryController,
|
||||
Controllers::Ble& bleController,
|
||||
Controllers::NotificationManager& notificatioManager,
|
||||
Controllers::Settings &settingsController,
|
||||
Controllers::Settings& settingsController,
|
||||
Controllers::HeartRateController& heartRateController,
|
||||
Controllers::MotionController& motionController) : Screen(app),
|
||||
dateTimeController{dateTimeController}, batteryController{batteryController},
|
||||
bleController{bleController}, notificatioManager{notificatioManager},
|
||||
settingsController{settingsController},
|
||||
heartRateController{heartRateController},
|
||||
motionController{motionController},
|
||||
screens{app,
|
||||
Controllers::MotionController& motionController)
|
||||
: Screen(app),
|
||||
dateTimeController {dateTimeController},
|
||||
batteryController {batteryController},
|
||||
bleController {bleController},
|
||||
notificatioManager {notificatioManager},
|
||||
settingsController {settingsController},
|
||||
heartRateController {heartRateController},
|
||||
motionController {motionController},
|
||||
screens {app,
|
||||
settingsController.GetClockFace(),
|
||||
{
|
||||
[this]() -> std::unique_ptr<Screen> { return WatchFaceDigitalScreen(); },
|
||||
[this]() -> std::unique_ptr<Screen> { return WatchFaceAnalogScreen(); },
|
||||
[this]() -> std::unique_ptr<Screen> {
|
||||
return WatchFaceDigitalScreen();
|
||||
},
|
||||
[this]() -> std::unique_ptr<Screen> {
|
||||
return WatchFaceAnalogScreen();
|
||||
},
|
||||
// Examples for more watch faces
|
||||
//[this]() -> std::unique_ptr<Screen> { return WatchFaceMinimalScreen(); },
|
||||
//[this]() -> std::unique_ptr<Screen> { return WatchFaceCustomScreen(); }
|
||||
},
|
||||
Screens::ScreenListModes::LongPress
|
||||
} {
|
||||
Screens::ScreenListModes::LongPress} {
|
||||
|
||||
settingsController.SetAppMenu(0);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Clock::~Clock() {
|
||||
lv_obj_clean(lv_scr_act());
|
||||
}
|
||||
|
||||
|
||||
bool Clock::Refresh() {
|
||||
screens.Refresh();
|
||||
return running;
|
||||
|
@ -62,20 +65,30 @@ bool Clock::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
|||
}
|
||||
|
||||
std::unique_ptr<Screen> Clock::WatchFaceDigitalScreen() {
|
||||
return std::make_unique<Screens::WatchFaceDigital>(app, dateTimeController, batteryController, bleController, notificatioManager, settingsController, heartRateController, motionController);
|
||||
return std::make_unique<Screens::WatchFaceDigital>(app,
|
||||
dateTimeController,
|
||||
batteryController,
|
||||
bleController,
|
||||
notificatioManager,
|
||||
settingsController,
|
||||
heartRateController,
|
||||
motionController);
|
||||
}
|
||||
|
||||
std::unique_ptr<Screen> Clock::WatchFaceAnalogScreen() {
|
||||
return std::make_unique<Screens::WatchFaceAnalog>(app, dateTimeController, batteryController, bleController, notificatioManager, settingsController);
|
||||
return std::make_unique<Screens::WatchFaceAnalog>(
|
||||
app, dateTimeController, batteryController, bleController, notificatioManager, settingsController);
|
||||
}
|
||||
|
||||
/*
|
||||
// Examples for more watch faces
|
||||
std::unique_ptr<Screen> Clock::WatchFaceMinimalScreen() {
|
||||
return std::make_unique<Screens::WatchFaceMinimal>(app, dateTimeController, batteryController, bleController, notificatioManager, settingsController);
|
||||
return std::make_unique<Screens::WatchFaceMinimal>(app, dateTimeController, batteryController, bleController, notificatioManager,
|
||||
settingsController);
|
||||
}
|
||||
|
||||
std::unique_ptr<Screen> Clock::WatchFaceCustomScreen() {
|
||||
return std::make_unique<Screens::WatchFaceCustom>(app, dateTimeController, batteryController, bleController, notificatioManager, settingsController);
|
||||
return std::make_unique<Screens::WatchFaceCustom>(app, dateTimeController, batteryController, bleController, notificatioManager,
|
||||
settingsController);
|
||||
}
|
||||
*/
|
|
@ -29,7 +29,7 @@ namespace Pinetime {
|
|||
Controllers::Battery& batteryController,
|
||||
Controllers::Ble& bleController,
|
||||
Controllers::NotificationManager& notificatioManager,
|
||||
Controllers::Settings &settingsController,
|
||||
Controllers::Settings& settingsController,
|
||||
Controllers::HeartRateController& heartRateController,
|
||||
Controllers::MotionController& motionController);
|
||||
~Clock() override;
|
||||
|
@ -39,7 +39,6 @@ namespace Pinetime {
|
|||
bool OnTouchEvent(TouchEvents event) override;
|
||||
|
||||
private:
|
||||
|
||||
Controllers::DateTime& dateTimeController;
|
||||
Controllers::Battery& batteryController;
|
||||
Controllers::Ble& bleController;
|
||||
|
@ -48,17 +47,13 @@ namespace Pinetime {
|
|||
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();
|
||||
|
||||
|
||||
|
||||
// std::unique_ptr<Screen> WatchFaceMinimalScreen();
|
||||
// std::unique_ptr<Screen> WatchFaceCustomScreen();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,10 +5,11 @@
|
|||
|
||||
using namespace Pinetime::Applications::Screens;
|
||||
|
||||
DropDownDemo::DropDownDemo(Pinetime::Applications::DisplayApp *app) : Screen(app) {
|
||||
DropDownDemo::DropDownDemo(Pinetime::Applications::DisplayApp* app) : Screen(app) {
|
||||
// Create the dropdown object, with many item, and fix its height
|
||||
ddlist = lv_ddlist_create(lv_scr_act(), nullptr);
|
||||
lv_ddlist_set_options(ddlist, "Apple\n"
|
||||
lv_ddlist_set_options(ddlist,
|
||||
"Apple\n"
|
||||
"Banana\n"
|
||||
"Orange\n"
|
||||
"Melon\n"
|
||||
|
@ -32,12 +33,12 @@ DropDownDemo::~DropDownDemo() {
|
|||
}
|
||||
|
||||
bool DropDownDemo::Refresh() {
|
||||
auto* list = static_cast<lv_ddlist_ext_t *>(ddlist->ext_attr);
|
||||
auto* list = static_cast<lv_ddlist_ext_t*>(ddlist->ext_attr);
|
||||
|
||||
// Switch touchmode to Polling if the dropdown is opened. This will allow to scroll inside the
|
||||
// dropdown while it is opened.
|
||||
// Disable the polling mode when the dropdown is closed to be able to handle the gestures.
|
||||
if(list->opened)
|
||||
if (list->opened)
|
||||
app->SetTouchMode(DisplayApp::TouchModes::Polling);
|
||||
else
|
||||
app->SetTouchMode(DisplayApp::TouchModes::Gestures);
|
||||
|
@ -47,11 +48,10 @@ bool DropDownDemo::Refresh() {
|
|||
bool DropDownDemo::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
||||
// If the dropdown is opened, notify Display app that it doesn't need to handle the event
|
||||
// (this will prevent displayApp from going back to the menu or clock scree).
|
||||
auto* list = static_cast<lv_ddlist_ext_t *>(ddlist->ext_attr);
|
||||
if(list->opened) {
|
||||
auto* list = static_cast<lv_ddlist_ext_t*>(ddlist->ext_attr);
|
||||
if (list->opened) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ namespace Pinetime {
|
|||
bool OnTouchEvent(TouchEvents event) override;
|
||||
|
||||
private:
|
||||
lv_obj_t * ddlist;
|
||||
lv_obj_t* ddlist;
|
||||
|
||||
bool isDropDownOpened = false;
|
||||
};
|
||||
|
|
|
@ -5,11 +5,10 @@
|
|||
|
||||
using namespace Pinetime::Applications::Screens;
|
||||
|
||||
FirmwareUpdate::FirmwareUpdate(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Ble& bleController)
|
||||
: Screen(app), bleController {bleController} {
|
||||
|
||||
FirmwareUpdate::FirmwareUpdate(Pinetime::Applications::DisplayApp *app, Pinetime::Controllers::Ble& bleController) :
|
||||
Screen(app), bleController{bleController} {
|
||||
|
||||
lv_obj_t * backgroundLabel = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_t* backgroundLabel = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_label_set_long_mode(backgroundLabel, LV_LABEL_LONG_CROP);
|
||||
lv_obj_set_size(backgroundLabel, 240, 240);
|
||||
lv_obj_set_pos(backgroundLabel, 0, 0);
|
||||
|
@ -38,21 +37,21 @@ FirmwareUpdate::~FirmwareUpdate() {
|
|||
}
|
||||
|
||||
bool FirmwareUpdate::Refresh() {
|
||||
switch(bleController.State()) {
|
||||
switch (bleController.State()) {
|
||||
default:
|
||||
case Pinetime::Controllers::Ble::FirmwareUpdateStates::Idle:
|
||||
case Pinetime::Controllers::Ble::FirmwareUpdateStates::Running:
|
||||
if(state != States::Running)
|
||||
if (state != States::Running)
|
||||
state = States::Running;
|
||||
return DisplayProgression();
|
||||
case Pinetime::Controllers::Ble::FirmwareUpdateStates::Validated:
|
||||
if(state != States::Validated) {
|
||||
if (state != States::Validated) {
|
||||
UpdateValidated();
|
||||
state = States::Validated;
|
||||
}
|
||||
return running;
|
||||
case Pinetime::Controllers::Ble::FirmwareUpdateStates::Error:
|
||||
if(state != States::Error) {
|
||||
if (state != States::Error) {
|
||||
UpdateError();
|
||||
state = States::Error;
|
||||
}
|
||||
|
|
|
@ -10,14 +10,13 @@ namespace Pinetime {
|
|||
namespace Applications {
|
||||
namespace Screens {
|
||||
|
||||
class FirmwareUpdate : public Screen{
|
||||
class FirmwareUpdate : public Screen {
|
||||
public:
|
||||
FirmwareUpdate(DisplayApp* app, Pinetime::Controllers::Ble& bleController);
|
||||
~FirmwareUpdate() override;
|
||||
|
||||
bool Refresh() override;
|
||||
|
||||
|
||||
private:
|
||||
enum class States { Idle, Running, Validated, Error };
|
||||
Pinetime::Controllers::Ble& bleController;
|
||||
|
|
|
@ -7,23 +7,20 @@
|
|||
using namespace Pinetime::Applications::Screens;
|
||||
|
||||
namespace {
|
||||
static void ButtonEventHandler(lv_obj_t * obj, lv_event_t event)
|
||||
{
|
||||
FirmwareValidation* screen = static_cast<FirmwareValidation *>(obj->user_data);
|
||||
static void ButtonEventHandler(lv_obj_t* obj, lv_event_t event) {
|
||||
FirmwareValidation* screen = static_cast<FirmwareValidation*>(obj->user_data);
|
||||
screen->OnButtonEvent(obj, event);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
FirmwareValidation::FirmwareValidation(Pinetime::Applications::DisplayApp *app,
|
||||
Pinetime::Controllers::FirmwareValidator &validator)
|
||||
: Screen{app}, validator{validator} {
|
||||
FirmwareValidation::FirmwareValidation(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::FirmwareValidator& validator)
|
||||
: Screen {app}, validator {validator} {
|
||||
labelVersionInfo = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_align(labelVersionInfo, nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0);
|
||||
lv_label_set_text(labelVersionInfo, "Version : ");
|
||||
lv_label_set_align(labelVersionInfo, LV_LABEL_ALIGN_LEFT);
|
||||
|
||||
|
||||
labelVersionValue = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_align(labelVersionValue, labelVersionInfo, LV_ALIGN_OUT_RIGHT_MID, 0, 0);
|
||||
lv_label_set_recolor(labelVersionValue, true);
|
||||
|
@ -36,11 +33,10 @@ FirmwareValidation::FirmwareValidation(Pinetime::Applications::DisplayApp *app,
|
|||
lv_label_set_long_mode(labelIsValidated, LV_LABEL_LONG_BREAK);
|
||||
lv_obj_set_width(labelIsValidated, 240);
|
||||
|
||||
if(validator.IsValidated())
|
||||
if (validator.IsValidated())
|
||||
lv_label_set_text(labelIsValidated, "You have already\n#00ff00 validated# this firmware#");
|
||||
else {
|
||||
lv_label_set_text(labelIsValidated,
|
||||
"Please #00ff00 Validate# this version or\n#ff0000 Reset# to rollback to the previous version.");
|
||||
lv_label_set_text(labelIsValidated, "Please #00ff00 Validate# this version or\n#ff0000 Reset# to rollback to the previous version.");
|
||||
|
||||
buttonValidate = lv_btn_create(lv_scr_act(), nullptr);
|
||||
lv_obj_align(buttonValidate, NULL, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0);
|
||||
|
@ -62,7 +58,6 @@ FirmwareValidation::FirmwareValidation(Pinetime::Applications::DisplayApp *app,
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
FirmwareValidation::~FirmwareValidation() {
|
||||
lv_obj_clean(lv_scr_act());
|
||||
}
|
||||
|
@ -71,12 +66,11 @@ bool FirmwareValidation::Refresh() {
|
|||
return running;
|
||||
}
|
||||
|
||||
void FirmwareValidation::OnButtonEvent(lv_obj_t *object, lv_event_t event) {
|
||||
if(object == buttonValidate && event == LV_EVENT_PRESSED) {
|
||||
void FirmwareValidation::OnButtonEvent(lv_obj_t* object, lv_event_t event) {
|
||||
if (object == buttonValidate && event == LV_EVENT_PRESSED) {
|
||||
validator.Validate();
|
||||
running = false;
|
||||
} else if(object == buttonReset && event == LV_EVENT_PRESSED) {
|
||||
} else if (object == buttonReset && event == LV_EVENT_PRESSED) {
|
||||
validator.Reset();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -11,15 +11,14 @@ namespace Pinetime {
|
|||
namespace Applications {
|
||||
namespace Screens {
|
||||
|
||||
class FirmwareValidation : public Screen{
|
||||
class FirmwareValidation : public Screen {
|
||||
public:
|
||||
FirmwareValidation(DisplayApp* app, Pinetime::Controllers::FirmwareValidator& validator);
|
||||
~FirmwareValidation() 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;
|
||||
|
@ -32,7 +31,6 @@ namespace Pinetime {
|
|||
lv_obj_t* labelButtonValidate;
|
||||
lv_obj_t* buttonReset;
|
||||
lv_obj_t* labelButtonReset;
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,19 +5,18 @@
|
|||
using namespace Pinetime::Applications::Screens;
|
||||
|
||||
namespace {
|
||||
static void event_handler(lv_obj_t * obj, lv_event_t event) {
|
||||
FlashLight* screen = static_cast<FlashLight *>(obj->user_data);
|
||||
static void event_handler(lv_obj_t* obj, lv_event_t event) {
|
||||
FlashLight* screen = static_cast<FlashLight*>(obj->user_data);
|
||||
screen->OnClickEvent(obj, event);
|
||||
}
|
||||
}
|
||||
|
||||
FlashLight::FlashLight(
|
||||
Pinetime::Applications::DisplayApp *app,
|
||||
System::SystemTask &systemTask,
|
||||
Controllers::BrightnessController& brightness) :
|
||||
Screen(app),
|
||||
systemTask{systemTask},
|
||||
brightness{brightness}
|
||||
FlashLight::FlashLight(Pinetime::Applications::DisplayApp* app,
|
||||
System::SystemTask& systemTask,
|
||||
Controllers::BrightnessController& brightness)
|
||||
: Screen(app),
|
||||
systemTask {systemTask},
|
||||
brightness {brightness}
|
||||
|
||||
{
|
||||
brightness.Backup();
|
||||
|
@ -41,10 +40,8 @@ FlashLight::FlashLight(
|
|||
lv_obj_set_event_cb(backgroundAction, event_handler);
|
||||
|
||||
systemTask.PushMessage(Pinetime::System::SystemTask::Messages::DisableSleeping);
|
||||
|
||||
}
|
||||
|
||||
|
||||
FlashLight::~FlashLight() {
|
||||
lv_obj_clean(lv_scr_act());
|
||||
lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
|
||||
|
@ -52,19 +49,18 @@ FlashLight::~FlashLight() {
|
|||
systemTask.PushMessage(Pinetime::System::SystemTask::Messages::EnableSleeping);
|
||||
}
|
||||
|
||||
void FlashLight::OnClickEvent(lv_obj_t *obj, lv_event_t event) {
|
||||
if(obj == backgroundAction) {
|
||||
void FlashLight::OnClickEvent(lv_obj_t* obj, lv_event_t event) {
|
||||
if (obj == backgroundAction) {
|
||||
if (event == LV_EVENT_CLICKED) {
|
||||
isOn = !isOn;
|
||||
|
||||
if ( isOn ) {
|
||||
if (isOn) {
|
||||
lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xFFFFFF));
|
||||
lv_obj_set_style_local_text_color(flashLight, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
|
||||
} else {
|
||||
lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
|
||||
lv_obj_set_style_local_text_color(flashLight, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xFFFFFF));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -76,4 +72,3 @@ bool FlashLight::Refresh() {
|
|||
bool FlashLight::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,21 +6,20 @@
|
|||
#include "systemtask/SystemTask.h"
|
||||
#include "components/brightness/BrightnessController.h"
|
||||
|
||||
|
||||
namespace Pinetime {
|
||||
|
||||
namespace Applications {
|
||||
namespace Screens {
|
||||
|
||||
class FlashLight : public Screen{
|
||||
class FlashLight : public Screen {
|
||||
public:
|
||||
FlashLight(DisplayApp* app, System::SystemTask &systemTask, Controllers::BrightnessController& brightness);
|
||||
FlashLight(DisplayApp* app, System::SystemTask& systemTask, Controllers::BrightnessController& brightness);
|
||||
~FlashLight() override;
|
||||
|
||||
bool Refresh() override;
|
||||
|
||||
bool OnTouchEvent(Pinetime::Applications::TouchEvents event) override;
|
||||
void OnClickEvent(lv_obj_t *obj, lv_event_t event);
|
||||
void OnClickEvent(lv_obj_t* obj, lv_event_t event);
|
||||
|
||||
private:
|
||||
Pinetime::System::SystemTask& systemTask;
|
||||
|
@ -29,7 +28,6 @@ namespace Pinetime {
|
|||
lv_obj_t* flashLight;
|
||||
lv_obj_t* backgroundAction;
|
||||
bool isOn = true;
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
using namespace Pinetime::Applications::Screens;
|
||||
|
||||
namespace {
|
||||
const char *ToString(Pinetime::Controllers::HeartRateController::States s) {
|
||||
const char* ToString(Pinetime::Controllers::HeartRateController::States s) {
|
||||
switch (s) {
|
||||
case Pinetime::Controllers::HeartRateController::States::NotEnoughData:
|
||||
return "Not enough data,\nplease wait...";
|
||||
|
@ -21,20 +21,22 @@ namespace {
|
|||
return "";
|
||||
}
|
||||
|
||||
static void btnStartStopEventHandler(lv_obj_t *obj, lv_event_t event) {
|
||||
HeartRate *screen = static_cast<HeartRate *>(obj->user_data);
|
||||
static void btnStartStopEventHandler(lv_obj_t* obj, lv_event_t event) {
|
||||
HeartRate* screen = static_cast<HeartRate*>(obj->user_data);
|
||||
screen->OnStartStopEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
HeartRate::HeartRate(Pinetime::Applications::DisplayApp *app, Controllers::HeartRateController& heartRateController, System::SystemTask &systemTask) :
|
||||
Screen(app), heartRateController{heartRateController}, systemTask{systemTask} {
|
||||
HeartRate::HeartRate(Pinetime::Applications::DisplayApp* app,
|
||||
Controllers::HeartRateController& heartRateController,
|
||||
System::SystemTask& systemTask)
|
||||
: Screen(app), heartRateController {heartRateController}, systemTask {systemTask} {
|
||||
bool isHrRunning = heartRateController.State() != Controllers::HeartRateController::States::Stopped;
|
||||
label_hr = lv_label_create(lv_scr_act(), nullptr);
|
||||
|
||||
lv_obj_set_style_local_text_font(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76);
|
||||
|
||||
if(isHrRunning)
|
||||
if (isHrRunning)
|
||||
lv_obj_set_style_local_text_color(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GREEN);
|
||||
else
|
||||
lv_obj_set_style_local_text_color(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
|
||||
|
@ -60,7 +62,7 @@ HeartRate::HeartRate(Pinetime::Applications::DisplayApp *app, Controllers::Heart
|
|||
|
||||
label_startStop = lv_label_create(btn_startStop, nullptr);
|
||||
UpdateStartStopButton(isHrRunning);
|
||||
if(isHrRunning)
|
||||
if (isHrRunning)
|
||||
systemTask.PushMessage(Pinetime::System::SystemTask::Messages::DisableSleeping);
|
||||
}
|
||||
|
||||
|
@ -72,10 +74,10 @@ HeartRate::~HeartRate() {
|
|||
bool HeartRate::Refresh() {
|
||||
|
||||
auto state = heartRateController.State();
|
||||
switch(state) {
|
||||
switch (state) {
|
||||
case Controllers::HeartRateController::States::NoTouch:
|
||||
case Controllers::HeartRateController::States::NotEnoughData:
|
||||
//case Controllers::HeartRateController::States::Stopped:
|
||||
// case Controllers::HeartRateController::States::Stopped:
|
||||
lv_label_set_text(label_hr, "000");
|
||||
break;
|
||||
default:
|
||||
|
@ -90,13 +92,12 @@ bool HeartRate::Refresh() {
|
|||
|
||||
void HeartRate::OnStartStopEvent(lv_event_t event) {
|
||||
if (event == LV_EVENT_CLICKED) {
|
||||
if(heartRateController.State() == Controllers::HeartRateController::States::Stopped) {
|
||||
if (heartRateController.State() == Controllers::HeartRateController::States::Stopped) {
|
||||
heartRateController.Start();
|
||||
UpdateStartStopButton(heartRateController.State() != Controllers::HeartRateController::States::Stopped);
|
||||
systemTask.PushMessage(Pinetime::System::SystemTask::Messages::DisableSleeping);
|
||||
lv_obj_set_style_local_text_color(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GREEN);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
heartRateController.Stop();
|
||||
UpdateStartStopButton(heartRateController.State() != Controllers::HeartRateController::States::Stopped);
|
||||
systemTask.PushMessage(Pinetime::System::SystemTask::Messages::EnableSleeping);
|
||||
|
@ -106,7 +107,7 @@ void HeartRate::OnStartStopEvent(lv_event_t event) {
|
|||
}
|
||||
|
||||
void HeartRate::UpdateStartStopButton(bool isRunning) {
|
||||
if(isRunning)
|
||||
if (isRunning)
|
||||
lv_label_set_text(label_startStop, "Stop");
|
||||
else
|
||||
lv_label_set_text(label_startStop, "Start");
|
||||
|
|
|
@ -15,9 +15,9 @@ namespace Pinetime {
|
|||
namespace Applications {
|
||||
namespace Screens {
|
||||
|
||||
class HeartRate : public Screen{
|
||||
class HeartRate : public Screen {
|
||||
public:
|
||||
HeartRate(DisplayApp* app, Controllers::HeartRateController& HeartRateController, System::SystemTask &systemTask);
|
||||
HeartRate(DisplayApp* app, Controllers::HeartRateController& HeartRateController, System::SystemTask& systemTask);
|
||||
~HeartRate() override;
|
||||
|
||||
bool Refresh() override;
|
||||
|
@ -33,9 +33,6 @@ namespace Pinetime {
|
|||
lv_obj_t* label_status;
|
||||
lv_obj_t* btn_startStop;
|
||||
lv_obj_t* label_startStop;
|
||||
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
using namespace Pinetime::Applications::Screens;
|
||||
|
||||
InfiniPaint::InfiniPaint(Pinetime::Applications::DisplayApp* app, Pinetime::Components::LittleVgl& lvgl) : Screen(app), lvgl{lvgl} {
|
||||
InfiniPaint::InfiniPaint(Pinetime::Applications::DisplayApp* app, Pinetime::Components::LittleVgl& lvgl) : Screen(app), lvgl {lvgl} {
|
||||
app->SetTouchMode(DisplayApp::TouchModes::Polling);
|
||||
std::fill(b, b + bufferSize, selectColor);
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ bool InfiniPaint::Refresh() {
|
|||
}
|
||||
|
||||
bool InfiniPaint::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
||||
switch(event) {
|
||||
switch (event) {
|
||||
case Pinetime::Applications::TouchEvents::LongTap:
|
||||
switch (color) {
|
||||
case 0:
|
||||
|
@ -72,4 +72,3 @@ bool InfiniPaint::OnTouchEvent(uint16_t x, uint16_t y) {
|
|||
lvgl.FlushDisplay(&area, b);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,6 @@ namespace Pinetime {
|
|||
lv_color_t b[bufferSize];
|
||||
lv_color_t selectColor = LV_COLOR_WHITE;
|
||||
uint8_t color = 2;
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,12 +2,10 @@
|
|||
|
||||
using namespace Pinetime::Applications::Screens;
|
||||
|
||||
Label::Label(uint8_t screenID, uint8_t numScreens,
|
||||
Pinetime::Applications::DisplayApp *app, lv_obj_t* labelText) :
|
||||
Screen(app),
|
||||
labelText{labelText} {
|
||||
Label::Label(uint8_t screenID, uint8_t numScreens, Pinetime::Applications::DisplayApp* app, lv_obj_t* labelText)
|
||||
: Screen(app), labelText {labelText} {
|
||||
|
||||
if ( numScreens > 1 ) {
|
||||
if (numScreens > 1) {
|
||||
pageIndicatorBasePoints[0].x = 240 - 1;
|
||||
pageIndicatorBasePoints[0].y = 6;
|
||||
pageIndicatorBasePoints[1].x = 240 - 1;
|
||||
|
@ -19,7 +17,6 @@ Label::Label(uint8_t screenID, uint8_t numScreens,
|
|||
lv_obj_set_style_local_line_rounded(pageIndicatorBase, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, true);
|
||||
lv_line_set_points(pageIndicatorBase, pageIndicatorBasePoints, 2);
|
||||
|
||||
|
||||
uint16_t indicatorSize = 228 / numScreens;
|
||||
uint16_t indicatorPos = indicatorSize * screenID;
|
||||
|
||||
|
@ -34,7 +31,6 @@ Label::Label(uint8_t screenID, uint8_t numScreens,
|
|||
lv_obj_set_style_local_line_rounded(pageIndicator, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, true);
|
||||
lv_line_set_points(pageIndicator, pageIndicatorPoints, 2);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Label::~Label() {
|
||||
|
|
|
@ -9,18 +9,15 @@ namespace Pinetime {
|
|||
|
||||
class Label : public Screen {
|
||||
public:
|
||||
Label( uint8_t screenID, uint8_t numScreens,
|
||||
DisplayApp* app, lv_obj_t* labelText );
|
||||
Label(uint8_t screenID, uint8_t numScreens, DisplayApp* app, lv_obj_t* labelText);
|
||||
~Label() override;
|
||||
|
||||
bool Refresh() override;
|
||||
|
||||
|
||||
private:
|
||||
|
||||
bool running = true;
|
||||
|
||||
lv_obj_t * labelText = nullptr;
|
||||
lv_obj_t* labelText = nullptr;
|
||||
lv_point_t pageIndicatorBasePoints[2];
|
||||
lv_point_t pageIndicatorPoints[2];
|
||||
lv_obj_t* pageIndicatorBase;
|
||||
|
|
|
@ -5,27 +5,26 @@
|
|||
using namespace Pinetime::Applications::Screens;
|
||||
|
||||
namespace {
|
||||
static void ButtonEventHandler(lv_obj_t * obj, lv_event_t event) {
|
||||
List* screen = static_cast<List *>(obj->user_data);
|
||||
static void ButtonEventHandler(lv_obj_t* obj, lv_event_t event) {
|
||||
List* screen = static_cast<List*>(obj->user_data);
|
||||
screen->OnButtonEvent(obj, event);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
List::List(uint8_t screenID, uint8_t numScreens,
|
||||
List::List(uint8_t screenID,
|
||||
uint8_t numScreens,
|
||||
DisplayApp* app,
|
||||
Controllers::Settings &settingsController,
|
||||
std::array<Applications, MAXLISTITEMS>& applications) :
|
||||
Screen(app),
|
||||
settingsController{settingsController}
|
||||
{
|
||||
Controllers::Settings& settingsController,
|
||||
std::array<Applications, MAXLISTITEMS>& applications)
|
||||
: Screen(app), settingsController {settingsController} {
|
||||
|
||||
// Set the background to Black
|
||||
lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, lv_color_make(0, 0, 0));
|
||||
|
||||
settingsController.SetSettingsMenu(screenID);
|
||||
|
||||
if ( numScreens > 1 ) {
|
||||
if (numScreens > 1) {
|
||||
pageIndicatorBasePoints[0].x = 240 - 1;
|
||||
pageIndicatorBasePoints[0].y = 6;
|
||||
pageIndicatorBasePoints[1].x = 240 - 1;
|
||||
|
@ -37,7 +36,6 @@ List::List(uint8_t screenID, uint8_t numScreens,
|
|||
lv_obj_set_style_local_line_rounded(pageIndicatorBase, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, true);
|
||||
lv_line_set_points(pageIndicatorBase, pageIndicatorBasePoints, 2);
|
||||
|
||||
|
||||
uint16_t indicatorSize = 228 / numScreens;
|
||||
uint16_t indicatorPos = indicatorSize * screenID;
|
||||
|
||||
|
@ -53,10 +51,9 @@ List::List(uint8_t screenID, uint8_t numScreens,
|
|||
lv_line_set_points(pageIndicator, pageIndicatorPoints, 2);
|
||||
}
|
||||
|
||||
|
||||
lv_obj_t* container1 = lv_cont_create(lv_scr_act(), nullptr);
|
||||
|
||||
//lv_obj_set_style_local_bg_color(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x111111));
|
||||
// lv_obj_set_style_local_bg_color(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x111111));
|
||||
lv_obj_set_style_local_bg_opa(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP);
|
||||
lv_obj_set_style_local_pad_all(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 10);
|
||||
lv_obj_set_style_local_pad_inner(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 5);
|
||||
|
@ -67,12 +64,12 @@ List::List(uint8_t screenID, uint8_t numScreens,
|
|||
lv_obj_set_height(container1, LV_VER_RES);
|
||||
lv_cont_set_layout(container1, LV_LAYOUT_COLUMN_LEFT);
|
||||
|
||||
lv_obj_t * labelBt;
|
||||
lv_obj_t * labelBtIco;
|
||||
lv_obj_t* labelBt;
|
||||
lv_obj_t* labelBtIco;
|
||||
|
||||
for(int i = 0; i < MAXLISTITEMS; i++) {
|
||||
for (int i = 0; i < MAXLISTITEMS; i++) {
|
||||
apps[i] = applications[i].application;
|
||||
if ( applications[i].application != Apps::None) {
|
||||
if (applications[i].application != Apps::None) {
|
||||
|
||||
itemApps[i] = lv_btn_create(container1, nullptr);
|
||||
lv_obj_set_style_local_bg_opa(itemApps[i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_20);
|
||||
|
@ -91,16 +88,14 @@ List::List(uint8_t screenID, uint8_t numScreens,
|
|||
|
||||
labelBt = lv_label_create(itemApps[i], nullptr);
|
||||
lv_label_set_text_fmt(labelBt, " %s", applications[i].name);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
lv_obj_t * backgroundLabel = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_t* backgroundLabel = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_label_set_long_mode(backgroundLabel, LV_LABEL_LONG_CROP);
|
||||
lv_obj_set_size(backgroundLabel, LV_HOR_RES, LV_VER_RES);
|
||||
lv_obj_set_pos(backgroundLabel, 0, 0);
|
||||
lv_label_set_text_static(backgroundLabel, "");
|
||||
|
||||
}
|
||||
|
||||
List::~List() {
|
||||
|
@ -112,10 +107,10 @@ bool List::Refresh() {
|
|||
return running;
|
||||
}
|
||||
|
||||
void List::OnButtonEvent(lv_obj_t * object, lv_event_t event) {
|
||||
if ( event == LV_EVENT_RELEASED ) {
|
||||
for(int i = 0; i < MAXLISTITEMS; i++) {
|
||||
if ( apps[i] != Apps::None && object == itemApps[i] ) {
|
||||
void List::OnButtonEvent(lv_obj_t* object, lv_event_t event) {
|
||||
if (event == LV_EVENT_RELEASED) {
|
||||
for (int i = 0; i < MAXLISTITEMS; i++) {
|
||||
if (apps[i] != Apps::None && object == itemApps[i]) {
|
||||
app->StartApp(apps[i], DisplayApp::FullRefreshDirections::Up);
|
||||
running = false;
|
||||
return;
|
||||
|
@ -123,4 +118,3 @@ void List::OnButtonEvent(lv_obj_t * object, lv_event_t event) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,8 @@ namespace Pinetime {
|
|||
Pinetime::Applications::Apps application;
|
||||
};
|
||||
|
||||
explicit List(uint8_t screenID, uint8_t numScreens,
|
||||
explicit List(uint8_t screenID,
|
||||
uint8_t numScreens,
|
||||
DisplayApp* app,
|
||||
Controllers::Settings& settingsController,
|
||||
std::array<Applications, MAXLISTITEMS>& applications);
|
||||
|
@ -28,21 +29,18 @@ namespace Pinetime {
|
|||
|
||||
bool Refresh() override;
|
||||
|
||||
|
||||
void OnButtonEvent(lv_obj_t *object, lv_event_t event);
|
||||
void OnButtonEvent(lv_obj_t* object, lv_event_t event);
|
||||
|
||||
private:
|
||||
|
||||
Controllers::Settings& settingsController;
|
||||
Pinetime::Applications::Apps apps[MAXLISTITEMS];
|
||||
|
||||
lv_obj_t * itemApps[MAXLISTITEMS];
|
||||
lv_obj_t* itemApps[MAXLISTITEMS];
|
||||
|
||||
lv_point_t pageIndicatorBasePoints[2];
|
||||
lv_point_t pageIndicatorPoints[2];
|
||||
lv_obj_t* pageIndicatorBase;
|
||||
lv_obj_t* pageIndicator;
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue