#include "mw_soft_watchdog.h" #include "list.h" #include "htime.h" #include "hthread.h" #include "hbase.h" #include "hlog.h" #include "hmutex.h" #include "hplatform.h" #define reboot_delay(miniutes) miniutes typedef struct { hsem_t sem; wd_item_s *p_items; uint16_t item_cnt; soft_watchdog_item_fail fail_cb; }sf_wtd_s; static sf_wtd_s *s_wtd; void soft_watchdog_stop(uint32_t item) { if(s_wtd->p_items[item].start_ms != IGNORE) { hlogi("%s item %d IGNORE", __func__, item); s_wtd->p_items[item].start_ms = IGNORE; } } void soft_watchdog_start(uint32_t item) { if( s_wtd->p_items[item].start_ms > 0 ) { /* already starting */ } else { s_wtd->p_items[item].start_ms = gettimeofday_ms(); hsem_post(&s_wtd->sem); hlogi("%s %u start_ms %lld", __func__, item, s_wtd->p_items[item].start_ms); } } void soft_watchdog_timeout(uint32_t item, uint32_t timeout_ms){ s_wtd->p_items[item].start_ms = gettimeofday_ms(); s_wtd->p_items[item].timeout_ms = timeout_ms; hsem_post(&s_wtd->sem); } //something happen, delay the watchdog some time void soft_watchdog_timeout_all(uint32_t timeout_ms){ for(uint32_t i = 0; i < s_wtd->item_cnt; i++){ wd_item_s * item = &s_wtd->p_items[i]; if (item->timeout_ms >= 0) { item->timeout_ms += timeout_ms; } } hlogi("wd_delay_all timeout_ms = %d", timeout_ms); } HTHREAD_ROUTINE(soft_wtd_thread_entry) { hlogd("%s", __func__); hsem_wait(&s_wtd->sem); for(;;) { uint64_t now_ms = gettimeofday_ms(); uint64_t expire_ms = (uint64_t)(-1); int32_t expire_item = -1; for(uint32_t i = 0; i < s_wtd->item_cnt; i++){ wd_item_s * item = &s_wtd->p_items[i]; uint64_t item_expire_ms; //hlogd("%d start_ms %d timeout_ms %d now_ms %d",i , item->start_ms, item->timeout_ms, now_ms); if (item->start_ms == IGNORE) { continue; } item_expire_ms = item->start_ms + item->timeout_ms; if( now_ms > item_expire_ms ){ hlogd("%d now_ms %llu, timeout_ms %llu timeout-now_ms:%llu", i, now_ms, item_expire_ms, item_expire_ms-now_ms); s_wtd->fail_cb(i); } /* 最近的时间 */ if ( item_expire_ms < expire_ms ) { expire_ms = item_expire_ms; expire_item = i; } } now_ms = gettimeofday_ms(); hlogd("%d now_ms %llu, timeout_ms %llu timeout-now_ms:%llu", expire_item, now_ms, expire_ms, expire_ms-now_ms); hsem_wait_for(&s_wtd->sem, expire_ms - now_ms + 1);/* '1' 避免, hsem_wait_for(sem, 0) 又快速循环 */ } return NULL; } void soft_watchdog_init(wd_item_s *items, uint32_t item_cnt, soft_watchdog_item_fail fail_cb) { if (!s_wtd){ s_wtd = (sf_wtd_s*)hv_malloc(sizeof(sf_wtd_s)); hsem_init(&s_wtd->sem, 0); s_wtd->p_items = items; s_wtd->item_cnt = item_cnt; s_wtd->fail_cb = fail_cb; hthread_create(soft_wtd_thread_entry, NULL); } } /*******************soft_watchdog_test**********************/ typedef enum{ WD_None = -1, WD_Sensor_Init = 0, /* Sensor 初始化 */ WD_Wifi_Init, /* WIFI 初始化 */ WD_Wifi_Associated, /* WIFI 连接 */ WD_Wifi_DHCP_IP, /* WIFI 获取IP */ WD_Connect_Server, /* 连接服务器 */ WD_AP_Wait_Client, /* AP模式 连接 */ WD_Suspend, /* 休眠过程 */ WD_Max }swd_e; typedef struct { swd_e last_fail_idx; uint8_t last_fail_cnt; }swd_last_s; static wd_item_s wditem_policy[] = { //WD_Sensor_Init, should call wd_set_ok in 3 seconds after system bootup [WD_Sensor_Init] = { IGNORE, 10*1000, { REBOOT, REBOOT, REBOOT, reboot_delay(2), reboot_delay(10), SHUTDOWN} }, //WD_Wifi_Init, should init done in 3 seconds after system bootup [WD_Wifi_Init] = { IGNORE, 10*1000, { REBOOT, REBOOT, reboot_delay(1), reboot_delay(2), reboot_delay(3), SHUTDOWN} }, //WD_Wifi_Associated, should Associate done in 13 seconds after system bootup [WD_Wifi_Associated] = { IGNORE, 60*1000, { REBOOT, reboot_delay(3), reboot_delay(10), reboot_delay(10), reboot_delay(30), reboot_delay(60)} }, //WD_Wifi_DHCP_IP, after enabled should be IGNORE to connect 30 seconds, try 2 times [WD_Wifi_DHCP_IP] = { IGNORE, 30*1000, { REBOOT, reboot_delay(2), reboot_delay(5), reboot_delay(10), reboot_delay(30), reboot_delay(60)} }, //WD_Connect_Server, after enabled, 60 seconds should be IGNORE, try 2 times. [WD_Connect_Server] = { IGNORE, 60*1000, { REBOOT, reboot_delay(3), reboot_delay(10), reboot_delay(10), reboot_delay(30), reboot_delay(30)} }, //WD_AP_Wait_Client, AP mode, wait client connect, 3minutes timeout_ms, just SUSPEND [WD_AP_Wait_Client] = { IGNORE, 180*1000, { SUSPEND, SUSPEND, SUSPEND, SUSPEND, SUSPEND, SUSPEND} }, //WD_Suspend [WD_Suspend] = { IGNORE, 60*1000, { REBOOT, REBOOT, REBOOT, REBOOT, REBOOT, REBOOT} } }; static const char* get_item_name(swd_e item) { switch (item) { case WD_Sensor_Init : return NAME(WD_Sensor_Init); case WD_Wifi_Init : return NAME(WD_Wifi_Init); case WD_Wifi_Associated : return NAME(WD_Wifi_Associated); case WD_Wifi_DHCP_IP : return NAME(WD_Wifi_DHCP_IP); case WD_Connect_Server : return NAME(WD_Connect_Server); case WD_AP_Wait_Client : return NAME(WD_AP_Wait_Client); case WD_Suspend : return NAME(WD_Suspend); case WD_None: return NAME(WD_None); case WD_Max: return NAME(WD_Max); } return "None"; } static swd_last_s swd_last; static void soft_watchdog_fail_cb(uint32_t fail_idx){ /* 这段主要是要执行对应的action */ if(swd_last.last_fail_idx == fail_idx) { swd_last.last_fail_cnt++; }else { swd_last.last_fail_cnt = 1; } if (swd_last.last_fail_cnt >= WD_POLICY_NUMBER) { swd_last.last_fail_cnt = WD_POLICY_NUMBER; } uint32_t action = wditem_policy[swd_last.last_fail_idx].action[swd_last.last_fail_cnt - 1]; uint8_t failed_info = ((swd_last.last_fail_cnt & 0xF) << 4) | (swd_last.last_fail_idx & 0xF); /* save failed_info, 比如保存到mcu去 */ hlogw("%s last_fail_idx : %d last_fail_cnt : %u", __func__, swd_last.last_fail_idx, swd_last.last_fail_cnt); } void soft_watchdog_test() { /* uint8_t failed_info = read 如从mcu读取 */ soft_watchdog_init(wditem_policy, ARRAY_SIZE(wditem_policy), soft_watchdog_fail_cb); soft_watchdog_timeout(WD_Wifi_Associated, 5000); }