433 lines
12 KiB
C
433 lines
12 KiB
C
#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)¤t_time);
|
||
for (u8 i = 0; i < M_MAX_ALARM_NUMS; i ++) {
|
||
if (alarm_tab[i].en) {
|
||
err = alarm_update_a_time_tab(¤t_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
|
||
|