Merge remote-tracking branch 'upstream/develop' into pinetimestyle-colorpicker

This commit is contained in:
Kieran Cawthray 2021-07-20 15:30:07 +02:00
commit db784fc2fb
27 changed files with 156 additions and 158 deletions

View File

@ -77,7 +77,7 @@
#define configENABLE_BACKWARD_COMPATIBILITY 1 #define configENABLE_BACKWARD_COMPATIBILITY 1
/* Hook function related definitions. */ /* Hook function related definitions. */
#define configUSE_IDLE_HOOK 1 #define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 0 #define configUSE_TICK_HOOK 0
#define configCHECK_FOR_STACK_OVERFLOW 0 #define configCHECK_FOR_STACK_OVERFLOW 0
#define configUSE_MALLOC_FAILED_HOOK 0 #define configUSE_MALLOC_FAILED_HOOK 0

View File

@ -1,9 +1,7 @@
#include "BatteryController.h" #include "BatteryController.h"
#include <hal/nrf_gpio.h> #include <hal/nrf_gpio.h>
#include <nrfx_saadc.h> #include <nrfx_saadc.h>
#include <libraries/log/nrf_log.h>
#include <algorithm> #include <algorithm>
#include <math.h>
using namespace Pinetime::Controllers; using namespace Pinetime::Controllers;
@ -18,7 +16,6 @@ void Battery::Init() {
} }
void Battery::Update() { void Battery::Update() {
isCharging = !nrf_gpio_pin_read(chargingPin); isCharging = !nrf_gpio_pin_read(chargingPin);
isPowerPresent = !nrf_gpio_pin_read(powerPresentPin); isPowerPresent = !nrf_gpio_pin_read(powerPresentPin);
@ -33,13 +30,13 @@ void Battery::Update() {
nrfx_saadc_sample(); nrfx_saadc_sample();
} }
void Battery::adcCallbackStatic(nrfx_saadc_evt_t const* event) { void Battery::AdcCallbackStatic(nrfx_saadc_evt_t const* event) {
instance->SaadcEventHandler(event); instance->SaadcEventHandler(event);
} }
void Battery::SaadcInit() { void Battery::SaadcInit() {
nrfx_saadc_config_t adcConfig = NRFX_SAADC_DEFAULT_CONFIG; nrfx_saadc_config_t adcConfig = NRFX_SAADC_DEFAULT_CONFIG;
APP_ERROR_CHECK(nrfx_saadc_init(&adcConfig, adcCallbackStatic)); APP_ERROR_CHECK(nrfx_saadc_init(&adcConfig, AdcCallbackStatic));
nrf_saadc_channel_config_t adcChannelConfig = {.resistor_p = NRF_SAADC_RESISTOR_DISABLED, nrf_saadc_channel_config_t adcChannelConfig = {.resistor_p = NRF_SAADC_RESISTOR_DISABLED,
.resistor_n = NRF_SAADC_RESISTOR_DISABLED, .resistor_n = NRF_SAADC_RESISTOR_DISABLED,
@ -55,7 +52,6 @@ void Battery::SaadcInit() {
} }
void Battery::SaadcEventHandler(nrfx_saadc_evt_t const* p_event) { void Battery::SaadcEventHandler(nrfx_saadc_evt_t const* p_event) {
const uint16_t battery_max = 4180; // maximum voltage of battery ( max charging voltage is 4.21 ) const uint16_t battery_max = 4180; // maximum voltage of battery ( max charging voltage is 4.21 )
const uint16_t battery_min = 3200; // minimum voltage of battery before shutdown ( depends on the battery ) const uint16_t battery_min = 3200; // minimum voltage of battery before shutdown ( depends on the battery )
@ -69,13 +65,10 @@ void Battery::SaadcEventHandler(nrfx_saadc_evt_t const* p_event) {
// reference_voltage is 0.6V // reference_voltage is 0.6V
// p_event->data.done.p_buffer[0] = (adc_voltage / reference_voltage) * 1024 // p_event->data.done.p_buffer[0] = (adc_voltage / reference_voltage) * 1024
voltage = p_event->data.done.p_buffer[0] * 6000 / 1024; voltage = p_event->data.done.p_buffer[0] * 6000 / 1024;
percentRemaining = (voltage - battery_min) * 100 / (battery_max - battery_min); percentRemaining = (voltage - battery_min) * 100 / (battery_max - battery_min);
percentRemaining = std::max(percentRemaining, 0); percentRemaining = std::max(percentRemaining, 0);
percentRemaining = std::min(percentRemaining, 100); percentRemaining = std::min(percentRemaining, 100);
percentRemainingBuffer.Insert(percentRemaining);
percentRemainingBuffer.insert(percentRemaining);
samples++; samples++;
if (samples > percentRemainingSamples) { if (samples > percentRemainingSamples) {

View File

@ -19,7 +19,7 @@ namespace Pinetime {
insert member function overwrites the next data to the current insert member function overwrites the next data to the current
HEAD and moves the HEAD to the newly inserted value. HEAD and moves the HEAD to the newly inserted value.
*/ */
void insert(const int num) { void Insert(const uint8_t num) {
head %= cap; head %= cap;
arr[head++] = num; arr[head++] = num;
if (sz != cap) { if (sz != cap) {
@ -27,13 +27,13 @@ namespace Pinetime {
} }
} }
int GetAverage() const { uint8_t GetAverage() const {
int sum = std::accumulate(arr.begin(), arr.end(), 0); int sum = std::accumulate(arr.begin(), arr.end(), 0);
return (sum / sz); return static_cast<uint8_t>(sum / sz);
} }
private: private:
std::array<int, N> arr; /**< internal array used to store the values*/ std::array<uint8_t, N> arr; /**< internal array used to store the values*/
uint8_t sz; /**< The current size of the array.*/ uint8_t sz; /**< The current size of the array.*/
uint8_t cap; /**< Total capacity of the CircBuffer.*/ uint8_t cap; /**< Total capacity of the CircBuffer.*/
uint8_t head; /**< The current head of the CircBuffer*/ uint8_t head; /**< The current head of the CircBuffer*/
@ -46,8 +46,11 @@ namespace Pinetime {
void Init(); void Init();
void Update(); void Update();
int PercentRemaining() const { uint8_t PercentRemaining() const {
return percentRemainingBuffer.GetAverage(); auto avg = percentRemainingBuffer.GetAverage();
avg = std::min(avg, static_cast<uint8_t>(100));
avg = std::max(avg, static_cast<uint8_t>(0));
return avg;
} }
uint16_t Voltage() const { uint16_t Voltage() const {
@ -57,6 +60,7 @@ namespace Pinetime {
bool IsCharging() const { bool IsCharging() const {
return isCharging; return isCharging;
} }
bool IsPowerPresent() const { bool IsPowerPresent() const {
return isPowerPresent; return isPowerPresent;
} }
@ -80,7 +84,7 @@ namespace Pinetime {
void SaadcInit(); void SaadcInit();
void SaadcEventHandler(nrfx_saadc_evt_t const* p_event); void SaadcEventHandler(nrfx_saadc_evt_t const* p_event);
static void adcCallbackStatic(nrfx_saadc_evt_t const* event); static void AdcCallbackStatic(nrfx_saadc_evt_t const* event);
bool isReading = false; bool isReading = false;
uint8_t samples = 0; uint8_t samples = 0;

View File

@ -17,7 +17,7 @@ BatteryInformationService::BatteryInformationService(Controllers::Battery& batte
characteristicDefinition {{.uuid = (ble_uuid_t*) &batteryLevelUuid, characteristicDefinition {{.uuid = (ble_uuid_t*) &batteryLevelUuid,
.access_cb = BatteryInformationServiceCallback, .access_cb = BatteryInformationServiceCallback,
.arg = this, .arg = this,
.flags = BLE_GATT_CHR_F_READ, .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY,
.val_handle = &batteryLevelHandle}, .val_handle = &batteryLevelHandle},
{0}}, {0}},
serviceDefinition { serviceDefinition {
@ -49,3 +49,7 @@ int BatteryInformationService::OnBatteryServiceRequested(uint16_t connectionHand
} }
return 0; return 0;
} }
void BatteryInformationService::NotifyBatteryLevel(uint16_t connectionHandle, uint8_t level) {
auto* om = ble_hs_mbuf_from_flat(&level, 1);
ble_gattc_notify_custom(connectionHandle, batteryLevelHandle, om);
}

View File

@ -17,7 +17,7 @@ namespace Pinetime {
void Init(); 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);
void NotifyBatteryLevel(uint16_t connectionHandle, uint8_t level);
private: private:
Controllers::Battery& batteryController; Controllers::Battery& batteryController;
static constexpr uint16_t batteryInformationServiceId {0x180F}; static constexpr uint16_t batteryInformationServiceId {0x180F};

View File

@ -235,3 +235,9 @@ void NimbleController::StartDiscovery() {
uint16_t NimbleController::connHandle() { uint16_t NimbleController::connHandle() {
return connectionHandle; return connectionHandle;
} }
void NimbleController::NotifyBatteryLevel(uint8_t level) {
if(connectionHandle != BLE_HS_CONN_HANDLE_NONE) {
batteryInformationService.NotifyBatteryLevel(connectionHandle, level);
}
}

View File

@ -70,6 +70,7 @@ namespace Pinetime {
}; };
uint16_t connHandle(); uint16_t connHandle();
void NotifyBatteryLevel(uint8_t level);
private: private:
static constexpr const char* deviceName = "InfiniTime"; static constexpr const char* deviceName = "InfiniTime";
@ -92,7 +93,7 @@ namespace Pinetime {
HeartRateService heartRateService; HeartRateService heartRateService;
uint8_t addrType; // 1 = Random, 0 = PUBLIC uint8_t addrType; // 1 = Random, 0 = PUBLIC
uint16_t connectionHandle = 0; uint16_t connectionHandle = BLE_HS_CONN_HANDLE_NONE;
ble_uuid128_t dfuServiceUuid { ble_uuid128_t dfuServiceUuid {
.u {.type = BLE_UUID_TYPE_128}, .u {.type = BLE_UUID_TYPE_128},

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include <cstdint> #include <cstdint>
#include <bitset>
#include "components/datetime/DateTimeController.h" #include "components/datetime/DateTimeController.h"
#include "components/brightness/BrightnessController.h" #include "components/brightness/BrightnessController.h"
#include "components/fs/FS.h" #include "components/fs/FS.h"
@ -11,7 +12,11 @@ namespace Pinetime {
public: public:
enum class ClockType : uint8_t { H24, H12 }; enum class ClockType : uint8_t { H24, H12 };
enum class Vibration : uint8_t { ON, OFF }; enum class Vibration : uint8_t { ON, OFF };
enum class WakeUpMode : uint8_t { None, SingleTap, DoubleTap, RaiseWrist }; enum class WakeUpMode : uint8_t {
SingleTap = 0,
DoubleTap = 1,
RaiseWrist = 2,
};
Settings(Pinetime::Controllers::FS& fs); Settings(Pinetime::Controllers::FS& fs);
@ -99,15 +104,33 @@ namespace Pinetime {
return settings.screenTimeOut; return settings.screenTimeOut;
}; };
void setWakeUpMode(WakeUpMode wakeUp) { void setWakeUpMode(WakeUpMode wakeUp, bool enabled) {
if (wakeUp != settings.wakeUpMode) { if (!isWakeUpModeOn(wakeUp)) {
settingsChanged = true; settingsChanged = true;
} }
settings.wakeUpMode = wakeUp; settings.wakeUpMode.set(static_cast<size_t>(wakeUp), enabled);
// Handle special behavior
if (enabled) {
switch (wakeUp) {
case WakeUpMode::SingleTap:
settings.wakeUpMode.set(static_cast<size_t>(WakeUpMode::DoubleTap), false);
break;
case WakeUpMode::DoubleTap:
settings.wakeUpMode.set(static_cast<size_t>(WakeUpMode::SingleTap), false);
break;
case WakeUpMode::RaiseWrist:
break;
}
}
}; };
WakeUpMode getWakeUpMode() const {
std::bitset<3> getWakeUpModes() const {
return settings.wakeUpMode; return settings.wakeUpMode;
}; }
bool isWakeUpModeOn(const WakeUpMode mode) const {
return getWakeUpModes()[static_cast<size_t>(mode)];
}
void SetBrightness(Controllers::BrightnessController::Levels level) { void SetBrightness(Controllers::BrightnessController::Levels level) {
if (level != settings.brightLevel) { if (level != settings.brightLevel) {
@ -147,7 +170,7 @@ namespace Pinetime {
uint8_t PTSColorBar = 11; uint8_t PTSColorBar = 11;
uint8_t PTSColorBG = 3; uint8_t PTSColorBG = 3;
WakeUpMode wakeUpMode = WakeUpMode::None; std::bitset<3> wakeUpMode {0};
Controllers::BrightnessController::Levels brightLevel = Controllers::BrightnessController::Levels::Medium; Controllers::BrightnessController::Levels brightLevel = Controllers::BrightnessController::Levels::Medium;
}; };

View File

@ -44,6 +44,8 @@
#include "displayapp/screens/settings/SettingSteps.h" #include "displayapp/screens/settings/SettingSteps.h"
#include "displayapp/screens/settings/SettingPineTimeStyle.h" #include "displayapp/screens/settings/SettingPineTimeStyle.h"
#include "libs/lv_conf.h"
using namespace Pinetime::Applications; using namespace Pinetime::Applications;
using namespace Pinetime::Applications::Display; using namespace Pinetime::Applications::Display;
@ -115,6 +117,7 @@ uint32_t count = 0;
bool toggle = true; bool toggle = true;
void DisplayApp::Refresh() { void DisplayApp::Refresh() {
TickType_t queueTimeout; TickType_t queueTimeout;
TickType_t delta;
switch (state) { switch (state) {
case States::Idle: case States::Idle:
IdleState(); IdleState();
@ -122,7 +125,11 @@ void DisplayApp::Refresh() {
break; break;
case States::Running: case States::Running:
RunningState(); RunningState();
queueTimeout = 20; delta = xTaskGetTickCount() - lastWakeTime;
if (delta > LV_DISP_DEF_REFR_PERIOD) {
delta = LV_DISP_DEF_REFR_PERIOD;
}
queueTimeout = LV_DISP_DEF_REFR_PERIOD - delta;
break; break;
default: default:
queueTimeout = portMAX_DELAY; queueTimeout = portMAX_DELAY;
@ -130,7 +137,9 @@ void DisplayApp::Refresh() {
} }
Messages msg; Messages msg;
if (xQueueReceive(msgQueue, &msg, queueTimeout)) { bool messageReceived = xQueueReceive(msgQueue, &msg, queueTimeout);
lastWakeTime = xTaskGetTickCount();
if (messageReceived) {
switch (msg) { switch (msg) {
case Messages::GoToSleep: case Messages::GoToSleep:
brightnessController.Backup(); brightnessController.Backup();

View File

@ -114,6 +114,7 @@ namespace Pinetime {
Apps nextApp = Apps::None; Apps nextApp = Apps::None;
DisplayApp::FullRefreshDirections nextDirection; DisplayApp::FullRefreshDirections nextDirection;
TickType_t lastWakeTime;
}; };
} }
} }

View File

@ -1,9 +1,10 @@
#include <cstdint>
#include "BatteryIcon.h" #include "BatteryIcon.h"
#include "Symbols.h" #include "Symbols.h"
using namespace Pinetime::Applications::Screens; using namespace Pinetime::Applications::Screens;
const char* BatteryIcon::GetBatteryIcon(int batteryPercent) { const char* BatteryIcon::GetBatteryIcon(uint8_t batteryPercent) {
if (batteryPercent > 90) if (batteryPercent > 90)
return Symbols::batteryFull; return Symbols::batteryFull;
if (batteryPercent > 75) if (batteryPercent > 75)

View File

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

View File

@ -9,11 +9,6 @@ static void lv_update_task(struct _lv_task_t* task) {
user_data->UpdateScreen(); user_data->UpdateScreen();
} }
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) BatteryInfo::BatteryInfo(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Battery& batteryController)
: Screen(app), batteryController {batteryController} { : Screen(app), batteryController {batteryController} {
@ -24,12 +19,12 @@ BatteryInfo::BatteryInfo(Pinetime::Applications::DisplayApp* app, Pinetime::Cont
lv_obj_set_size(charging_bar, 200, 15); lv_obj_set_size(charging_bar, 200, 15);
lv_bar_set_range(charging_bar, 0, 100); lv_bar_set_range(charging_bar, 0, 100);
lv_obj_align(charging_bar, nullptr, LV_ALIGN_CENTER, 0, 10); lv_obj_align(charging_bar, nullptr, LV_ALIGN_CENTER, 0, 10);
lv_bar_set_anim_time(charging_bar, 2000); lv_bar_set_anim_time(charging_bar, 1000);
lv_obj_set_style_local_radius(charging_bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); lv_obj_set_style_local_radius(charging_bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, lv_color_hex(0x222222)); lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, lv_color_hex(0x222222));
lv_obj_set_style_local_bg_opa(charging_bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, LV_OPA_100); lv_obj_set_style_local_bg_opa(charging_bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, LV_OPA_100);
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, lv_color_hex(0xFF0000)); lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, lv_color_hex(0xFF0000));
lv_bar_set_value(charging_bar, batteryPercent, LV_ANIM_OFF); lv_bar_set_value(charging_bar, batteryPercent, LV_ANIM_ON);
status = lv_label_create(lv_scr_act(), nullptr); status = lv_label_create(lv_scr_act(), nullptr);
lv_label_set_text_static(status, "Reading Battery status"); lv_label_set_text_static(status, "Reading Battery status");
@ -38,11 +33,7 @@ BatteryInfo::BatteryInfo(Pinetime::Applications::DisplayApp* app, Pinetime::Cont
percent = lv_label_create(lv_scr_act(), nullptr); percent = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_font(percent, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76); lv_obj_set_style_local_text_font(percent, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76);
if (batteryPercent >= 0) { lv_label_set_text_fmt(percent, "%02i%%", batteryPercent);
lv_label_set_text_fmt(percent, "%02i%%", batteryPercent);
} else {
lv_label_set_text(percent, "--%");
}
lv_label_set_align(percent, LV_LABEL_ALIGN_LEFT); lv_label_set_align(percent, LV_LABEL_ALIGN_LEFT);
lv_obj_align(percent, nullptr, LV_ALIGN_CENTER, 0, -60); lv_obj_align(percent, nullptr, LV_ALIGN_CENTER, 0, -60);
@ -58,40 +49,15 @@ BatteryInfo::BatteryInfo(Pinetime::Applications::DisplayApp* app, Pinetime::Cont
lv_obj_set_pos(backgroundLabel, 0, 0); lv_obj_set_pos(backgroundLabel, 0, 0);
lv_label_set_text_static(backgroundLabel, ""); lv_label_set_text_static(backgroundLabel, "");
taskUpdate = lv_task_create(lv_update_task, 500000, LV_TASK_PRIO_LOW, this); taskUpdate = lv_task_create(lv_update_task, 5000, LV_TASK_PRIO_LOW, this);
taskAnim = lv_task_create(lv_anim_task, 1000, LV_TASK_PRIO_LOW, this);
UpdateScreen(); UpdateScreen();
} }
BatteryInfo::~BatteryInfo() { BatteryInfo::~BatteryInfo() {
lv_task_del(taskUpdate); lv_task_del(taskUpdate);
lv_task_del(taskAnim);
lv_obj_clean(lv_scr_act()); lv_obj_clean(lv_scr_act());
} }
void BatteryInfo::UpdateAnim() {
batteryPercent = batteryController.PercentRemaining();
if (batteryPercent >= 0) {
if (batteryController.IsCharging() and batteryPercent < 100) {
animation += 1;
if (animation >= 100) {
animation = 0;
}
} else {
if (animation > batteryPercent) {
animation--;
}
if (animation < batteryPercent) {
animation++;
}
}
lv_bar_set_value(charging_bar, animation, LV_ANIM_OFF);
}
}
void BatteryInfo::UpdateScreen() { void BatteryInfo::UpdateScreen() {
batteryController.Update(); batteryController.Update();
@ -99,33 +65,27 @@ void BatteryInfo::UpdateScreen() {
batteryPercent = batteryController.PercentRemaining(); batteryPercent = batteryController.PercentRemaining();
batteryVoltage = batteryController.Voltage(); batteryVoltage = batteryController.Voltage();
if (batteryPercent >= 0) { if (batteryController.IsCharging() and batteryPercent < 100) {
if (batteryController.IsCharging() and batteryPercent < 100) { lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_RED);
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_RED); lv_label_set_text_static(status, "Charging");
lv_label_set_text_static(status, "Charging"); } else if (batteryPercent == 100) {
} else if (batteryPercent == 100) { lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_BLUE);
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_BLUE); lv_label_set_text_static(status, "Fully charged");
lv_label_set_text_static(status, "Fully charged"); } else if (batteryPercent < 10) {
} else if (batteryPercent < 10) { lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_YELLOW);
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_YELLOW); lv_label_set_text_static(status, "Battery low");
lv_label_set_text_static(status, "Battery 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, "Discharging");
}
lv_label_set_text_fmt(percent, "%02i%%", batteryPercent);
} else { } else {
lv_label_set_text_static(status, "Reading Battery status"); lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_GREEN);
lv_label_set_text(percent, "--%"); lv_label_set_text_static(status, "Discharging");
} }
lv_label_set_text_fmt(percent, "%02i%%", batteryPercent);
lv_obj_align(status, charging_bar, LV_ALIGN_OUT_BOTTOM_MID, 0, 20); lv_obj_align(status, charging_bar, LV_ALIGN_OUT_BOTTOM_MID, 0, 20);
lv_label_set_text_fmt(voltage, "%1i.%02i volts", batteryVoltage / 1000, batteryVoltage % 1000 / 10); lv_label_set_text_fmt(voltage, "%1i.%02i volts", batteryVoltage / 1000, batteryVoltage % 1000 / 10);
lv_bar_set_value(charging_bar, batteryPercent, LV_ANIM_ON);
} }
bool BatteryInfo::Refresh() { bool BatteryInfo::Refresh() {
return running; return running;
} }

View File

@ -22,7 +22,6 @@ namespace Pinetime {
bool Refresh() override; bool Refresh() override;
void UpdateScreen(); void UpdateScreen();
void UpdateAnim();
private: private:
Pinetime::Controllers::Battery& batteryController; Pinetime::Controllers::Battery& batteryController;
@ -33,10 +32,8 @@ namespace Pinetime {
lv_obj_t* status; lv_obj_t* status;
lv_task_t* taskUpdate; lv_task_t* taskUpdate;
lv_task_t* taskAnim;
int8_t animation = 0; uint8_t batteryPercent = 0;
int8_t batteryPercent = -1;
uint16_t batteryVoltage = 0; uint16_t batteryVoltage = 0;
}; };
} }

View File

@ -42,7 +42,7 @@ namespace Pinetime {
Pinetime::Controllers::DateTime::Days currentDayOfWeek = Pinetime::Controllers::DateTime::Days::Unknown; Pinetime::Controllers::DateTime::Days currentDayOfWeek = Pinetime::Controllers::DateTime::Days::Unknown;
uint8_t currentDay = 0; uint8_t currentDay = 0;
DirtyValue<int> batteryPercentRemaining {}; DirtyValue<uint8_t> batteryPercentRemaining {};
DirtyValue<bool> bleState {}; DirtyValue<bool> bleState {};
DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>> currentDateTime {}; DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>> currentDateTime {};
DirtyValue<bool> motionSensorOk {}; DirtyValue<bool> motionSensorOk {};

View File

@ -103,7 +103,7 @@ std::unique_ptr<Screen> SystemInfo::CreateScreen1() {
} }
std::unique_ptr<Screen> SystemInfo::CreateScreen2() { std::unique_ptr<Screen> SystemInfo::CreateScreen2() {
auto batteryPercent = static_cast<uint8_t>(batteryController.PercentRemaining()); auto batteryPercent = batteryController.PercentRemaining();
auto resetReason = [this]() { auto resetReason = [this]() {
switch (watchdog.ResetReason()) { switch (watchdog.ResetReason()) {
case Drivers::Watchdog::ResetReasons::Watchdog: case Drivers::Watchdog::ResetReasons::Watchdog:

View File

@ -107,7 +107,7 @@ Tile::Tile(uint8_t screenID,
lv_obj_set_pos(backgroundLabel, 0, 0); lv_obj_set_pos(backgroundLabel, 0, 0);
lv_label_set_text_static(backgroundLabel, ""); lv_label_set_text_static(backgroundLabel, "");
taskUpdate = lv_task_create(lv_update_task, 500000, LV_TASK_PRIO_MID, this); taskUpdate = lv_task_create(lv_update_task, 5000, LV_TASK_PRIO_MID, this);
} }
Tile::~Tile() { Tile::~Tile() {

View File

@ -177,7 +177,6 @@ void WatchFaceAnalog::UpdateClock() {
} }
bool WatchFaceAnalog::Refresh() { bool WatchFaceAnalog::Refresh() {
batteryPercentRemaining = batteryController.PercentRemaining(); batteryPercentRemaining = batteryController.PercentRemaining();
if (batteryPercentRemaining.IsUpdated()) { if (batteryPercentRemaining.IsUpdated()) {
auto batteryPercent = batteryPercentRemaining.Get(); auto batteryPercent = batteryPercentRemaining.Get();

View File

@ -48,7 +48,7 @@ namespace Pinetime {
Pinetime::Controllers::DateTime::Days currentDayOfWeek = Pinetime::Controllers::DateTime::Days::Unknown; Pinetime::Controllers::DateTime::Days currentDayOfWeek = Pinetime::Controllers::DateTime::Days::Unknown;
uint8_t currentDay = 0; uint8_t currentDay = 0;
DirtyValue<float> batteryPercentRemaining {0}; DirtyValue<uint8_t> batteryPercentRemaining {0};
DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>> currentDateTime; DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>> currentDateTime;
DirtyValue<bool> notificationState {false}; DirtyValue<bool> notificationState {false};

View File

@ -45,7 +45,7 @@ namespace Pinetime {
Pinetime::Controllers::DateTime::Days currentDayOfWeek = Pinetime::Controllers::DateTime::Days::Unknown; Pinetime::Controllers::DateTime::Days currentDayOfWeek = Pinetime::Controllers::DateTime::Days::Unknown;
uint8_t currentDay = 0; uint8_t currentDay = 0;
DirtyValue<int> batteryPercentRemaining {}; DirtyValue<uint8_t> batteryPercentRemaining {};
DirtyValue<bool> bleState {}; DirtyValue<bool> bleState {};
DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>> currentDateTime {}; DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>> currentDateTime {};
DirtyValue<bool> motionSensorOk {}; DirtyValue<bool> motionSensorOk {};

View File

@ -110,7 +110,7 @@ QuickSettings::QuickSettings(Pinetime::Applications::DisplayApp* app,
lv_obj_set_pos(backgroundLabel, 0, 0); lv_obj_set_pos(backgroundLabel, 0, 0);
lv_label_set_text_static(backgroundLabel, ""); lv_label_set_text_static(backgroundLabel, "");
taskUpdate = lv_task_create(lv_update_task, 500000, LV_TASK_PRIO_MID, this); taskUpdate = lv_task_create(lv_update_task, 5000, LV_TASK_PRIO_MID, this);
} }
QuickSettings::~QuickSettings() { QuickSettings::~QuickSettings() {

View File

@ -16,7 +16,7 @@ namespace {
SettingWakeUp::SettingWakeUp(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Settings& settingsController) SettingWakeUp::SettingWakeUp(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Settings& settingsController)
: Screen(app), settingsController {settingsController} { : Screen(app), settingsController {settingsController} {
ignoringEvents = false;
lv_obj_t* container1 = lv_cont_create(lv_scr_act(), nullptr); lv_obj_t* container1 = lv_cont_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_bg_opa(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP); lv_obj_set_style_local_bg_opa(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP);
@ -42,18 +42,10 @@ SettingWakeUp::SettingWakeUp(Pinetime::Applications::DisplayApp* app, Pinetime::
optionsTotal = 0; optionsTotal = 0;
cbOption[optionsTotal] = lv_checkbox_create(container1, nullptr); cbOption[optionsTotal] = lv_checkbox_create(container1, nullptr);
lv_checkbox_set_text_static(cbOption[optionsTotal], " None");
cbOption[optionsTotal]->user_data = this;
lv_obj_set_event_cb(cbOption[optionsTotal], event_handler);
if (settingsController.getWakeUpMode() == Pinetime::Controllers::Settings::WakeUpMode::None) {
lv_checkbox_set_checked(cbOption[optionsTotal], true);
}
optionsTotal++;
cbOption[optionsTotal] = lv_checkbox_create(container1, nullptr);
lv_checkbox_set_text_static(cbOption[optionsTotal], " Single Tap"); lv_checkbox_set_text_static(cbOption[optionsTotal], " Single Tap");
cbOption[optionsTotal]->user_data = this; cbOption[optionsTotal]->user_data = this;
lv_obj_set_event_cb(cbOption[optionsTotal], event_handler); lv_obj_set_event_cb(cbOption[optionsTotal], event_handler);
if (settingsController.getWakeUpMode() == Pinetime::Controllers::Settings::WakeUpMode::SingleTap) { if (settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::SingleTap)) {
lv_checkbox_set_checked(cbOption[optionsTotal], true); lv_checkbox_set_checked(cbOption[optionsTotal], true);
} }
optionsTotal++; optionsTotal++;
@ -61,7 +53,7 @@ SettingWakeUp::SettingWakeUp(Pinetime::Applications::DisplayApp* app, Pinetime::
lv_checkbox_set_text_static(cbOption[optionsTotal], " Double Tap"); lv_checkbox_set_text_static(cbOption[optionsTotal], " Double Tap");
cbOption[optionsTotal]->user_data = this; cbOption[optionsTotal]->user_data = this;
lv_obj_set_event_cb(cbOption[optionsTotal], event_handler); lv_obj_set_event_cb(cbOption[optionsTotal], event_handler);
if (settingsController.getWakeUpMode() == Pinetime::Controllers::Settings::WakeUpMode::DoubleTap) { if (settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::DoubleTap)) {
lv_checkbox_set_checked(cbOption[optionsTotal], true); lv_checkbox_set_checked(cbOption[optionsTotal], true);
} }
optionsTotal++; optionsTotal++;
@ -69,7 +61,7 @@ SettingWakeUp::SettingWakeUp(Pinetime::Applications::DisplayApp* app, Pinetime::
lv_checkbox_set_text_static(cbOption[optionsTotal], " Raise Wrist"); lv_checkbox_set_text_static(cbOption[optionsTotal], " Raise Wrist");
cbOption[optionsTotal]->user_data = this; cbOption[optionsTotal]->user_data = this;
lv_obj_set_event_cb(cbOption[optionsTotal], event_handler); lv_obj_set_event_cb(cbOption[optionsTotal], event_handler);
if (settingsController.getWakeUpMode() == Pinetime::Controllers::Settings::WakeUpMode::RaiseWrist) { if (settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::RaiseWrist)) {
lv_checkbox_set_checked(cbOption[optionsTotal], true); lv_checkbox_set_checked(cbOption[optionsTotal], true);
} }
optionsTotal++; optionsTotal++;
@ -85,27 +77,31 @@ bool SettingWakeUp::Refresh() {
} }
void SettingWakeUp::UpdateSelected(lv_obj_t* object, lv_event_t event) { void SettingWakeUp::UpdateSelected(lv_obj_t* object, lv_event_t event) {
if (event == LV_EVENT_VALUE_CHANGED) { using WakeUpMode = Pinetime::Controllers::Settings::WakeUpMode;
for (int i = 0; i < optionsTotal; i++) { if (event == LV_EVENT_VALUE_CHANGED && !ignoringEvents) {
if (object == cbOption[i]) { ignoringEvents = true;
lv_checkbox_set_checked(cbOption[i], true);
if (i == 0) { // Find the index of the checkbox that triggered the event
settingsController.setWakeUpMode(Pinetime::Controllers::Settings::WakeUpMode::None); int index = 0;
}; for (; index < optionsTotal; ++index) {
if (i == 1) { if (cbOption[index] == object) {
settingsController.setWakeUpMode(Pinetime::Controllers::Settings::WakeUpMode::SingleTap); break;
};
if (i == 2) {
settingsController.setWakeUpMode(Pinetime::Controllers::Settings::WakeUpMode::DoubleTap);
};
if (i == 3) {
settingsController.setWakeUpMode(Pinetime::Controllers::Settings::WakeUpMode::RaiseWrist);
};
} else {
lv_checkbox_set_checked(cbOption[i], false);
} }
} }
// Toggle needed wakeup mode
auto mode = static_cast<WakeUpMode>(index);
auto currentState = settingsController.isWakeUpModeOn(mode);
settingsController.setWakeUpMode(mode, !currentState);
// Update checkbox according to current wakeup modes.
// This is needed because we can have extra logic when setting or unsetting wakeup modes,
// for example, when setting SingleTap, DoubleTap is unset and vice versa.
auto modes = settingsController.getWakeUpModes();
for (int i = 0; i < optionsTotal; ++i) {
lv_checkbox_set_checked(cbOption[i], modes[i]);
}
ignoringEvents = false;
} }
} }

View File

@ -22,6 +22,11 @@ namespace Pinetime {
Controllers::Settings& settingsController; Controllers::Settings& settingsController;
uint8_t optionsTotal; uint8_t optionsTotal;
lv_obj_t* cbOption[4]; lv_obj_t* cbOption[4];
// When UpdateSelected is called, it uses lv_checkbox_set_checked,
// which can cause extra events to be fired,
// which might trigger UpdateSelected again, causing a loop.
// This variable is used as a mutex to prevent that.
bool ignoringEvents;
}; };
} }
} }

View File

@ -42,7 +42,7 @@
/* Default display refresh period. /* Default display refresh period.
* Can be changed in the display driver (`lv_disp_drv_t`).*/ * Can be changed in the display driver (`lv_disp_drv_t`).*/
#define LV_DISP_DEF_REFR_PERIOD 30 /*[ms]*/ #define LV_DISP_DEF_REFR_PERIOD 20 /*[ms]*/
/* Dot Per Inch: used to initialize default sizes. /* Dot Per Inch: used to initialize default sizes.
* E.g. a button with width = LV_DPI / 2 -> half inch wide * E.g. a button with width = LV_DPI / 2 -> half inch wide
@ -112,7 +112,7 @@ typedef int16_t lv_coord_t;
* Can be changed in the Input device driver (`lv_indev_drv_t`)*/ * Can be changed in the Input device driver (`lv_indev_drv_t`)*/
/* Input device read period in milliseconds */ /* Input device read period in milliseconds */
#define LV_INDEV_DEF_READ_PERIOD 30 #define LV_INDEV_DEF_READ_PERIOD 20
/* Drag threshold in pixels */ /* Drag threshold in pixels */
#define LV_INDEV_DEF_DRAG_LIMIT 10 #define LV_INDEV_DEF_DRAG_LIMIT 10
@ -128,7 +128,6 @@ typedef int16_t lv_coord_t;
* Time between `LV_EVENT_LONG_PRESSED_REPEAT */ * Time between `LV_EVENT_LONG_PRESSED_REPEAT */
#define LV_INDEV_DEF_LONG_PRESS_REP_TIME 100 #define LV_INDEV_DEF_LONG_PRESS_REP_TIME 100
/* Gesture threshold in pixels */ /* Gesture threshold in pixels */
#define LV_INDEV_DEF_GESTURE_LIMIT 50 #define LV_INDEV_DEF_GESTURE_LIMIT 50
@ -293,10 +292,10 @@ typedef void* lv_img_decoder_user_data_t;
/* 1: use a custom tick source. /* 1: use a custom tick source.
* It removes the need to manually update the tick with `lv_tick_inc`) */ * It removes the need to manually update the tick with `lv_tick_inc`) */
#define LV_TICK_CUSTOM 0 #define LV_TICK_CUSTOM 1
#if LV_TICK_CUSTOM == 1 #if LV_TICK_CUSTOM == 1
#define LV_TICK_CUSTOM_INCLUDE "Arduino.h" /*Header for the system time function*/ #define LV_TICK_CUSTOM_INCLUDE "FreeRTOS.h" /*Header for the system time function*/
#define LV_TICK_CUSTOM_SYS_TIME_EXPR (millis()) /*Expression evaluating to current system time in ms*/ #define LV_TICK_CUSTOM_SYS_TIME_EXPR (xTaskGetTickCount()) /*Expression evaluating to current system time in ms*/
#endif /*LV_TICK_CUSTOM*/ #endif /*LV_TICK_CUSTOM*/
typedef void* lv_disp_drv_user_data_t; /*Type of user data in the display driver*/ typedef void* lv_disp_drv_user_data_t; /*Type of user data in the display driver*/

View File

@ -178,13 +178,6 @@ void nrfx_gpiote_evt_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action
portYIELD_FROM_ISR(xHigherPriorityTaskWoken); portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
} }
extern "C" {
void vApplicationIdleHook(void) {
if (!isFactory)
lv_tick_inc(1);
}
}
void DebounceTimerChargeCallback(TimerHandle_t xTimer) { void DebounceTimerChargeCallback(TimerHandle_t xTimer) {
xTimerStop(xTimer, 0); xTimerStop(xTimer, 0);
systemTask.PushMessage(Pinetime::System::Messages::OnChargingEvent); systemTask.PushMessage(Pinetime::System::Messages::OnChargingEvent);

View File

@ -211,7 +211,7 @@ void SystemTask::Work() {
twiMaster.Wakeup(); twiMaster.Wakeup();
// Double Tap needs the touch screen to be in normal mode // Double Tap needs the touch screen to be in normal mode
if (settingsController.getWakeUpMode() != Pinetime::Controllers::Settings::WakeUpMode::DoubleTap) { if (!settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::DoubleTap)) {
touchPanel.Wakeup(); touchPanel.Wakeup();
} }
@ -232,9 +232,9 @@ void SystemTask::Work() {
auto touchInfo = touchPanel.GetTouchInfo(); auto touchInfo = touchPanel.GetTouchInfo();
twiMaster.Sleep(); twiMaster.Sleep();
if (touchInfo.isTouch and ((touchInfo.gesture == Pinetime::Drivers::Cst816S::Gestures::DoubleTap and if (touchInfo.isTouch and ((touchInfo.gesture == Pinetime::Drivers::Cst816S::Gestures::DoubleTap and
settingsController.getWakeUpMode() == Pinetime::Controllers::Settings::WakeUpMode::DoubleTap) or settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::DoubleTap)) or
(touchInfo.gesture == Pinetime::Drivers::Cst816S::Gestures::SingleTap and (touchInfo.gesture == Pinetime::Drivers::Cst816S::Gestures::SingleTap and
settingsController.getWakeUpMode() == Pinetime::Controllers::Settings::WakeUpMode::SingleTap))) { settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::SingleTap)))) {
GoToRunning(); GoToRunning();
} }
} break; } break;
@ -296,7 +296,7 @@ void SystemTask::Work() {
spi.Sleep(); spi.Sleep();
// Double Tap needs the touch screen to be in normal mode // Double Tap needs the touch screen to be in normal mode
if (settingsController.getWakeUpMode() != Pinetime::Controllers::Settings::WakeUpMode::DoubleTap) { if (!settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::DoubleTap)) {
touchPanel.Sleep(); touchPanel.Sleep();
} }
twiMaster.Sleep(); twiMaster.Sleep();
@ -330,6 +330,11 @@ void SystemTask::Work() {
} }
} }
if (xTaskGetTickCount() - batteryNotificationTick > batteryNotificationPeriod) {
nimbleController.NotifyBatteryLevel(batteryController.PercentRemaining());
batteryNotificationTick = xTaskGetTickCount();
}
monitor.Process(); monitor.Process();
uint32_t systick_counter = nrf_rtc_counter_get(portNRF_RTC_REG); uint32_t systick_counter = nrf_rtc_counter_get(portNRF_RTC_REG);
dateTimeController.UpdateTime(systick_counter); dateTimeController.UpdateTime(systick_counter);
@ -343,7 +348,7 @@ void SystemTask::UpdateMotion() {
if (isGoingToSleep or isWakingUp) if (isGoingToSleep or isWakingUp)
return; return;
if (isSleeping && settingsController.getWakeUpMode() != Pinetime::Controllers::Settings::WakeUpMode::RaiseWrist) if (isSleeping && !settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::RaiseWrist))
return; return;
if (isSleeping) if (isSleeping)
@ -394,10 +399,10 @@ void SystemTask::OnTouchEvent() {
PushMessage(Messages::OnTouchEvent); PushMessage(Messages::OnTouchEvent);
displayApp.PushMessage(Pinetime::Applications::Display::Messages::TouchEvent); displayApp.PushMessage(Pinetime::Applications::Display::Messages::TouchEvent);
} else if (!isWakingUp) { } else if (!isWakingUp) {
if (settingsController.getWakeUpMode() == Pinetime::Controllers::Settings::WakeUpMode::None or if (settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::SingleTap) or
settingsController.getWakeUpMode() == Pinetime::Controllers::Settings::WakeUpMode::RaiseWrist) settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::DoubleTap)) {
return; PushMessage(Messages::TouchWakeUp);
PushMessage(Messages::TouchWakeUp); }
} }
} }

View File

@ -135,6 +135,8 @@ namespace Pinetime {
void GoToRunning(); void GoToRunning();
void UpdateMotion(); void UpdateMotion();
bool stepCounterMustBeReset = false; bool stepCounterMustBeReset = false;
static constexpr TickType_t batteryNotificationPeriod = 1000 * 60 * 10; // 1 tick ~= 1ms. 1ms * 60 * 10 = 10 minutes
TickType_t batteryNotificationTick = 0;
#if configUSE_TRACE_FACILITY == 1 #if configUSE_TRACE_FACILITY == 1
SystemMonitor<FreeRtosMonitor> monitor; SystemMonitor<FreeRtosMonitor> monitor;