#include "daemon.h"
static uint32_t daemon_wd_flag_get(struct daemon_object *daemon);
static void daemon_watchdog_init(struct daemon_object *daemon);
static void daemon_wd_feed(struct daemon_object *daemon);
static struct daemon_register_thread* daemon_find_thread(struct daemon_object *daemon, uint8_t index);
static inline uint32_t daemon_wd_flag_clear(struct daemon_object *daemon);
void daemon_thread_entry(void * param){
uint32_t threadFlag = 0;
struct daemon_object *daemon = (struct daemon_object *)param;
uint32_t time = daemon->wdtTimeout*1000;;
while(1){
threadFlag = daemon_wd_flag_get(daemon);
if(threadFlag !=0){
rt_err_t err = rt_event_recv(&daemon->event, threadFlag,
RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR,
time, RT_NULL);
if (err == RT_EOK){
daemon_wd_flag_clear(daemon);
LOG_D("All threads are running, feed the watch dog");
daemon_wd_feed(daemon);
rt_thread_mdelay(1000);
}else if(err == -RT_ETIMEOUT){
daemon->threadFlag = ~daemon->threadFlag;
for(uint8_t i=0; i < daemon->daemonNum; i++){
if(daemon->threadFlag & 0x01){
struct daemon_register_thread* temp = daemon_find_thread(daemon, i);
if(temp != RT_NULL)
LOG_E("Thread [%s] is not running", temp->thread->name);
}
daemon->threadFlag >>=1;
}
daemon_wd_flag_clear(daemon);
LOG_E("Wait watch dog reset the mcu");
while(1){
rt_thread_mdelay(1000);
}
}else{
LOG_E("Event recv err:%d", err);
rt_thread_mdelay(100);
}
}else{
LOG_D("No thread register..");
daemon_wd_feed(daemon);
rt_thread_mdelay(1000);
}
}
}
static uint32_t daemon_wd_flag_get(struct daemon_object *daemon){
uint32_t flag = 0;
for(uint8_t i=0; idaemonNum; i++){
flag <<= 1;
flag |= 0x01;
}
return flag;
}
static inline uint32_t daemon_wd_flag_clear(struct daemon_object *daemon){
daemon->threadFlag = 0;
}
APP_ErrType daemon_init(struct daemon_object *daemon, const char *wd_device_name, uint32_t timeout){
APP_ErrType err = APP_OK;
rt_err_t result;
rt_slist_init(&daemon->threadHead);
daemon->daemonNum = 0;
daemon->threadFlag = 0;
daemon->iwgDevice = rt_device_find(wd_device_name);
if(daemon->iwgDevice == RT_NULL){
LOG_D("Cant find watch dog device");
return APP_ERR;
}
daemon->wdtTimeout = timeout;
daemon_watchdog_init(daemon);
result = rt_event_init(&daemon->event, "wd_event", RT_IPC_FLAG_FIFO);
if (result != RT_EOK){
err = APP_ERR;
goto errend;
}
daemon->daemonThread = rt_thread_create("daemon", daemon_thread_entry, daemon, 1024, 3, 40);
if(daemon->daemonThread == RT_NULL)
err = APP_OUT_OF_MEM;
rt_thread_startup(daemon->daemonThread);
errend:
return err;
}
uint32_t daemon_thread_register(struct daemon_object *daemon, rt_thread_t tid){
uint32_t flag = 0;
if(daemon->daemonNum < 32){
struct daemon_register_thread *temp = rt_malloc(sizeof(struct daemon_register_thread));
if(temp != RT_NULL){
daemon->daemonNum ++;
temp->thread = tid;
rt_slist_append(&daemon->threadHead, &temp->list);
flag = (1
}
}
return flag;
}
void daemon_fd_wd(struct daemon_object *daemon, uint32_t flag){
rt_event_send(&daemon->event, flag);
daemon->threadFlag |= flag;
}
static struct daemon_register_thread* daemon_find_thread(struct daemon_object *daemon, uint8_t index){
struct daemon_register_thread* thread = RT_NULL;
rt_slist_t *temp_list;
if(index < daemon->daemonNum){
temp_list = rt_slist_next(&daemon->threadHead);
for(uint8_t i=0; i < index; i++){
if(temp_list != RT_NULL)
temp_list = rt_slist_next(temp_list);
else
break;
}
if(temp_list != RT_NULL)
thread = rt_slist_entry(temp_list, struct daemon_register_thread, list);
}
return thread;
}
static void daemon_watchdog_init(struct daemon_object *daemon){
rt_device_t iwgDevice;
iwgDevice = daemon->iwgDevice;
rt_err_t ret = rt_device_init(iwgDevice);
if (ret != RT_EOK){
LOG_E("Init wdt failed!\n");
return;
}
ret = rt_device_control(iwgDevice, RT_DEVICE_CTRL_WDT_SET_TIMEOUT, &daemon->wdtTimeout + 3);
if (ret != RT_EOK){
LOG_E("Set wdt timeout failed!\n");
return;
}
ret = rt_device_control(iwgDevice, RT_DEVICE_CTRL_WDT_START, RT_NULL);
if (ret != RT_EOK){
LOG_E("start wdt failed!\n");
return;
}
}
static void daemon_wd_feed(struct daemon_object *daemon){
rt_device_control(daemon->iwgDevice, RT_DEVICE_CTRL_WDT_KEEPALIVE, NULL);
}