/* * Copyright (c) 2006-2021, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2023-06-19 murmur the first version */ /* ** 程序清单:这是一个 RTC 设备使用例程 ** 例程导出了 alarm_sample 命令到控制终端 ** 命令调用格式:alarm_sample ** 程序功能:设置RTC时间,创建闹钟,模式:每秒触发,启动闹钟 **/ #include #include #define LOG_TAG "alarm" #define LOG_LVL LOG_LVL_DBG #include //#define BOOT_PER_HOUR void user_alarm_callback(rt_alarm_t alarm, time_t timestamp) { rt_kprintf("user alarm callback function.\n"); } void alarm_sample(int argc, char *argv[]) { // rt_device_t dev = rt_device_find("rtc"); struct rt_alarm_setup setup; struct rt_alarm * alarm = RT_NULL; static time_t now; struct tm p_tm; if (alarm != RT_NULL) return; /* 获取当前时间戳,并把下一秒时间设置为闹钟时间 */ now = time(NULL) + 10; gmtime_r(&now,&p_tm); setup.flag = RT_ALARM_DAILY; setup.wktime.tm_year = p_tm.tm_year; setup.wktime.tm_mon = p_tm.tm_mon; setup.wktime.tm_mday = p_tm.tm_mday; setup.wktime.tm_wday = p_tm.tm_wday; setup.wktime.tm_hour = atoi(argv[1]);//p_tm.tm_hour; setup.wktime.tm_min = 0;//p_tm.tm_min; setup.wktime.tm_sec = 0;//p_tm.tm_sec; alarm = rt_alarm_create(user_alarm_callback, &setup); if(RT_NULL != alarm) { rt_alarm_start(alarm); LOG_D("alarm started."); } } /* export msh cmd */ MSH_CMD_EXPORT(alarm_sample,alarm sample); /** * 开窗回调 * @param alarm * @param timestamp */ void poTT_callback(rt_alarm_t alarm, time_t timestamp) { LOG_I("power UP TT by RTC."); // timerIsReady(); setWindowMode(); initTT(); } /** * 关窗回调 * @param alarm * @param timestamp */ void pdTT_callback(rt_alarm_t alarm, time_t timestamp) { LOG_I("power DOWN TT by RTC."); clearWindowMode(); deInitTT(); //预置开窗会更新多次尝试逻辑,未激活时会始终尝试 } /** * 每小时开窗回调 * @param alarm * @param timestamp */ void poTT2_callback(rt_alarm_t alarm, time_t timestamp) { // LOG_I("power UP TT by INTERVAL RTC"); // timerIsReady(); // initTT(); } static uint8_t rstCnt=0; /** * 定时更新debug文件名 * @param alarm * @param timestamp */ void updatelog_callback(rt_alarm_t alarm, time_t timestamp) { //idle且TT未开启状态下主动重启 if (++rstCnt >= 2)//每N小时一检 { rstCnt = 0; if (isIdle()) { rt_hw_cpu_reset(); //reboot } } else { updateDebuglogName(); } } void addDefaultAlarm() { struct rt_alarm_setup setup; struct rt_alarm * alarm = RT_NULL; static time_t now; struct tm p_tm; /* 获取当前时间戳,并把下一秒时间设置为闹钟时间 */ now = time(NULL); gmtime_r(&now, &p_tm); setup.flag = RT_ALARM_HOUR;//小时重复 setup.wktime.tm_year = p_tm.tm_year; setup.wktime.tm_mon = p_tm.tm_mon; setup.wktime.tm_mday = p_tm.tm_mday; setup.wktime.tm_wday = p_tm.tm_wday; setup.wktime.tm_hour = 0; //整点 setup.wktime.tm_min = 0; //p_tm.tm_min; setup.wktime.tm_sec = 1; //p_tm.tm_sec; if (RT_NULL != alarm) { rt_alarm_delete(alarm); // } alarm = rt_alarm_create(updatelog_callback, &setup); if (alarm != RT_NULL) { rt_alarm_start(alarm); // LOG_D("alarm %d(%02d:%02d) started.",var+1,alarm[var]->wktime.tm_hour+8,alarm[var]->wktime.tm_min); } else { LOG_E("Failed to start alarm."); } } #define BOOT_PER_HOUR #ifdef BOOT_PER_HOUR INIT_APP_EXPORT(addDefaultAlarm); #endif extern struct rt_alarm_container _container; static rt_alarm_t a[50]; static size_t cnt = 0; #ifdef BOOT_PER_HOUR static size_t indexBegin=1; #else static size_t indexBegin=0; #endif /** *获取所有RTC闹钟,不含预置闹钟 */ void getAllAlarm() { rt_list_t *next; rt_alarm_t alarm; cnt = 0; for (next = _container.head.next; next != &_container.head; next = next->next) { alarm = rt_list_entry(next, struct rt_alarm, list); a[cnt++] = alarm; } } /** * 清空所有RTC闹钟 */ void clearAlarm(void) { getAllAlarm(); for (size_t i = 0; i < cnt-indexBegin; ++i) { rt_alarm_delete(a[i]); } } /** * 关闭rtc闹钟, */ void stopAlarm() { getAllAlarm(); for (size_t i = 0; i < cnt-indexBegin; ++i) { rt_alarm_stop(a[i]); } } /** * 恢复rtc闹钟, */ void startAlarm() { getAllAlarm(); for (size_t i = 0; i < cnt-indexBegin; ++i) { rt_alarm_start(a[i]); } } void addAlarm(uint8_t *din, rt_alarm_callback_t callback) { struct rt_alarm_setup setup; struct rt_alarm * alarm = RT_NULL; static time_t now; struct tm p_tm; if (alarm != RT_NULL) return; /* 获取当前时间戳,并把下一秒时间设置为闹钟时间 */ now = time(NULL) + 10; gmtime_r(&now, &p_tm); setup.flag = RT_ALARM_DAILY; setup.wktime.tm_year = p_tm.tm_year; setup.wktime.tm_mon = p_tm.tm_mon; setup.wktime.tm_mday = p_tm.tm_mday; setup.wktime.tm_wday = p_tm.tm_wday; setup.wktime.tm_hour = din[0]; //p_tm.tm_hour; setup.wktime.tm_min = din[1]; //p_tm.tm_min; setup.wktime.tm_sec = 0; //p_tm.tm_sec; alarm = rt_alarm_create(callback, &setup); if (RT_NULL != alarm) { // rt_alarm_start(alarm);//默认不启动 // LOG_D("alarm started."); } else { LOG_E("Failed to start alarm."); } } /** * 更新rtc闹钟 * @param t 每个rtc时刻组成的数组,依次对应开窗时段的开始和结束 */ void updateAlarm(uint8_t *t, size_t len) { clearAlarm(); for (int var = 0; var < len; var+=4) { addAlarm(t+var, poTT_callback); addAlarm(t+var+2, pdTT_callback); } } static int isInAlarm(rt_alarm_t stop, rt_alarm_t start) { struct tm alBegin = start->wktime; alBegin.tm_hour += 8; time_t tBegin = mktime(&alBegin); struct tm alEnd = stop->wktime; alEnd.tm_hour += 8; time_t tEnd = mktime(&alEnd); time_t now = time(RT_NULL); int rst = (now >= tBegin) && (now <= tEnd); return rst; } /** * check if in the WINs zone * @return 1-in,0-not in */ int isInWindowZone() { getAllAlarm(); int rst = 0; for (size_t i = 0; i < cnt-indexBegin; i+=2) { if(isInAlarm(a[i], a[i+1])) { LOG_I("is in window zone."); rst = 1; break; } } return rst; } MSH_CMD_EXPORT(clearAlarm,clear all alarms); MSH_CMD_EXPORT(stopAlarm,stop); MSH_CMD_EXPORT(startAlarm,start); MSH_CMD_EXPORT(isInWindowZone,isInWindow); //MSH_CMD_EXPORT(getCurrentTime,getCurrentTime);