AC63_BT_SDK/apps/hid/modules/rtc_alarm.c

433 lines
12 KiB
C
Raw Normal View History

2025-02-18 15:40:42 +08:00
#include "rtc_alarm.h"
#include "system/timer.h"
#include "app_config.h"
#include "asm/rtc.h"
#if TCFG_RTC_ALARM_ENABLE
#define ALARM_DEBUG_EN 0
#if ALARM_DEBUG_EN
#define alarm_printf(x, ...) printf("[RTC_ALARM]" x " ", ## __VA_ARGS__)
#define alarm_printf_buf put_buf
#define alarm_putchar putchar
#else
#define alarm_printf(...)
#define alarm_printf_buf(...)
#define alarm_putchar(...)
#endif
#define RTC_MASK (0xaa55)
static T_ALARM alarm_tab[M_MAX_ALARM_NUMS];
static T_ALARM_VM_MASK alarm_mask;
static u8 alarm_pnd_flag = 0;
static void (*_user_isr_cbfun)(u8) = NULL;
void alarm_send_event(u8 index);
#if TCFG_RTC_ALARM_ENABLE
struct sys_time rtc_read_test;
struct sys_time alm_read_test;
struct sys_time alm_write_test = {
.year = 2024,
.month  =  1,
.day = 1,
.hour = 0,
.min = 0,
.sec = 20,
};
#endif
static u8 alarm_vm_write_mask(u8 alarm_active_index)
{
alarm_mask.head = RTC_MASK;
alarm_mask.alarm_active_index = alarm_active_index;
int ret = syscfg_write(VM_ALARM_MASK, (u8 *)&alarm_mask, sizeof(T_ALARM_VM_MASK));
if (ret <= 0) {
alarm_printf("alarm mask write vm err!\n");
return 1;
}
return 0;
}
static u8 alarm_vm_read_mask(void)
{
memset((u8 *)&alarm_mask, 0, sizeof(T_ALARM_VM_MASK));
int ret = syscfg_read(VM_ALARM_MASK, (u8 *)&alarm_mask, sizeof(T_ALARM_VM_MASK));
if ((ret <= 0) || (alarm_mask.head != RTC_MASK)) { //第一次读的时候
alarm_printf("alarm mask read vm err!\n");
return 1;
}
return 0;
}
static u8 alarm_vm_write_time_tab(T_ALARM_VM *pAlarm_tab, u8 index)
{
int ret;
T_ALARM_VM tmp = {0};
tmp.head = RTC_MASK;
memcpy((u8 *)&tmp.alarm, (u8 *)pAlarm_tab, sizeof(T_ALARM));
ret = syscfg_write(VM_ALARM_0 + index, (u8 *)&tmp, sizeof(T_ALARM_VM));
if (ret <= 0) {
alarm_printf("alarm write vm err!\n");
return 1;
}
return 0;
}
static u8 alarm_vm_read_time_tab(T_ALARM_VM *pAlarm_tab, u8 index)
{
T_ALARM_VM tmp = {0};
int ret = syscfg_read(VM_ALARM_0 + index, (u8 *)&tmp, sizeof(T_ALARM_VM));
if ((ret <= 0) || (tmp.head != RTC_MASK)) {
alarm_printf("alarm read vm err!\n");
return 1;
}
memcpy((u8 *)pAlarm_tab, (u8 *)&tmp.alarm, sizeof(T_ALARM));
return 0;
}
static void alarm_calculate_next_few_time(struct sys_time *time, u16 days)
{
if (!days) {
return;
}
u16 tmp_day = ymd_to_day(time);
tmp_day += days;
day_to_ymd(tmp_day, time);
}
static void alarm_calculate_time_by_week_mode(struct sys_time *pTime, u8 mode)
{
if (0 == mode) {
return;
}
if ((BIT(0)) == mode) {
return;
}
u16 tmp_mode = ((mode & 0xfe) << 7) | mode ;
u8 alarm_week = caculate_weekday_by_time(pTime); //获取闹钟是周几1~7
u8 i;
for (i = 1; i < 15; i++) {
if (tmp_mode & BIT(i)) {
if (i >= alarm_week) {
break;
}
}
}
alarm_calculate_next_few_time(pTime, i - alarm_week);
}
static u8 alarm_update_a_time_tab(struct sys_time *cTime, T_ALARM *pAlarm_tab, u32 *diff)
{
struct sys_time *pTime = &(pAlarm_tab->time);
u32 c_tmp = (ymd_to_day(cTime) << 17) | ((cTime->hour & 0x1f) << 12) | ((cTime->min & 0x3f) << 6) | (cTime->sec & 0x3f);
u32 p_tmp = (ymd_to_day(pTime) << 17) | ((pTime->hour & 0x1f) << 12) | ((pTime->min & 0x3f) << 6) | (pTime->sec & 0x3f);
if (c_tmp >= p_tmp) {
pTime->year = cTime->year;
pTime->month = cTime->month;
pTime->day = cTime->day;
alarm_calculate_next_few_time(pTime, 1);
alarm_calculate_time_by_week_mode(pTime, pAlarm_tab->mode);
p_tmp = (ymd_to_day(pTime) << 17) | ((pTime->hour & 0x1f) << 12) | ((pTime->min & 0x3f) << 6) | (pTime->sec & 0x3f);
*diff = p_tmp - c_tmp;
return 1;
} else if (pAlarm_tab->mode & 0xfe) {
alarm_calculate_time_by_week_mode(pTime, pAlarm_tab->mode);
p_tmp = (ymd_to_day(pTime) << 17) | ((pTime->hour & 0x1f) << 12) | ((pTime->min & 0x3f) << 6) | (pTime->sec & 0x3f);
*diff = p_tmp - c_tmp;
return 1;
}
*diff = p_tmp - c_tmp;
return 0;
}
static u8 alarm_update_all_time(void)
{
u8 err = 0;
u32 diff = 0;
u32 diff_min = -1;
u8 closest = -1;
struct sys_time current_time = {0};
rtc_ioctl(IOCTL_GET_SYS_TIME, (u32)&current_time);
for (u8 i = 0; i < M_MAX_ALARM_NUMS; i ++) {
if (alarm_tab[i].en) {
err = alarm_update_a_time_tab(&current_time, &alarm_tab[i], (u32 *)&diff);
if (err) { //时间有更新
err = alarm_vm_write_time_tab(&alarm_tab[i], i);
if (err) {
return 1;
}
}
if (diff < diff_min) {
diff_min = diff;
closest = i;
}
}
}
if (closest > M_MAX_ALARM_NUMS) {
set_alarm_ctrl(0);
}
if ((alarm_tab[closest].en)) { //最接近闹钟号跟记录的不一样,则要重设硬件寄存器,更新记录
rtc_ioctl(IOCTL_SET_ALARM, (u32)&alarm_tab[closest].time);
if (closest != alarm_mask.alarm_active_index) { //最接近闹钟号跟记录不一样更新VM
err = alarm_vm_write_mask(closest);
if (err) {
return 1;
}
}
}
return 0;
}
void alarm_init(const struct rtc_dev_platform_data *arg)
{
rtc_init(arg);
_user_isr_cbfun = arg->cbfun;
u8 err = alarm_vm_read_mask();
if (err) {
err = alarm_vm_write_mask(0xff);
if (err) {
alarm_printf("init : alarm mask read & write vm err!\n");
return;
}
}
for (u8 i = 0; i < M_MAX_ALARM_NUMS; i ++) {
memset(&(alarm_tab[i]), 0, sizeof(T_ALARM));
alarm_vm_read_time_tab(&(alarm_tab[i]), i); //读出数组
}
if (alarm_pnd_flag) { //防止初始化前,就已经起闹钟中断了
alarm_send_event(alarm_mask.alarm_active_index);
} else {
err = alarm_update_all_time(); //更新数组
if (err) {
alarm_printf("init : update alarm write vm err!\n");
return;
}
}
alarm_pnd_flag = 1;
rtc_ioctl(IOCTL_GET_SYS_TIME,  &rtc_read_test); //读时钟
alarm_printf("rtc_read_sys_time: %d-%d-%d %d:%d:%d\n",
rtc_read_test.year,
rtc_read_test.month,
rtc_read_test.day,
rtc_read_test.hour,
rtc_read_test.min,
rtc_read_test.sec);
rtc_ioctl(IOCTL_GET_ALARM, &alm_read_test); //读闹钟
alarm_printf("rtc_read_alarm: %d-%d-%d %d:%d:%d\n",
alm_read_test.year,                        
alm_read_test.month,
alm_read_test.day,
alm_read_test.hour,
alm_read_test.min,
alm_read_test.sec);
}
void alarm_rtc_stop(void)
{
set_alarm_ctrl(0);
}
void alarm_rtc_start(void)
{
set_alarm_ctrl(1);
}
u8 alarm_get_active_index(void)
{
return alarm_mask.alarm_active_index;
}
u8 alarm_get_en_info(void)
{
u8 en = 0;
for (u8 i = 0; i < M_MAX_ALARM_NUMS; i ++) {
en |= BIT(!!(alarm_tab[i].en));
}
return en;
}
void alarm_get_time_info(T_ALARM *p, u8 index)
{
memcpy((u8 *)p, (u8 *)&alarm_tab[index], sizeof(T_ALARM));
}
u8 alarm_add(T_ALARM *p, u8 index)
{
if (index > M_MAX_ALARM_INDEX) {
return 1;
}
if (p->mode > M_MAX_ALARM_MODE) {
return 1;
}
memcpy((u8 *)&alarm_tab[index], (u8 *)p, sizeof(T_ALARM));
u8 err = alarm_vm_write_time_tab(&alarm_tab[index], index);
if (err) {
return 1;
}
err = alarm_update_all_time(); //更新数组
if (err) {
return 1;
}
return 0;
}
u8 alarm_en(u8 index, u8 en)
{
if (index > M_MAX_ALARM_INDEX) {
return 1;
}
if ((!!en) == alarm_tab[index].en) {
return 0;
}
alarm_tab[index].en = !!en;
u8 err = alarm_vm_write_time_tab(&alarm_tab[index], index);
if (err) {
return 1;
}
err = alarm_update_all_time(); //更新数组
if (err) {
return 1;
}
return 0;
}
//设备事件响应demo
static void alarm_event_handler(struct sys_event *e)
{
u8 index;
u8 err;
if ((u32)e->arg == DEVICE_EVENT_FROM_ALM) {
if (e->u.dev.event == DEVICE_EVENT_IN) {
index = (u8)(e->u.dev.value);
if (alarm_tab[index].mode == E_ALARM_MODE_ONCE) {
err = alarm_en(index, 0);
} else {
err = alarm_update_all_time(); //更新数组
}
if (err) {
alarm_printf("isr : update alarm %d err!\n", index);
return;
}
if (_user_isr_cbfun) {
_user_isr_cbfun(index);
}
}
}
}
SYS_EVENT_HANDLER(SYS_DEVICE_EVENT, alarm_event_handler, 0);
void alarm_send_event(u8 index)
{
struct sys_event e;
e.type = SYS_DEVICE_EVENT;
e.arg = (void *)DEVICE_EVENT_FROM_ALM;
e.u.dev.event = DEVICE_EVENT_IN;
e.u.dev.value = index;
sys_event_notify(&e);
}
void alm_wakeup_isr(void)
{
if (alarm_pnd_flag) {
alarm_send_event(alarm_mask.alarm_active_index);
} else {
alarm_pnd_flag = 1;
}
}
void __attribute__((weak)) alarm_isr_user_cbfun(u8 index)
{
printf("**** alarm %d : hello world ****\n", index);
}
//参考的测试代码
void user_alarm_test(void)
{
T_ALARM tmp_alarm = {0};
rtc_ioctl(IOCTL_GET_SYS_TIME, (u32)&tmp_alarm.time);
tmp_alarm.en = 1; //初始化默认打开
#if 1
tmp_alarm.mode = E_ALARM_MODE_ONCE; //此闹钟只起作用一次
tmp_alarm.time.hour = 0;
tmp_alarm.time.min = 1;
alarm_add(&tmp_alarm, 0);
#endif
#if 1
tmp_alarm.mode = E_ALARM_MODE_EVERY_DAY; //此闹钟每天都起作用
tmp_alarm.time.hour = 0;
tmp_alarm.time.min = 2;
alarm_add(&tmp_alarm, 1);
#endif
#if 1
tmp_alarm.mode = E_ALARM_MODE_EVERY_MONDAY | E_ALARM_MODE_EVERY_WEDNESDAY | E_ALARM_MODE_EVERY_SATURDAY; //此闹钟周1周3周6起作用
tmp_alarm.time.hour = 0;
tmp_alarm.time.min = 3;
alarm_add(&tmp_alarm, 2);
#endif
}
#if TCFG_RTC_ALARM_ENABLE
//24小时内定时起来
void rtc_alarm_set_timer(u32 seconds)
{
alarm_printf("rtc_alarm_set_timer");
u8 add_hour = seconds / 3600;
u8 add_min = (seconds % 3600) / 60;
u8 add_sec = seconds % 60;
rtc_ioctl(IOCTL_GET_SYS_TIME,  &rtc_read_test); //读时钟
alarm_printf("rtc_read_sys_time: %d-%d-%d %d:%d:%d\n",
rtc_read_test.year,
rtc_read_test.month,
rtc_read_test.day,
rtc_read_test.hour,
rtc_read_test.min,
rtc_read_test.sec);
rtc_ioctl(IOCTL_GET_ALARM, &alm_read_test); //读闹钟
u16 tmp = rtc_read_test.sec + add_sec;
rtc_read_test.sec = tmp % 60;
tmp = rtc_read_test.min + add_min + tmp / 60;
rtc_read_test.min = tmp % 60;
tmp = rtc_read_test.hour + add_hour + tmp / 60;
rtc_read_test.hour = tmp % 24;
rtc_read_test.day += (tmp / 24);
T_ALARM tmp_alarm = {0};
tmp_alarm.en = 1; //初始化默认打开
tmp_alarm.mode = E_ALARM_MODE_ONCE; //此闹钟只起作用一次
memcpy(&tmp_alarm.time, &rtc_read_test, sizeof(struct sys_time));
alarm_add(&tmp_alarm, 0);
memset(&rtc_read_test, 0, sizeof(struct sys_time));
rtc_ioctl(IOCTL_GET_ALARM,  &alm_read_test); //读闹钟,校验是否写成功
alarm_printf("rtc_read_alarm: %d-%d-%d %d:%d:%d\n",
alm_read_test.year,                        
alm_read_test.month,
alm_read_test.day,
alm_read_test.hour,
alm_read_test.min,
alm_read_test.sec);
}
#endif
#endif