/* * SPDX-License-Identifier: AGPL-3.0-only * Copyright (c) Camden Dixie O'Brien */ #include "alarms.h" #include "console.h" #include "sound.h" #include "time_manager.h" #include "esp_log.h" #include #include #include #define TAG "Alarms" typedef struct { bool set; Time time; } Alarm; typedef struct { const Alarm *alarm; Time end; } ActiveAlarm; static Alarm alarms[CONFIG_MAX_ALARMS]; static ActiveAlarm active[CONFIG_MAX_ALARMS]; static unsigned active_count; static Time last_check; static bool add_alarm(Time time) { for (unsigned i = 0; i < CONFIG_MAX_ALARMS; ++i) { if (!alarms[i].set) { alarms[i].set = true; alarms[i].time = time; return true; } } return false; } static void remove_alarm(unsigned index) { alarms[index].set = false; } static void activate(unsigned index, Time end) { if (active_count == 0) sound_alert_on(); active[active_count].alarm = &alarms[index]; active[active_count].end = end; ++active_count; ESP_LOGI(TAG, "Alarm %u activated", index); } static void dismiss(unsigned index) { if (active_count == 1) sound_alert_off(); for (unsigned i = index + 1; i < active_count; ++i) active[i - 1] = active[i]; --active_count; ESP_LOGI(TAG, "Alarm %u dismissed", index); } static bool passed_since_last_check(Time time, const Time *now) { return last_check.hour <= time.hour && time.hour <= now->hour && last_check.minute <= time.minute && time.minute <= now->minute && last_check.second <= time.second && time.second <= now->second; } static Time add_minutes(const Time *time, unsigned minutes) { Time new_time = { .hour = time->hour, .minute = time->minute + minutes, .second = time->second, }; if (new_time.minute >= 60) { new_time.minute %= 60; ++new_time.hour; } return new_time; } static void check_alarms(const Time *now) { for (unsigned i = 0; i < CONFIG_MAX_ALARMS; ++i) { if (!alarms[i].set) continue; if (passed_since_last_check(alarms[i].time, now)) activate(i, add_minutes(now, CONFIG_ALERT_MINUTES)); } for (unsigned i = 0; i != active_count; ++i) { if (passed_since_last_check(active[i].end, now)) dismiss(i); } last_check = *now; } static int command_func(int argc, char **argv) { if (argc == 1) { for (unsigned i = 0; i < CONFIG_MAX_ALARMS; ++i) { if (!alarms[i].set) continue; printf( "[%2u] %02u:%02u\n", i, alarms[i].time.hour, alarms[i].time.minute); } return 0; } else if (argc >= 3) { if (strcmp(argv[1], "add") == 0) { Time time = { .second = 0 }; int n = sscanf(argv[2], "%02u:%02u", &time.hour, &time.minute); if (n != 2) { printf("Invalid time\n"); return 1; } if (!add_alarm(time)) { printf("Max number of alarms already set.\n"); return 1; } return 0; } else if (strcmp(argv[1], "remove") == 0) { unsigned index; int n = sscanf(argv[2], "%u", &index); if (n != 1 || !alarms[index].set) { printf("Invalid index\n"); return 1; } remove_alarm(index); return 0; } else { printf("Unrecognised subcommand\n"); return 1; } } else { printf("Invalid number of arguments\n"); return 1; } } void alarms_init(void) { memset(alarms, 0, sizeof(alarms)); memset(active, 0, sizeof(active)); active_count = 0; last_check = get_time(); add_time_callback(check_alarms); console_register( "alarms", "List, add and remove alarms", "alarms OR alarms add OR alarms remove ", command_func); } void alarm_snooze(void) { } void alarm_dismiss(void) { if (active_count > 0) dismiss(0); }