169 lines
4.7 KiB
C
169 lines
4.7 KiB
C
#include "app_no_disturb.h"
|
|
#include "usr_rtc.h"
|
|
#include "system/includes.h"
|
|
|
|
#define APP_MINUTES_PER_DAY (24U * 60U)
|
|
#define APP_NO_DISTURB_VM_MAGIC 0x444e4431UL
|
|
#define APP_NO_DISTURB_VM_VERSION 1U
|
|
|
|
typedef struct {
|
|
uint8_t enabled;
|
|
uint8_t weekdays_mask;
|
|
uint16_t start_minute;
|
|
uint16_t end_minute;
|
|
} AppNoDisturbCtx_t;
|
|
|
|
typedef struct {
|
|
uint32_t magic;
|
|
uint8_t version;
|
|
uint8_t length;
|
|
uint16_t checksum;
|
|
uint8_t data[APP_NO_DISTURB_DATA_LEN];
|
|
} AppNoDisturbVm_t;
|
|
|
|
static AppNoDisturbCtx_t s_no_disturb;
|
|
static uint8_t s_saved_data[APP_NO_DISTURB_DATA_LEN];
|
|
static uint8_t s_saved_valid;
|
|
|
|
static uint16_t app_no_disturb_checksum(const uint8_t *data)
|
|
{
|
|
uint16_t checksum = 0xa55aU;
|
|
uint8_t i;
|
|
|
|
for (i = 0; i < APP_NO_DISTURB_DATA_LEN; i++) {
|
|
checksum = (uint16_t)((checksum << 5) | (checksum >> 11));
|
|
checksum ^= data[i];
|
|
}
|
|
return checksum;
|
|
}
|
|
|
|
static uint8_t app_no_disturb_vm_valid(const AppNoDisturbVm_t *vm)
|
|
{
|
|
return vm->magic == APP_NO_DISTURB_VM_MAGIC &&
|
|
vm->version == APP_NO_DISTURB_VM_VERSION &&
|
|
vm->length == APP_NO_DISTURB_DATA_LEN &&
|
|
vm->checksum == app_no_disturb_checksum(vm->data);
|
|
}
|
|
|
|
static uint8_t app_no_disturb_weekday_monday0(const struct sys_time *time)
|
|
{
|
|
static const uint8_t month_offset[12] = {
|
|
0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4
|
|
};
|
|
uint32_t year = time->year;
|
|
uint8_t sunday0;
|
|
|
|
if (time->month < 3U) {
|
|
year--;
|
|
}
|
|
sunday0 = (uint8_t)((year + year / 4U - year / 100U + year / 400U +
|
|
month_offset[time->month - 1U] + time->day) % 7U);
|
|
return (uint8_t)((sunday0 + 6U) % 7U);
|
|
}
|
|
|
|
static uint8_t app_no_disturb_day_selected(uint8_t weekday)
|
|
{
|
|
return (uint8_t)((s_no_disturb.weekdays_mask & (1U << weekday)) != 0U);
|
|
}
|
|
|
|
void app_no_disturb_configure(uint8_t enable, uint8_t weekdays_mask,
|
|
uint16_t start_minute, uint16_t end_minute)
|
|
{
|
|
s_no_disturb.enabled = !!enable;
|
|
s_no_disturb.weekdays_mask = weekdays_mask & 0x7fU;
|
|
s_no_disturb.start_minute = start_minute;
|
|
s_no_disturb.end_minute = end_minute;
|
|
}
|
|
|
|
uint8_t app_no_disturb_is_active_at(const struct sys_time *time)
|
|
{
|
|
uint8_t weekday;
|
|
uint16_t now_minute;
|
|
|
|
if (!time || !s_no_disturb.enabled || !s_no_disturb.weekdays_mask ||
|
|
s_no_disturb.start_minute >= APP_MINUTES_PER_DAY ||
|
|
s_no_disturb.end_minute >= APP_MINUTES_PER_DAY ||
|
|
time->month < 1U || time->month > 12U ||
|
|
time->day < 1U || time->day > 31U ||
|
|
time->hour > 23U || time->min > 59U) {
|
|
return 0;
|
|
}
|
|
|
|
weekday = app_no_disturb_weekday_monday0(time);
|
|
now_minute = (uint16_t)(time->hour * 60U + time->min);
|
|
|
|
if (s_no_disturb.start_minute == s_no_disturb.end_minute) {
|
|
return app_no_disturb_day_selected(weekday);
|
|
}
|
|
if (s_no_disturb.start_minute < s_no_disturb.end_minute) {
|
|
return app_no_disturb_day_selected(weekday) &&
|
|
now_minute >= s_no_disturb.start_minute &&
|
|
now_minute < s_no_disturb.end_minute;
|
|
}
|
|
if (now_minute >= s_no_disturb.start_minute) {
|
|
return app_no_disturb_day_selected(weekday);
|
|
}
|
|
if (now_minute < s_no_disturb.end_minute) {
|
|
return app_no_disturb_day_selected((uint8_t)((weekday + 6U) % 7U));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
uint8_t app_no_disturb_is_active(void)
|
|
{
|
|
struct sys_time time;
|
|
|
|
if (!usr_rtc_get_time(&time)) {
|
|
return 0;
|
|
}
|
|
return app_no_disturb_is_active_at(&time);
|
|
}
|
|
|
|
uint8_t app_no_disturb_storage_load(uint8_t data[APP_NO_DISTURB_DATA_LEN])
|
|
{
|
|
AppNoDisturbVm_t vm;
|
|
int ret;
|
|
|
|
if (!data) {
|
|
return 0;
|
|
}
|
|
memset(&vm, 0, sizeof(vm));
|
|
ret = syscfg_read(CFG_USER_NO_DISTURB, (uint8_t *)&vm, sizeof(vm));
|
|
if (ret != (int)sizeof(vm) || !app_no_disturb_vm_valid(&vm)) {
|
|
s_saved_valid = 0;
|
|
return 0;
|
|
}
|
|
memcpy(data, vm.data, APP_NO_DISTURB_DATA_LEN);
|
|
memcpy(s_saved_data, vm.data, APP_NO_DISTURB_DATA_LEN);
|
|
s_saved_valid = 1;
|
|
return 1;
|
|
}
|
|
|
|
uint8_t app_no_disturb_storage_save(const uint8_t data[APP_NO_DISTURB_DATA_LEN])
|
|
{
|
|
AppNoDisturbVm_t vm;
|
|
int ret;
|
|
|
|
if (!data) {
|
|
return 0;
|
|
}
|
|
if (s_saved_valid &&
|
|
!memcmp(s_saved_data, data, APP_NO_DISTURB_DATA_LEN)) {
|
|
return 1;
|
|
}
|
|
|
|
memset(&vm, 0, sizeof(vm));
|
|
vm.magic = APP_NO_DISTURB_VM_MAGIC;
|
|
vm.version = APP_NO_DISTURB_VM_VERSION;
|
|
vm.length = APP_NO_DISTURB_DATA_LEN;
|
|
memcpy(vm.data, data, APP_NO_DISTURB_DATA_LEN);
|
|
vm.checksum = app_no_disturb_checksum(vm.data);
|
|
ret = syscfg_write(CFG_USER_NO_DISTURB, (uint8_t *)&vm, sizeof(vm));
|
|
if (ret != (int)sizeof(vm)) {
|
|
return 0;
|
|
}
|
|
memcpy(s_saved_data, data, APP_NO_DISTURB_DATA_LEN);
|
|
s_saved_valid = 1;
|
|
return 1;
|
|
}
|