@@ -26,6 +26,14 @@ using namespace std::chrono_literals;
2626
2727AlarmController::AlarmController (Controllers::DateTime& dateTimeController, Controllers::FS& fs)
2828 : dateTimeController {dateTimeController}, fs {fs} {
29+ // Initialize all alarms with defaults
30+ for (uint8_t i = 0 ; i < MaxAlarms; i++) {
31+ alarms[i].version = alarmFormatVersion;
32+ alarms[i].hours = 6 + i;
33+ alarms[i].minutes = 0 ;
34+ alarms[i].recurrence = RecurType::Weekdays;
35+ alarms[i].isEnabled = false ;
36+ }
2937}
3038
3139namespace {
@@ -39,9 +47,13 @@ void AlarmController::Init(System::SystemTask* systemTask) {
3947 this ->systemTask = systemTask;
4048 alarmTimer = xTimerCreate (" Alarm" , 1 , pdFALSE, this , SetOffAlarm);
4149 LoadSettingsFromFile ();
42- if (alarm.isEnabled ) {
43- NRF_LOG_INFO (" [AlarmController] Loaded alarm was enabled, scheduling" );
44- ScheduleAlarm ();
50+ // Check if any alarms are enabled and schedule the next one
51+ for (uint8_t i = 0 ; i < MaxAlarms; i++) {
52+ if (alarms[i].isEnabled ) {
53+ NRF_LOG_INFO (" [AlarmController] Found enabled alarm %u, scheduling next alarm" , i);
54+ ScheduleAlarm ();
55+ break ;
56+ }
4557 }
4658}
4759
@@ -53,38 +65,47 @@ void AlarmController::SaveAlarm() {
5365 alarmChanged = false ;
5466}
5567
56- void AlarmController::SetAlarmTime (uint8_t alarmHr, uint8_t alarmMin) {
57- if (alarm. hours == alarmHr && alarm. minutes == alarmMin ) {
68+ void AlarmController::SetAlarmTime (uint8_t index, uint8_t alarmHr, uint8_t alarmMin) {
69+ if (index >= MaxAlarms ) {
5870 return ;
5971 }
60- alarm.hours = alarmHr;
61- alarm.minutes = alarmMin;
72+ if (alarms[index].hours == alarmHr && alarms[index].minutes == alarmMin) {
73+ return ;
74+ }
75+ alarms[index].hours = alarmHr;
76+ alarms[index].minutes = alarmMin;
6277 alarmChanged = true ;
6378}
6479
6580void AlarmController::ScheduleAlarm () {
66- // Determine the next time the alarm needs to go off and set the timer
81+ // Determine the next alarm to schedule and set the timer
6782 xTimerStop (alarmTimer, 0 );
6883
84+ nextAlarmIndex = CalculateNextAlarm ();
85+ if (nextAlarmIndex >= MaxAlarms) {
86+ // No enabled alarms found
87+ return ;
88+ }
89+
6990 auto now = dateTimeController.CurrentDateTime ();
7091 alarmTime = now;
7192 time_t ttAlarmTime = std::chrono::system_clock::to_time_t (std::chrono::time_point_cast<std::chrono::system_clock::duration>(alarmTime));
7293 tm* tmAlarmTime = std::localtime (&ttAlarmTime);
7394
7495 // If the time being set has already passed today,the alarm should be set for tomorrow
75- if (alarm .hours < dateTimeController.Hours () ||
76- (alarm .hours == dateTimeController.Hours () && alarm .minutes <= dateTimeController.Minutes ())) {
96+ if (alarms[nextAlarmIndex] .hours < dateTimeController.Hours () ||
97+ (alarms[nextAlarmIndex] .hours == dateTimeController.Hours () && alarms[nextAlarmIndex] .minutes <= dateTimeController.Minutes ())) {
7798 tmAlarmTime->tm_mday += 1 ;
7899 // tm_wday doesn't update automatically
79100 tmAlarmTime->tm_wday = (tmAlarmTime->tm_wday + 1 ) % 7 ;
80101 }
81102
82- tmAlarmTime->tm_hour = alarm .hours ;
83- tmAlarmTime->tm_min = alarm .minutes ;
103+ tmAlarmTime->tm_hour = alarms[nextAlarmIndex] .hours ;
104+ tmAlarmTime->tm_min = alarms[nextAlarmIndex] .minutes ;
84105 tmAlarmTime->tm_sec = 0 ;
85106
86107 // if alarm is in weekday-only mode, make sure it shifts to the next weekday
87- if (alarm .recurrence == RecurType::Weekdays) {
108+ if (alarms[nextAlarmIndex] .recurrence == RecurType::Weekdays) {
88109 if (tmAlarmTime->tm_wday == 0 ) { // Sunday, shift 1 day
89110 tmAlarmTime->tm_mday += 1 ;
90111 } else if (tmAlarmTime->tm_wday == 6 ) { // Saturday, shift 2 days
@@ -98,69 +119,104 @@ void AlarmController::ScheduleAlarm() {
98119 auto secondsToAlarm = std::chrono::duration_cast<std::chrono::seconds>(alarmTime - now).count ();
99120 xTimerChangePeriod (alarmTimer, secondsToAlarm * configTICK_RATE_HZ, 0 );
100121 xTimerStart (alarmTimer, 0 );
101-
102- if (!alarm.isEnabled ) {
103- alarm.isEnabled = true ;
104- alarmChanged = true ;
105- }
106122}
107123
108124uint32_t AlarmController::SecondsToAlarm () const {
109125 return std::chrono::duration_cast<std::chrono::seconds>(alarmTime - dateTimeController.CurrentDateTime ()).count ();
110126}
111127
112- void AlarmController::DisableAlarm () {
113- xTimerStop (alarmTimer, 0 );
114- if (alarm.isEnabled ) {
115- alarm.isEnabled = false ;
128+ void AlarmController::DisableAlarm (uint8_t index) {
129+ if (index >= MaxAlarms) {
130+ return ;
131+ }
132+ if (alarms[index].isEnabled ) {
133+ alarms[index].isEnabled = false ;
116134 alarmChanged = true ;
135+ ScheduleAlarm ();
136+ }
137+ }
138+
139+ void AlarmController::SetEnabled (uint8_t index, bool enabled) {
140+ if (index >= MaxAlarms) {
141+ return ;
142+ }
143+ if (alarms[index].isEnabled != enabled) {
144+ alarms[index].isEnabled = enabled;
145+ alarmChanged = true ;
146+ ScheduleAlarm ();
117147 }
118148}
119149
120150void AlarmController::SetOffAlarmNow () {
121151 isAlerting = true ;
152+ alertingAlarmIndex = nextAlarmIndex;
122153 systemTask->PushMessage (System::Messages::SetOffAlarm);
123154}
124155
125156void AlarmController::StopAlerting () {
126157 isAlerting = false ;
127158 // Disable alarm unless it is recurring
128- if (alarm .recurrence == RecurType::None) {
129- alarm .isEnabled = false ;
159+ if (alarms[alertingAlarmIndex] .recurrence == RecurType::None) {
160+ alarms[alertingAlarmIndex] .isEnabled = false ;
130161 alarmChanged = true ;
131- } else {
132- // set next instance
133- ScheduleAlarm ();
134162 }
163+ ScheduleAlarm ();
135164}
136165
137- void AlarmController::SetRecurrence (RecurType recurrence) {
138- if (alarm.recurrence != recurrence) {
139- alarm.recurrence = recurrence;
166+ void AlarmController::SetRecurrence (uint8_t index, RecurType recurrence) {
167+ if (index >= MaxAlarms) {
168+ return ;
169+ }
170+ if (alarms[index].recurrence != recurrence) {
171+ alarms[index].recurrence = recurrence;
140172 alarmChanged = true ;
141173 }
142174}
143175
144176void AlarmController::LoadSettingsFromFile () {
145177 lfs_file_t alarmFile;
146- AlarmSettings alarmBuffer;
147178
148179 if (fs.FileOpen (&alarmFile, " /.system/alarm.dat" , LFS_O_RDONLY) != LFS_ERR_OK) {
149180 NRF_LOG_WARNING (" [AlarmController] Failed to open alarm data file" );
150181 return ;
151182 }
152183
153- fs.FileRead (&alarmFile, reinterpret_cast <uint8_t *>(&alarmBuffer), sizeof (alarmBuffer));
154- fs.FileClose (&alarmFile);
155- if (alarmBuffer.version != alarmFormatVersion) {
156- NRF_LOG_WARNING (" [AlarmController] Loaded alarm settings has version %u instead of %u, discarding" ,
157- alarmBuffer.version ,
158- alarmFormatVersion);
159- return ;
160- }
184+ // Read version byte to determine format
185+ uint8_t version;
186+ fs.FileRead (&alarmFile, &version, sizeof (version));
187+ fs.FileSeek (&alarmFile, 0 );
188+
189+ if (version == 1 ) {
190+ // Migrate from old single-alarm format
191+ NRF_LOG_INFO (" [AlarmController] Migrating from version 1 to version 2" );
192+ AlarmSettings oldAlarm;
193+ fs.FileRead (&alarmFile, reinterpret_cast <uint8_t *>(&oldAlarm), sizeof (oldAlarm));
194+ fs.FileClose (&alarmFile);
195+
196+ // Copy old alarm to first slot
197+ alarms[0 ] = oldAlarm;
198+ alarms[0 ].version = alarmFormatVersion;
161199
162- alarm = alarmBuffer;
163- NRF_LOG_INFO (" [AlarmController] Loaded alarm settings from file" );
200+ // Initialize other alarms with defaults
201+ for (uint8_t i = 1 ; i < MaxAlarms; i++) {
202+ alarms[i].version = alarmFormatVersion;
203+ alarms[i].hours = 6 + i;
204+ alarms[i].minutes = 0 ;
205+ alarms[i].recurrence = RecurType::Weekdays;
206+ alarms[i].isEnabled = false ;
207+ }
208+
209+ alarmChanged = true ;
210+ NRF_LOG_INFO (" [AlarmController] Migrated alarm settings from version 1" );
211+ } else if (version == alarmFormatVersion) {
212+ // Read new multi-alarm format
213+ fs.FileRead (&alarmFile, reinterpret_cast <uint8_t *>(alarms.data ()), sizeof (alarms));
214+ fs.FileClose (&alarmFile);
215+ NRF_LOG_INFO (" [AlarmController] Loaded %u alarms from file" , MaxAlarms);
216+ } else {
217+ NRF_LOG_WARNING (" [AlarmController] Unknown alarm version %u, using defaults" , version);
218+ fs.FileClose (&alarmFile);
219+ }
164220}
165221
166222void AlarmController::SaveSettingsToFile () const {
@@ -175,7 +231,56 @@ void AlarmController::SaveSettingsToFile() const {
175231 return ;
176232 }
177233
178- fs.FileWrite (&alarmFile, reinterpret_cast <const uint8_t *>(&alarm) , sizeof (alarm ));
234+ fs.FileWrite (&alarmFile, reinterpret_cast <const uint8_t *>(alarms. data ()) , sizeof (alarms ));
179235 fs.FileClose (&alarmFile);
180- NRF_LOG_INFO (" [AlarmController] Saved alarm settings with format version %u to file" , alarm.version );
236+ NRF_LOG_INFO (" [AlarmController] Saved %u alarms with format version %u to file" , MaxAlarms, alarmFormatVersion);
237+ }
238+
239+ uint8_t AlarmController::CalculateNextAlarm () const {
240+ auto now = dateTimeController.CurrentDateTime ();
241+ uint32_t minSecondsToAlarm = UINT32_MAX;
242+ uint8_t nextIndex = MaxAlarms; // Invalid index means no alarm found
243+
244+ for (uint8_t i = 0 ; i < MaxAlarms; i++) {
245+ if (!alarms[i].isEnabled ) {
246+ continue ;
247+ }
248+
249+ // Calculate seconds to this alarm
250+ auto alarmTimePoint = now;
251+ time_t ttAlarmTime =
252+ std::chrono::system_clock::to_time_t (std::chrono::time_point_cast<std::chrono::system_clock::duration>(alarmTimePoint));
253+ tm* tmAlarmTime = std::localtime (&ttAlarmTime);
254+
255+ // If the time has already passed today, schedule for tomorrow
256+ if (alarms[i].hours < dateTimeController.Hours () ||
257+ (alarms[i].hours == dateTimeController.Hours () && alarms[i].minutes <= dateTimeController.Minutes ())) {
258+ tmAlarmTime->tm_mday += 1 ;
259+ tmAlarmTime->tm_wday = (tmAlarmTime->tm_wday + 1 ) % 7 ;
260+ }
261+
262+ tmAlarmTime->tm_hour = alarms[i].hours ;
263+ tmAlarmTime->tm_min = alarms[i].minutes ;
264+ tmAlarmTime->tm_sec = 0 ;
265+
266+ // Handle weekday-only mode
267+ if (alarms[i].recurrence == RecurType::Weekdays) {
268+ if (tmAlarmTime->tm_wday == 0 ) { // Sunday, shift 1 day
269+ tmAlarmTime->tm_mday += 1 ;
270+ } else if (tmAlarmTime->tm_wday == 6 ) { // Saturday, shift 2 days
271+ tmAlarmTime->tm_mday += 2 ;
272+ }
273+ }
274+ tmAlarmTime->tm_isdst = -1 ;
275+
276+ auto thisAlarmTime = std::chrono::system_clock::from_time_t (std::mktime (tmAlarmTime));
277+ auto secondsToThisAlarm = std::chrono::duration_cast<std::chrono::seconds>(thisAlarmTime - now).count ();
278+
279+ if (secondsToThisAlarm > 0 && static_cast <uint32_t >(secondsToThisAlarm) < minSecondsToAlarm) {
280+ minSecondsToAlarm = static_cast <uint32_t >(secondsToThisAlarm);
281+ nextIndex = i;
282+ }
283+ }
284+
285+ return nextIndex;
181286}
0 commit comments