📄 c06b_wdog.c
字号:
/******************************************************************
*
* tran_control.c - 使用看门狗定时器监视两个任务之间的消息交互流程.
*
* Copy writes Oct, 2003
*
*/
/* 头文件*/
#include "vxworks.h"
#include "logLib.h"
#include "taskLib.h"
#include "wdLib.h"
#include "msgQLib.h"
#include "sigLib.h"
#include "stdio.h"
/* 宏定义*/
#define SENDER_TASK_PRIORITY 100 /* 接受任务优先级 */
#define RECVER_TASK_PRIORITY 100 /* 发送任务优先级 */
#define TASK_STACK_SIZE 0x1000 /* 任务堆栈去大小 */
#define TIME_TO_DELAY 100 /* 任务时延 */
#define SENDER_SIG SIGRTMIN + 1 /* 与发送方task绑定的信号 */
#define RECVER_SIG SIGRTMIN + 2 /* 与接收方task绑定的信号 */
#define SEND_STR "REQ" /* 发送的消息 */
#define REPLY_STR "ACK" /* 应答的消息 */
#define RESEND_INTV 100 /* 重发消息的间隔 */
#define IDLE_INTV 300 /* 接收方空闲时间 */
#define NO_PARAMETER 0 /* 启动看门狗定时器参数 */
#define NO_OPTION 0 /* 绑定信号处理程序的选项 */
#define MSG_MAX_QUEUE_NUM 10 /* 消息队列中消息的最大个数 */
#define MSG_MAX_LEN 3 /* 消息接收区消息的最大长度 */
/* 全局变量 */
LOCAL int SendTask_ID = ERROR; /* 发送消息的task ID */
LOCAL int RecvTask_ID = ERROR; /* 接收消息的task ID */
LOCAL WDOG_ID ReSender_Wdog = NULL; /* 重发看门狗定时器的ID */
LOCAL WDOG_ID Idle_Wdog = NULL; /* 空闲看门狗定时器的ID */
LOCAL MSG_Q_ID SendMsgQ; /* 发送task的消息队列ID */
LOCAL MSG_Q_ID RecvMsgQ; /* 接收task的消息队列ID */
LOCAL UINT8 Send_Sequence = 0; /* 标记是否已经重发过 */
/* 绑定到信号SENDER_SIG的处理句柄 */
LOCAL struct sigvec newSigHandler_Sender;
/* 记录原来绑定到信号SENDER_SIG的处理句柄 */
LOCAL struct sigvec oldSigHandler_Sender;
/* 绑定到信号RECVER_SIG的处理句柄 */
LOCAL struct sigvec newSigHandler_Recver;
/* 记录原来绑定到信号RECVER_SIG的处理句柄 */
LOCAL struct sigvec oldSigHandler_Recver;
/* 函数说明 */
/* 重发定时器超时后的ISR */
void Resender_Wdog_Timeout_Handler(void);
/* 空闲定时器超时后的ISR */
void Idle_Wdog_Timeout_Handler(void);
/* 接收task收到信号SENDER_SIG后的信号服务程序 */
void Send_Sig_Handler(int sigNum);
/* 发送task收到信号RECVER_SIG后的信号服务程序 */
void Recv_Sig_Handler(int sigNum);
/*******************************************************************
* Sender_Task - 发送消息的task.
* 操作步骤如下:
* 1.初始化阶段,首先创建重发看门狗定时器
* 2.绑定SENDER_SIG的信号服务程序
* 3.进入循环体开始每隔TIME_TO_DELAY发送一个消息,并且等待接收ACK
* 4.在接收到ACK后,停止看门狗定时器的计时,并开始下一轮的消息发送
* 5.如果在指定的时间内没有收到ACK,则会收到信号SENDER_SIG,从而执行
* 指定的信号处理程序.
*/
LOCAL void Sender_Task(void)
{
char RecvBuffer[MSG_MAX_LEN];
/* 创建重发看门狗定时器,并且输出ID信息 */
if ((ReSender_Wdog = wdCreate()) == NULL)
{
printf("\n[SEND] Create Watchdog Timer Fail!");
return;
}
printf("\n[SEND]ReSender_Wdog ID = %x",(int)ReSender_Wdog);
/* 绑定信号处理程序 */
if (sigvec(SENDER_SIG, &newSigHandler_Sender,
&oldSigHandler_Sender) == ERROR)
{
printf("\n[SEND] Bind Signal Service Routine Fail!");
wdDelete(ReSender_Wdog);
return;
}
/* 周期性发送消息并等待ACK */
FOREVER
{
taskDelay(TIME_TO_DELAY);
if (msgQSend(RecvMsgQ, SEND_STR, (int)strlen(SEND_STR),
NO_WAIT, MSG_PRI_NORMAL) == ERROR)
{
printf("\n[SEND] Send Msg Fail!");
wdDelete(ReSender_Wdog);
return;
}
if (wdStart(ReSender_Wdog, RESEND_INTV,
(FUNCPTR)Resender_Wdog_Timeout_Handler, NO_PARAMETER)
== ERROR)
{
printf("\n[SEND] Start Watchdog Timer Fail!");
wdDelete(ReSender_Wdog);
return;
};
if (msgQReceive(SendMsgQ, (char*)&RecvBuffer, MSG_MAX_LEN,
WAIT_FOREVER) == ERROR)
{
printf("\n[SEND] Receive Msg Fail!");
wdDelete(ReSender_Wdog);
return;
};
printf("\n[Send] REQ");
wdCancel(ReSender_Wdog);
Send_Sequence = 0;
}
}
/******************************************************************
* Recver_Task - 接收消息的task.
* 操作步骤如下:
* 1.初始化阶段,首先创建空闲看门狗定时器
* 2.绑定RECVER_SIG的信号服务程序
* 3.进入循环体开始启动定时器,并且等待接收REQ
* 4.在接收到REQ后,停止看门狗定时器的计时,并开始下一轮的等待
* 5.如果在定义的时长之内,没有收到任何消息,那么就会收到信号RECVER_SIG
* 从而执行指定的信号处理程序。
*/
LOCAL void Recver_Task(void)
{
char RecvBuffer[MSG_MAX_LEN];
if ((Idle_Wdog = wdCreate()) == NULL)
{
printf("\n[RECV] Create Watchdog Timer Fail!");
return;
}
printf("\n[RECV]Idle_Wdog ID = %x",(int)Idle_Wdog);
if (sigvec(RECVER_SIG, &newSigHandler_Recver,
&oldSigHandler_Recver) == ERROR)
{
printf("\n[RECV] Bind Signal Service Routine Fail!");
wdDelete(Idle_Wdog);
return;
}
FOREVER
{
if (wdStart(Idle_Wdog, IDLE_INTV,
(FUNCPTR)Idle_Wdog_Timeout_Handler, NO_PARAMETER)
== ERROR)
{
printf("\n[RECV] Start Watchdog Timer Fail!");
wdDelete(Idle_Wdog);
return;
};
if (msgQReceive(RecvMsgQ, (char*)&RecvBuffer, MSG_MAX_LEN,
WAIT_FOREVER) == ERROR)
{
printf("\n[RECV] Receive Msg Fail!");
wdDelete(Idle_Wdog);
return;
};
printf("\n[RECV] ACK");
if (msgQSend(SendMsgQ, REPLY_STR, (int)strlen(REPLY_STR),
NO_WAIT, MSG_PRI_NORMAL) == ERROR)
{
printf("\n[RECV] Send Msg Fail!");
wdDelete(ReSender_Wdog);
return;
}
wdCancel(Idle_Wdog);
}
}
/******************************************************************
* Resender_Wdog_Timeout_Handler - 重发看门狗定时器超时中断的处理程序
*/
void Resender_Wdog_Timeout_Handler(void)
{
/* 发送信号SENDER_SIG */
if (kill(SendTask_ID, SENDER_SIG) == ERROR)
{
logMsg("\n[Resender] Send Signal Fail!", 0, 0, 0, 0, 0, 0);
}
else
{
logMsg("\n[Resender] Send Signal!", 0, 0, 0, 0, 0, 0);
}
return;
}
/******************************************************************
* Idle_Wdog_Timeout_Handler - 空闲计时看门狗定时器超时中断的处理程序
*/
void Idle_Wdog_Timeout_Handler(void)
{
/* 发送信号给接收task,并输出信息 */
if (kill(RecvTask_ID, RECVER_SIG) == ERROR)
{
logMsg("\n[Idle] Send Signal Fail!", 0, 0, 0, 0, 0, 0);
}
else
{
logMsg("\n[Idle] Send Signal!", 0, 0, 0, 0, 0, 0);
}
return;
}
/******************************************************************
* Send_Sig_Handler - 发送task绑定的信号处理程序.
* 步骤如下:
* 1.判断是否已经重发过.
* 2.如果没有重发,则重发REQ,并且再次启动重发定时器
* 3.否则,输出信息好将当前的task置为挂起态.
*/
void Send_Sig_Handler(int sigNum)
{
if (Send_Sequence == 0)
{
Send_Sequence = 1;
if (msgQSend(RecvMsgQ, SEND_STR, (int)strlen(SEND_STR),
NO_WAIT, MSG_PRI_NORMAL) == ERROR)
{
printf("\n[SIGNAL_SEND] Send Msg Fail!");
return;
}
if (wdStart(ReSender_Wdog, RESEND_INTV,
(FUNCPTR)Resender_Wdog_Timeout_Handler, NO_PARAMETER)
== ERROR)
{
printf("\n[SIGNAL_SEND] Start Watchdog Timer Fail!");
return;
};
printf("\n[SIGNAL_SEND] Resend!");
}
else
{
Send_Sequence = 0;
printf("\n[SIGNAL_SEND] NO ACK! Suspend!");
taskSuspend(SendTask_ID);
}
return;
}
/******************************************************************
* Recv_Sig_Handler - 接收task绑定的信号处理程序.
* 步骤如下:
* 1.由于空闲时间过长,将接收task挂起
*/
void Recv_Sig_Handler(int sigNum)
{
printf("\n[SIGNAL_RECV] NO Message! Suspend!");
taskSuspend(RecvTask_ID);
return;
}
/******************************************************************
* WatchdogRoot - 根task,创建各个task,并初始化必备的设施:
* 步骤如下:
* 1.创建发送和接收task
* 2.创建发送和接收task的消息队列
* 3.配置两个信号的处理句柄
*/
void WatchdogRoot(void)
{
if ((SendTask_ID = taskSpawn("tSendtask", SENDER_TASK_PRIORITY,
VX_NO_STACK_FILL, TASK_STACK_SIZE,
(FUNCPTR)Sender_Task, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)) == ERROR)
{
printf("\n[ROOT]Task Spawn Fail!");
return;
}
if ((RecvTask_ID = taskSpawn("tRecvtask", RECVER_TASK_PRIORITY,
VX_NO_STACK_FILL, TASK_STACK_SIZE,
(FUNCPTR)Recver_Task, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)) == ERROR)
{
printf("\n[ROOT]Task Spawn Fail!");
taskDelete(SendTask_ID);
return;
}
if ((SendMsgQ = msgQCreate(MSG_MAX_QUEUE_NUM, MSG_MAX_LEN,
MSG_Q_FIFO)) == NULL)
{
printf("\n[ROOT]Msg Queue Create Fail!");
taskDelete(SendTask_ID);
taskDelete(RecvTask_ID);
return;
}
if ((RecvMsgQ = msgQCreate(MSG_MAX_QUEUE_NUM, MSG_MAX_LEN,
MSG_Q_FIFO)) == NULL)
{
printf("\n[ROOT]Msg Queue Create Fail!");
msgQDelete(SendMsgQ);
taskDelete(SendTask_ID);
taskDelete(RecvTask_ID);
return;
}
newSigHandler_Sender.sv_handler = Send_Sig_Handler;
newSigHandler_Sender.sv_mask = SIGUSR2;
newSigHandler_Sender.sv_flags = NO_OPTION;
newSigHandler_Recver.sv_handler = Recv_Sig_Handler;
newSigHandler_Recver.sv_mask = SIGUSR2;
newSigHandler_Recver.sv_flags = NO_OPTION;
}
/******************************************************************
* TaskController - 依据参数的不同分别挂起发送或是发送task,从而触发看门狗
* 定时器超时,进而执行响应的信号处理程序:
* 步骤如下:
* 1.判断两个task是否已经被创建
* 2.依据taskNum挂起响应的task
*/
void TaskController(UINT8 taskNum)
{
if ((SendTask_ID == ERROR) || (RecvTask_ID == ERROR))
{
printf("\n[CONTROLLER] Task Not Exist");
return;
}
switch (taskNum)
{
case 0:
taskSuspend(SendTask_ID);
break;
case 1:
taskSuspend(RecvTask_ID);
break;
default :
break;
}
return;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -