#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; }