From 0bc8592ec7911cba8890aa144139c74f7172cbaa Mon Sep 17 00:00:00 2001 From: Michele Bini Date: Thu, 31 Mar 2022 14:40:41 +0200 Subject: add back alarm diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 32ff520..20e0dcb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -399,6 +399,7 @@ list(APPEND SOURCE_FILES displayapp/screens/FlashLight.cpp displayapp/screens/List.cpp displayapp/screens/Error.cpp + displayapp/screens/Alarm.cpp displayapp/screens/Styles.cpp displayapp/Colors.cpp @@ -446,6 +447,7 @@ list(APPEND SOURCE_FILES components/firmwarevalidator/FirmwareValidator.cpp components/motor/MotorController.cpp components/settings/Settings.cpp + components/alarm/AlarmController.cpp drivers/Cst816s.cpp FreeRTOS/port.c FreeRTOS/port_cmsis_systick.c @@ -498,6 +500,7 @@ list(APPEND RECOVERY_SOURCE_FILES components/ble/ServiceDiscovery.cpp components/firmwarevalidator/FirmwareValidator.cpp components/settings/Settings.cpp + components/alarm/AlarmController.cpp drivers/Cst816s.cpp FreeRTOS/port.c FreeRTOS/port_cmsis_systick.c @@ -558,6 +561,7 @@ set(INCLUDE_FILES displayapp/screens/ApplicationList.h displayapp/Apps.h displayapp/screens/Notifications.h + displayapp/screens/Alarm.h displayapp/Colors.h drivers/St7789.h drivers/SpiNorFlash.h @@ -591,6 +595,7 @@ set(INCLUDE_FILES components/ble/ServiceDiscovery.h components/ble/BleClient.h components/settings/Settings.h + components/alarm/AlarmController.h drivers/Cst816s.h FreeRTOS/portmacro.h FreeRTOS/portmacro_cmsis.h diff --git a/src/components/alarm/AlarmController.cpp b/src/components/alarm/AlarmController.cpp new file mode 100644 index 0000000..28b328d --- /dev/null +++ b/src/components/alarm/AlarmController.cpp @@ -0,0 +1,114 @@ +/* Copyright (C) 2021 mruss77, Florian + + This file is part of InfiniTime. + + InfiniTime is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + InfiniTime is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#include "components/alarm/AlarmController.h" +#include "systemtask/SystemTask.h" +#include "app_timer.h" +#include "task.h" +#include + +using namespace Pinetime::Controllers; +using namespace std::chrono_literals; + +AlarmController::AlarmController(Controllers::DateTime& dateTimeController) : dateTimeController {dateTimeController} { +} + +APP_TIMER_DEF(alarmAppTimer); + +namespace { + void SetOffAlarm(void* p_context) { + auto* controller = static_cast(p_context); + if (controller != nullptr) { + controller->SetOffAlarmNow(); + } + } +} + +void AlarmController::Init(System::SystemTask* systemTask) { + app_timer_create(&alarmAppTimer, APP_TIMER_MODE_SINGLE_SHOT, SetOffAlarm); + this->systemTask = systemTask; +} + +void AlarmController::SetAlarmTime(uint8_t alarmHr, uint8_t alarmMin) { + hours = alarmHr; + minutes = alarmMin; +} + +void AlarmController::ScheduleAlarm() { + // Determine the next time the alarm needs to go off and set the app_timer + app_timer_stop(alarmAppTimer); + + auto now = dateTimeController.CurrentDateTime(); + alarmTime = now; + time_t ttAlarmTime = std::chrono::system_clock::to_time_t(alarmTime); + 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())) { + 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_sec = 0; + + // if alarm is in weekday-only mode, make sure it shifts to the next weekday + if (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 + tmAlarmTime->tm_mday += 2; + } + } + tmAlarmTime->tm_isdst = -1; // use system timezone setting to determine DST + + // now can convert back to a time_point + alarmTime = std::chrono::system_clock::from_time_t(std::mktime(tmAlarmTime)); + auto mSecToAlarm = std::chrono::duration_cast(alarmTime - now).count(); + app_timer_start(alarmAppTimer, APP_TIMER_TICKS(mSecToAlarm), this); + + state = AlarmState::Set; +} + +uint32_t AlarmController::SecondsToAlarm() { + return std::chrono::duration_cast(alarmTime - dateTimeController.CurrentDateTime()).count(); +} + +void AlarmController::DisableAlarm() { + app_timer_stop(alarmAppTimer); + state = AlarmState::Not_Set; +} + +void AlarmController::SetOffAlarmNow() { + state = AlarmState::Alerting; + systemTask->PushMessage(System::Messages::SetOffAlarm); +} + +void AlarmController::StopAlerting() { + systemTask->PushMessage(System::Messages::StopRinging); + + // Alarm state is off unless this is a recurring alarm + if (recurrence == RecurType::None) { + state = AlarmState::Not_Set; + } else { + state = AlarmState::Set; + // set next instance + ScheduleAlarm(); + } +} diff --git a/src/components/alarm/AlarmController.h b/src/components/alarm/AlarmController.h new file mode 100644 index 0000000..f39fbde --- /dev/null +++ b/src/components/alarm/AlarmController.h @@ -0,0 +1,67 @@ +/* Copyright (C) 2021 mruss77, Florian + + This file is part of InfiniTime. + + InfiniTime is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + InfiniTime is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#pragma once + +#include +#include "components/datetime/DateTimeController.h" + +namespace Pinetime { + namespace System { + class SystemTask; + } + namespace Controllers { + class AlarmController { + public: + AlarmController(Controllers::DateTime& dateTimeController); + + void Init(System::SystemTask* systemTask); + void SetAlarmTime(uint8_t alarmHr, uint8_t alarmMin); + void ScheduleAlarm(); + void DisableAlarm(); + 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; + } + uint8_t Minutes() const { + return minutes; + } + AlarmState State() const { + return state; + } + RecurType Recurrence() const { + return recurrence; + } + void SetRecurrence(RecurType recurType) { + recurrence = recurType; + } + + private: + Controllers::DateTime& dateTimeController; + System::SystemTask* systemTask = nullptr; + uint8_t hours = 7; + uint8_t minutes = 0; + std::chrono::time_point alarmTime; + AlarmState state = AlarmState::Not_Set; + RecurType recurrence = RecurType::None; + }; + } +} diff --git a/src/displayapp/Apps.h b/src/displayapp/Apps.h index 3cbaa9e..3b125d4 100644 --- a/src/displayapp/Apps.h +++ b/src/displayapp/Apps.h @@ -11,6 +11,7 @@ namespace Pinetime { NotificationsPreview, Notifications, FlashLight, + Alarm, QuickSettings, Settings, SettingTimeFormat, diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index f84bf57..a841f1e 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -1,5 +1,6 @@ #include "displayapp/DisplayApp.h" #include +#include "displayapp/screens/Alarm.h" #include "components/battery/BatteryController.h" #include "components/ble/BleController.h" #include "components/datetime/DateTimeController.h" @@ -73,6 +74,7 @@ DisplayApp::DisplayApp(Drivers::St7789& lcd, Controllers::Settings& settingsController, Pinetime::Controllers::MotorController& motorController, Pinetime::Controllers::MotionController& motionController, + Pinetime::Controllers::AlarmController& alarmController, Pinetime::Controllers::BrightnessController& brightnessController, Pinetime::Controllers::TouchHandler& touchHandler) : lcd {lcd}, @@ -86,6 +88,7 @@ DisplayApp::DisplayApp(Drivers::St7789& lcd, settingsController {settingsController}, motorController {motorController}, motionController {motionController}, + alarmController {alarmController}, brightnessController {brightnessController}, touchHandler {touchHandler} { } @@ -176,6 +179,14 @@ void DisplayApp::Refresh() { case Messages::NewNotification: LoadApp(Apps::NotificationsPreview, DisplayApp::FullRefreshDirections::Down); break; + case Messages::AlarmTriggered: + if (currentApp == Apps::Alarm) { + auto* alarm = static_cast(currentScreen.get()); + alarm->SetAlerting(); + } else { + LoadApp(Apps::Alarm); + } + break; case Messages::TouchEvent: { if (state != States::Running) { break; @@ -324,6 +335,10 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction) this, notificationManager, systemTask->nimble().alertService(), motorController, *systemTask, Screens::Notifications::Modes::Preview); ReturnApp(Apps::Clock, FullRefreshDirections::Up, TouchEvents::SwipeUp); break; + case Apps::Alarm: + currentScreen = std::make_unique(this, alarmController, settingsController, *systemTask); + break; + // Settings case Apps::QuickSettings: currentScreen = std::make_unique( diff --git a/src/displayapp/DisplayApp.h b/src/displayapp/DisplayApp.h index b79952d..b5186dd 100644 --- a/src/displayapp/DisplayApp.h +++ b/src/displayapp/DisplayApp.h @@ -13,6 +13,7 @@ #include "components/firmwarevalidator/FirmwareValidator.h" #include "components/settings/Settings.h" #include "displayapp/screens/Screen.h" +#include "components/alarm/AlarmController.h" #include "touchhandler/TouchHandler.h" #include "displayapp/Messages.h" @@ -55,6 +56,7 @@ namespace Pinetime { Controllers::Settings& settingsController, Pinetime::Controllers::MotorController& motorController, Pinetime::Controllers::MotionController& motionController, + Pinetime::Controllers::AlarmController& alarmController, Pinetime::Controllers::BrightnessController& brightnessController, Pinetime::Controllers::TouchHandler& touchHandler); void Start(System::BootErrors error); @@ -79,6 +81,7 @@ namespace Pinetime { Pinetime::Controllers::Settings& settingsController; Pinetime::Controllers::MotorController& motorController; Pinetime::Controllers::MotionController& motionController; + Pinetime::Controllers::AlarmController& alarmController; Pinetime::Controllers::BrightnessController &brightnessController; Pinetime::Controllers::TouchHandler& touchHandler; diff --git a/src/displayapp/DisplayAppRecovery.cpp b/src/displayapp/DisplayAppRecovery.cpp index a33308f..4a3ddf6 100644 --- a/src/displayapp/DisplayAppRecovery.cpp +++ b/src/displayapp/DisplayAppRecovery.cpp @@ -20,6 +20,7 @@ DisplayApp::DisplayApp(Drivers::St7789& lcd, Controllers::Settings& settingsController, Pinetime::Controllers::MotorController& motorController, Pinetime::Controllers::MotionController& motionController, + Pinetime::Controllers::AlarmController& alarmController, Pinetime::Controllers::BrightnessController& brightnessController, Pinetime::Controllers::TouchHandler& touchHandler) : lcd {lcd}, bleController {bleController} { diff --git a/src/displayapp/DisplayAppRecovery.h b/src/displayapp/DisplayAppRecovery.h index 8f25cbe..b358c11 100644 --- a/src/displayapp/DisplayAppRecovery.h +++ b/src/displayapp/DisplayAppRecovery.h @@ -32,6 +32,7 @@ namespace Pinetime { class TouchHandler; class MotorController; class TimerController; + class AlarmController; class BrightnessController; } @@ -53,6 +54,7 @@ namespace Pinetime { Controllers::Settings& settingsController, Pinetime::Controllers::MotorController& motorController, Pinetime::Controllers::MotionController& motionController, + Pinetime::Controllers::AlarmController& alarmController, Pinetime::Controllers::BrightnessController& brightnessController, Pinetime::Controllers::TouchHandler& touchHandler); void Start(); diff --git a/src/displayapp/Messages.h b/src/displayapp/Messages.h index c27c5e5..2891d90 100644 --- a/src/displayapp/Messages.h +++ b/src/displayapp/Messages.h @@ -18,6 +18,7 @@ namespace Pinetime { UpdateTimeOut, DimScreen, RestoreBrightness, + AlarmTriggered, Clock, }; } diff --git a/src/displayapp/screens/Alarm.cpp b/src/displayapp/screens/Alarm.cpp new file mode 100644 index 0000000..879e50d --- /dev/null +++ b/src/displayapp/screens/Alarm.cpp @@ -0,0 +1,343 @@ +/* Copyright (C) 2021 mruss77, Florian + + This file is part of InfiniTime. + + InfiniTime is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + InfiniTime is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#include "displayapp/screens/Alarm.h" +#include "displayapp/screens/Screen.h" +#include "displayapp/screens/Symbols.h" + +using namespace Pinetime::Applications::Screens; +using Pinetime::Controllers::AlarmController; + +static void btnEventHandler(lv_obj_t* obj, lv_event_t event) { + auto* screen = static_cast(obj->user_data); + screen->OnButtonEvent(obj, event); +} + +static void StopAlarmTaskCallback(lv_task_t* task) { + auto* screen = static_cast(task->user_data); + screen->StopAlerting(); +} + +Alarm::Alarm(DisplayApp* app, + Controllers::AlarmController& alarmController, + Pinetime::Controllers::Settings& settingsController, + System::SystemTask& systemTask) + : Screen(app), alarmController {alarmController}, settingsController {settingsController}, systemTask {systemTask} { + + time = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_font(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76); + lv_obj_set_style_local_text_color(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY); + + alarmHours = alarmController.Hours(); + alarmMinutes = alarmController.Minutes(); + lv_label_set_text_fmt(time, "%02hhu:%02hhu", alarmHours, alarmMinutes); + + lv_obj_align(time, lv_scr_act(), LV_ALIGN_CENTER, 0, -25); + + lblampm = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_font(lblampm, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_bold_20); + lv_obj_set_style_local_text_color(lblampm, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY); + lv_label_set_text_static(lblampm, " "); + lv_label_set_align(lblampm, LV_LABEL_ALIGN_CENTER); + lv_obj_align(lblampm, lv_scr_act(), LV_ALIGN_CENTER, 0, 30); + + btnHoursUp = lv_btn_create(lv_scr_act(), nullptr); + btnHoursUp->user_data = this; + lv_obj_set_event_cb(btnHoursUp, btnEventHandler); + lv_obj_set_size(btnHoursUp, 60, 40); + lv_obj_align(btnHoursUp, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 20, -85); + txtHrUp = lv_label_create(btnHoursUp, nullptr); + lv_label_set_text_static(txtHrUp, "+"); + + btnHoursDown = lv_btn_create(lv_scr_act(), nullptr); + btnHoursDown->user_data = this; + lv_obj_set_event_cb(btnHoursDown, btnEventHandler); + lv_obj_set_size(btnHoursDown, 60, 40); + lv_obj_align(btnHoursDown, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 20, 35); + txtHrDown = lv_label_create(btnHoursDown, nullptr); + lv_label_set_text_static(txtHrDown, "-"); + + btnMinutesUp = lv_btn_create(lv_scr_act(), nullptr); + btnMinutesUp->user_data = this; + lv_obj_set_event_cb(btnMinutesUp, btnEventHandler); + lv_obj_set_size(btnMinutesUp, 60, 40); + lv_obj_align(btnMinutesUp, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, -20, -85); + txtMinUp = lv_label_create(btnMinutesUp, nullptr); + lv_label_set_text_static(txtMinUp, "+"); + + btnMinutesDown = lv_btn_create(lv_scr_act(), nullptr); + btnMinutesDown->user_data = this; + lv_obj_set_event_cb(btnMinutesDown, btnEventHandler); + lv_obj_set_size(btnMinutesDown, 60, 40); + lv_obj_align(btnMinutesDown, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, -20, 35); + txtMinDown = lv_label_create(btnMinutesDown, nullptr); + lv_label_set_text_static(txtMinDown, "-"); + + btnStop = lv_btn_create(lv_scr_act(), nullptr); + btnStop->user_data = this; + lv_obj_set_event_cb(btnStop, btnEventHandler); + lv_obj_set_size(btnStop, 115, 50); + lv_obj_align(btnStop, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 0, 0); + lv_obj_set_style_local_bg_color(btnStop, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED); + txtStop = lv_label_create(btnStop, nullptr); + lv_label_set_text_static(txtStop, Symbols::stop); + lv_obj_set_hidden(btnStop, true); + + btnRecur = lv_btn_create(lv_scr_act(), nullptr); + btnRecur->user_data = this; + lv_obj_set_event_cb(btnRecur, btnEventHandler); + lv_obj_set_size(btnRecur, 115, 50); + lv_obj_align(btnRecur, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0); + txtRecur = lv_label_create(btnRecur, nullptr); + SetRecurButtonState(); + + btnInfo = lv_btn_create(lv_scr_act(), nullptr); + btnInfo->user_data = this; + lv_obj_set_event_cb(btnInfo, btnEventHandler); + lv_obj_set_size(btnInfo, 50, 40); + lv_obj_align(btnInfo, lv_scr_act(), LV_ALIGN_CENTER, 0, -85); + txtInfo = lv_label_create(btnInfo, nullptr); + lv_label_set_text_static(txtInfo, "i"); + + enableSwitch = lv_switch_create(lv_scr_act(), nullptr); + enableSwitch->user_data = this; + lv_obj_set_event_cb(enableSwitch, btnEventHandler); + lv_obj_set_size(enableSwitch, 100, 50); + // Align to the center of 115px from edge + lv_obj_align(enableSwitch, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 7, 0); + + UpdateAlarmTime(); + + if (alarmController.State() == Controllers::AlarmController::AlarmState::Alerting) { + SetAlerting(); + } else { + SetSwitchState(LV_ANIM_OFF); + } +} + +Alarm::~Alarm() { + if (alarmController.State() == AlarmController::AlarmState::Alerting) { + StopAlerting(); + } + lv_obj_clean(lv_scr_act()); +} + +void Alarm::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { + using Pinetime::Controllers::AlarmController; + if (event == LV_EVENT_CLICKED) { + if (obj == btnStop) { + StopAlerting(); + return; + } + if (obj == btnInfo) { + ShowInfo(); + return; + } + if (obj == btnMessage) { + HideInfo(); + return; + } + if (obj == enableSwitch) { + if (lv_switch_get_state(enableSwitch)) { + alarmController.ScheduleAlarm(); + } else { + alarmController.DisableAlarm(); + } + return; + } + // If any other button was pressed, disable the alarm + // this is to make it clear that the alarm won't be set until it is turned back on + if (alarmController.State() == AlarmController::AlarmState::Set) { + alarmController.DisableAlarm(); + lv_switch_off(enableSwitch, LV_ANIM_ON); + } + if (obj == btnMinutesUp) { + if (alarmMinutes >= 59) { + alarmMinutes = 0; + } else { + alarmMinutes++; + } + UpdateAlarmTime(); + return; + } + if (obj == btnMinutesDown) { + if (alarmMinutes == 0) { + alarmMinutes = 59; + } else { + alarmMinutes--; + } + UpdateAlarmTime(); + return; + } + if (obj == btnHoursUp) { + if (alarmHours >= 23) { + alarmHours = 0; + } else { + alarmHours++; + } + UpdateAlarmTime(); + return; + } + if (obj == btnHoursDown) { + if (alarmHours == 0) { + alarmHours = 23; + } else { + alarmHours--; + } + UpdateAlarmTime(); + return; + } + if (obj == btnRecur) { + ToggleRecurrence(); + } + } +} + +bool Alarm::OnButtonPushed() { + if (txtMessage != nullptr && btnMessage != nullptr) { + HideInfo(); + return true; + } + if (alarmController.State() == AlarmController::AlarmState::Alerting) { + StopAlerting(); + return true; + } + return false; +} + +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; +} + +void Alarm::UpdateAlarmTime() { + if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) { + switch (alarmHours) { + case 0: + lv_label_set_text_static(lblampm, "AM"); + lv_label_set_text_fmt(time, "%02d:%02d", 12, alarmMinutes); + break; + case 1 ... 11: + lv_label_set_text_static(lblampm, "AM"); + lv_label_set_text_fmt(time, "%02d:%02d", alarmHours, alarmMinutes); + break; + case 12: + lv_label_set_text_static(lblampm, "PM"); + lv_label_set_text_fmt(time, "%02d:%02d", 12, alarmMinutes); + break; + case 13 ... 23: + lv_label_set_text_static(lblampm, "PM"); + lv_label_set_text_fmt(time, "%02d:%02d", alarmHours - 12, alarmMinutes); + break; + } + } else { + lv_label_set_text_fmt(time, "%02d:%02d", alarmHours, alarmMinutes); + } + alarmController.SetAlarmTime(alarmHours, alarmMinutes); +} + +void Alarm::SetAlerting() { + lv_obj_set_hidden(enableSwitch, true); + lv_obj_set_hidden(btnStop, false); + taskStopAlarm = lv_task_create(StopAlarmTaskCallback, pdMS_TO_TICKS(60 * 1000), LV_TASK_PRIO_MID, this); + systemTask.PushMessage(System::Messages::DisableSleeping); +} + +void Alarm::StopAlerting() { + alarmController.StopAlerting(); + SetSwitchState(LV_ANIM_OFF); + if (taskStopAlarm != nullptr) { + lv_task_del(taskStopAlarm); + taskStopAlarm = nullptr; + } + systemTask.PushMessage(System::Messages::EnableSleeping); + 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: + lv_switch_on(enableSwitch, anim); + break; + case AlarmController::AlarmState::Not_Set: + lv_switch_off(enableSwitch, anim); + break; + default: + break; + } +} + +void Alarm::ShowInfo() { + btnMessage = lv_btn_create(lv_scr_act(), nullptr); + btnMessage->user_data = this; + lv_obj_set_event_cb(btnMessage, btnEventHandler); + lv_obj_set_height(btnMessage, 200); + lv_obj_set_width(btnMessage, 150); + lv_obj_align(btnMessage, lv_scr_act(), LV_ALIGN_CENTER, 0, 0); + 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) { + auto timeToAlarm = alarmController.SecondsToAlarm(); + + auto daysToAlarm = timeToAlarm / 86400; + auto hrsToAlarm = (timeToAlarm % 86400) / 3600; + auto minToAlarm = (timeToAlarm % 3600) / 60; + auto secToAlarm = timeToAlarm % 60; + + lv_label_set_text_fmt( + txtMessage, "Time to\nalarm:\n%2lu Days\n%2lu Hours\n%2lu Minutes\n%2lu Seconds", daysToAlarm, hrsToAlarm, minToAlarm, secToAlarm); + } else { + lv_label_set_text(txtMessage, "Alarm\nis not\nset."); + } +} + +void Alarm::HideInfo() { + lv_obj_del(btnMessage); + txtMessage = nullptr; + btnMessage = nullptr; +} + +void Alarm::SetRecurButtonState() { + using Pinetime::Controllers::AlarmController; + switch (alarmController.Recurrence()) { + case AlarmController::RecurType::None: + lv_label_set_text(txtRecur, "ONCE"); + break; + case AlarmController::RecurType::Daily: + lv_label_set_text(txtRecur, "DAILY"); + break; + case AlarmController::RecurType::Weekdays: + lv_label_set_text(txtRecur, "MON-FRI"); + } +} + +void Alarm::ToggleRecurrence() { + using Pinetime::Controllers::AlarmController; + switch (alarmController.Recurrence()) { + case AlarmController::RecurType::None: + alarmController.SetRecurrence(AlarmController::RecurType::Daily); + break; + case AlarmController::RecurType::Daily: + alarmController.SetRecurrence(AlarmController::RecurType::Weekdays); + break; + case AlarmController::RecurType::Weekdays: + alarmController.SetRecurrence(AlarmController::RecurType::None); + } + SetRecurButtonState(); +} diff --git a/src/displayapp/screens/Alarm.h b/src/displayapp/screens/Alarm.h new file mode 100644 index 0000000..f74dd68 --- /dev/null +++ b/src/displayapp/screens/Alarm.h @@ -0,0 +1,65 @@ +/* Copyright (C) 2021 mruss77, Florian + + This file is part of InfiniTime. + + InfiniTime is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + InfiniTime is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#pragma once + +#include "displayapp/screens/Screen.h" +#include "systemtask/SystemTask.h" +#include "displayapp/LittleVgl.h" +#include "components/alarm/AlarmController.h" + +namespace Pinetime { + namespace Applications { + namespace Screens { + class Alarm : public Screen { + public: + Alarm(DisplayApp* app, + Controllers::AlarmController& alarmController, + Pinetime::Controllers::Settings& settingsController, + System::SystemTask& systemTask); + ~Alarm() override; + void SetAlerting(); + void OnButtonEvent(lv_obj_t* obj, lv_event_t event); + bool OnButtonPushed() override; + bool OnTouchEvent(TouchEvents event) override; + void StopAlerting(); + + private: + uint8_t alarmHours; + uint8_t alarmMinutes; + Controllers::AlarmController& alarmController; + Controllers::Settings& settingsController; + System::SystemTask& systemTask; + + lv_obj_t *time, *lblampm, *btnStop, *txtStop, *btnMinutesUp, *btnMinutesDown, *btnHoursUp, *btnHoursDown, *txtMinUp, + *txtMinDown, *txtHrUp, *txtHrDown, *btnRecur, *txtRecur, *btnInfo, *txtInfo, *enableSwitch; + lv_obj_t* txtMessage = nullptr; + lv_obj_t* btnMessage = nullptr; + lv_task_t* taskStopAlarm = nullptr; + + enum class EnableButtonState { On, Off, Alerting }; + void SetRecurButtonState(); + void SetSwitchState(lv_anim_enable_t anim); + void SetAlarm(); + void ShowInfo(); + void HideInfo(); + void ToggleRecurrence(); + void UpdateAlarmTime(); + }; + }; + }; +} diff --git a/src/displayapp/screens/ApplicationList.cpp b/src/displayapp/screens/ApplicationList.cpp index b7c8ebd..5daafd1 100644 --- a/src/displayapp/screens/ApplicationList.cpp +++ b/src/displayapp/screens/ApplicationList.cpp @@ -36,7 +36,7 @@ bool ApplicationList::OnTouchEvent(Pinetime::Applications::TouchEvents event) { std::unique_ptr ApplicationList::CreateScreen1() { std::array applications {{ - {Symbols::clock}, + {Symbols::clock, Apps::Alarm}, }}; return std::make_unique(0, 1, app, settingsController, batteryController, dateTimeController, applications); diff --git a/src/main.cpp b/src/main.cpp index 8022595..062e64c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -103,6 +103,7 @@ Pinetime::Drivers::Watchdog watchdog; Pinetime::Drivers::WatchdogView watchdogView(watchdog); Pinetime::Controllers::NotificationManager notificationManager; Pinetime::Controllers::MotionController motionController; +Pinetime::Controllers::AlarmController alarmController {dateTimeController}; Pinetime::Controllers::TouchHandler touchHandler(touchPanel, lvgl); Pinetime::Controllers::ButtonHandler buttonHandler; Pinetime::Controllers::BrightnessController brightnessController {}; @@ -118,6 +119,7 @@ Pinetime::Applications::DisplayApp displayApp(lcd, settingsController, motorController, motionController, + alarmController, brightnessController, touchHandler); @@ -130,6 +132,7 @@ Pinetime::System::SystemTask systemTask(spi, batteryController, bleController, dateTimeController, + alarmController, watchdog, notificationManager, motorController, diff --git a/src/systemtask/Messages.h b/src/systemtask/Messages.h index c2a18e2..1210bbc 100644 --- a/src/systemtask/Messages.h +++ b/src/systemtask/Messages.h @@ -23,6 +23,7 @@ namespace Pinetime { OnNewHour, OnChime, OnChargingEvent, + SetOffAlarm, StopRinging, MeasureBatteryTimerExpired, BatteryPercentageUpdated, diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp index 7a0d151..6f32843 100644 --- a/src/systemtask/SystemTask.cpp +++ b/src/systemtask/SystemTask.cpp @@ -56,6 +56,7 @@ SystemTask::SystemTask(Drivers::SpiMaster& spi, Controllers::Battery& batteryController, Controllers::Ble& bleController, Controllers::DateTime& dateTimeController, + Controllers::AlarmController& alarmController, Drivers::Watchdog& watchdog, Pinetime::Controllers::NotificationManager& notificationManager, Pinetime::Controllers::MotorController& motorController, @@ -74,6 +75,7 @@ SystemTask::SystemTask(Drivers::SpiMaster& spi, batteryController {batteryController}, bleController {bleController}, dateTimeController {dateTimeController}, + alarmController {alarmController}, watchdog {watchdog}, notificationManager {notificationManager}, motorController {motorController}, @@ -133,6 +135,7 @@ void SystemTask::Work() { batteryController.Register(this); motorController.Init(); motionSensor.SoftReset(); + alarmController.Init(this); // Reset the TWI device because the motion sensor chip most probably crashed it... twiMaster.Sleep(); @@ -261,6 +264,9 @@ void SystemTask::Work() { case Messages::OnNewTime: ReloadIdleTimer(); displayApp.PushMessage(Pinetime::Applications::Display::Messages::UpdateDateTime); + if (alarmController.State() == Controllers::AlarmController::AlarmState::Set) { + alarmController.ScheduleAlarm(); + } break; case Messages::OnNewNotification: if (settingsController.GetNotificationStatus() == Pinetime::Controllers::Settings::Notification::ON) { @@ -272,6 +278,13 @@ void SystemTask::Work() { displayApp.PushMessage(Pinetime::Applications::Display::Messages::NewNotification); } break; + case Messages::SetOffAlarm: + if (isSleeping && !isWakingUp) { + GoToRunning(); + } + motorController.StartRinging(); + displayApp.PushMessage(Pinetime::Applications::Display::Messages::AlarmTriggered); + break; case Messages::StopRinging: motorController.StopRinging(); break; @@ -343,7 +356,8 @@ void SystemTask::Work() { stepCounterMustBeReset = true; break; case Messages::OnNewHour: - if (settingsController.GetChimeOption() == Controllers::Settings::ChimesOption::Hours) { + using Pinetime::Controllers::AlarmController; + if (settingsController.GetChimeOption() == Controllers::Settings::ChimesOption::Hours && alarmController.State() != AlarmController::AlarmState::Alerting) { if (isSleeping && !isWakingUp) { GoToRunning(); displayApp.PushMessage(Pinetime::Applications::Display::Messages::Clock); @@ -351,9 +365,10 @@ void SystemTask::Work() { motorController.RunForDuration(22); } break; - case Messages::OnChime: - if (settingsController.GetChimeOption() == Controllers::Settings::ChimesOption::HalfHours) { - if (false && isSleeping && !isWakingUp) { + case Messages::OnNewHalfHour: + using Pinetime::Controllers::AlarmController; + if (settingsController.GetChimeOption() == Controllers::Settings::ChimesOption::HalfHours && alarmController.State() != AlarmController::AlarmState::Alerting) { + if (isSleeping && !isWakingUp) { GoToRunning(); displayApp.PushMessage(Pinetime::Applications::Display::Messages::Clock); } diff --git a/src/systemtask/SystemTask.h b/src/systemtask/SystemTask.h index 600d13e..8fc48f1 100644 --- a/src/systemtask/SystemTask.h +++ b/src/systemtask/SystemTask.h @@ -15,6 +15,7 @@ #include "components/ble/NimbleController.h" #include "components/ble/NotificationManager.h" #include "components/motor/MotorController.h" +#include "components/alarm/AlarmController.h" #include "touchhandler/TouchHandler.h" #include "buttonhandler/ButtonHandler.h" #include "buttonhandler/ButtonActions.h" @@ -57,6 +58,7 @@ namespace Pinetime { Controllers::Battery& batteryController, Controllers::Ble& bleController, Controllers::DateTime& dateTimeController, + Controllers::AlarmController& alarmController, Drivers::Watchdog& watchdog, Pinetime::Controllers::NotificationManager& notificationManager, Pinetime::Controllers::MotorController& motorController, @@ -96,6 +98,7 @@ namespace Pinetime { Pinetime::Controllers::Ble& bleController; Pinetime::Controllers::DateTime& dateTimeController; + Pinetime::Controllers::AlarmController& alarmController; QueueHandle_t systemTasksMsgQueue; std::atomic isSleeping {false}; std::atomic isGoingToSleep {false}; -- cgit v0.10.2