Skip to content

Commit a0cd439

Browse files
NeroBurnerght
andauthored
Alarm persist to flash (InfiniTimeOrg#1367)
* AlarmController: Add saving alarm time to file Save the set alarm time to the SPI NOR flash, so it does not reset to the default value when the watch resets, e.g. due to watchdog timeout or reflashing of a new version of InfiniTime. Just like the `Settings.h` `LoadSettingsFromFile()` the previous alarm at boot (if available) and `SaveSettingsToFile()` the current alarm when the `Alarm.h` screen is closed (only if the settings have changed). The alarm-settings file is stored in `.system/alarm.dat`. The `.system` folder is created if it doesn't yet exist. Fixes: InfiniTimeOrg#1330 * alarmController: close .system dir after usage Close the `lfs_dir` object for the `.system` dir after usage. Otherwise on the second changed alarm the system will lockup because the `.system` dir is already open and was never closed. --------- Co-authored-by: Galdor Takacs <g@ldor.de>
1 parent 997e4ce commit a0cd439

File tree

5 files changed

+135
-48
lines changed

5 files changed

+135
-48
lines changed

‎src/components/alarm/AlarmController.cpp‎

Lines changed: 88 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,13 @@
1919
#include "systemtask/SystemTask.h"
2020
#include "task.h"
2121
#include <chrono>
22+
#include <libraries/log/nrf_log.h>
2223

2324
using namespace Pinetime::Controllers;
2425
using namespace std::chrono_literals;
2526

26-
AlarmController::AlarmController(Controllers::DateTime& dateTimeController) : dateTimeController {dateTimeController} {
27+
AlarmController::AlarmController(Controllers::DateTime& dateTimeController, Controllers::FS& fs)
28+
: dateTimeController {dateTimeController}, fs {fs} {
2729
}
2830

2931
namespace {
@@ -36,11 +38,28 @@ namespace {
3638
void AlarmController::Init(System::SystemTask* systemTask) {
3739
this->systemTask = systemTask;
3840
alarmTimer = xTimerCreate("Alarm", 1, pdFALSE, this, SetOffAlarm);
41+
LoadSettingsFromFile();
42+
if (alarm.isEnabled) {
43+
NRF_LOG_INFO("[AlarmController] Loaded alarm was enabled, scheduling");
44+
ScheduleAlarm();
45+
}
46+
}
47+
48+
void AlarmController::SaveAlarm() {
49+
// verify if it is necessary to save
50+
if (alarmChanged) {
51+
SaveSettingsToFile();
52+
}
53+
alarmChanged = false;
3954
}
4055

4156
void AlarmController::SetAlarmTime(uint8_t alarmHr, uint8_t alarmMin) {
42-
hours = alarmHr;
43-
minutes = alarmMin;
57+
if (alarm.hours == alarmHr && alarm.minutes == alarmMin) {
58+
return;
59+
}
60+
alarm.hours = alarmHr;
61+
alarm.minutes = alarmMin;
62+
alarmChanged = true;
4463
}
4564

4665
void AlarmController::ScheduleAlarm() {
@@ -53,18 +72,19 @@ void AlarmController::ScheduleAlarm() {
5372
tm* tmAlarmTime = std::localtime(&ttAlarmTime);
5473

5574
// If the time being set has already passed today,the alarm should be set for tomorrow
56-
if (hours < dateTimeController.Hours() || (hours == dateTimeController.Hours() && minutes <= dateTimeController.Minutes())) {
75+
if (alarm.hours < dateTimeController.Hours() ||
76+
(alarm.hours == dateTimeController.Hours() && alarm.minutes <= dateTimeController.Minutes())) {
5777
tmAlarmTime->tm_mday += 1;
5878
// tm_wday doesn't update automatically
5979
tmAlarmTime->tm_wday = (tmAlarmTime->tm_wday + 1) % 7;
6080
}
6181

62-
tmAlarmTime->tm_hour = hours;
63-
tmAlarmTime->tm_min = minutes;
82+
tmAlarmTime->tm_hour = alarm.hours;
83+
tmAlarmTime->tm_min = alarm.minutes;
6484
tmAlarmTime->tm_sec = 0;
6585

6686
// if alarm is in weekday-only mode, make sure it shifts to the next weekday
67-
if (recurrence == RecurType::Weekdays) {
87+
if (alarm.recurrence == RecurType::Weekdays) {
6888
if (tmAlarmTime->tm_wday == 0) { // Sunday, shift 1 day
6989
tmAlarmTime->tm_mday += 1;
7090
} else if (tmAlarmTime->tm_wday == 6) { // Saturday, shift 2 days
@@ -79,7 +99,10 @@ void AlarmController::ScheduleAlarm() {
7999
xTimerChangePeriod(alarmTimer, secondsToAlarm * configTICK_RATE_HZ, 0);
80100
xTimerStart(alarmTimer, 0);
81101

82-
state = AlarmState::Set;
102+
if (!alarm.isEnabled) {
103+
alarm.isEnabled = true;
104+
alarmChanged = true;
105+
}
83106
}
84107

85108
uint32_t AlarmController::SecondsToAlarm() const {
@@ -88,20 +111,72 @@ uint32_t AlarmController::SecondsToAlarm() const {
88111

89112
void AlarmController::DisableAlarm() {
90113
xTimerStop(alarmTimer, 0);
91-
state = AlarmState::Not_Set;
114+
isAlerting = false;
115+
if (alarm.isEnabled) {
116+
alarm.isEnabled = false;
117+
alarmChanged = true;
118+
}
92119
}
93120

94121
void AlarmController::SetOffAlarmNow() {
95-
state = AlarmState::Alerting;
122+
isAlerting = true;
96123
systemTask->PushMessage(System::Messages::SetOffAlarm);
97124
}
98125

99126
void AlarmController::StopAlerting() {
100-
// Alarm state is off unless this is a recurring alarm
101-
if (recurrence == RecurType::None) {
102-
state = AlarmState::Not_Set;
127+
isAlerting = false;
128+
// Disable alarm unless it is recurring
129+
if (alarm.recurrence == RecurType::None) {
130+
alarm.isEnabled = false;
131+
alarmChanged = true;
103132
} else {
104133
// set next instance
105134
ScheduleAlarm();
106135
}
107136
}
137+
138+
void AlarmController::SetRecurrence(RecurType recurrence) {
139+
if (alarm.recurrence != recurrence) {
140+
alarm.recurrence = recurrence;
141+
alarmChanged = true;
142+
}
143+
}
144+
145+
void AlarmController::LoadSettingsFromFile() {
146+
lfs_file_t alarmFile;
147+
AlarmSettings alarmBuffer;
148+
149+
if (fs.FileOpen(&alarmFile, "/.system/alarm.dat", LFS_O_RDONLY) != LFS_ERR_OK) {
150+
NRF_LOG_WARNING("[AlarmController] Failed to open alarm data file");
151+
return;
152+
}
153+
154+
fs.FileRead(&alarmFile, reinterpret_cast<uint8_t*>(&alarmBuffer), sizeof(alarmBuffer));
155+
fs.FileClose(&alarmFile);
156+
if (alarmBuffer.version != alarmFormatVersion) {
157+
NRF_LOG_WARNING("[AlarmController] Loaded alarm settings has version %u instead of %u, discarding",
158+
alarmBuffer.version,
159+
alarmFormatVersion);
160+
return;
161+
}
162+
163+
alarm = alarmBuffer;
164+
NRF_LOG_INFO("[AlarmController] Loaded alarm settings from file");
165+
}
166+
167+
void AlarmController::SaveSettingsToFile() const {
168+
lfs_dir systemDir;
169+
if (fs.DirOpen("/.system", &systemDir) != LFS_ERR_OK) {
170+
fs.DirCreate("/.system");
171+
}
172+
fs.DirClose(&systemDir);
173+
lfs_file_t alarmFile;
174+
if (fs.FileOpen(&alarmFile, "/.system/alarm.dat", LFS_O_WRONLY | LFS_O_CREAT) != LFS_ERR_OK) {
175+
NRF_LOG_WARNING("[AlarmController] Failed to open alarm data file for saving");
176+
return;
177+
}
178+
179+
fs.FileWrite(&alarmFile, reinterpret_cast<const uint8_t*>(&alarm), sizeof(alarm));
180+
fs.FileClose(&alarmFile);
181+
NRF_LOG_INFO("[AlarmController] Saved alarm settings with format version %u to file", alarm.version);
182+
}

‎src/components/alarm/AlarmController.h‎

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -30,47 +30,65 @@ namespace Pinetime {
3030
namespace Controllers {
3131
class AlarmController {
3232
public:
33-
AlarmController(Controllers::DateTime& dateTimeController);
33+
AlarmController(Controllers::DateTime& dateTimeController, Controllers::FS& fs);
3434

3535
void Init(System::SystemTask* systemTask);
36+
void SaveAlarm();
3637
void SetAlarmTime(uint8_t alarmHr, uint8_t alarmMin);
3738
void ScheduleAlarm();
3839
void DisableAlarm();
3940
void SetOffAlarmNow();
4041
uint32_t SecondsToAlarm() const;
4142
void StopAlerting();
42-
enum class AlarmState { Not_Set, Set, Alerting };
4343
enum class RecurType { None, Daily, Weekdays };
4444

4545
uint8_t Hours() const {
46-
return hours;
46+
return alarm.hours;
4747
}
4848

4949
uint8_t Minutes() const {
50-
return minutes;
50+
return alarm.minutes;
5151
}
5252

53-
AlarmState State() const {
54-
return state;
53+
bool IsAlerting() const {
54+
return isAlerting;
5555
}
5656

57-
RecurType Recurrence() const {
58-
return recurrence;
57+
bool IsEnabled() const {
58+
return alarm.isEnabled;
5959
}
6060

61-
void SetRecurrence(RecurType recurType) {
62-
recurrence = recurType;
61+
RecurType Recurrence() const {
62+
return alarm.recurrence;
6363
}
6464

65+
void SetRecurrence(RecurType recurrence);
66+
6567
private:
68+
// Versions 255 is reserved for now, so the version field can be made
69+
// bigger, should it ever be needed.
70+
static constexpr uint8_t alarmFormatVersion = 1;
71+
72+
struct AlarmSettings {
73+
uint8_t version = alarmFormatVersion;
74+
uint8_t hours = 7;
75+
uint8_t minutes = 0;
76+
RecurType recurrence = RecurType::None;
77+
bool isEnabled = false;
78+
};
79+
80+
bool isAlerting = false;
81+
bool alarmChanged = false;
82+
6683
Controllers::DateTime& dateTimeController;
84+
Controllers::FS& fs;
6785
System::SystemTask* systemTask = nullptr;
6886
TimerHandle_t alarmTimer;
69-
uint8_t hours = 7;
70-
uint8_t minutes = 0;
87+
AlarmSettings alarm;
7188
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> alarmTime;
72-
AlarmState state = AlarmState::Not_Set;
73-
RecurType recurrence = RecurType::None;
89+
90+
void LoadSettingsFromFile();
91+
void SaveSettingsToFile() const;
7492
};
7593
}
7694
}

‎src/displayapp/screens/Alarm.cpp‎

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -117,22 +117,23 @@ Alarm::Alarm(Controllers::AlarmController& alarmController,
117117

118118
UpdateAlarmTime();
119119

120-
if (alarmController.State() == Controllers::AlarmController::AlarmState::Alerting) {
120+
if (alarmController.IsAlerting()) {
121121
SetAlerting();
122122
} else {
123123
SetSwitchState(LV_ANIM_OFF);
124124
}
125125
}
126126

127127
Alarm::~Alarm() {
128-
if (alarmController.State() == AlarmController::AlarmState::Alerting) {
128+
if (alarmController.IsAlerting()) {
129129
StopAlerting();
130130
}
131131
lv_obj_clean(lv_scr_act());
132+
alarmController.SaveAlarm();
132133
}
133134

134135
void Alarm::DisableAlarm() {
135-
if (alarmController.State() == AlarmController::AlarmState::Set) {
136+
if (alarmController.IsEnabled()) {
136137
alarmController.DisableAlarm();
137138
lv_switch_off(enableSwitch, LV_ANIM_ON);
138139
}
@@ -172,7 +173,7 @@ bool Alarm::OnButtonPushed() {
172173
HideInfo();
173174
return true;
174175
}
175-
if (alarmController.State() == AlarmController::AlarmState::Alerting) {
176+
if (alarmController.IsAlerting()) {
176177
StopAlerting();
177178
return true;
178179
}
@@ -181,7 +182,7 @@ bool Alarm::OnButtonPushed() {
181182

182183
bool Alarm::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
183184
// Don't allow closing the screen by swiping while the alarm is alerting
184-
return alarmController.State() == AlarmController::AlarmState::Alerting && event == TouchEvents::SwipeDown;
185+
return alarmController.IsAlerting() && event == TouchEvents::SwipeDown;
185186
}
186187

187188
void Alarm::OnValueChanged() {
@@ -222,15 +223,10 @@ void Alarm::StopAlerting() {
222223
}
223224

224225
void Alarm::SetSwitchState(lv_anim_enable_t anim) {
225-
switch (alarmController.State()) {
226-
case AlarmController::AlarmState::Set:
227-
lv_switch_on(enableSwitch, anim);
228-
break;
229-
case AlarmController::AlarmState::Not_Set:
230-
lv_switch_off(enableSwitch, anim);
231-
break;
232-
default:
233-
break;
226+
if (alarmController.IsEnabled()) {
227+
lv_switch_on(enableSwitch, anim);
228+
} else {
229+
lv_switch_off(enableSwitch, anim);
234230
}
235231
}
236232

@@ -247,7 +243,7 @@ void Alarm::ShowInfo() {
247243
txtMessage = lv_label_create(btnMessage, nullptr);
248244
lv_obj_set_style_local_bg_color(btnMessage, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_NAVY);
249245

250-
if (alarmController.State() == AlarmController::AlarmState::Set) {
246+
if (alarmController.IsEnabled()) {
251247
auto timeToAlarm = alarmController.SecondsToAlarm();
252248

253249
auto daysToAlarm = timeToAlarm / 86400;

‎src/main.cpp‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ Pinetime::Controllers::DateTime dateTimeController {settingsController};
104104
Pinetime::Drivers::Watchdog watchdog;
105105
Pinetime::Controllers::NotificationManager notificationManager;
106106
Pinetime::Controllers::MotionController motionController;
107-
Pinetime::Controllers::AlarmController alarmController {dateTimeController};
107+
Pinetime::Controllers::AlarmController alarmController {dateTimeController, fs};
108108
Pinetime::Controllers::TouchHandler touchHandler;
109109
Pinetime::Controllers::ButtonHandler buttonHandler;
110110
Pinetime::Controllers::BrightnessController brightnessController {};

‎src/systemtask/SystemTask.cpp‎

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ void SystemTask::Work() {
216216
GoToSleep();
217217
break;
218218
case Messages::OnNewTime:
219-
if (alarmController.State() == Controllers::AlarmController::AlarmState::Set) {
219+
if (alarmController.IsEnabled()) {
220220
alarmController.ScheduleAlarm();
221221
}
222222
break;
@@ -317,17 +317,15 @@ void SystemTask::Work() {
317317
case Messages::OnNewHour:
318318
using Pinetime::Controllers::AlarmController;
319319
if (settingsController.GetNotificationStatus() != Controllers::Settings::Notification::Sleep &&
320-
settingsController.GetChimeOption() == Controllers::Settings::ChimesOption::Hours &&
321-
alarmController.State() != AlarmController::AlarmState::Alerting) {
320+
settingsController.GetChimeOption() == Controllers::Settings::ChimesOption::Hours && !alarmController.IsAlerting()) {
322321
GoToRunning();
323322
displayApp.PushMessage(Pinetime::Applications::Display::Messages::Chime);
324323
}
325324
break;
326325
case Messages::OnNewHalfHour:
327326
using Pinetime::Controllers::AlarmController;
328327
if (settingsController.GetNotificationStatus() != Controllers::Settings::Notification::Sleep &&
329-
settingsController.GetChimeOption() == Controllers::Settings::ChimesOption::HalfHours &&
330-
alarmController.State() != AlarmController::AlarmState::Alerting) {
328+
settingsController.GetChimeOption() == Controllers::Settings::ChimesOption::HalfHours && !alarmController.IsAlerting()) {
331329
GoToRunning();
332330
displayApp.PushMessage(Pinetime::Applications::Display::Messages::Chime);
333331
}

0 commit comments

Comments
 (0)