mirror of
https://github.com/InfiniTimeOrg/InfiniTime.git
synced 2024-10-22 15:11:51 +02:00
Compare commits
16 commits
bb5c06f81f
...
f0211e5fcb
Author | SHA1 | Date | |
---|---|---|---|
f0211e5fcb | |||
8f3b7b1f41 | |||
56e98195df | |||
a2356f2f4a | |||
3db4e012ce | |||
a0cd439efc | |||
997e4cee8c | |||
ad3bf49c7b | |||
7ca0418c82 | |||
c3d05901a0 | |||
b3756e45fa | |||
a266202831 | |||
c8236afbef | |||
5040733a97 | |||
fd019c7aad | |||
975bfc5420 |
|
@ -402,6 +402,7 @@ list(APPEND SOURCE_FILES
|
|||
displayapp/widgets/PageIndicator.cpp
|
||||
displayapp/widgets/DotIndicator.cpp
|
||||
displayapp/widgets/StatusIcons.cpp
|
||||
displayapp/widgets/PopupMessage.cpp
|
||||
|
||||
## Settings
|
||||
displayapp/screens/settings/QuickSettings.cpp
|
||||
|
@ -478,6 +479,7 @@ list(APPEND SOURCE_FILES
|
|||
|
||||
systemtask/SystemTask.cpp
|
||||
systemtask/SystemMonitor.cpp
|
||||
systemtask/WakeLock.cpp
|
||||
drivers/TwiMaster.cpp
|
||||
|
||||
heartratetask/HeartRateTask.cpp
|
||||
|
@ -542,6 +544,7 @@ list(APPEND RECOVERY_SOURCE_FILES
|
|||
|
||||
systemtask/SystemTask.cpp
|
||||
systemtask/SystemMonitor.cpp
|
||||
systemtask/WakeLock.cpp
|
||||
drivers/TwiMaster.cpp
|
||||
components/rle/RleDecoder.cpp
|
||||
components/heartrate/HeartRateController.cpp
|
||||
|
@ -660,6 +663,7 @@ set(INCLUDE_FILES
|
|||
displayapp/InfiniTimeTheme.h
|
||||
systemtask/SystemTask.h
|
||||
systemtask/SystemMonitor.h
|
||||
systemtask/WakeLock.h
|
||||
displayapp/screens/Symbols.h
|
||||
drivers/TwiMaster.h
|
||||
heartratetask/HeartRateTask.h
|
||||
|
@ -860,7 +864,6 @@ target_compile_options(nrf-sdk PRIVATE
|
|||
$<$<CONFIG:RELEASE>: ${RELEASE_FLAGS}>
|
||||
$<$<COMPILE_LANGUAGE:CXX>: ${CXX_FLAGS}>
|
||||
$<$<COMPILE_LANGUAGE:ASM>: ${ASM_FLAGS}>
|
||||
-O3
|
||||
)
|
||||
|
||||
# NimBLE
|
||||
|
|
|
@ -62,7 +62,7 @@
|
|||
#define configTICK_RATE_HZ 1024
|
||||
#define configMAX_PRIORITIES (3)
|
||||
#define configMINIMAL_STACK_SIZE (120)
|
||||
#define configTOTAL_HEAP_SIZE (1024 * 40)
|
||||
#define configTOTAL_HEAP_SIZE (1024 * 35)
|
||||
#define configMAX_TASK_NAME_LEN (4)
|
||||
#define configUSE_16_BIT_TICKS 0
|
||||
#define configIDLE_SHOULD_YIELD 1
|
||||
|
|
|
@ -19,11 +19,13 @@
|
|||
#include "systemtask/SystemTask.h"
|
||||
#include "task.h"
|
||||
#include <chrono>
|
||||
#include <libraries/log/nrf_log.h>
|
||||
|
||||
using namespace Pinetime::Controllers;
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
AlarmController::AlarmController(Controllers::DateTime& dateTimeController) : dateTimeController {dateTimeController} {
|
||||
AlarmController::AlarmController(Controllers::DateTime& dateTimeController, Controllers::FS& fs)
|
||||
: dateTimeController {dateTimeController}, fs {fs} {
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
@ -36,11 +38,28 @@ namespace {
|
|||
void AlarmController::Init(System::SystemTask* systemTask) {
|
||||
this->systemTask = systemTask;
|
||||
alarmTimer = xTimerCreate("Alarm", 1, pdFALSE, this, SetOffAlarm);
|
||||
LoadSettingsFromFile();
|
||||
if (alarm.isEnabled) {
|
||||
NRF_LOG_INFO("[AlarmController] Loaded alarm was enabled, scheduling");
|
||||
ScheduleAlarm();
|
||||
}
|
||||
}
|
||||
|
||||
void AlarmController::SaveAlarm() {
|
||||
// verify if it is necessary to save
|
||||
if (alarmChanged) {
|
||||
SaveSettingsToFile();
|
||||
}
|
||||
alarmChanged = false;
|
||||
}
|
||||
|
||||
void AlarmController::SetAlarmTime(uint8_t alarmHr, uint8_t alarmMin) {
|
||||
hours = alarmHr;
|
||||
minutes = alarmMin;
|
||||
if (alarm.hours == alarmHr && alarm.minutes == alarmMin) {
|
||||
return;
|
||||
}
|
||||
alarm.hours = alarmHr;
|
||||
alarm.minutes = alarmMin;
|
||||
alarmChanged = true;
|
||||
}
|
||||
|
||||
void AlarmController::ScheduleAlarm() {
|
||||
|
@ -53,18 +72,19 @@ void AlarmController::ScheduleAlarm() {
|
|||
tm* tmAlarmTime = std::localtime(&ttAlarmTime);
|
||||
|
||||
// If the time being set has already passed today,the alarm should be set for tomorrow
|
||||
if (hours < dateTimeController.Hours() || (hours == dateTimeController.Hours() && minutes <= dateTimeController.Minutes())) {
|
||||
if (alarm.hours < dateTimeController.Hours() ||
|
||||
(alarm.hours == dateTimeController.Hours() && alarm.minutes <= dateTimeController.Minutes())) {
|
||||
tmAlarmTime->tm_mday += 1;
|
||||
// tm_wday doesn't update automatically
|
||||
tmAlarmTime->tm_wday = (tmAlarmTime->tm_wday + 1) % 7;
|
||||
}
|
||||
|
||||
tmAlarmTime->tm_hour = hours;
|
||||
tmAlarmTime->tm_min = minutes;
|
||||
tmAlarmTime->tm_hour = alarm.hours;
|
||||
tmAlarmTime->tm_min = alarm.minutes;
|
||||
tmAlarmTime->tm_sec = 0;
|
||||
|
||||
// if alarm is in weekday-only mode, make sure it shifts to the next weekday
|
||||
if (recurrence == RecurType::Weekdays) {
|
||||
if (alarm.recurrence == RecurType::Weekdays) {
|
||||
if (tmAlarmTime->tm_wday == 0) { // Sunday, shift 1 day
|
||||
tmAlarmTime->tm_mday += 1;
|
||||
} else if (tmAlarmTime->tm_wday == 6) { // Saturday, shift 2 days
|
||||
|
@ -79,7 +99,10 @@ void AlarmController::ScheduleAlarm() {
|
|||
xTimerChangePeriod(alarmTimer, secondsToAlarm * configTICK_RATE_HZ, 0);
|
||||
xTimerStart(alarmTimer, 0);
|
||||
|
||||
state = AlarmState::Set;
|
||||
if (!alarm.isEnabled) {
|
||||
alarm.isEnabled = true;
|
||||
alarmChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t AlarmController::SecondsToAlarm() const {
|
||||
|
@ -88,20 +111,72 @@ uint32_t AlarmController::SecondsToAlarm() const {
|
|||
|
||||
void AlarmController::DisableAlarm() {
|
||||
xTimerStop(alarmTimer, 0);
|
||||
state = AlarmState::Not_Set;
|
||||
isAlerting = false;
|
||||
if (alarm.isEnabled) {
|
||||
alarm.isEnabled = false;
|
||||
alarmChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
void AlarmController::SetOffAlarmNow() {
|
||||
state = AlarmState::Alerting;
|
||||
isAlerting = true;
|
||||
systemTask->PushMessage(System::Messages::SetOffAlarm);
|
||||
}
|
||||
|
||||
void AlarmController::StopAlerting() {
|
||||
// Alarm state is off unless this is a recurring alarm
|
||||
if (recurrence == RecurType::None) {
|
||||
state = AlarmState::Not_Set;
|
||||
isAlerting = false;
|
||||
// Disable alarm unless it is recurring
|
||||
if (alarm.recurrence == RecurType::None) {
|
||||
alarm.isEnabled = false;
|
||||
alarmChanged = true;
|
||||
} else {
|
||||
// set next instance
|
||||
ScheduleAlarm();
|
||||
}
|
||||
}
|
||||
|
||||
void AlarmController::SetRecurrence(RecurType recurrence) {
|
||||
if (alarm.recurrence != recurrence) {
|
||||
alarm.recurrence = recurrence;
|
||||
alarmChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
void AlarmController::LoadSettingsFromFile() {
|
||||
lfs_file_t alarmFile;
|
||||
AlarmSettings alarmBuffer;
|
||||
|
||||
if (fs.FileOpen(&alarmFile, "/.system/alarm.dat", LFS_O_RDONLY) != LFS_ERR_OK) {
|
||||
NRF_LOG_WARNING("[AlarmController] Failed to open alarm data file");
|
||||
return;
|
||||
}
|
||||
|
||||
fs.FileRead(&alarmFile, reinterpret_cast<uint8_t*>(&alarmBuffer), sizeof(alarmBuffer));
|
||||
fs.FileClose(&alarmFile);
|
||||
if (alarmBuffer.version != alarmFormatVersion) {
|
||||
NRF_LOG_WARNING("[AlarmController] Loaded alarm settings has version %u instead of %u, discarding",
|
||||
alarmBuffer.version,
|
||||
alarmFormatVersion);
|
||||
return;
|
||||
}
|
||||
|
||||
alarm = alarmBuffer;
|
||||
NRF_LOG_INFO("[AlarmController] Loaded alarm settings from file");
|
||||
}
|
||||
|
||||
void AlarmController::SaveSettingsToFile() const {
|
||||
lfs_dir systemDir;
|
||||
if (fs.DirOpen("/.system", &systemDir) != LFS_ERR_OK) {
|
||||
fs.DirCreate("/.system");
|
||||
}
|
||||
fs.DirClose(&systemDir);
|
||||
lfs_file_t alarmFile;
|
||||
if (fs.FileOpen(&alarmFile, "/.system/alarm.dat", LFS_O_WRONLY | LFS_O_CREAT) != LFS_ERR_OK) {
|
||||
NRF_LOG_WARNING("[AlarmController] Failed to open alarm data file for saving");
|
||||
return;
|
||||
}
|
||||
|
||||
fs.FileWrite(&alarmFile, reinterpret_cast<const uint8_t*>(&alarm), sizeof(alarm));
|
||||
fs.FileClose(&alarmFile);
|
||||
NRF_LOG_INFO("[AlarmController] Saved alarm settings with format version %u to file", alarm.version);
|
||||
}
|
||||
|
|
|
@ -30,47 +30,65 @@ namespace Pinetime {
|
|||
namespace Controllers {
|
||||
class AlarmController {
|
||||
public:
|
||||
AlarmController(Controllers::DateTime& dateTimeController);
|
||||
AlarmController(Controllers::DateTime& dateTimeController, Controllers::FS& fs);
|
||||
|
||||
void Init(System::SystemTask* systemTask);
|
||||
void SaveAlarm();
|
||||
void SetAlarmTime(uint8_t alarmHr, uint8_t alarmMin);
|
||||
void ScheduleAlarm();
|
||||
void DisableAlarm();
|
||||
void SetOffAlarmNow();
|
||||
uint32_t SecondsToAlarm() const;
|
||||
void StopAlerting();
|
||||
enum class AlarmState { Not_Set, Set, Alerting };
|
||||
enum class RecurType { None, Daily, Weekdays };
|
||||
|
||||
uint8_t Hours() const {
|
||||
return hours;
|
||||
return alarm.hours;
|
||||
}
|
||||
|
||||
uint8_t Minutes() const {
|
||||
return minutes;
|
||||
return alarm.minutes;
|
||||
}
|
||||
|
||||
AlarmState State() const {
|
||||
return state;
|
||||
bool IsAlerting() const {
|
||||
return isAlerting;
|
||||
}
|
||||
|
||||
bool IsEnabled() const {
|
||||
return alarm.isEnabled;
|
||||
}
|
||||
|
||||
RecurType Recurrence() const {
|
||||
return recurrence;
|
||||
return alarm.recurrence;
|
||||
}
|
||||
|
||||
void SetRecurrence(RecurType recurType) {
|
||||
recurrence = recurType;
|
||||
}
|
||||
void SetRecurrence(RecurType recurrence);
|
||||
|
||||
private:
|
||||
Controllers::DateTime& dateTimeController;
|
||||
System::SystemTask* systemTask = nullptr;
|
||||
TimerHandle_t alarmTimer;
|
||||
// Versions 255 is reserved for now, so the version field can be made
|
||||
// bigger, should it ever be needed.
|
||||
static constexpr uint8_t alarmFormatVersion = 1;
|
||||
|
||||
struct AlarmSettings {
|
||||
uint8_t version = alarmFormatVersion;
|
||||
uint8_t hours = 7;
|
||||
uint8_t minutes = 0;
|
||||
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> alarmTime;
|
||||
AlarmState state = AlarmState::Not_Set;
|
||||
RecurType recurrence = RecurType::None;
|
||||
bool isEnabled = false;
|
||||
};
|
||||
|
||||
bool isAlerting = false;
|
||||
bool alarmChanged = false;
|
||||
|
||||
Controllers::DateTime& dateTimeController;
|
||||
Controllers::FS& fs;
|
||||
System::SystemTask* systemTask = nullptr;
|
||||
TimerHandle_t alarmTimer;
|
||||
AlarmSettings alarm;
|
||||
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> alarmTime;
|
||||
|
||||
void LoadSettingsFromFile();
|
||||
void SaveSettingsToFile() const;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -124,9 +124,11 @@ int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf* om) {
|
|||
bootloaderSize,
|
||||
applicationSize);
|
||||
|
||||
// wait until SystemTask has finished waking up all devices
|
||||
while (systemTask.IsSleeping()) {
|
||||
vTaskDelay(50); // 50ms
|
||||
// Wait until SystemTask has disabled sleeping
|
||||
// This isn't quite correct, as we don't actually know
|
||||
// if BleFirmwareUpdateStarted has been received yet
|
||||
while (!systemTask.IsSleepDisabled()) {
|
||||
vTaskDelay(pdMS_TO_TICKS(5));
|
||||
}
|
||||
|
||||
dfuImage.Erase();
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
#include "components/ble/MusicService.h"
|
||||
#include "components/ble/NimbleController.h"
|
||||
#include <cstring>
|
||||
#include <FreeRTOS.h>
|
||||
#include <task.h>
|
||||
|
||||
namespace {
|
||||
// 0000yyxx-78fc-48fe-8e23-433b3a1942d0
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <host/ble_uuid.h>
|
||||
#undef max
|
||||
#undef min
|
||||
#include <FreeRTOS.h>
|
||||
|
||||
namespace Pinetime {
|
||||
namespace Controllers {
|
||||
|
|
|
@ -454,9 +454,15 @@ void NimbleController::PersistBond(struct ble_gap_conn_desc& desc) {
|
|||
/* Wakeup Spi and SpiNorFlash before accessing the file system
|
||||
* This should be fixed in the FS driver
|
||||
*/
|
||||
systemTask.PushMessage(Pinetime::System::Messages::GoToRunning);
|
||||
systemTask.PushMessage(Pinetime::System::Messages::DisableSleeping);
|
||||
vTaskDelay(10);
|
||||
|
||||
// This isn't quite correct
|
||||
// SystemTask could receive EnableSleeping right after passing this check
|
||||
// We need some guarantee that the SystemTask has processed the above message
|
||||
// before we can continue
|
||||
while (!systemTask.IsSleepDisabled()) {
|
||||
vTaskDelay(pdMS_TO_TICKS(5));
|
||||
}
|
||||
|
||||
lfs_file_t file_p;
|
||||
|
||||
|
|
|
@ -142,7 +142,7 @@ Ppg::Ppg() {
|
|||
spectrum.fill(0.0f);
|
||||
}
|
||||
|
||||
int8_t Ppg::Preprocess(uint32_t hrs, uint32_t als) {
|
||||
int8_t Ppg::Preprocess(uint16_t hrs, uint16_t als) {
|
||||
if (dataIndex < dataLength) {
|
||||
dataHRS[dataIndex++] = hrs;
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ namespace Pinetime {
|
|||
class Ppg {
|
||||
public:
|
||||
Ppg();
|
||||
int8_t Preprocess(uint32_t hrs, uint32_t als);
|
||||
int8_t Preprocess(uint16_t hrs, uint16_t als);
|
||||
int HeartRate();
|
||||
void Reset(bool resetDaqBuffer);
|
||||
static constexpr int deltaTms = 100;
|
||||
|
|
|
@ -13,7 +13,14 @@ namespace Pinetime {
|
|||
enum class WeatherFormat : uint8_t { Metric, Imperial };
|
||||
enum class Notification : uint8_t { On, Off, Sleep };
|
||||
enum class ChimesOption : uint8_t { None, Hours, HalfHours };
|
||||
enum class WakeUpMode : uint8_t { SingleTap = 0, DoubleTap = 1, RaiseWrist = 2, Shake = 3, LowerWrist = 4 };
|
||||
enum class WakeUpMode : uint8_t {
|
||||
SingleTap = 0,
|
||||
DoubleTap = 1,
|
||||
RaiseWrist = 2,
|
||||
Shake = 3,
|
||||
LowerWrist = 4,
|
||||
ButtonUnlocks = 5,
|
||||
};
|
||||
enum class Colors : uint8_t {
|
||||
White,
|
||||
Silver,
|
||||
|
@ -260,7 +267,7 @@ namespace Pinetime {
|
|||
}
|
||||
};
|
||||
|
||||
std::bitset<5> getWakeUpModes() const {
|
||||
std::bitset<6> getWakeUpModes() const {
|
||||
return settings.wakeUpMode;
|
||||
}
|
||||
|
||||
|
@ -321,7 +328,7 @@ namespace Pinetime {
|
|||
|
||||
WatchFaceInfineat watchFaceInfineat;
|
||||
|
||||
std::bitset<5> wakeUpMode {0};
|
||||
std::bitset<6> wakeUpMode {0};
|
||||
uint16_t shakeWakeThreshold = 150;
|
||||
|
||||
Controllers::BrightnessController::Levels brightLevel = Controllers::BrightnessController::Levels::Medium;
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "displayapp/screens/Weather.h"
|
||||
#include "displayapp/screens/PassKey.h"
|
||||
#include "displayapp/screens/Error.h"
|
||||
#include "displayapp/screens/Symbols.h"
|
||||
|
||||
#include "drivers/Cst816s.h"
|
||||
#include "drivers/St7789.h"
|
||||
|
@ -101,6 +102,7 @@ DisplayApp::DisplayApp(Drivers::St7789& lcd,
|
|||
spiNorFlash {spiNorFlash},
|
||||
lvgl {lcd, filesystem},
|
||||
timer(this, TimerCallback),
|
||||
popupMessage {Screens::Symbols::lock, 90, 90},
|
||||
controllers {batteryController,
|
||||
bleController,
|
||||
dateTimeController,
|
||||
|
@ -209,21 +211,6 @@ void DisplayApp::Refresh() {
|
|||
LoadScreen(returnAppStack.Pop(), returnDirection);
|
||||
};
|
||||
|
||||
auto DimScreen = [this]() {
|
||||
if (brightnessController.Level() != Controllers::BrightnessController::Levels::Off) {
|
||||
isDimmed = true;
|
||||
brightnessController.Set(Controllers::BrightnessController::Levels::Low);
|
||||
}
|
||||
};
|
||||
|
||||
auto RestoreBrightness = [this]() {
|
||||
if (brightnessController.Level() != Controllers::BrightnessController::Levels::Off) {
|
||||
isDimmed = false;
|
||||
lv_disp_trig_activity(nullptr);
|
||||
ApplyBrightness();
|
||||
}
|
||||
};
|
||||
|
||||
auto IsPastDimTime = [this]() -> bool {
|
||||
return lv_disp_get_inactive_time(nullptr) >= pdMS_TO_TICKS(settingsController.GetScreenTimeOut() - 2000);
|
||||
};
|
||||
|
@ -267,14 +254,27 @@ void DisplayApp::Refresh() {
|
|||
|
||||
if (!systemTask->IsSleepDisabled() && IsPastDimTime()) {
|
||||
if (!isDimmed) {
|
||||
DimScreen();
|
||||
isDimmed = true;
|
||||
brightnessController.Set(Controllers::BrightnessController::Levels::Low);
|
||||
}
|
||||
if (IsPastSleepTime()) {
|
||||
systemTask->PushMessage(System::Messages::GoToSleep);
|
||||
state = States::Idle;
|
||||
if (IsPastSleepTime() && uxQueueMessagesWaiting(msgQueue) == 0) {
|
||||
PushMessageToSystemTask(System::Messages::GoToSleep);
|
||||
// Can't set state to Idle here, something may send
|
||||
// DisableSleeping before this GoToSleep arrives
|
||||
// Instead we check we have no messages queued before sending GoToSleep
|
||||
// This works as the SystemTask is higher priority than DisplayApp
|
||||
// As soon as we send GoToSleep, SystemTask pre-empts DisplayApp
|
||||
// Whenever DisplayApp is running again, it is guaranteed that
|
||||
// SystemTask has handled the message
|
||||
// If it responded, we will have a GoToSleep waiting in the queue
|
||||
// By checking that there are no messages in the queue, we avoid
|
||||
// resending GoToSleep when we already have a response
|
||||
// SystemTask is resilient to duplicate messages, this is an
|
||||
// optimisation to reduce pressure on the message queues
|
||||
}
|
||||
} else if (isDimmed) {
|
||||
RestoreBrightness();
|
||||
isDimmed = false;
|
||||
ApplyBrightness();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -285,10 +285,10 @@ void DisplayApp::Refresh() {
|
|||
Messages msg;
|
||||
if (xQueueReceive(msgQueue, &msg, queueTimeout) == pdTRUE) {
|
||||
switch (msg) {
|
||||
case Messages::DimScreen:
|
||||
DimScreen();
|
||||
break;
|
||||
case Messages::GoToSleep:
|
||||
if (state != States::Running) {
|
||||
break;
|
||||
}
|
||||
while (brightnessController.Level() != Controllers::BrightnessController::Levels::Low) {
|
||||
brightnessController.Lower();
|
||||
vTaskDelay(100);
|
||||
|
@ -323,6 +323,9 @@ void DisplayApp::Refresh() {
|
|||
lv_disp_trig_activity(nullptr);
|
||||
break;
|
||||
case Messages::GoToRunning:
|
||||
if (state == States::Running) {
|
||||
break;
|
||||
}
|
||||
if (settingsController.GetAlwaysOnDisplay()) {
|
||||
lcd.LowPowerOff();
|
||||
} else {
|
||||
|
@ -333,8 +336,7 @@ void DisplayApp::Refresh() {
|
|||
state = States::Running;
|
||||
break;
|
||||
case Messages::UpdateBleConnection:
|
||||
// clockScreen.SetBleConnectionState(bleController.IsConnected() ? Screens::Clock::BleConnectionStates::Connected :
|
||||
// Screens::Clock::BleConnectionStates::NotConnected);
|
||||
// Only used for recovery firmware
|
||||
break;
|
||||
case Messages::NewNotification:
|
||||
LoadNewScreen(Apps::NotificationsPreview, DisplayApp::FullRefreshDirections::Down);
|
||||
|
@ -449,18 +451,19 @@ void DisplayApp::Refresh() {
|
|||
case Messages::BleRadioEnableToggle:
|
||||
PushMessageToSystemTask(System::Messages::BleRadioEnableToggle);
|
||||
break;
|
||||
case Messages::UpdateDateTime:
|
||||
// Added to remove warning
|
||||
// What should happen here?
|
||||
break;
|
||||
case Messages::Chime:
|
||||
LoadNewScreen(Apps::Clock, DisplayApp::FullRefreshDirections::None);
|
||||
motorController.RunForDuration(35);
|
||||
break;
|
||||
case Messages::OnChargingEvent:
|
||||
RestoreBrightness();
|
||||
motorController.RunForDuration(15);
|
||||
break;
|
||||
case Messages::ShowIgnoreTouchPopup:
|
||||
popupMessage.SetHidden(false);
|
||||
break;
|
||||
case Messages::HideIgnoreTouchPopup:
|
||||
popupMessage.SetHidden(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -584,10 +587,10 @@ void DisplayApp::LoadScreen(Apps app, DisplayApp::FullRefreshDirections directio
|
|||
currentScreen = std::make_unique<Screens::SettingWeatherFormat>(settingsController);
|
||||
break;
|
||||
case Apps::SettingWakeUp:
|
||||
currentScreen = std::make_unique<Screens::SettingWakeUp>(settingsController);
|
||||
currentScreen = std::make_unique<Screens::SettingWakeUp>(this, settingsController);
|
||||
break;
|
||||
case Apps::SettingDisplay:
|
||||
currentScreen = std::make_unique<Screens::SettingDisplay>(this, settingsController);
|
||||
currentScreen = std::make_unique<Screens::SettingDisplay>(settingsController);
|
||||
break;
|
||||
case Apps::SettingSteps:
|
||||
currentScreen = std::make_unique<Screens::SettingSteps>(settingsController);
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "components/timer/Timer.h"
|
||||
#include "components/alarm/AlarmController.h"
|
||||
#include "touchhandler/TouchHandler.h"
|
||||
#include "displayapp/widgets/PopupMessage.h"
|
||||
|
||||
#include "displayapp/Messages.h"
|
||||
#include "BootErrors.h"
|
||||
|
@ -102,8 +103,10 @@ namespace Pinetime {
|
|||
Pinetime::Controllers::FirmwareValidator validator;
|
||||
Pinetime::Components::LittleVgl lvgl;
|
||||
Pinetime::Controllers::Timer timer;
|
||||
Pinetime::Applications::Widgets::PopupMessage popupMessage;
|
||||
|
||||
AppControllers controllers;
|
||||
|
||||
TaskHandle_t taskHandle;
|
||||
|
||||
States state = States::Running;
|
||||
|
|
|
@ -7,7 +7,6 @@ namespace Pinetime {
|
|||
enum class Messages : uint8_t {
|
||||
GoToSleep,
|
||||
GoToRunning,
|
||||
UpdateDateTime,
|
||||
UpdateBleConnection,
|
||||
TouchEvent,
|
||||
ButtonPushed,
|
||||
|
@ -17,13 +16,16 @@ namespace Pinetime {
|
|||
NewNotification,
|
||||
TimerDone,
|
||||
BleFirmwareUpdateStarted,
|
||||
DimScreen,
|
||||
// Resets the screen timeout timer when awake
|
||||
// Does nothing when asleep
|
||||
NotifyDeviceActivity,
|
||||
ShowPairingKey,
|
||||
AlarmTriggered,
|
||||
Chime,
|
||||
BleRadioEnableToggle,
|
||||
OnChargingEvent,
|
||||
ShowIgnoreTouchPopup,
|
||||
HideIgnoreTouchPopup
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
set(FONTS jetbrains_mono_42 jetbrains_mono_76 jetbrains_mono_bold_20
|
||||
jetbrains_mono_extrabold_compressed lv_font_sys_48
|
||||
jetbrains_mono_extrabold_compressed lv_font_sys_48 lv_font_sys_80
|
||||
open_sans_light fontawesome_weathericons)
|
||||
find_program(LV_FONT_CONV "lv_font_conv" NO_CACHE REQUIRED
|
||||
HINTS "${CMAKE_SOURCE_DIR}/node_modules/.bin")
|
||||
|
|
|
@ -64,6 +64,16 @@
|
|||
"bpp": 1,
|
||||
"size": 48
|
||||
},
|
||||
"lv_font_sys_80": {
|
||||
"sources": [
|
||||
{
|
||||
"file": "material-design-icons/MaterialIcons-Regular.ttf",
|
||||
"range": "0xe897"
|
||||
}
|
||||
],
|
||||
"bpp": 1,
|
||||
"size": 80
|
||||
},
|
||||
"fontawesome_weathericons": {
|
||||
"sources": [
|
||||
{
|
||||
|
|
|
@ -48,7 +48,7 @@ Alarm::Alarm(Controllers::AlarmController& alarmController,
|
|||
Controllers::Settings::ClockType clockType,
|
||||
System::SystemTask& systemTask,
|
||||
Controllers::MotorController& motorController)
|
||||
: alarmController {alarmController}, systemTask {systemTask}, motorController {motorController} {
|
||||
: alarmController {alarmController}, wakeLock(systemTask), motorController {motorController} {
|
||||
|
||||
hourCounter.Create();
|
||||
lv_obj_align(hourCounter.GetObject(), nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0);
|
||||
|
@ -117,7 +117,7 @@ Alarm::Alarm(Controllers::AlarmController& alarmController,
|
|||
|
||||
UpdateAlarmTime();
|
||||
|
||||
if (alarmController.State() == Controllers::AlarmController::AlarmState::Alerting) {
|
||||
if (alarmController.IsAlerting()) {
|
||||
SetAlerting();
|
||||
} else {
|
||||
SetSwitchState(LV_ANIM_OFF);
|
||||
|
@ -125,14 +125,15 @@ Alarm::Alarm(Controllers::AlarmController& alarmController,
|
|||
}
|
||||
|
||||
Alarm::~Alarm() {
|
||||
if (alarmController.State() == AlarmController::AlarmState::Alerting) {
|
||||
if (alarmController.IsAlerting()) {
|
||||
StopAlerting();
|
||||
}
|
||||
lv_obj_clean(lv_scr_act());
|
||||
alarmController.SaveAlarm();
|
||||
}
|
||||
|
||||
void Alarm::DisableAlarm() {
|
||||
if (alarmController.State() == AlarmController::AlarmState::Set) {
|
||||
if (alarmController.IsEnabled()) {
|
||||
alarmController.DisableAlarm();
|
||||
lv_switch_off(enableSwitch, LV_ANIM_ON);
|
||||
}
|
||||
|
@ -172,7 +173,7 @@ bool Alarm::OnButtonPushed() {
|
|||
HideInfo();
|
||||
return true;
|
||||
}
|
||||
if (alarmController.State() == AlarmController::AlarmState::Alerting) {
|
||||
if (alarmController.IsAlerting()) {
|
||||
StopAlerting();
|
||||
return true;
|
||||
}
|
||||
|
@ -181,7 +182,7 @@ bool Alarm::OnButtonPushed() {
|
|||
|
||||
bool Alarm::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
||||
// Don't allow closing the screen by swiping while the alarm is alerting
|
||||
return alarmController.State() == AlarmController::AlarmState::Alerting && event == TouchEvents::SwipeDown;
|
||||
return alarmController.IsAlerting() && event == TouchEvents::SwipeDown;
|
||||
}
|
||||
|
||||
void Alarm::OnValueChanged() {
|
||||
|
@ -205,7 +206,7 @@ void Alarm::SetAlerting() {
|
|||
lv_obj_set_hidden(btnStop, false);
|
||||
taskStopAlarm = lv_task_create(StopAlarmTaskCallback, pdMS_TO_TICKS(60 * 1000), LV_TASK_PRIO_MID, this);
|
||||
motorController.StartRinging();
|
||||
systemTask.PushMessage(System::Messages::DisableSleeping);
|
||||
wakeLock.Lock();
|
||||
}
|
||||
|
||||
void Alarm::StopAlerting() {
|
||||
|
@ -216,21 +217,16 @@ void Alarm::StopAlerting() {
|
|||
lv_task_del(taskStopAlarm);
|
||||
taskStopAlarm = nullptr;
|
||||
}
|
||||
systemTask.PushMessage(System::Messages::EnableSleeping);
|
||||
wakeLock.Release();
|
||||
lv_obj_set_hidden(enableSwitch, false);
|
||||
lv_obj_set_hidden(btnStop, true);
|
||||
}
|
||||
|
||||
void Alarm::SetSwitchState(lv_anim_enable_t anim) {
|
||||
switch (alarmController.State()) {
|
||||
case AlarmController::AlarmState::Set:
|
||||
if (alarmController.IsEnabled()) {
|
||||
lv_switch_on(enableSwitch, anim);
|
||||
break;
|
||||
case AlarmController::AlarmState::Not_Set:
|
||||
} else {
|
||||
lv_switch_off(enableSwitch, anim);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -247,7 +243,7 @@ void Alarm::ShowInfo() {
|
|||
txtMessage = lv_label_create(btnMessage, nullptr);
|
||||
lv_obj_set_style_local_bg_color(btnMessage, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_NAVY);
|
||||
|
||||
if (alarmController.State() == AlarmController::AlarmState::Set) {
|
||||
if (alarmController.IsEnabled()) {
|
||||
auto timeToAlarm = alarmController.SecondsToAlarm();
|
||||
|
||||
auto daysToAlarm = timeToAlarm / 86400;
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "displayapp/screens/Screen.h"
|
||||
#include "displayapp/widgets/Counter.h"
|
||||
#include "displayapp/Controllers.h"
|
||||
#include "systemtask/WakeLock.h"
|
||||
#include "Symbols.h"
|
||||
|
||||
namespace Pinetime {
|
||||
|
@ -43,7 +44,7 @@ namespace Pinetime {
|
|||
|
||||
private:
|
||||
Controllers::AlarmController& alarmController;
|
||||
System::SystemTask& systemTask;
|
||||
System::WakeLock wakeLock;
|
||||
Controllers::MotorController& motorController;
|
||||
|
||||
lv_obj_t *btnStop, *txtStop, *btnRecur, *txtRecur, *btnInfo, *enableSwitch;
|
||||
|
|
|
@ -15,7 +15,7 @@ namespace {
|
|||
}
|
||||
|
||||
FlashLight::FlashLight(System::SystemTask& systemTask, Controllers::BrightnessController& brightnessController)
|
||||
: systemTask {systemTask}, brightnessController {brightnessController} {
|
||||
: wakeLock(systemTask), brightnessController {brightnessController} {
|
||||
|
||||
previousBrightnessLevel = brightnessController.Level();
|
||||
brightnessController.Set(Controllers::BrightnessController::Levels::Low);
|
||||
|
@ -47,14 +47,13 @@ FlashLight::FlashLight(System::SystemTask& systemTask, Controllers::BrightnessCo
|
|||
backgroundAction->user_data = this;
|
||||
lv_obj_set_event_cb(backgroundAction, EventHandler);
|
||||
|
||||
systemTask.PushMessage(Pinetime::System::Messages::DisableSleeping);
|
||||
wakeLock.Lock();
|
||||
}
|
||||
|
||||
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_BLACK);
|
||||
brightnessController.Set(previousBrightnessLevel);
|
||||
systemTask.PushMessage(Pinetime::System::Messages::EnableSleeping);
|
||||
}
|
||||
|
||||
void FlashLight::SetColors() {
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "displayapp/screens/Screen.h"
|
||||
#include "components/brightness/BrightnessController.h"
|
||||
#include "systemtask/SystemTask.h"
|
||||
#include "systemtask/WakeLock.h"
|
||||
#include <cstdint>
|
||||
#include <lvgl/lvgl.h>
|
||||
|
||||
|
@ -23,7 +24,7 @@ namespace Pinetime {
|
|||
void SetIndicators();
|
||||
void SetColors();
|
||||
|
||||
Pinetime::System::SystemTask& systemTask;
|
||||
Pinetime::System::WakeLock wakeLock;
|
||||
Controllers::BrightnessController& brightnessController;
|
||||
|
||||
Controllers::BrightnessController::Levels brightnessLevel = Controllers::BrightnessController::Levels::High;
|
||||
|
|
|
@ -29,7 +29,7 @@ namespace {
|
|||
}
|
||||
|
||||
HeartRate::HeartRate(Controllers::HeartRateController& heartRateController, System::SystemTask& systemTask)
|
||||
: heartRateController {heartRateController}, systemTask {systemTask} {
|
||||
: heartRateController {heartRateController}, wakeLock(systemTask) {
|
||||
bool isHrRunning = heartRateController.State() != Controllers::HeartRateController::States::Stopped;
|
||||
label_hr = lv_label_create(lv_scr_act(), nullptr);
|
||||
|
||||
|
@ -63,7 +63,7 @@ HeartRate::HeartRate(Controllers::HeartRateController& heartRateController, Syst
|
|||
label_startStop = lv_label_create(btn_startStop, nullptr);
|
||||
UpdateStartStopButton(isHrRunning);
|
||||
if (isHrRunning) {
|
||||
systemTask.PushMessage(Pinetime::System::Messages::DisableSleeping);
|
||||
wakeLock.Lock();
|
||||
}
|
||||
|
||||
taskRefresh = lv_task_create(RefreshTaskCallback, 100, LV_TASK_PRIO_MID, this);
|
||||
|
@ -72,7 +72,6 @@ HeartRate::HeartRate(Controllers::HeartRateController& heartRateController, Syst
|
|||
HeartRate::~HeartRate() {
|
||||
lv_task_del(taskRefresh);
|
||||
lv_obj_clean(lv_scr_act());
|
||||
systemTask.PushMessage(Pinetime::System::Messages::EnableSleeping);
|
||||
}
|
||||
|
||||
void HeartRate::Refresh() {
|
||||
|
@ -101,12 +100,12 @@ void HeartRate::OnStartStopEvent(lv_event_t event) {
|
|||
if (heartRateController.State() == Controllers::HeartRateController::States::Stopped) {
|
||||
heartRateController.Start();
|
||||
UpdateStartStopButton(heartRateController.State() != Controllers::HeartRateController::States::Stopped);
|
||||
systemTask.PushMessage(Pinetime::System::Messages::DisableSleeping);
|
||||
wakeLock.Lock();
|
||||
lv_obj_set_style_local_text_color(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::highlight);
|
||||
} else {
|
||||
heartRateController.Stop();
|
||||
UpdateStartStopButton(heartRateController.State() != Controllers::HeartRateController::States::Stopped);
|
||||
systemTask.PushMessage(Pinetime::System::Messages::EnableSleeping);
|
||||
wakeLock.Release();
|
||||
lv_obj_set_style_local_text_color(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <chrono>
|
||||
#include "displayapp/screens/Screen.h"
|
||||
#include "systemtask/SystemTask.h"
|
||||
#include "systemtask/WakeLock.h"
|
||||
#include "Symbols.h"
|
||||
#include <lvgl/src/lv_core/lv_style.h>
|
||||
#include <lvgl/src/lv_core/lv_obj.h>
|
||||
|
@ -27,7 +28,7 @@ namespace Pinetime {
|
|||
|
||||
private:
|
||||
Controllers::HeartRateController& heartRateController;
|
||||
Pinetime::System::SystemTask& systemTask;
|
||||
Pinetime::System::WakeLock wakeLock;
|
||||
void UpdateStartStopButton(bool isRunning);
|
||||
lv_obj_t* label_hr;
|
||||
lv_obj_t* label_bpm;
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace {
|
|||
}
|
||||
|
||||
Metronome::Metronome(Controllers::MotorController& motorController, System::SystemTask& systemTask)
|
||||
: motorController {motorController}, systemTask {systemTask} {
|
||||
: motorController {motorController}, wakeLock(systemTask) {
|
||||
|
||||
bpmArc = lv_arc_create(lv_scr_act(), nullptr);
|
||||
bpmArc->user_data = this;
|
||||
|
@ -72,7 +72,6 @@ Metronome::Metronome(Controllers::MotorController& motorController, System::Syst
|
|||
|
||||
Metronome::~Metronome() {
|
||||
lv_task_del(taskRefresh);
|
||||
systemTask.PushMessage(System::Messages::EnableSleeping);
|
||||
lv_obj_clean(lv_scr_act());
|
||||
}
|
||||
|
||||
|
@ -128,12 +127,12 @@ void Metronome::OnEvent(lv_obj_t* obj, lv_event_t event) {
|
|||
metronomeStarted = !metronomeStarted;
|
||||
if (metronomeStarted) {
|
||||
lv_label_set_text_static(lblPlayPause, Symbols::pause);
|
||||
systemTask.PushMessage(System::Messages::DisableSleeping);
|
||||
wakeLock.Lock();
|
||||
startTime = xTaskGetTickCount();
|
||||
counter = 1;
|
||||
} else {
|
||||
lv_label_set_text_static(lblPlayPause, Symbols::play);
|
||||
systemTask.PushMessage(System::Messages::EnableSleeping);
|
||||
wakeLock.Release();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "systemtask/SystemTask.h"
|
||||
#include "systemtask/WakeLock.h"
|
||||
#include "components/motor/MotorController.h"
|
||||
#include "displayapp/screens/Screen.h"
|
||||
#include "Symbols.h"
|
||||
|
@ -21,7 +22,7 @@ namespace Pinetime {
|
|||
TickType_t startTime = 0;
|
||||
TickType_t tappedTime = 0;
|
||||
Controllers::MotorController& motorController;
|
||||
System::SystemTask& systemTask;
|
||||
System::WakeLock wakeLock;
|
||||
int16_t bpm = 120;
|
||||
uint8_t bpb = 4;
|
||||
uint8_t counter = 1;
|
||||
|
|
|
@ -20,7 +20,7 @@ Notifications::Notifications(DisplayApp* app,
|
|||
notificationManager {notificationManager},
|
||||
alertNotificationService {alertNotificationService},
|
||||
motorController {motorController},
|
||||
systemTask {systemTask},
|
||||
wakeLock(systemTask),
|
||||
mode {mode} {
|
||||
|
||||
notificationManager.ClearNewNotificationFlag();
|
||||
|
@ -40,7 +40,7 @@ Notifications::Notifications(DisplayApp* app,
|
|||
validDisplay = false;
|
||||
}
|
||||
if (mode == Modes::Preview) {
|
||||
systemTask.PushMessage(System::Messages::DisableSleeping);
|
||||
wakeLock.Lock();
|
||||
if (notification.category == Controllers::NotificationManager::Categories::IncomingCall) {
|
||||
motorController.StartRinging();
|
||||
} else {
|
||||
|
@ -65,7 +65,6 @@ Notifications::~Notifications() {
|
|||
lv_task_del(taskRefresh);
|
||||
// make sure we stop any vibrations before exiting
|
||||
motorController.StopRinging();
|
||||
systemTask.PushMessage(System::Messages::EnableSleeping);
|
||||
lv_obj_clean(lv_scr_act());
|
||||
}
|
||||
|
||||
|
@ -82,7 +81,6 @@ void Notifications::Refresh() {
|
|||
|
||||
} else if (mode == Modes::Preview && dismissingNotification) {
|
||||
running = false;
|
||||
currentItem = std::make_unique<NotificationItem>(alertNotificationService, motorController);
|
||||
|
||||
} else if (dismissingNotification) {
|
||||
dismissingNotification = false;
|
||||
|
@ -113,15 +111,15 @@ void Notifications::Refresh() {
|
|||
alertNotificationService,
|
||||
motorController);
|
||||
} else {
|
||||
currentItem = std::make_unique<NotificationItem>(alertNotificationService, motorController);
|
||||
running = false;
|
||||
}
|
||||
}
|
||||
|
||||
running = currentItem->IsRunning() && running;
|
||||
running = running && currentItem->IsRunning();
|
||||
}
|
||||
|
||||
void Notifications::OnPreviewInteraction() {
|
||||
systemTask.PushMessage(System::Messages::EnableSleeping);
|
||||
wakeLock.Release();
|
||||
motorController.StopRinging();
|
||||
if (timeoutLine != nullptr) {
|
||||
lv_obj_del(timeoutLine);
|
||||
|
@ -173,7 +171,9 @@ bool Notifications::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
|||
} else if (nextMessage.valid) {
|
||||
currentId = nextMessage.id;
|
||||
} else {
|
||||
// don't update id, won't be found be refresh and try to load latest message or no message box
|
||||
// don't update id, notification manager will try to fetch
|
||||
// but not find it. Refresh will try to load latest message
|
||||
// or dismiss to watchface
|
||||
}
|
||||
DismissToBlack();
|
||||
return true;
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "components/ble/NotificationManager.h"
|
||||
#include "components/motor/MotorController.h"
|
||||
#include "systemtask/SystemTask.h"
|
||||
#include "systemtask/WakeLock.h"
|
||||
|
||||
namespace Pinetime {
|
||||
namespace Controllers {
|
||||
|
@ -73,7 +74,7 @@ namespace Pinetime {
|
|||
Pinetime::Controllers::NotificationManager& notificationManager;
|
||||
Pinetime::Controllers::AlertNotificationService& alertNotificationService;
|
||||
Pinetime::Controllers::MotorController& motorController;
|
||||
System::SystemTask& systemTask;
|
||||
System::WakeLock wakeLock;
|
||||
Modes mode = Modes::Normal;
|
||||
std::unique_ptr<NotificationItem> currentItem;
|
||||
Pinetime::Controllers::NotificationManager::Notification::Id currentId;
|
||||
|
|
29
src/displayapp/screens/Page.h
Normal file
29
src/displayapp/screens/Page.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <lvgl/lvgl.h>
|
||||
#include "displayapp/screens/Screen.h"
|
||||
#include "displayapp/widgets/PageIndicator.h"
|
||||
|
||||
namespace Pinetime {
|
||||
|
||||
namespace Applications {
|
||||
namespace Screens {
|
||||
|
||||
class Page : public Screen {
|
||||
public:
|
||||
Page(uint8_t screenID, uint8_t numScreens, lv_obj_t* contentObj) : contentObj {contentObj}, pageIndicator(screenID, numScreens) {
|
||||
pageIndicator.Create();
|
||||
}
|
||||
|
||||
~Page() override {
|
||||
lv_obj_clean(lv_scr_act());
|
||||
}
|
||||
|
||||
private:
|
||||
lv_obj_t* contentObj = nullptr;
|
||||
Widgets::PageIndicator pageIndicator;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -34,7 +34,7 @@ namespace {
|
|||
constexpr TickType_t blinkInterval = pdMS_TO_TICKS(1000);
|
||||
}
|
||||
|
||||
StopWatch::StopWatch(System::SystemTask& systemTask) : systemTask {systemTask} {
|
||||
StopWatch::StopWatch(System::SystemTask& systemTask) : wakeLock(systemTask) {
|
||||
static constexpr uint8_t btnWidth = 115;
|
||||
static constexpr uint8_t btnHeight = 80;
|
||||
btnPlayPause = lv_btn_create(lv_scr_act(), nullptr);
|
||||
|
@ -79,7 +79,6 @@ StopWatch::StopWatch(System::SystemTask& systemTask) : systemTask {systemTask} {
|
|||
|
||||
StopWatch::~StopWatch() {
|
||||
lv_task_del(taskRefresh);
|
||||
systemTask.PushMessage(Pinetime::System::Messages::EnableSleeping);
|
||||
lv_obj_clean(lv_scr_act());
|
||||
}
|
||||
|
||||
|
@ -135,7 +134,7 @@ void StopWatch::Start() {
|
|||
SetInterfaceRunning();
|
||||
startTime = xTaskGetTickCount();
|
||||
currentState = States::Running;
|
||||
systemTask.PushMessage(Pinetime::System::Messages::DisableSleeping);
|
||||
wakeLock.Lock();
|
||||
}
|
||||
|
||||
void StopWatch::Pause() {
|
||||
|
@ -145,7 +144,7 @@ void StopWatch::Pause() {
|
|||
oldTimeElapsed = laps[lapsDone];
|
||||
blinkTime = xTaskGetTickCount() + blinkInterval;
|
||||
currentState = States::Halted;
|
||||
systemTask.PushMessage(Pinetime::System::Messages::EnableSleeping);
|
||||
wakeLock.Release();
|
||||
}
|
||||
|
||||
void StopWatch::Refresh() {
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "portmacro_cmsis.h"
|
||||
|
||||
#include "systemtask/SystemTask.h"
|
||||
#include "systemtask/WakeLock.h"
|
||||
#include "displayapp/apps/Apps.h"
|
||||
#include "displayapp/Controllers.h"
|
||||
#include "Symbols.h"
|
||||
|
@ -43,7 +44,7 @@ namespace Pinetime {
|
|||
void Start();
|
||||
void Pause();
|
||||
|
||||
Pinetime::System::SystemTask& systemTask;
|
||||
Pinetime::System::WakeLock wakeLock;
|
||||
States currentState = States::Init;
|
||||
TickType_t startTime;
|
||||
TickType_t oldTimeElapsed = 0;
|
||||
|
|
|
@ -64,6 +64,9 @@ namespace Pinetime {
|
|||
|
||||
static constexpr const char* flashlight = "\xEF\x80\x8B";
|
||||
static constexpr const char* paintbrushLg = "\xEE\x90\x8A";
|
||||
|
||||
// wake-up screenlock icon, from material icons
|
||||
static constexpr const char* lock = "\xEE\xA2\x97";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,8 +40,7 @@ SystemInfo::SystemInfo(Pinetime::Applications::DisplayApp* app,
|
|||
Pinetime::Controllers::MotionController& motionController,
|
||||
const Pinetime::Drivers::Cst816S& touchPanel,
|
||||
const Pinetime::Drivers::SpiNorFlash& spiNorFlash)
|
||||
: app {app},
|
||||
dateTimeController {dateTimeController},
|
||||
: dateTimeController {dateTimeController},
|
||||
batteryController {batteryController},
|
||||
brightnessController {brightnessController},
|
||||
bleController {bleController},
|
||||
|
|
|
@ -35,7 +35,6 @@ namespace Pinetime {
|
|||
bool OnTouchEvent(TouchEvents event) override;
|
||||
|
||||
private:
|
||||
DisplayApp* app;
|
||||
Pinetime::Controllers::DateTime& dateTimeController;
|
||||
const Pinetime::Controllers::Battery& batteryController;
|
||||
Pinetime::Controllers::BrightnessController& brightnessController;
|
||||
|
|
|
@ -104,9 +104,7 @@ void Timer::UpdateMask() {
|
|||
|
||||
void Timer::Refresh() {
|
||||
if (timer.IsRunning()) {
|
||||
auto secondsRemaining = std::chrono::duration_cast<std::chrono::seconds>(timer.GetTimeRemaining());
|
||||
minuteCounter.SetValue(secondsRemaining.count() / 60);
|
||||
secondCounter.SetValue(secondsRemaining.count() % 60);
|
||||
DisplayTime();
|
||||
} else if (buttonPressing && xTaskGetTickCount() > pressTime + pdMS_TO_TICKS(150)) {
|
||||
lv_label_set_text_static(txtPlayPause, "Reset");
|
||||
maskPosition += 15;
|
||||
|
@ -119,6 +117,14 @@ void Timer::Refresh() {
|
|||
}
|
||||
}
|
||||
|
||||
void Timer::DisplayTime() {
|
||||
displaySeconds = std::chrono::duration_cast<std::chrono::seconds>(timer.GetTimeRemaining());
|
||||
if (displaySeconds.IsUpdated()) {
|
||||
minuteCounter.SetValue(displaySeconds.Get().count() / 60);
|
||||
secondCounter.SetValue(displaySeconds.Get().count() % 60);
|
||||
}
|
||||
}
|
||||
|
||||
void Timer::SetTimerRunning() {
|
||||
minuteCounter.HideControls();
|
||||
secondCounter.HideControls();
|
||||
|
@ -133,9 +139,7 @@ void Timer::SetTimerStopped() {
|
|||
|
||||
void Timer::ToggleRunning() {
|
||||
if (timer.IsRunning()) {
|
||||
auto secondsRemaining = std::chrono::duration_cast<std::chrono::seconds>(timer.GetTimeRemaining());
|
||||
minuteCounter.SetValue(secondsRemaining.count() / 60);
|
||||
secondCounter.SetValue(secondsRemaining.count() % 60);
|
||||
DisplayTime();
|
||||
timer.StopTimer();
|
||||
SetTimerStopped();
|
||||
} else if (secondCounter.GetValue() + minuteCounter.GetValue() > 0) {
|
||||
|
@ -147,7 +151,6 @@ void Timer::ToggleRunning() {
|
|||
}
|
||||
|
||||
void Timer::Reset() {
|
||||
minuteCounter.SetValue(0);
|
||||
secondCounter.SetValue(0);
|
||||
DisplayTime();
|
||||
SetTimerStopped();
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "systemtask/SystemTask.h"
|
||||
#include "displayapp/LittleVgl.h"
|
||||
#include "displayapp/widgets/Counter.h"
|
||||
#include "utility/DirtyValue.h"
|
||||
#include <lvgl/lvgl.h>
|
||||
|
||||
#include "components/timer/Timer.h"
|
||||
|
@ -26,6 +27,7 @@ namespace Pinetime::Applications {
|
|||
void SetTimerRunning();
|
||||
void SetTimerStopped();
|
||||
void UpdateMask();
|
||||
void DisplayTime();
|
||||
Pinetime::Controllers::Timer& timer;
|
||||
|
||||
lv_obj_t* btnPlayPause;
|
||||
|
@ -43,6 +45,7 @@ namespace Pinetime::Applications {
|
|||
bool buttonPressing = false;
|
||||
lv_coord_t maskPosition = 0;
|
||||
TickType_t pressTime = 0;
|
||||
Utility::DirtyValue<std::chrono::seconds> displaySeconds;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -24,8 +24,7 @@ namespace {
|
|||
|
||||
constexpr std::array<uint16_t, 6> SettingDisplay::options;
|
||||
|
||||
SettingDisplay::SettingDisplay(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Settings& settingsController)
|
||||
: app {app}, settingsController {settingsController} {
|
||||
SettingDisplay::SettingDisplay(Pinetime::Controllers::Settings& settingsController) : settingsController {settingsController} {
|
||||
|
||||
lv_obj_t* container1 = lv_cont_create(lv_scr_act(), nullptr);
|
||||
|
||||
|
|
|
@ -14,14 +14,13 @@ namespace Pinetime {
|
|||
|
||||
class SettingDisplay : public Screen {
|
||||
public:
|
||||
SettingDisplay(DisplayApp* app, Pinetime::Controllers::Settings& settingsController);
|
||||
SettingDisplay(Pinetime::Controllers::Settings& settingsController);
|
||||
~SettingDisplay() override;
|
||||
|
||||
void UpdateSelected(lv_obj_t* object, lv_event_t event);
|
||||
void ToggleAlwaysOn();
|
||||
|
||||
private:
|
||||
DisplayApp* app;
|
||||
static constexpr std::array<uint16_t, 6> options = {5000, 7000, 10000, 15000, 20000, 30000};
|
||||
|
||||
Controllers::Settings& settingsController;
|
||||
|
|
|
@ -15,8 +15,7 @@ bool SettingSetDateTime::OnTouchEvent(Pinetime::Applications::TouchEvents event)
|
|||
SettingSetDateTime::SettingSetDateTime(Pinetime::Applications::DisplayApp* app,
|
||||
Pinetime::Controllers::DateTime& dateTimeController,
|
||||
Pinetime::Controllers::Settings& settingsController)
|
||||
: app {app},
|
||||
dateTimeController {dateTimeController},
|
||||
: dateTimeController {dateTimeController},
|
||||
settingsController {settingsController},
|
||||
screens {app,
|
||||
0,
|
||||
|
|
|
@ -20,7 +20,6 @@ namespace Pinetime {
|
|||
void Quit();
|
||||
|
||||
private:
|
||||
DisplayApp* app;
|
||||
Controllers::DateTime& dateTimeController;
|
||||
Controllers::Settings& settingsController;
|
||||
|
||||
|
|
|
@ -8,7 +8,17 @@
|
|||
|
||||
using namespace Pinetime::Applications::Screens;
|
||||
|
||||
constexpr std::array<SettingWakeUp::Option, 5> SettingWakeUp::options;
|
||||
constexpr std::array<SettingWakeUp::Option, SettingWakeUp::numOptions> SettingWakeUp::options;
|
||||
|
||||
auto SettingWakeUp::CreateScreenList() {
|
||||
std::array<std::function<std::unique_ptr<Screen>()>, nScreens> screens;
|
||||
for (size_t i = 0; i < screens.size(); i++) {
|
||||
screens[i] = [this, i]() -> std::unique_ptr<Screen> {
|
||||
return CreateScreen(i);
|
||||
};
|
||||
}
|
||||
return screens;
|
||||
}
|
||||
|
||||
namespace {
|
||||
void event_handler(lv_obj_t* obj, lv_event_t event) {
|
||||
|
@ -19,7 +29,16 @@ namespace {
|
|||
}
|
||||
}
|
||||
|
||||
SettingWakeUp::SettingWakeUp(Pinetime::Controllers::Settings& settingsController) : settingsController {settingsController} {
|
||||
SettingWakeUp::SettingWakeUp(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Settings& settingsController)
|
||||
: settingsController {settingsController}, screens {app, 0, CreateScreenList(), Screens::ScreenListModes::UpDown} {
|
||||
}
|
||||
|
||||
SettingWakeUp::~SettingWakeUp() {
|
||||
lv_obj_clean(lv_scr_act());
|
||||
settingsController.SaveSettings();
|
||||
}
|
||||
|
||||
std::unique_ptr<Screen> SettingWakeUp::CreateScreen(size_t screenNum) {
|
||||
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);
|
||||
|
@ -43,20 +62,29 @@ SettingWakeUp::SettingWakeUp(Pinetime::Controllers::Settings& settingsController
|
|||
lv_label_set_align(icon, LV_LABEL_ALIGN_CENTER);
|
||||
lv_obj_align(icon, title, LV_ALIGN_OUT_LEFT_MID, -10, 0);
|
||||
|
||||
for (unsigned int i = 0; i < options.size(); i++) {
|
||||
// cleanup any old pointers
|
||||
cbOption.fill(nullptr);
|
||||
|
||||
// only loop as far as the list size aĺlows
|
||||
unsigned int loopMax = screenNum * optionsPerScreen + optionsPerScreen;
|
||||
if (loopMax > options.size()) {
|
||||
loopMax = options.size();
|
||||
}
|
||||
|
||||
for (unsigned int i = screenNum * optionsPerScreen; i < loopMax; i++) {
|
||||
cbOption[i] = lv_checkbox_create(container1, nullptr);
|
||||
lv_checkbox_set_text(cbOption[i], options[i].name);
|
||||
if (settingsController.isWakeUpModeOn(static_cast<Controllers::Settings::WakeUpMode>(i))) {
|
||||
if (settingsController.isWakeUpModeOn(options[i].wakeUpMode)) {
|
||||
lv_checkbox_set_checked(cbOption[i], true);
|
||||
}
|
||||
cbOption[i]->user_data = this;
|
||||
lv_obj_set_event_cb(cbOption[i], event_handler);
|
||||
}
|
||||
return std::make_unique<Screens::Page>(screenNum, nScreens, container1);
|
||||
}
|
||||
|
||||
SettingWakeUp::~SettingWakeUp() {
|
||||
lv_obj_clean(lv_scr_act());
|
||||
settingsController.SaveSettings();
|
||||
bool SettingWakeUp::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
||||
return screens.OnTouchEvent(event);
|
||||
}
|
||||
|
||||
void SettingWakeUp::UpdateSelected(lv_obj_t* object) {
|
||||
|
@ -74,6 +102,8 @@ void SettingWakeUp::UpdateSelected(lv_obj_t* object) {
|
|||
// for example, when setting SingleTap, DoubleTap is unset and vice versa.
|
||||
auto modes = settingsController.getWakeUpModes();
|
||||
for (size_t i = 0; i < options.size(); ++i) {
|
||||
if (cbOption[i]) {
|
||||
lv_checkbox_set_checked(cbOption[i], modes[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,10 @@
|
|||
#include <cstdint>
|
||||
#include <lvgl/lvgl.h>
|
||||
#include "components/settings/Settings.h"
|
||||
#include "displayapp/screens/Page.h"
|
||||
#include "displayapp/screens/Screen.h"
|
||||
#include "displayapp/screens/ScreenList.h"
|
||||
#include "displayapp/widgets/PageIndicator.h"
|
||||
|
||||
namespace Pinetime {
|
||||
|
||||
|
@ -13,27 +16,40 @@ namespace Pinetime {
|
|||
|
||||
class SettingWakeUp : public Screen {
|
||||
public:
|
||||
SettingWakeUp(Pinetime::Controllers::Settings& settingsController);
|
||||
SettingWakeUp(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Settings& settingsController);
|
||||
~SettingWakeUp() override;
|
||||
|
||||
void UpdateSelected(lv_obj_t* object);
|
||||
|
||||
bool OnTouchEvent(TouchEvents event) override;
|
||||
|
||||
private:
|
||||
auto CreateScreenList();
|
||||
std::unique_ptr<Screen> CreateScreen(size_t screenNum);
|
||||
|
||||
struct Option {
|
||||
Controllers::Settings::WakeUpMode wakeUpMode;
|
||||
const char* name;
|
||||
};
|
||||
|
||||
static constexpr size_t numOptions = 6;
|
||||
static constexpr size_t optionsPerScreen = 4;
|
||||
static constexpr size_t nScreens = 2;
|
||||
|
||||
Controllers::Settings& settingsController;
|
||||
static constexpr std::array<Option, 5> options = {{
|
||||
|
||||
ScreenList<nScreens> screens;
|
||||
|
||||
static constexpr std::array<Option, numOptions> options = {{
|
||||
{Controllers::Settings::WakeUpMode::SingleTap, "Single Tap"},
|
||||
{Controllers::Settings::WakeUpMode::DoubleTap, "Double Tap"},
|
||||
{Controllers::Settings::WakeUpMode::RaiseWrist, "Raise Wrist"},
|
||||
{Controllers::Settings::WakeUpMode::Shake, "Shake Wake"},
|
||||
{Controllers::Settings::WakeUpMode::LowerWrist, "Lower Wrist"},
|
||||
{Controllers::Settings::WakeUpMode::ButtonUnlocks, "Button Unlock"},
|
||||
}};
|
||||
|
||||
lv_obj_t* cbOption[options.size()];
|
||||
std::array<lv_obj_t*, numOptions> cbOption;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,8 +54,7 @@ SettingWatchFace::SettingWatchFace(Pinetime::Applications::DisplayApp* app,
|
|||
std::array<Screens::SettingWatchFace::Item, UserWatchFaceTypes::Count>&& watchfaceItems,
|
||||
Pinetime::Controllers::Settings& settingsController,
|
||||
Pinetime::Controllers::FS& filesystem)
|
||||
: app {app},
|
||||
watchfaceItems {std::move(watchfaceItems)},
|
||||
: watchfaceItems {std::move(watchfaceItems)},
|
||||
settingsController {settingsController},
|
||||
filesystem {filesystem},
|
||||
screens {app, 0, CreateScreenList(), Screens::ScreenListModes::UpDown} {
|
||||
|
|
|
@ -34,7 +34,6 @@ namespace Pinetime {
|
|||
bool OnTouchEvent(TouchEvents event) override;
|
||||
|
||||
private:
|
||||
DisplayApp* app;
|
||||
auto CreateScreenList() const;
|
||||
std::unique_ptr<Screen> CreateScreen(unsigned int screenNum) const;
|
||||
|
||||
|
|
37
src/displayapp/widgets/PopupMessage.cpp
Normal file
37
src/displayapp/widgets/PopupMessage.cpp
Normal file
|
@ -0,0 +1,37 @@
|
|||
#include "displayapp/widgets/PopupMessage.h"
|
||||
#include <libraries/log/nrf_log.h>
|
||||
|
||||
using namespace Pinetime::Applications::Widgets;
|
||||
|
||||
PopupMessage::PopupMessage(const char* msg, int16_t h, int16_t w) : message {msg}, height {h}, width {w} {
|
||||
}
|
||||
|
||||
void PopupMessage::Create() {
|
||||
btnPopup = lv_btn_create(lv_scr_act(), nullptr);
|
||||
btnPopup->user_data = this;
|
||||
lv_obj_set_size(btnPopup, height, width);
|
||||
lv_obj_align(btnPopup, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
|
||||
lv_obj_set_style_local_bg_opa(btnPopup, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_60);
|
||||
lv_obj_set_style_local_text_font(btnPopup, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &lv_font_sys_80);
|
||||
lv_obj_t* lblMessage = lv_label_create(btnPopup, nullptr);
|
||||
lv_label_set_text_static(lblMessage, message);
|
||||
lv_obj_set_hidden(btnPopup, isHidden);
|
||||
}
|
||||
|
||||
void PopupMessage::SetHidden(bool hidden) {
|
||||
if (isHidden == hidden) {
|
||||
return;
|
||||
}
|
||||
isHidden = hidden;
|
||||
// create/delete on demand
|
||||
if (btnPopup == nullptr && !isHidden) {
|
||||
Create();
|
||||
} else if (btnPopup != nullptr) {
|
||||
lv_obj_del(btnPopup);
|
||||
btnPopup = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool PopupMessage::IsHidden() {
|
||||
return isHidden;
|
||||
}
|
24
src/displayapp/widgets/PopupMessage.h
Normal file
24
src/displayapp/widgets/PopupMessage.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
#pragma once
|
||||
#include <lvgl/lvgl.h>
|
||||
|
||||
namespace Pinetime {
|
||||
namespace Applications {
|
||||
namespace Widgets {
|
||||
class PopupMessage {
|
||||
public:
|
||||
// The caller owns the message string, it is not copied.
|
||||
PopupMessage(const char* msg, int16_t h, int16_t w);
|
||||
void Create();
|
||||
void SetHidden(bool hidden);
|
||||
bool IsHidden();
|
||||
|
||||
private:
|
||||
const char* message;
|
||||
lv_obj_t* btnPopup = nullptr;
|
||||
bool isHidden = true;
|
||||
int16_t height;
|
||||
int16_t width;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "drivers/Hrs3300.h"
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <nrf_gpio.h>
|
||||
|
||||
#include <FreeRTOS.h>
|
||||
|
@ -67,40 +68,37 @@ void Hrs3300::Disable() {
|
|||
WriteRegister(static_cast<uint8_t>(Registers::PDriver), 0);
|
||||
}
|
||||
|
||||
uint32_t Hrs3300::ReadHrs() {
|
||||
auto m = ReadRegister(static_cast<uint8_t>(Registers::C0DataM));
|
||||
auto h = ReadRegister(static_cast<uint8_t>(Registers::C0DataH));
|
||||
auto l = ReadRegister(static_cast<uint8_t>(Registers::C0dataL));
|
||||
return ((l & 0x30) << 12) | (m << 8) | ((h & 0x0f) << 4) | (l & 0x0f);
|
||||
}
|
||||
Hrs3300::PackedHrsAls Hrs3300::ReadHrsAls() {
|
||||
constexpr Registers dataRegisters[] =
|
||||
{Registers::C1dataM, Registers::C0DataM, Registers::C0DataH, Registers::C1dataH, Registers::C1dataL, Registers::C0dataL};
|
||||
// Calculate smallest register address
|
||||
constexpr uint8_t baseOffset = static_cast<uint8_t>(*std::min_element(std::begin(dataRegisters), std::end(dataRegisters)));
|
||||
// Calculate largest address to determine length of read needed
|
||||
// Add one to largest relative index to find the length
|
||||
constexpr uint8_t length = static_cast<uint8_t>(*std::max_element(std::begin(dataRegisters), std::end(dataRegisters))) - baseOffset + 1;
|
||||
|
||||
uint32_t Hrs3300::ReadAls() {
|
||||
auto m = ReadRegister(static_cast<uint8_t>(Registers::C1dataM));
|
||||
auto h = ReadRegister(static_cast<uint8_t>(Registers::C1dataH));
|
||||
auto l = ReadRegister(static_cast<uint8_t>(Registers::C1dataL));
|
||||
return ((h & 0x3f) << 11) | (m << 3) | (l & 0x07);
|
||||
}
|
||||
|
||||
void Hrs3300::SetGain(uint8_t gain) {
|
||||
constexpr uint8_t maxGain = 64U;
|
||||
gain = std::min(gain, maxGain);
|
||||
uint8_t hgain = 0;
|
||||
while ((1 << hgain) < gain) {
|
||||
++hgain;
|
||||
Hrs3300::PackedHrsAls res;
|
||||
uint8_t buf[length];
|
||||
auto ret = twiMaster.Read(twiAddress, baseOffset, buf, length);
|
||||
if (ret != TwiMaster::ErrorCodes::NoError) {
|
||||
NRF_LOG_INFO("READ ERROR");
|
||||
}
|
||||
// hrs
|
||||
uint8_t m = static_cast<uint8_t>(Registers::C0DataM) - baseOffset;
|
||||
uint8_t h = static_cast<uint8_t>(Registers::C0DataH) - baseOffset;
|
||||
uint8_t l = static_cast<uint8_t>(Registers::C0dataL) - baseOffset;
|
||||
// There are two extra bits (17 and 18) but they are not read here
|
||||
// as resolutions >16bit aren't practically useful (too slow) and
|
||||
// all hrs values throughout InfiniTime are 16bit
|
||||
res.hrs = (buf[m] << 8) | ((buf[h] & 0x0f) << 4) | (buf[l] & 0x0f);
|
||||
|
||||
WriteRegister(static_cast<uint8_t>(Registers::Hgain), hgain << 2);
|
||||
}
|
||||
// als
|
||||
m = static_cast<uint8_t>(Registers::C1dataM) - baseOffset;
|
||||
h = static_cast<uint8_t>(Registers::C1dataH) - baseOffset;
|
||||
l = static_cast<uint8_t>(Registers::C1dataL) - baseOffset;
|
||||
res.als = ((buf[h] & 0x3f) << 11) | (buf[m] << 3) | (buf[l] & 0x07);
|
||||
|
||||
void Hrs3300::SetDrive(uint8_t drive) {
|
||||
auto en = ReadRegister(static_cast<uint8_t>(Registers::Enable));
|
||||
auto pd = ReadRegister(static_cast<uint8_t>(Registers::PDriver));
|
||||
|
||||
en = (en & 0xf7) | ((drive & 2) << 2);
|
||||
pd = (pd & 0xbf) | ((drive & 1) << 6);
|
||||
|
||||
WriteRegister(static_cast<uint8_t>(Registers::Enable), en);
|
||||
WriteRegister(static_cast<uint8_t>(Registers::PDriver), pd);
|
||||
return res;
|
||||
}
|
||||
|
||||
void Hrs3300::WriteRegister(uint8_t reg, uint8_t data) {
|
||||
|
|
|
@ -21,6 +21,11 @@ namespace Pinetime {
|
|||
Hgain = 0x17
|
||||
};
|
||||
|
||||
struct PackedHrsAls {
|
||||
uint16_t hrs;
|
||||
uint16_t als;
|
||||
};
|
||||
|
||||
Hrs3300(TwiMaster& twiMaster, uint8_t twiAddress);
|
||||
Hrs3300(const Hrs3300&) = delete;
|
||||
Hrs3300& operator=(const Hrs3300&) = delete;
|
||||
|
@ -30,10 +35,7 @@ namespace Pinetime {
|
|||
void Init();
|
||||
void Enable();
|
||||
void Disable();
|
||||
uint32_t ReadHrs();
|
||||
uint32_t ReadAls();
|
||||
void SetGain(uint8_t gain);
|
||||
void SetDrive(uint8_t drive);
|
||||
PackedHrsAls ReadHrsAls();
|
||||
|
||||
private:
|
||||
TwiMaster& twiMaster;
|
||||
|
|
|
@ -70,7 +70,8 @@ void HeartRateTask::Work() {
|
|||
}
|
||||
|
||||
if (measurementStarted) {
|
||||
int8_t ambient = ppg.Preprocess(heartRateSensor.ReadHrs(), heartRateSensor.ReadAls());
|
||||
auto sensorData = heartRateSensor.ReadHrsAls();
|
||||
int8_t ambient = ppg.Preprocess(sensorData.hrs, sensorData.als);
|
||||
int bpm = ppg.HeartRate();
|
||||
|
||||
// If ambient light detected or a reset requested (bpm < 0)
|
||||
|
|
|
@ -419,7 +419,8 @@ typedef void* lv_indev_drv_user_data_t; /*Type of user data in the in
|
|||
LV_FONT_DECLARE(jetbrains_mono_76) \
|
||||
LV_FONT_DECLARE(open_sans_light) \
|
||||
LV_FONT_DECLARE(fontawesome_weathericons) \
|
||||
LV_FONT_DECLARE(lv_font_sys_48)
|
||||
LV_FONT_DECLARE(lv_font_sys_48) \
|
||||
LV_FONT_DECLARE(lv_font_sys_80)
|
||||
|
||||
/* Enable it if you have fonts with a lot of characters.
|
||||
* The limit depends on the font size, font face and bpp
|
||||
|
|
|
@ -104,7 +104,7 @@ Pinetime::Controllers::DateTime dateTimeController {settingsController};
|
|||
Pinetime::Drivers::Watchdog watchdog;
|
||||
Pinetime::Controllers::NotificationManager notificationManager;
|
||||
Pinetime::Controllers::MotionController motionController;
|
||||
Pinetime::Controllers::AlarmController alarmController {dateTimeController};
|
||||
Pinetime::Controllers::AlarmController alarmController {dateTimeController, fs};
|
||||
Pinetime::Controllers::TouchHandler touchHandler;
|
||||
Pinetime::Controllers::ButtonHandler buttonHandler;
|
||||
Pinetime::Controllers::BrightnessController brightnessController {};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#include "systemtask/SystemTask.h"
|
||||
#if configUSE_TRACE_FACILITY == 1
|
||||
#if NRF_LOG_ENABLED
|
||||
// FreeRtosMonitor
|
||||
#include <FreeRTOS.h>
|
||||
#include <task.h>
|
||||
|
|
|
@ -189,40 +189,21 @@ void SystemTask::Work() {
|
|||
if (xQueueReceive(systemTasksMsgQueue, &msg, 100) == pdTRUE) {
|
||||
switch (msg) {
|
||||
case Messages::EnableSleeping:
|
||||
// Make sure that exiting an app doesn't enable sleeping,
|
||||
// if the exiting was caused by a firmware update
|
||||
if (!bleController.IsFirmwareUpdating()) {
|
||||
doNotGoToSleep = false;
|
||||
}
|
||||
displayApp.PushMessage(Pinetime::Applications::Display::Messages::NotifyDeviceActivity);
|
||||
wakeLocksHeld--;
|
||||
break;
|
||||
case Messages::DisableSleeping:
|
||||
doNotGoToSleep = true;
|
||||
GoToRunning();
|
||||
wakeLocksHeld++;
|
||||
break;
|
||||
case Messages::GoToRunning:
|
||||
// SPI doesn't go to sleep for always on mode
|
||||
if (!settingsController.GetAlwaysOnDisplay()) {
|
||||
spi.Wakeup();
|
||||
}
|
||||
|
||||
// Double Tap needs the touch screen to be in normal mode
|
||||
if (!settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::DoubleTap)) {
|
||||
touchPanel.Wakeup();
|
||||
}
|
||||
|
||||
spiNorFlash.Wakeup();
|
||||
|
||||
displayApp.PushMessage(Pinetime::Applications::Display::Messages::GoToRunning);
|
||||
heartRateApp.PushMessage(Pinetime::Applications::HeartRateTask::Messages::WakeUp);
|
||||
|
||||
if (bleController.IsRadioEnabled() && !bleController.IsConnected()) {
|
||||
nimbleController.RestartFastAdv();
|
||||
}
|
||||
|
||||
state = SystemTaskState::Running;
|
||||
GoToRunning();
|
||||
break;
|
||||
case Messages::TouchWakeUp: {
|
||||
if (touchHandler.ProcessTouchInfo(touchPanel.GetTouchInfo())) {
|
||||
Pinetime::Controllers::TouchHandler::TouchProcessReply reply;
|
||||
reply =
|
||||
touchHandler.ProcessTouchInfo(touchPanel.GetTouchInfo(),
|
||||
settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::ButtonUnlocks));
|
||||
if (reply == Pinetime::Controllers::TouchHandler::TouchProcessReply::TouchEvent) {
|
||||
auto gesture = touchHandler.GestureGet();
|
||||
if (settingsController.GetNotificationStatus() != Controllers::Settings::Notification::Sleep &&
|
||||
gesture != Pinetime::Applications::TouchEvents::None &&
|
||||
|
@ -230,41 +211,32 @@ void SystemTask::Work() {
|
|||
settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::DoubleTap)) ||
|
||||
(gesture == Pinetime::Applications::TouchEvents::Tap &&
|
||||
settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::SingleTap)))) {
|
||||
touchHandler.SetWokenBy(Pinetime::Controllers::TouchHandler::WokenBy::WakeUpAction, true);
|
||||
GoToRunning();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Messages::GoToSleep:
|
||||
if (doNotGoToSleep) {
|
||||
break;
|
||||
}
|
||||
state = SystemTaskState::GoingToSleep; // Already set in PushMessage()
|
||||
NRF_LOG_INFO("[systemtask] Going to sleep");
|
||||
displayApp.PushMessage(Pinetime::Applications::Display::Messages::GoToSleep);
|
||||
heartRateApp.PushMessage(Pinetime::Applications::HeartRateTask::Messages::GoToSleep);
|
||||
GoToSleep();
|
||||
break;
|
||||
case Messages::OnNewTime:
|
||||
displayApp.PushMessage(Pinetime::Applications::Display::Messages::NotifyDeviceActivity);
|
||||
displayApp.PushMessage(Pinetime::Applications::Display::Messages::UpdateDateTime);
|
||||
if (alarmController.State() == Controllers::AlarmController::AlarmState::Set) {
|
||||
if (alarmController.IsEnabled()) {
|
||||
alarmController.ScheduleAlarm();
|
||||
}
|
||||
break;
|
||||
case Messages::OnNewNotification:
|
||||
if (settingsController.GetNotificationStatus() == Pinetime::Controllers::Settings::Notification::On) {
|
||||
if (state == SystemTaskState::Sleeping) {
|
||||
if (IsSleeping()) {
|
||||
GoToRunning();
|
||||
} else {
|
||||
displayApp.PushMessage(Pinetime::Applications::Display::Messages::NotifyDeviceActivity);
|
||||
}
|
||||
touchHandler.SetWokenBy(Pinetime::Controllers::TouchHandler::WokenBy::Other, false);
|
||||
displayApp.PushMessage(Pinetime::Applications::Display::Messages::NewNotification);
|
||||
}
|
||||
break;
|
||||
case Messages::SetOffAlarm:
|
||||
if (state == SystemTaskState::Sleeping) {
|
||||
GoToRunning();
|
||||
}
|
||||
touchHandler.SetWokenBy(Pinetime::Controllers::TouchHandler::WokenBy::Other, false);
|
||||
displayApp.PushMessage(Pinetime::Applications::Display::Messages::AlarmTriggered);
|
||||
break;
|
||||
case Messages::BleConnected:
|
||||
|
@ -273,42 +245,54 @@ void SystemTask::Work() {
|
|||
bleDiscoveryTimer = 5;
|
||||
break;
|
||||
case Messages::BleFirmwareUpdateStarted:
|
||||
doNotGoToSleep = true;
|
||||
if (state == SystemTaskState::Sleeping) {
|
||||
GoToRunning();
|
||||
}
|
||||
wakeLocksHeld++;
|
||||
touchHandler.SetWokenBy(Pinetime::Controllers::TouchHandler::WokenBy::Other, false);
|
||||
displayApp.PushMessage(Pinetime::Applications::Display::Messages::BleFirmwareUpdateStarted);
|
||||
break;
|
||||
case Messages::BleFirmwareUpdateFinished:
|
||||
if (bleController.State() == Pinetime::Controllers::Ble::FirmwareUpdateStates::Validated) {
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
doNotGoToSleep = false;
|
||||
wakeLocksHeld--;
|
||||
break;
|
||||
case Messages::StartFileTransfer:
|
||||
NRF_LOG_INFO("[systemtask] FS Started");
|
||||
doNotGoToSleep = true;
|
||||
if (state == SystemTaskState::Sleeping) {
|
||||
GoToRunning();
|
||||
}
|
||||
wakeLocksHeld++;
|
||||
touchHandler.SetWokenBy(Pinetime::Controllers::TouchHandler::WokenBy::Other, false);
|
||||
// TODO add intent of fs access icon or something
|
||||
break;
|
||||
case Messages::StopFileTransfer:
|
||||
NRF_LOG_INFO("[systemtask] FS Stopped");
|
||||
doNotGoToSleep = false;
|
||||
wakeLocksHeld--;
|
||||
// TODO add intent of fs access icon or something
|
||||
break;
|
||||
case Messages::OnTouchEvent:
|
||||
if (touchHandler.ProcessTouchInfo(touchPanel.GetTouchInfo())) {
|
||||
Pinetime::Controllers::TouchHandler::TouchProcessReply reply;
|
||||
reply =
|
||||
touchHandler.ProcessTouchInfo(touchPanel.GetTouchInfo(),
|
||||
settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::ButtonUnlocks));
|
||||
if (reply == Pinetime::Controllers::TouchHandler::TouchProcessReply::TouchEvent) {
|
||||
displayApp.PushMessage(Pinetime::Applications::Display::Messages::TouchEvent);
|
||||
} else if (reply == Pinetime::Controllers::TouchHandler::TouchProcessReply::IgnoreTouchPopup) {
|
||||
displayApp.PushMessage(Pinetime::Applications::Display::Messages::ShowIgnoreTouchPopup);
|
||||
touchHandler.SetIgnoreTouchPopupHidden(false);
|
||||
}
|
||||
break;
|
||||
case Messages::HandleButtonEvent: {
|
||||
// if the IgnoreTouchPopup is active the first button event unlocks the device
|
||||
if (!touchHandler.IsIgnoreTouchPopupHidden()) {
|
||||
touchHandler.SetWokenBy(Pinetime::Controllers::TouchHandler::WokenBy::Button, false);
|
||||
touchHandler.SetIgnoreTouchPopupHidden(true);
|
||||
displayApp.PushMessage(Pinetime::Applications::Display::Messages::HideIgnoreTouchPopup);
|
||||
} else {
|
||||
Controllers::ButtonActions action = Controllers::ButtonActions::None;
|
||||
if (nrf_gpio_pin_read(Pinetime::PinMap::Button) == 0) {
|
||||
action = buttonHandler.HandleEvent(Controllers::ButtonHandler::Events::Release);
|
||||
} else {
|
||||
action = buttonHandler.HandleEvent(Controllers::ButtonHandler::Events::Press);
|
||||
touchHandler.SetWokenBy(Pinetime::Controllers::TouchHandler::WokenBy::Button, false);
|
||||
// This is for faster wakeup, sacrificing special longpress and doubleclick handling while sleeping
|
||||
if (IsSleeping()) {
|
||||
fastWakeUpDone = true;
|
||||
|
@ -317,12 +301,20 @@ void SystemTask::Work() {
|
|||
}
|
||||
}
|
||||
HandleButtonAction(action);
|
||||
}
|
||||
} break;
|
||||
case Messages::HandleButtonTimerEvent: {
|
||||
auto action = buttonHandler.HandleEvent(Controllers::ButtonHandler::Events::Timer);
|
||||
HandleButtonAction(action);
|
||||
} break;
|
||||
case Messages::OnDisplayTaskSleeping:
|
||||
// The state was set to GoingToSleep when GoToSleep() was called
|
||||
// If the state is no longer GoingToSleep, we have since transitioned back to Running
|
||||
// In this case absorb the OnDisplayTaskSleeping
|
||||
// as DisplayApp is about to receive GoToRunning
|
||||
if (state != SystemTaskState::GoingToSleep) {
|
||||
break;
|
||||
}
|
||||
if (BootloaderVersion::IsValid()) {
|
||||
// First versions of the bootloader do not expose their version and cannot initialize the SPI NOR FLASH
|
||||
// if it's in sleep mode. Avoid bricked device by disabling sleep mode on these versions.
|
||||
|
@ -340,6 +332,8 @@ void SystemTask::Work() {
|
|||
}
|
||||
|
||||
state = SystemTaskState::Sleeping;
|
||||
// reset touch restrictions when going to sleep
|
||||
touchHandler.SetWokenBy(Pinetime::Controllers::TouchHandler::WokenBy::Other, false);
|
||||
break;
|
||||
case Messages::OnNewDay:
|
||||
// We might be sleeping (with TWI device disabled.
|
||||
|
@ -349,39 +343,26 @@ void SystemTask::Work() {
|
|||
case Messages::OnNewHour:
|
||||
using Pinetime::Controllers::AlarmController;
|
||||
if (settingsController.GetNotificationStatus() != Controllers::Settings::Notification::Sleep &&
|
||||
settingsController.GetChimeOption() == Controllers::Settings::ChimesOption::Hours &&
|
||||
alarmController.State() != AlarmController::AlarmState::Alerting) {
|
||||
// if sleeping, we can't send a chime to displayApp yet (SPI flash switched off)
|
||||
// request running first and repush the chime message
|
||||
if (state == SystemTaskState::Sleeping) {
|
||||
settingsController.GetChimeOption() == Controllers::Settings::ChimesOption::Hours && !alarmController.IsAlerting()) {
|
||||
GoToRunning();
|
||||
PushMessage(msg);
|
||||
} else {
|
||||
touchHandler.SetWokenBy(Pinetime::Controllers::TouchHandler::WokenBy::Other, false);
|
||||
displayApp.PushMessage(Pinetime::Applications::Display::Messages::Chime);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Messages::OnNewHalfHour:
|
||||
using Pinetime::Controllers::AlarmController;
|
||||
if (settingsController.GetNotificationStatus() != Controllers::Settings::Notification::Sleep &&
|
||||
settingsController.GetChimeOption() == Controllers::Settings::ChimesOption::HalfHours &&
|
||||
alarmController.State() != AlarmController::AlarmState::Alerting) {
|
||||
// if sleeping, we can't send a chime to displayApp yet (SPI flash switched off)
|
||||
// request running first and repush the chime message
|
||||
if (state == SystemTaskState::Sleeping) {
|
||||
settingsController.GetChimeOption() == Controllers::Settings::ChimesOption::HalfHours && !alarmController.IsAlerting()) {
|
||||
GoToRunning();
|
||||
PushMessage(msg);
|
||||
} else {
|
||||
touchHandler.SetWokenBy(Pinetime::Controllers::TouchHandler::WokenBy::Other, false);
|
||||
displayApp.PushMessage(Pinetime::Applications::Display::Messages::Chime);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Messages::OnChargingEvent:
|
||||
batteryController.ReadPowerState();
|
||||
displayApp.PushMessage(Applications::Display::Messages::OnChargingEvent);
|
||||
if (state == SystemTaskState::Sleeping) {
|
||||
GoToRunning();
|
||||
}
|
||||
touchHandler.SetWokenBy(Pinetime::Controllers::TouchHandler::WokenBy::Other, false);
|
||||
displayApp.PushMessage(Applications::Display::Messages::OnChargingEvent);
|
||||
break;
|
||||
case Messages::MeasureBatteryTimerExpired:
|
||||
batteryController.MeasureVoltage();
|
||||
|
@ -390,9 +371,8 @@ void SystemTask::Work() {
|
|||
nimbleController.NotifyBatteryLevel(batteryController.PercentRemaining());
|
||||
break;
|
||||
case Messages::OnPairing:
|
||||
if (state == SystemTaskState::Sleeping) {
|
||||
GoToRunning();
|
||||
}
|
||||
touchHandler.SetWokenBy(Pinetime::Controllers::TouchHandler::WokenBy::Other, false);
|
||||
displayApp.PushMessage(Pinetime::Applications::Display::Messages::ShowPairingKey);
|
||||
break;
|
||||
case Messages::BleRadioEnableToggle:
|
||||
|
@ -427,12 +407,50 @@ void SystemTask::Work() {
|
|||
#pragma clang diagnostic pop
|
||||
}
|
||||
|
||||
void SystemTask::UpdateMotion() {
|
||||
if (state == SystemTaskState::GoingToSleep || state == SystemTaskState::WakingUp) {
|
||||
void SystemTask::GoToRunning() {
|
||||
if (state == SystemTaskState::Running) {
|
||||
return;
|
||||
}
|
||||
// SPI doesn't go to sleep for always on mode
|
||||
if (!settingsController.GetAlwaysOnDisplay()) {
|
||||
spi.Wakeup();
|
||||
}
|
||||
|
||||
if (state == SystemTaskState::Sleeping && !(settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::RaiseWrist) ||
|
||||
// Double Tap needs the touch screen to be in normal mode
|
||||
if (!settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::DoubleTap)) {
|
||||
touchPanel.Wakeup();
|
||||
}
|
||||
|
||||
spiNorFlash.Wakeup();
|
||||
|
||||
displayApp.PushMessage(Pinetime::Applications::Display::Messages::GoToRunning);
|
||||
heartRateApp.PushMessage(Pinetime::Applications::HeartRateTask::Messages::WakeUp);
|
||||
|
||||
if (bleController.IsRadioEnabled() && !bleController.IsConnected()) {
|
||||
nimbleController.RestartFastAdv();
|
||||
}
|
||||
|
||||
state = SystemTaskState::Running;
|
||||
};
|
||||
|
||||
void SystemTask::GoToSleep() {
|
||||
if (IsSleeping()) {
|
||||
return;
|
||||
}
|
||||
if (IsSleepDisabled()) {
|
||||
return;
|
||||
}
|
||||
NRF_LOG_INFO("[systemtask] Going to sleep");
|
||||
displayApp.PushMessage(Pinetime::Applications::Display::Messages::GoToSleep);
|
||||
heartRateApp.PushMessage(Pinetime::Applications::HeartRateTask::Messages::GoToSleep);
|
||||
touchHandler.SetIgnoreTouchPopupHidden(true);
|
||||
displayApp.PushMessage(Pinetime::Applications::Display::Messages::HideIgnoreTouchPopup);
|
||||
|
||||
state = SystemTaskState::GoingToSleep;
|
||||
};
|
||||
|
||||
void SystemTask::UpdateMotion() {
|
||||
if (IsSleeping() && !(settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::RaiseWrist) ||
|
||||
settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::Shake) ||
|
||||
motionController.GetService()->IsMotionNotificationSubscribed())) {
|
||||
return;
|
||||
|
@ -452,12 +470,15 @@ void SystemTask::UpdateMotion() {
|
|||
motionController.ShouldRaiseWake()) ||
|
||||
(settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::Shake) &&
|
||||
motionController.ShouldShakeWake(settingsController.GetShakeThreshold()))) {
|
||||
if (state == SystemTaskState::Sleeping) {
|
||||
touchHandler.SetWokenBy(Pinetime::Controllers::TouchHandler::WokenBy::WakeUpAction, true);
|
||||
}
|
||||
GoToRunning();
|
||||
}
|
||||
}
|
||||
if (settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::LowerWrist) && state == SystemTaskState::Running &&
|
||||
motionController.ShouldLowerSleep()) {
|
||||
PushMessage(Messages::GoToSleep);
|
||||
GoToSleep();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -473,7 +494,7 @@ void SystemTask::HandleButtonAction(Controllers::ButtonActions action) {
|
|||
switch (action) {
|
||||
case Actions::Click:
|
||||
// If the first action after fast wakeup is a click, it should be ignored.
|
||||
if (!fastWakeUpDone && state != SystemTaskState::GoingToSleep) {
|
||||
if (!fastWakeUpDone) {
|
||||
displayApp.PushMessage(Applications::Display::Messages::ButtonPushed);
|
||||
}
|
||||
break;
|
||||
|
@ -493,17 +514,10 @@ void SystemTask::HandleButtonAction(Controllers::ButtonActions action) {
|
|||
fastWakeUpDone = false;
|
||||
}
|
||||
|
||||
void SystemTask::GoToRunning() {
|
||||
if (state == SystemTaskState::Sleeping) {
|
||||
state = SystemTaskState::WakingUp;
|
||||
PushMessage(Messages::GoToRunning);
|
||||
}
|
||||
}
|
||||
|
||||
void SystemTask::OnTouchEvent() {
|
||||
if (state == SystemTaskState::Running) {
|
||||
PushMessage(Messages::OnTouchEvent);
|
||||
} else if (state == SystemTaskState::Sleeping) {
|
||||
} else {
|
||||
if (settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::SingleTap) or
|
||||
settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::DoubleTap)) {
|
||||
PushMessage(Messages::TouchWakeUp);
|
||||
|
@ -512,10 +526,6 @@ void SystemTask::OnTouchEvent() {
|
|||
}
|
||||
|
||||
void SystemTask::PushMessage(System::Messages msg) {
|
||||
if (msg == Messages::GoToSleep && !doNotGoToSleep) {
|
||||
state = SystemTaskState::GoingToSleep;
|
||||
}
|
||||
|
||||
if (in_isr()) {
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
xQueueSendFromISR(systemTasksMsgQueue, &msg, &xHigherPriorityTaskWoken);
|
||||
|
|
|
@ -52,7 +52,12 @@ namespace Pinetime {
|
|||
namespace System {
|
||||
class SystemTask {
|
||||
public:
|
||||
enum class SystemTaskState { Sleeping, Running, GoingToSleep, WakingUp };
|
||||
enum class SystemTaskState { Sleeping, Running, GoingToSleep };
|
||||
// Enum describes how the watch was woken:
|
||||
// * WakeUpAction: The actions selected in the wakeup settings, single/double tap, raise, shake
|
||||
// * Button: The hardware button
|
||||
// * Other: Other things that can wake the watch up, eg. apps and notifications.
|
||||
enum class WokenBy { WakeUpAction, Button, Other };
|
||||
SystemTask(Drivers::SpiMaster& spi,
|
||||
Pinetime::Drivers::SpiNorFlash& spiNorFlash,
|
||||
Drivers::TwiMaster& twiMaster,
|
||||
|
@ -79,11 +84,8 @@ namespace Pinetime {
|
|||
|
||||
void OnTouchEvent();
|
||||
|
||||
void OnIdle();
|
||||
void OnDim();
|
||||
|
||||
bool IsSleepDisabled() {
|
||||
return doNotGoToSleep;
|
||||
return wakeLocksHeld > 0;
|
||||
}
|
||||
|
||||
Pinetime::Controllers::NimbleController& nimble() {
|
||||
|
@ -91,7 +93,7 @@ namespace Pinetime {
|
|||
};
|
||||
|
||||
bool IsSleeping() const {
|
||||
return state == SystemTaskState::Sleeping || state == SystemTaskState::WakingUp;
|
||||
return state != SystemTaskState::Running;
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -127,13 +129,14 @@ namespace Pinetime {
|
|||
bool isBleDiscoveryTimerRunning = false;
|
||||
uint8_t bleDiscoveryTimer = 0;
|
||||
TimerHandle_t measureBatteryTimer;
|
||||
bool doNotGoToSleep = false;
|
||||
uint8_t wakeLocksHeld = 0;
|
||||
SystemTaskState state = SystemTaskState::Running;
|
||||
|
||||
void HandleButtonAction(Controllers::ButtonActions action);
|
||||
bool fastWakeUpDone = false;
|
||||
|
||||
void GoToRunning();
|
||||
void GoToSleep();
|
||||
void UpdateMotion();
|
||||
bool stepCounterMustBeReset = false;
|
||||
static constexpr TickType_t batteryMeasurementPeriod = pdMS_TO_TICKS(10 * 60 * 1000);
|
||||
|
|
27
src/systemtask/WakeLock.cpp
Normal file
27
src/systemtask/WakeLock.cpp
Normal file
|
@ -0,0 +1,27 @@
|
|||
#include "systemtask/WakeLock.h"
|
||||
|
||||
using namespace Pinetime::System;
|
||||
|
||||
WakeLock::WakeLock(SystemTask& systemTask) : systemTask {systemTask} {
|
||||
lockHeld = false;
|
||||
}
|
||||
|
||||
WakeLock::~WakeLock() {
|
||||
Release();
|
||||
}
|
||||
|
||||
void WakeLock::Lock() {
|
||||
if (lockHeld) {
|
||||
return;
|
||||
}
|
||||
systemTask.PushMessage(Messages::DisableSleeping);
|
||||
lockHeld = true;
|
||||
}
|
||||
|
||||
void WakeLock::Release() {
|
||||
if (!lockHeld) {
|
||||
return;
|
||||
}
|
||||
systemTask.PushMessage(Messages::EnableSleeping);
|
||||
lockHeld = false;
|
||||
}
|
19
src/systemtask/WakeLock.h
Normal file
19
src/systemtask/WakeLock.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
#include "systemtask/SystemTask.h"
|
||||
|
||||
namespace Pinetime {
|
||||
namespace System {
|
||||
class WakeLock {
|
||||
public:
|
||||
WakeLock(SystemTask& systemTask);
|
||||
~WakeLock();
|
||||
void Lock();
|
||||
void Release();
|
||||
|
||||
private:
|
||||
bool lockHeld;
|
||||
SystemTask& systemTask;
|
||||
};
|
||||
}
|
||||
}
|
|
@ -33,9 +33,9 @@ Pinetime::Applications::TouchEvents TouchHandler::GestureGet() {
|
|||
return returnGesture;
|
||||
}
|
||||
|
||||
bool TouchHandler::ProcessTouchInfo(Drivers::Cst816S::TouchInfos info) {
|
||||
TouchHandler::TouchProcessReply TouchHandler::ProcessTouchInfo(Drivers::Cst816S::TouchInfos info, bool buttonUnlocksOn) {
|
||||
if (!info.isValid) {
|
||||
return false;
|
||||
return TouchHandler::TouchProcessReply::NoAction;
|
||||
}
|
||||
|
||||
// Only a single gesture per touch
|
||||
|
@ -62,5 +62,19 @@ bool TouchHandler::ProcessTouchInfo(Drivers::Cst816S::TouchInfos info) {
|
|||
|
||||
currentTouchPoint = {info.x, info.y, info.touching};
|
||||
|
||||
return true;
|
||||
// if the watch was just woken by touch and button must be used to unlock, ignore the first touch event which
|
||||
// is the touch event that woke the watch. Otherwise the lock-popup will be displayed
|
||||
if (buttonUnlocksOn && ignoreNextTouchEvent) {
|
||||
ignoreNextTouchEvent = false;
|
||||
return TouchHandler::TouchProcessReply::NoAction;
|
||||
|
||||
} else if (!buttonUnlocksOn || wokenBy != WokenBy::WakeUpAction) {
|
||||
|
||||
// if we get to here TouchEvents is allowed and the "ButtonUnlocks" requirement can be overridden
|
||||
wokenBy = WokenBy::Other;
|
||||
|
||||
return TouchHandler::TouchProcessReply::TouchEvent;
|
||||
} else {
|
||||
return TouchHandler::TouchProcessReply::IgnoreTouchPopup;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,13 +6,25 @@ namespace Pinetime {
|
|||
namespace Controllers {
|
||||
class TouchHandler {
|
||||
public:
|
||||
// Enum describes how the watch was woken:
|
||||
// * WakeUpAction: The actions selected in the wakeup settings, single/double tap, raise, shake
|
||||
// * Button: The hardware button
|
||||
// * Other: Other things that can wake the watch up, eg. apps and notifications.
|
||||
enum class WokenBy { WakeUpAction, Button, Other };
|
||||
|
||||
// Enum describes how the reply from ProcessTouchInfo should be interpreted:
|
||||
// * NoAction: Do nothing, ignore input.
|
||||
// * TouchEvent: The input should be treated as a normal touch event.
|
||||
// * IgnoreTouchPopup: Show the popup when ignoring touch input.
|
||||
enum class TouchProcessReply { NoAction, TouchEvent, IgnoreTouchPopup };
|
||||
|
||||
struct TouchPoint {
|
||||
int x;
|
||||
int y;
|
||||
bool touching;
|
||||
};
|
||||
|
||||
bool ProcessTouchInfo(Drivers::Cst816S::TouchInfos info);
|
||||
TouchProcessReply ProcessTouchInfo(Drivers::Cst816S::TouchInfos info, bool buttonUnlocksOn = false);
|
||||
|
||||
bool IsTouching() const {
|
||||
return currentTouchPoint.touching;
|
||||
|
@ -26,12 +38,29 @@ namespace Pinetime {
|
|||
return currentTouchPoint.y;
|
||||
}
|
||||
|
||||
void SetIgnoreTouchPopupHidden(bool hidden) {
|
||||
ignoreTouchPopupHidden = hidden;
|
||||
}
|
||||
|
||||
bool IsIgnoreTouchPopupHidden() {
|
||||
return ignoreTouchPopupHidden;
|
||||
}
|
||||
|
||||
void SetWokenBy(WokenBy woken, bool ifButtonUnlocksIgnoreTouch) {
|
||||
wokenBy = woken;
|
||||
ignoreNextTouchEvent = ifButtonUnlocksIgnoreTouch;
|
||||
}
|
||||
|
||||
Pinetime::Applications::TouchEvents GestureGet();
|
||||
|
||||
private:
|
||||
Pinetime::Applications::TouchEvents gesture;
|
||||
TouchPoint currentTouchPoint = {};
|
||||
bool gestureReleased = true;
|
||||
|
||||
WokenBy wokenBy;
|
||||
bool ignoreNextTouchEvent = false;
|
||||
bool ignoreTouchPopupHidden = true;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue