146 lines
4.1 KiB
C
146 lines
4.1 KiB
C
#include "app_no_disturb.h"
|
|
#include "system/includes.h"
|
|
#include "usr_rtc.h"
|
|
|
|
#define APP_NO_DISTURB_VM_ID 28U
|
|
#define APP_NO_DISTURB_MAGIC 0x4e44U
|
|
#define APP_NO_DISTURB_VERSION 1U
|
|
#define APP_MINUTES_PER_DAY (24U * 60U)
|
|
|
|
typedef struct __attribute__((packed)) {
|
|
uint16_t magic;
|
|
uint8_t version;
|
|
uint8_t cfg[APP_NO_DISTURB_CFG_LEN];
|
|
} AppNoDisturbVm_t;
|
|
|
|
typedef struct {
|
|
uint8_t enabled;
|
|
uint8_t weekdays_mask;
|
|
uint16_t start_minute;
|
|
uint16_t end_minute;
|
|
} AppNoDisturbCtx_t;
|
|
|
|
static AppNoDisturbCtx_t s_no_disturb;
|
|
|
|
static uint8_t app_no_disturb_cfg_valid(const uint8_t cfg[APP_NO_DISTURB_CFG_LEN])
|
|
{
|
|
uint8_t i;
|
|
|
|
if (!cfg || cfg[0] > 1U || cfg[9] >= 24U || cfg[11] >= 24U ||
|
|
cfg[10] >= 60U || cfg[12] >= 60U) {
|
|
return 0;
|
|
}
|
|
for (i = 0; i < 7U; i++) {
|
|
if (cfg[2U + i] > 1U) {
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
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_storage_load(uint8_t cfg[APP_NO_DISTURB_CFG_LEN])
|
|
{
|
|
AppNoDisturbVm_t vm;
|
|
int ret;
|
|
|
|
if (!cfg) {
|
|
return 0;
|
|
}
|
|
memset(&vm, 0, sizeof(vm));
|
|
ret = syscfg_read(APP_NO_DISTURB_VM_ID, &vm, sizeof(vm));
|
|
if (ret != (int)sizeof(vm) || vm.magic != APP_NO_DISTURB_MAGIC ||
|
|
vm.version != APP_NO_DISTURB_VERSION || !app_no_disturb_cfg_valid(vm.cfg)) {
|
|
memset(cfg, 0, APP_NO_DISTURB_CFG_LEN);
|
|
return 0;
|
|
}
|
|
memcpy(cfg, vm.cfg, APP_NO_DISTURB_CFG_LEN);
|
|
return 1;
|
|
}
|
|
|
|
uint8_t app_no_disturb_storage_save(const uint8_t cfg[APP_NO_DISTURB_CFG_LEN])
|
|
{
|
|
AppNoDisturbVm_t vm;
|
|
|
|
if (!app_no_disturb_cfg_valid(cfg)) {
|
|
return 0;
|
|
}
|
|
memset(&vm, 0, sizeof(vm));
|
|
vm.magic = APP_NO_DISTURB_MAGIC;
|
|
vm.version = APP_NO_DISTURB_VERSION;
|
|
memcpy(vm.cfg, cfg, APP_NO_DISTURB_CFG_LEN);
|
|
return (uint8_t)(syscfg_write(APP_NO_DISTURB_VM_ID, &vm, sizeof(vm)) ==
|
|
(int)sizeof(vm));
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
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);
|
|
}
|