From e4668f0c049973844a366e284ac9dfce597ab8f6 Mon Sep 17 00:00:00 2001 From: Camden Dixie O'Brien Date: Fri, 19 May 2023 16:15:17 +0100 Subject: [PATCH] Implement persistent alarm storage --- components/alarms/CMakeLists.txt | 4 +- components/alarms/alarm_store.c | 77 ++++++++++++++++++++++++++++++++ components/alarms/alarm_store.h | 31 +++++++++++++ components/alarms/alarms.c | 13 +++--- partitions.csv | 6 +++ sdkconfig.defaults | 1 + 6 files changed, 122 insertions(+), 10 deletions(-) create mode 100644 components/alarms/alarm_store.c create mode 100644 components/alarms/alarm_store.h create mode 100644 partitions.csv diff --git a/components/alarms/CMakeLists.txt b/components/alarms/CMakeLists.txt index 47ec2eb..20dd1bb 100644 --- a/components/alarms/CMakeLists.txt +++ b/components/alarms/CMakeLists.txt @@ -1,5 +1,5 @@ idf_component_register( - SRCS "alarms.c" + SRCS "alarm_store.c" "alarms.c" INCLUDE_DIRS "." - REQUIRES console_wrapper sound time + REQUIRES console_wrapper esp_partition fatal sound system_utils time ) diff --git a/components/alarms/alarm_store.c b/components/alarms/alarm_store.c new file mode 100644 index 0000000..7a87b87 --- /dev/null +++ b/components/alarms/alarm_store.c @@ -0,0 +1,77 @@ +/* + * SPDX-License-Identifier: AGPL-3.0-only + * Copyright (c) Camden Dixie O'Brien + */ + +#include "alarm_store.h" + +#include "fatal.h" + +#include "esp_log.h" +#include "esp_partition.h" +#include "system_utils.h" +#include + +#define TAG "Alarm store" + +Alarm alarms[CONFIG_MAX_ALARMS]; + +static const esp_partition_t *partition; + +static unsigned erase_size(void) +{ + unsigned sector_count = sizeof(alarms) / partition->erase_size; + if (sizeof(alarms) % partition->erase_size != 0) + ++sector_count; + return partition->erase_size * sector_count; +} + +static void load() +{ + const esp_err_t error + = esp_partition_read(partition, 0, alarms, sizeof(alarms)); + if (error != ESP_OK) { + ESP_LOGE(TAG, "Error reading from alarms partition: %02x", error); + FATAL(); + } + unsigned count = 0; + for (unsigned i = 0; i < CONFIG_MAX_ALARMS; ++i) { + if (alarms[i].set) + ++count; + } + ESP_LOGI(TAG, "Loaded %u alarms from storage", count); +} + +void alarm_store_init() +{ + partition = esp_partition_find_first( + ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_UNDEFINED, + "alarms"); + if (partition == NULL) { + ESP_LOGE(TAG, "Unable to find alarms partition"); + FATAL(); + } + + if (is_first_boot()) { + ESP_LOGI(TAG, "Zeroing alarm store"); + memset(alarms, 0, sizeof(alarms)); + alarm_store_save(); + } else { + load(); + } +} + +void alarm_store_save() +{ + esp_err_t error; + + error = esp_partition_erase_range(partition, 0, erase_size()); + if (error != ESP_OK) { + ESP_LOGE(TAG, "Error erasing alarm storage: %02x", error); + return; + } + + error = esp_partition_write(partition, 0, alarms, sizeof(alarms)); + if (error != ESP_OK) + ESP_LOGE(TAG, "Error writing alarm storage: %02x", error); +} diff --git a/components/alarms/alarm_store.h b/components/alarms/alarm_store.h new file mode 100644 index 0000000..2341940 --- /dev/null +++ b/components/alarms/alarm_store.h @@ -0,0 +1,31 @@ +/* + * SPDX-License-Identifier: AGPL-3.0-only + * Copyright (c) Camden Dixie O'Brien + */ + +#ifndef ALARM_STORE_H +#define ALARM_STORE_H + +#include "time_manager.h" + +#include "sdkconfig.h" +#include + +typedef struct { + bool set; + Time time; +} Alarm; + +extern Alarm alarms[CONFIG_MAX_ALARMS]; + +/** + * Initialize alarm store and load alarms from storage. + */ +void alarm_store_init(void); + +/** + * Save alarms to storage. + */ +void alarm_store_save(void); + +#endif diff --git a/components/alarms/alarms.c b/components/alarms/alarms.c index e504664..8fc0c5c 100644 --- a/components/alarms/alarms.c +++ b/components/alarms/alarms.c @@ -5,9 +5,9 @@ #include "alarms.h" +#include "alarm_store.h" #include "console.h" #include "sound.h" -#include "time_manager.h" #include "esp_log.h" #include "freertos/FreeRTOS.h" @@ -18,17 +18,11 @@ #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 ActiveAlarm snoozed[CONFIG_MAX_ALARMS]; @@ -53,6 +47,7 @@ static bool add_alarm(Time time) if (!alarms[i].set) { alarms[i].set = true; alarms[i].time = time; + alarm_store_save(); return true; } } @@ -62,6 +57,7 @@ static bool add_alarm(Time time) static void remove_alarm(unsigned index) { alarms[index].set = false; + alarm_store_save(); } static void activate(const Alarm *alarm) @@ -212,13 +208,14 @@ static int command_func(int argc, char **argv) void alarms_init(void) { - memset(alarms, 0, sizeof(alarms)); memset(active, 0, sizeof(active)); active_count = 0; memset(snoozed, 0, sizeof(snoozed)); snoozed_count = 0; last_check = get_time(); + alarm_store_init(); + add_time_callback(check_alarms); console_register( diff --git a/partitions.csv b/partitions.csv new file mode 100644 index 0000000..74575a1 --- /dev/null +++ b/partitions.csv @@ -0,0 +1,6 @@ +# ESP-IDF Partition Table +# Name, Type, SubType, Offset, Size, Flags +nvs,data,nvs,0x9000,24K, +phy_init,data,phy,0xf000,4K, +factory,app,factory,0x10000,1M, +alarms,data,undefined,,8K diff --git a/sdkconfig.defaults b/sdkconfig.defaults index 8803627..e83218b 100644 --- a/sdkconfig.defaults +++ b/sdkconfig.defaults @@ -1,4 +1,5 @@ # This file was generated using idf.py save-defconfig. It can be edited manually. # Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration # +CONFIG_PARTITION_TABLE_CUSTOM=y CONFIG_FREERTOS_UNICORE=y