194 lines
6.7 KiB
C
194 lines
6.7 KiB
C
|
#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);
|
||
|
}
|
||
|
|