Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 75 additions & 13 deletions src/components/alarm/AlarmController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -36,11 +38,20 @@ namespace {
void AlarmController::Init(System::SystemTask* systemTask) {
this->systemTask = systemTask;
alarmTimer = xTimerCreate("Alarm", 1, pdFALSE, this, SetOffAlarm);
LoadAlarmFromFile();
if (alarm.isEnabled) {
NRF_LOG_INFO("[AlarmController] Loaded alarm was enabled, scheduling");
ScheduleAlarm();
}
}

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;
SaveAlarmToFile();
}

void AlarmController::ScheduleAlarm() {
Expand All @@ -53,18 +64,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
Expand All @@ -79,7 +91,10 @@ void AlarmController::ScheduleAlarm() {
xTimerChangePeriod(alarmTimer, secondsToAlarm * configTICK_RATE_HZ, 0);
xTimerStart(alarmTimer, 0);

state = AlarmState::Set;
if (!alarm.isEnabled) {
alarm.isEnabled = true;
SaveAlarmToFile();
}
}

uint32_t AlarmController::SecondsToAlarm() {
Expand All @@ -88,21 +103,68 @@ uint32_t AlarmController::SecondsToAlarm() {

void AlarmController::DisableAlarm() {
xTimerStop(alarmTimer, 0);
state = AlarmState::Not_Set;
isAlerting = false;
if (alarm.isEnabled) {
alarm.isEnabled = false;
SaveAlarmToFile();
}
}

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;
SaveAlarmToFile();
Comment thread
ght marked this conversation as resolved.
} else {
// set next instance
ScheduleAlarm();
}
systemTask->PushMessage(System::Messages::StopRinging);
}

void AlarmController::SetRecurrence(RecurType recurrence) {
if (alarm.recurrence != recurrence) {
alarm.recurrence = recurrence;
SaveAlarmToFile();
}
}

void AlarmController::LoadAlarmFromFile() {
lfs_file_t alarmFile;
AlarmData alarmBuffer;

if (fs.FileOpen(&alarmFile, "/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 data has version %u instead of %u, discarding",
alarmBuffer.version,
alarmFormatVersion);
return;
}

alarm = alarmBuffer;
NRF_LOG_INFO("[AlarmController] Loaded alarm data from file");
}

void AlarmController::SaveAlarmToFile() {
lfs_file_t alarmFile;
if (fs.FileOpen(&alarmFile, "/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<uint8_t*>(&alarm), sizeof(alarm));
fs.FileClose(&alarmFile);
NRF_LOG_INFO("[AlarmController] Saved alarm data with format version %u to file", alarm.version);
}
41 changes: 27 additions & 14 deletions src/components/alarm/AlarmController.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ namespace Pinetime {
namespace Controllers {
class AlarmController {
public:
AlarmController(Controllers::DateTime& dateTimeController);
AlarmController(Controllers::DateTime& dateTimeController, Controllers::FS& fs);

void Init(System::SystemTask* systemTask);
void SetAlarmTime(uint8_t alarmHr, uint8_t alarmMin);
Expand All @@ -38,33 +38,46 @@ namespace Pinetime {
void SetOffAlarmNow();
uint32_t SecondsToAlarm();
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;
}
RecurType Recurrence() const {
return recurrence;
bool IsEnabled() const {
return alarm.isEnabled;
}
void SetRecurrence(RecurType recurType) {
recurrence = recurType;
RecurType Recurrence() const {
return alarm.recurrence;
}
void SetRecurrence(RecurType recurrence);

private:
// 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;
Comment thread
ght marked this conversation as resolved.
struct AlarmData {
uint8_t version = alarmFormatVersion;
Comment thread
ght marked this conversation as resolved.
uint8_t hours = 7;
uint8_t minutes = 0;
RecurType recurrence = RecurType::None;
bool isEnabled = false;
};
bool isAlerting = false;

Controllers::DateTime& dateTimeController;
Controllers::FS& fs;
System::SystemTask* systemTask = nullptr;
TimerHandle_t alarmTimer;
uint8_t hours = 7;
uint8_t minutes = 0;
AlarmData alarm;
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> alarmTime;
AlarmState state = AlarmState::Not_Set;
RecurType recurrence = RecurType::None;

void LoadAlarmFromFile();
void SaveAlarmToFile();
};
}
}
37 changes: 19 additions & 18 deletions src/displayapp/screens/Alarm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ Alarm::Alarm(DisplayApp* app,
System::SystemTask& systemTask)
: Screen(app), alarmController {alarmController}, systemTask {systemTask} {

hours = alarmController.Hours();
minutes = alarmController.Minutes();

hourCounter.Create();
lv_obj_align(hourCounter.GetObject(), nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0);
if (clockType == Controllers::Settings::ClockType::H12) {
Expand All @@ -57,12 +60,12 @@ Alarm::Alarm(DisplayApp* app,
lv_label_set_align(lblampm, LV_LABEL_ALIGN_CENTER);
lv_obj_align(lblampm, lv_scr_act(), LV_ALIGN_CENTER, 0, 30);
}
hourCounter.SetValue(alarmController.Hours());
hourCounter.SetValue(hours);
hourCounter.SetValueChangedEventCallback(this, ValueChangedHandler);

minuteCounter.Create();
lv_obj_align(minuteCounter.GetObject(), nullptr, LV_ALIGN_IN_TOP_RIGHT, 0, 0);
minuteCounter.SetValue(alarmController.Minutes());
minuteCounter.SetValue(minutes);
minuteCounter.SetValueChangedEventCallback(this, ValueChangedHandler);

lv_obj_t* colonLabel = lv_label_create(lv_scr_act(), nullptr);
Expand Down Expand Up @@ -113,22 +116,23 @@ Alarm::Alarm(DisplayApp* app,

UpdateAlarmTime();

if (alarmController.State() == Controllers::AlarmController::AlarmState::Alerting) {
if (alarmController.IsAlerting()) {
SetAlerting();
} else {
SetSwitchState(LV_ANIM_OFF);
}
}

Alarm::~Alarm() {
if (alarmController.State() == AlarmController::AlarmState::Alerting) {
if (alarmController.IsAlerting()) {
StopAlerting();
}
alarmController.SetAlarmTime(hours, minutes);
lv_obj_clean(lv_scr_act());
}

void Alarm::DisableAlarm() {
if (alarmController.State() == AlarmController::AlarmState::Set) {
if (alarmController.IsEnabled()) {
alarmController.DisableAlarm();
lv_switch_off(enableSwitch, LV_ANIM_ON);
}
Expand All @@ -150,6 +154,7 @@ void Alarm::OnButtonEvent(lv_obj_t* obj, lv_event_t event) {
}
if (obj == enableSwitch) {
if (lv_switch_get_state(enableSwitch)) {
alarmController.SetAlarmTime(hours, minutes);
alarmController.ScheduleAlarm();
} else {
alarmController.DisableAlarm();
Expand All @@ -168,7 +173,7 @@ bool Alarm::OnButtonPushed() {
HideInfo();
return true;
}
if (alarmController.State() == AlarmController::AlarmState::Alerting) {
if (alarmController.IsAlerting()) {
StopAlerting();
return true;
}
Expand All @@ -177,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() {
Expand All @@ -193,7 +198,8 @@ void Alarm::UpdateAlarmTime() {
lv_label_set_text_static(lblampm, "AM");
}
}
alarmController.SetAlarmTime(hourCounter.GetValue(), minuteCounter.GetValue());
hours = hourCounter.GetValue();
minutes = minuteCounter.GetValue();
}

void Alarm::SetAlerting() {
Expand All @@ -216,15 +222,10 @@ void Alarm::StopAlerting() {
}

void Alarm::SetSwitchState(lv_anim_enable_t anim) {
switch (alarmController.State()) {
case AlarmController::AlarmState::Set:
lv_switch_on(enableSwitch, anim);
break;
case AlarmController::AlarmState::Not_Set:
lv_switch_off(enableSwitch, anim);
break;
default:
break;
if (alarmController.IsEnabled()) {
lv_switch_on(enableSwitch, anim);
} else {
lv_switch_off(enableSwitch, anim);
}
}

Expand All @@ -241,7 +242,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;
Expand Down
3 changes: 3 additions & 0 deletions src/displayapp/screens/Alarm.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ namespace Pinetime {
Controllers::AlarmController& alarmController;
System::SystemTask& systemTask;

uint8_t hours = 0;
uint8_t minutes = 0;

lv_obj_t *btnStop, *txtStop, *btnRecur, *txtRecur, *btnInfo, *enableSwitch;
lv_obj_t* lblampm = nullptr;
lv_obj_t* txtMessage = nullptr;
Expand Down
2 changes: 1 addition & 1 deletion src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ Pinetime::Drivers::WatchdogView watchdogView(watchdog);
Pinetime::Controllers::NotificationManager notificationManager;
Pinetime::Controllers::MotionController motionController;
Pinetime::Controllers::TimerController timerController;
Pinetime::Controllers::AlarmController alarmController {dateTimeController};
Pinetime::Controllers::AlarmController alarmController {dateTimeController, fs};
Pinetime::Controllers::TouchHandler touchHandler(touchPanel, lvgl);
Pinetime::Controllers::ButtonHandler buttonHandler;
Pinetime::Controllers::BrightnessController brightnessController {};
Expand Down
8 changes: 3 additions & 5 deletions src/systemtask/SystemTask.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ void SystemTask::Work() {
case Messages::OnNewTime:
ReloadIdleTimer();
displayApp.PushMessage(Pinetime::Applications::Display::Messages::UpdateDateTime);
if (alarmController.State() == Controllers::AlarmController::AlarmState::Set) {
if (alarmController.IsEnabled()) {
alarmController.ScheduleAlarm();
}
break;
Expand Down Expand Up @@ -390,8 +390,7 @@ 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) {
settingsController.GetChimeOption() == Controllers::Settings::ChimesOption::Hours && !alarmController.IsAlerting()) {
if (state == SystemTaskState::Sleeping) {
GoToRunning();
displayApp.PushMessage(Pinetime::Applications::Display::Messages::Clock);
Expand All @@ -402,8 +401,7 @@ void SystemTask::Work() {
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) {
settingsController.GetChimeOption() == Controllers::Settings::ChimesOption::HalfHours && !alarmController.IsAlerting()) {
if (state == SystemTaskState::Sleeping) {
GoToRunning();
displayApp.PushMessage(Pinetime::Applications::Display::Messages::Clock);
Expand Down