fusion/mw/soft_watchdog/mw_soft_watchdog.c

194 lines
6.7 KiB
C
Raw Normal View History

2025-08-05 07:53:44 +00:00
#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);
}