Merge branch 'develop' into update_touch_driver

This commit is contained in:
Riku Isokoski 2021-10-05 12:45:03 +03:00
commit f61e88b842
28 changed files with 110 additions and 107 deletions

View file

@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.10)
project(pinetime VERSION 1.4.0 LANGUAGES C CXX ASM)
project(pinetime VERSION 1.6.0 LANGUAGES C CXX ASM)
set(CMAKE_C_STANDARD 99)
set(CMAKE_CXX_STANDARD 14)

View file

@ -67,7 +67,7 @@ As of now, here is the list of achievements of this project:
* **[Experimental]** [WebBLEWatch](https://hubmartin.github.io/WebBLEWatch/) Synchronize time directly from your web browser. [video](https://youtu.be/IakiuhVDdrY)
* **[Experimental]** [Infini-iOS](https://github.com/xan-m/Infini-iOS) (on iOS)
- OTA (Over-the-air) update via BLE
- [Bootloader](https://github.com/JF002/pinetime-mcuboot-bootloader) based on [MCUBoot](https://juullabs-oss.github.io/mcuboot/)
- [Bootloader](https://github.com/JF002/pinetime-mcuboot-bootloader) based on [MCUBoot](https://www.mcuboot.com)
## Documentation

View file

@ -18,18 +18,18 @@ You want to fix a bug, add a cool new functionality or improve the code? See *Ho
The Pinetime is a cool open source project that deserves to be known. Talk about it around you, on social networks, on your blog,... and let people know that we are working on an open source firmware for a smartwatch!
# How to submit a pull request ?
# How to submit a pull request?
## TL;DR
- Create a branch from develop;
- Work on a single subject in this branch. Create multiple branches/pulls-requests if you want to work on multiple subjects (bugs, features,...);
- Test your modifications on the actual hardware;
- Check the code formatting against our coding conventions and [clang-format](../.clang-format) and [clang-tidy](../.clang-tidy);
- Clean your code and remove files that are not needed;
- Write documentation related to your new feature if applicable;
- Create a pull request and write a great description about it : what does your PR do, why, how,... Add pictures and video if possible;
- Wait for someone to review your PR and take part in the review process;
- Create a branch from develop
- Work on a single subject in this branch. Create multiple branches/pulls-requests if you want to work on multiple subjects (bugs, features,...)
- Test your modifications on the actual hardware
- Check the code formatting against our coding conventions and [clang-format](../.clang-format) and [clang-tidy](../.clang-tidy)
- Clean your code and remove files that are not needed
- Write documentation related to your new feature if applicable
- Create a pull request and write a great description about it: what does your PR do, why, how,... Add pictures and video if possible
- Wait for someone to review your PR and take part in the review process
- Your PR will eventually be merged :)
Your contributions are more than welcome!

View file

@ -17,6 +17,12 @@ void Battery::Update() {
isCharging = !nrf_gpio_pin_read(PinMap::Charging);
isPowerPresent = !nrf_gpio_pin_read(PinMap::PowerPresent);
if (isPowerPresent && !isCharging) {
isFull = true;
} else if (!isPowerPresent) {
isFull = false;
}
if (isReading) {
return;
}
@ -63,12 +69,12 @@ void Battery::SaadcEventHandler(nrfx_saadc_evt_t const* p_event) {
// p_event->data.done.p_buffer[0] = (adc_voltage / reference_voltage) * 1024
voltage = p_event->data.done.p_buffer[0] * (8 * 600) / 1024;
if (voltage > battery_max) {
if (isFull) {
percentRemaining = 100;
} else if (voltage < battery_min) {
percentRemaining = 0;
} else {
percentRemaining = (voltage - battery_min) * 100 / (battery_max - battery_min);
percentRemaining = std::min((voltage - battery_min) * 100 / (battery_max - battery_min), isCharging ? 99 : 100);
}
nrfx_saadc_uninit();

View file

@ -22,7 +22,9 @@ namespace Pinetime {
}
bool IsCharging() const {
return isCharging;
// isCharging will go up and down when fully charged
// isFull makes sure this returns false while fully charged.
return isCharging && !isFull;
}
bool IsPowerPresent() const {
@ -37,6 +39,7 @@ namespace Pinetime {
uint16_t voltage = 0;
uint8_t percentRemaining = 0;
bool isFull = false;
bool isCharging = false;
bool isPowerPresent = false;

View file

@ -43,7 +43,7 @@ int BatteryInformationService::OnBatteryServiceRequested(uint16_t connectionHand
ble_gatt_access_ctxt* context) {
if (attributeHandle == batteryLevelHandle) {
NRF_LOG_INFO("BATTERY : handle = %d", batteryLevelHandle);
static uint8_t batteryValue = batteryController.PercentRemaining();
uint8_t batteryValue = batteryController.PercentRemaining();
int res = os_mbuf_append(context->om, &batteryValue, 1);
return (res == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
}

View file

@ -79,14 +79,6 @@ bool NotificationManager::AreNewNotificationsAvailable() {
return newNotification;
}
bool NotificationManager::IsVibrationEnabled() {
return vibrationEnabled;
}
void NotificationManager::ToggleVibrations() {
vibrationEnabled = !vibrationEnabled;
}
bool NotificationManager::ClearNewNotificationFlag() {
return newNotification.exchange(false);
}

View file

@ -44,8 +44,6 @@ namespace Pinetime {
Notification GetPrevious(Notification::Id id);
bool ClearNewNotificationFlag();
bool AreNewNotificationsAvailable();
bool IsVibrationEnabled();
void ToggleVibrations();
static constexpr size_t MaximumMessageSize() {
return MessageSize;
@ -60,7 +58,6 @@ namespace Pinetime {
uint8_t writeIndex = 0;
bool empty = true;
std::atomic<bool> newNotification {false};
bool vibrationEnabled = true;
};
}
}

View file

@ -7,6 +7,7 @@ using namespace Pinetime::Controllers;
void DateTime::SetCurrentTime(std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> t) {
this->currentDateTime = t;
UpdateTime(previousSystickCounter); // Update internal state without updating the time
}
void DateTime::SetTime(

View file

@ -53,7 +53,7 @@ namespace Pinetime {
*
*/
static constexpr size_t startAddress = 0x0B4000;
static constexpr size_t size = 0x3C0000;
static constexpr size_t size = 0x34C000;
static constexpr size_t blockSize = 4096;
bool resourcesValid = false;

View file

@ -9,9 +9,6 @@ APP_TIMER_DEF(longVibTimer);
using namespace Pinetime::Controllers;
MotorController::MotorController(Controllers::Settings& settingsController) : settingsController {settingsController} {
}
void MotorController::Init() {
nrf_gpio_cfg_output(PinMap::Motor);
nrf_gpio_pin_set(PinMap::Motor);
@ -27,18 +24,11 @@ void MotorController::Ring(void* p_context) {
}
void MotorController::RunForDuration(uint8_t motorDuration) {
if (settingsController.GetVibrationStatus() == Controllers::Settings::Vibration::OFF) {
return;
}
nrf_gpio_pin_clear(PinMap::Motor);
app_timer_start(shortVibTimer, APP_TIMER_TICKS(motorDuration), nullptr);
}
void MotorController::StartRinging() {
if (settingsController.GetVibrationStatus() == Controllers::Settings::Vibration::OFF) {
return;
}
Ring(this);
app_timer_start(longVibTimer, APP_TIMER_TICKS(1000), this);
}

View file

@ -1,14 +1,14 @@
#pragma once
#include <cstdint>
#include "components/settings/Settings.h"
namespace Pinetime {
namespace Controllers {
class MotorController {
public:
MotorController(Controllers::Settings& settingsController);
MotorController() = default;
void Init();
void RunForDuration(uint8_t motorDuration);
void StartRinging();
@ -16,7 +16,6 @@ namespace Pinetime {
private:
static void Ring(void* p_context);
Controllers::Settings& settingsController;
static void StopMotor(void* p_context);
};
}

View file

@ -11,7 +11,7 @@ namespace Pinetime {
class Settings {
public:
enum class ClockType : uint8_t { H24, H12 };
enum class Vibration : uint8_t { ON, OFF };
enum class Notification : uint8_t { ON, OFF };
enum class WakeUpMode : uint8_t {
SingleTap = 0,
DoubleTap = 1,
@ -93,14 +93,14 @@ namespace Pinetime {
return settings.clockType;
};
void SetVibrationStatus(Vibration status) {
if (status != settings.vibrationStatus) {
void SetNotificationStatus(Notification status) {
if (status != settings.notificationStatus) {
settingsChanged = true;
}
settings.vibrationStatus = status;
settings.notificationStatus = status;
};
Vibration GetVibrationStatus() const {
return settings.vibrationStatus;
Notification GetNotificationStatus() const {
return settings.notificationStatus;
};
void SetScreenTimeOut(uint32_t timeout) {
@ -170,7 +170,7 @@ namespace Pinetime {
uint32_t screenTimeOut = 15000;
ClockType clockType = ClockType::H24;
Vibration vibrationStatus = Vibration::ON;
Notification notificationStatus = Notification::ON;
uint8_t clockFace = 0;

View file

@ -147,19 +147,15 @@ void DisplayApp::InitHw() {
void DisplayApp::Refresh() {
TickType_t queueTimeout;
TickType_t delta;
switch (state) {
case States::Idle:
IdleState();
queueTimeout = portMAX_DELAY;
break;
case States::Running:
RunningState();
delta = xTaskGetTickCount() - lastWakeTime;
if (delta > LV_DISP_DEF_REFR_PERIOD) {
delta = LV_DISP_DEF_REFR_PERIOD;
if (!currentScreen->IsRunning()) {
LoadApp(returnToApp, returnDirection);
}
queueTimeout = LV_DISP_DEF_REFR_PERIOD - delta;
queueTimeout = lv_task_handler();
break;
default:
queueTimeout = portMAX_DELAY;
@ -167,9 +163,7 @@ void DisplayApp::Refresh() {
}
Messages msg;
bool messageReceived = xQueueReceive(msgQueue, &msg, queueTimeout);
lastWakeTime = xTaskGetTickCount();
if (messageReceived) {
if (xQueueReceive(msgQueue, &msg, queueTimeout)) {
switch (msg) {
case Messages::DimScreen:
// Backup brightness is the brightness to return to after dimming or sleeping
@ -285,13 +279,6 @@ void DisplayApp::Refresh() {
}
}
void DisplayApp::RunningState() {
if (!currentScreen->IsRunning()) {
LoadApp(returnToApp, returnDirection);
}
lv_task_handler();
}
void DisplayApp::StartApp(Apps app, DisplayApp::FullRefreshDirections direction) {
nextApp = app;
nextDirection = direction;
@ -441,9 +428,6 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction)
currentApp = app;
}
void DisplayApp::IdleState() {
}
void DisplayApp::PushMessage(Messages msg) {
if (in_isr()) {
BaseType_t xHigherPriorityTaskWoken;

View file

@ -108,8 +108,6 @@ namespace Pinetime {
TouchEvents returnTouchEvent = TouchEvents::None;
TouchEvents GetGesture();
void RunningState();
void IdleState();
static void Process(void* instance);
void InitHw();
void Refresh();
@ -119,8 +117,6 @@ namespace Pinetime {
Apps nextApp = Apps::None;
DisplayApp::FullRefreshDirections nextDirection;
TickType_t lastWakeTime;
System::BootErrors bootError;
};
}

View file

@ -58,7 +58,7 @@ void BatteryInfo::Refresh() {
batteryPercent = batteryController.PercentRemaining();
batteryVoltage = batteryController.Voltage();
if (batteryController.IsCharging() and batteryPercent < 100) {
if (batteryController.IsCharging()) {
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");
} else if (batteryPercent == 100) {

View file

@ -78,7 +78,7 @@ Metronome::~Metronome() {
void Metronome::Refresh() {
if (metronomeStarted) {
if (xTaskGetTickCount() - startTime > 60 * configTICK_RATE_HZ / bpm) {
if (xTaskGetTickCount() - startTime > 60u * configTICK_RATE_HZ / static_cast<uint16_t>(bpm)) {
startTime += 60 * configTICK_RATE_HZ / bpm;
counter--;
if (counter == 0) {

View file

@ -129,10 +129,6 @@ bool Notifications::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
alertNotificationService);
}
return true;
case Pinetime::Applications::TouchEvents::LongTap: {
// notificationManager.ToggleVibrations();
return true;
}
default:
return false;
}

View file

@ -100,10 +100,7 @@ PineTimeStyle::PineTimeStyle(DisplayApp* app,
lv_obj_set_style_local_text_color(batteryIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
lv_label_set_text(batteryIcon, Symbols::batteryFull);
lv_obj_align(batteryIcon, sidebar, LV_ALIGN_IN_TOP_MID, 0, 2);
batteryPlug = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(batteryPlug, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
lv_obj_align(batteryPlug, sidebar, LV_ALIGN_IN_TOP_MID, 0, 2);
lv_obj_set_auto_realign(batteryIcon, true);
bleIcon = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(bleIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
@ -205,18 +202,24 @@ PineTimeStyle::~PineTimeStyle() {
lv_obj_clean(lv_scr_act());
}
void PineTimeStyle::SetBatteryIcon() {
auto batteryPercent = batteryPercentRemaining.Get();
lv_label_set_text(batteryIcon, BatteryIcon::GetBatteryIcon(batteryPercent));
}
void PineTimeStyle::Refresh() {
batteryPercentRemaining = batteryController.PercentRemaining();
if (batteryPercentRemaining.IsUpdated()) {
auto batteryPercent = batteryPercentRemaining.Get();
if (batteryController.IsCharging()) {
auto isCharging = batteryController.IsCharging() || batteryController.IsPowerPresent();
lv_label_set_text(batteryPlug, BatteryIcon::GetPlugIcon(isCharging));
lv_obj_realign(batteryPlug);
lv_label_set_text(batteryIcon, "");
isCharging = batteryController.IsCharging();
if (isCharging.IsUpdated()) {
if (isCharging.Get()) {
lv_label_set_text(batteryIcon, Symbols::plug);
} else {
lv_label_set_text(batteryIcon, BatteryIcon::GetBatteryIcon(batteryPercent));
lv_label_set_text(batteryPlug, "");
SetBatteryIcon();
}
}
if (!isCharging.Get()) {
batteryPercentRemaining = batteryController.PercentRemaining();
if (batteryPercentRemaining.IsUpdated()) {
SetBatteryIcon();
}
}

View file

@ -41,6 +41,7 @@ namespace Pinetime {
uint8_t currentDay = 0;
DirtyValue<uint8_t> batteryPercentRemaining {};
DirtyValue<bool> isCharging {};
DirtyValue<bool> bleState {};
DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>> currentDateTime {};
DirtyValue<bool> motionSensorOk {};
@ -58,7 +59,6 @@ namespace Pinetime {
lv_obj_t* backgroundLabel;
lv_obj_t* batteryIcon;
lv_obj_t* bleIcon;
lv_obj_t* batteryPlug;
lv_obj_t* calendarOuter;
lv_obj_t* calendarInner;
lv_obj_t* calendarBar1;
@ -76,6 +76,8 @@ namespace Pinetime {
Controllers::Settings& settingsController;
Controllers::MotionController& motionController;
void SetBatteryIcon();
lv_task_t* taskRefresh;
};
}

View file

@ -68,6 +68,7 @@ WatchFaceAnalog::WatchFaceAnalog(Pinetime::Applications::DisplayApp* app,
batteryIcon = lv_label_create(lv_scr_act(), nullptr);
lv_label_set_text(batteryIcon, Symbols::batteryHalf);
lv_obj_align(batteryIcon, NULL, LV_ALIGN_IN_TOP_RIGHT, 0, 0);
lv_obj_set_auto_realign(batteryIcon, true);
notificationIcon = lv_label_create(lv_scr_act(), NULL);
lv_obj_set_style_local_text_color(notificationIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x00FF00));
@ -176,11 +177,31 @@ void WatchFaceAnalog::UpdateClock() {
}
}
void WatchFaceAnalog::SetBatteryIcon() {
auto batteryPercent = batteryPercentRemaining.Get();
if (batteryPercent == 100) {
lv_obj_set_style_local_text_color(batteryIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GREEN);
} else {
lv_obj_set_style_local_text_color(batteryIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
}
lv_label_set_text(batteryIcon, BatteryIcon::GetBatteryIcon(batteryPercent));
}
void WatchFaceAnalog::Refresh() {
batteryPercentRemaining = batteryController.PercentRemaining();
if (batteryPercentRemaining.IsUpdated()) {
auto batteryPercent = batteryPercentRemaining.Get();
lv_label_set_text(batteryIcon, BatteryIcon::GetBatteryIcon(batteryPercent));
isCharging = batteryController.IsCharging();
if (isCharging.IsUpdated()) {
if (isCharging.Get()) {
lv_obj_set_style_local_text_color(batteryIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED);
lv_label_set_text(batteryIcon, Symbols::plug);
} else {
SetBatteryIcon();
}
}
if (!isCharging.Get()) {
batteryPercentRemaining = batteryController.PercentRemaining();
if (batteryPercentRemaining.IsUpdated()) {
SetBatteryIcon();
}
}
notificationState = notificationManager.AreNewNotificationsAvailable();

View file

@ -49,6 +49,7 @@ namespace Pinetime {
uint8_t currentDay = 0;
DirtyValue<uint8_t> batteryPercentRemaining {0};
DirtyValue<bool> isCharging {};
DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>> currentDateTime;
DirtyValue<bool> notificationState {false};
@ -81,6 +82,7 @@ namespace Pinetime {
Controllers::Settings& settingsController;
void UpdateClock();
void SetBatteryIcon();
lv_task_t* taskRefresh;
};

View file

@ -102,12 +102,20 @@ WatchFaceDigital::~WatchFaceDigital() {
}
void WatchFaceDigital::Refresh() {
powerPresent = batteryController.IsPowerPresent();
if (powerPresent.IsUpdated()) {
lv_label_set_text(batteryPlug, BatteryIcon::GetPlugIcon(powerPresent.Get()));
}
batteryPercentRemaining = batteryController.PercentRemaining();
if (batteryPercentRemaining.IsUpdated()) {
auto batteryPercent = batteryPercentRemaining.Get();
if (batteryPercent == 100) {
lv_obj_set_style_local_text_color(batteryIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GREEN);
} else {
lv_obj_set_style_local_text_color(batteryIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
}
lv_label_set_text(batteryIcon, BatteryIcon::GetBatteryIcon(batteryPercent));
auto isCharging = batteryController.IsCharging() or batteryController.IsPowerPresent();
lv_label_set_text(batteryPlug, BatteryIcon::GetPlugIcon(isCharging));
}
bleState = bleController.IsConnected();

View file

@ -44,6 +44,7 @@ namespace Pinetime {
uint8_t currentDay = 0;
DirtyValue<uint8_t> batteryPercentRemaining {};
DirtyValue<bool> powerPresent {};
DirtyValue<bool> bleState {};
DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>> currentDateTime {};
DirtyValue<bool> motionSensorOk {};

View file

@ -88,7 +88,7 @@ QuickSettings::QuickSettings(Pinetime::Applications::DisplayApp* app,
btn3_lvl = lv_label_create(btn3, nullptr);
lv_obj_set_style_local_text_font(btn3_lvl, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &lv_font_sys_48);
if (settingsController.GetVibrationStatus() == Controllers::Settings::Vibration::ON) {
if (settingsController.GetNotificationStatus() == Controllers::Settings::Notification::ON) {
lv_obj_add_state(btn3, LV_STATE_CHECKED);
lv_label_set_text_static(btn3_lvl, Symbols::notificationsOn);
} else {
@ -142,11 +142,11 @@ void QuickSettings::OnButtonEvent(lv_obj_t* object, lv_event_t event) {
} else if (object == btn3 && event == LV_EVENT_VALUE_CHANGED) {
if (lv_obj_get_state(btn3, LV_BTN_PART_MAIN) & LV_STATE_CHECKED) {
settingsController.SetVibrationStatus(Controllers::Settings::Vibration::ON);
settingsController.SetNotificationStatus(Controllers::Settings::Notification::ON);
motorController.RunForDuration(35);
lv_label_set_text_static(btn3_lvl, Symbols::notificationsOn);
} else {
settingsController.SetVibrationStatus(Controllers::Settings::Vibration::OFF);
settingsController.SetNotificationStatus(Controllers::Settings::Notification::OFF);
lv_label_set_text_static(btn3_lvl, Symbols::notificationsOff);
}

View file

@ -51,7 +51,7 @@ static inline void ble_ll_rfmgmt_reset(void) { }
static inline void ble_ll_rfmgmt_scan_changed(bool e, uint32_t n) { }
static inline void ble_ll_rfmgmt_sched_changed(struct ble_ll_sched_item *f) { }
static inline void ble_ll_rfmgmt_release(void) { }
static inline uint32_t ble_ll_rfmgmt_enable_now(void) { return 0; }
static inline uint32_t ble_ll_rfmgmt_enable_now(void) { return os_cputime_get32(); }
static inline bool ble_ll_rfmgmt_is_enabled(void) { return true; }
#endif

View file

@ -113,7 +113,7 @@ Pinetime::Controllers::TouchHandler touchHandler(touchPanel, lvgl);
Pinetime::Controllers::FS fs {spiNorFlash};
Pinetime::Controllers::Settings settingsController {fs};
Pinetime::Controllers::MotorController motorController {settingsController};
Pinetime::Controllers::MotorController motorController {};
Pinetime::Applications::DisplayApp displayApp(lcd,
lvgl,

View file

@ -274,10 +274,12 @@ void SystemTask::Work() {
displayApp.PushMessage(Pinetime::Applications::Display::Messages::UpdateDateTime);
break;
case Messages::OnNewNotification:
if (isSleeping && !isWakingUp) {
GoToRunning();
if (settingsController.GetNotificationStatus() == Pinetime::Controllers::Settings::Notification::ON) {
if (isSleeping && !isWakingUp) {
GoToRunning();
}
displayApp.PushMessage(Pinetime::Applications::Display::Messages::NewNotification);
}
displayApp.PushMessage(Pinetime::Applications::Display::Messages::NewNotification);
break;
case Messages::OnTimerDone:
if (isSleeping && !isWakingUp) {