Add alarms component
This commit is contained in:
181
components/alarms/alarms.c
Normal file
181
components/alarms/alarms.c
Normal file
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
* 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 <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#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 <hh:mm> OR alarms remove <index>",
|
||||
command_func);
|
||||
}
|
||||
|
||||
void alarm_snooze(void)
|
||||
{
|
||||
}
|
||||
|
||||
void alarm_dismiss(void)
|
||||
{
|
||||
if (active_count > 0)
|
||||
dismiss(0);
|
||||
}
|
||||
Reference in New Issue
Block a user