监控任务设计
文章目錄
- 1 監控任務設計
- 1.1 概述
- 1.2 代碼實現
1 監控任務設計
1.1 概述
監控任務用于監控CPU利用率、管腳狀態,然后在串口中報告狀態。示例較簡單,也可以做得更為復雜些。系統結構圖如下:
監控任務設計:
雖然監控任務基本上也是周期性去檢查各個狀態;但是系統中沒有使用軟定時器去周期檢查。因為除周期性檢查狀態外,還需要做一些其它工作,在定時函數中完成并不方便。如果再考慮以后想在監控任務中做一些其它耗時操作,如果這些也放在定時器中去做,則會影響到系統中其它定時器。
監控任務的主要工作是等待郵箱中的消息。一旦等不到超時,則認為需要檢查狀態。不過,這種方式有個缺點:比如5s監控,在4.9秒后收到郵箱消息時,則會重新等待延時。
命令鏈表:
我們將所有的命令用一個復雜的聯合體來保存,當然你也可以分開寫成多個結構體。所有命令塊的分配與釋放通過存儲塊來管理。
具體監控任務通過命令鏈表來配置。該鏈表中的插入和刪除操作完全由監控任務自己來負責,而不是允許命令解釋器任務直接操作,這樣就避免了兩個任務同時讀寫監控列表問題的情況出現,這樣就不必添加任務資源保護處理。此外,通過郵箱來發送請求,命令解釋器任務可以在發送請求后立即做自己的工作。監控任務可以在有空閑時再對該命令進行處理。整體效率更高。
1.2 代碼實現
cli.c:
/*** @brief 命令解釋器設計* @details* @author 01課堂 李述銅 http://01ketang.cc* @date 2017-06-01* @version 1.0* @copyright 版權所有,禁止用于商業用途*/ #include <string.h> #include <stdlib.h> #include "tinyOS.h" #include "cli.h" #include "uart.h" #include "extio.h" #include "WaveGen.h" #include "monitor.h"#define TERMINAL_BS 0x08 #define TERMINAL_SPACE ' ' #define TERMINAL_CR '\r' #define TERMINAL_LF '\n' #define TERMINAL_TAB '\t'// 空白字符 static const char spaceCh[] = {TERMINAL_SPACE, TERMINAL_CR, TERMINAL_LF, TERMINAL_TAB, '\0'}; static const char * unknownPinMsg = "Unknown Pin\r\n"; static const char * unknownCmdMsg = "Unknown Command!\r\n"; static const char * noEnoughParamMsg = "No Enough Param!\r\n";// 任務相關 static tTaskStack cliTaskEnv[CLI_TASK_ENV_SIZE]; // 任務1的堆棧空間 static tTask cliTask;// 命令行提示緩沖區 static char promoteBuffer[CLI_CMD_PROMATE_SIZE];/*** 顯示消息*/ static void showMsg (const char * msg) {UartWrite(msg, strlen(msg)); }/*** 輸出顯示字符* @param ch*/ static void showCh (const char ch) {UartWrite(&ch, 1); }/*** 顯示提示符*/ static void showPromote (void) {UartWrite(promoteBuffer, strlen(promoteBuffer)); }/*** 更改提示符*/ static void setPromote (const char * newPromote) {strncpy(promoteBuffer, newPromote, sizeof(promoteBuffer));promoteBuffer[sizeof(promoteBuffer) - 1] = '\0'; }/*** 提示符修改命令*/ static void promoteCmd (void) {char * promote = strtok(NULL, spaceCh);if (promote == NULL) {showMsg(noEnoughParamMsg);return;}setPromote(promote); }/*** 將引腳名轉換為內部序號* @param pinCh* @return*/ static ExtIOPin convertPinNum (char * pinCh) {ExtIOPin pinNum;if (pinCh == NULL) {return ExtIOPinEnd;}pinNum = (ExtIOPin)(*pinCh - '0');if (pinNum >= ExtIOPinEnd) {return ExtIOPinEnd;}return pinNum; }/*** 外部IO命令解析*/ static void extioCmd () {char * type = strtok(NULL, spaceCh);if (type == NULL) {showMsg(noEnoughParamMsg);return;}if (strstr(type, "get")) { // 命令extio get pinExtIOPin pin;ExtIOState state;pin = convertPinNum(strtok(NULL, spaceCh));if (pin == ExtIOPinEnd) {showMsg(unknownPinMsg);return;}state = ExtIOGetState(pin);showMsg((state == ExtIOHigh) ? "1\r\n" : "0\r\n");} else if (strstr(type, "set")) { // 命令extio set pin valueExtIOPin pin;char * value;pin = convertPinNum(strtok(NULL, spaceCh));if (pin == ExtIOPinEnd) {showMsg(unknownPinMsg);return;}value = strtok(NULL, spaceCh);if (value == NULL) {showMsg(noEnoughParamMsg);return;}ExtIOSetState(pin, *value == '0' ? ExtIOLow : ExtIOHigh);} else if (strstr(type, "dir")) { // 命令extio dir pin in/outExtIOPin pin;char *outType;pin = convertPinNum(strtok(NULL, spaceCh));if (pin == ExtIOPinEnd) {showMsg(unknownPinMsg);return;}outType = strtok(NULL, spaceCh);if (outType == NULL) {showMsg(noEnoughParamMsg);return;}ExtIOSetDir(pin, strstr(outType, "in") ? 1 : 0);} else {showMsg(noEnoughParamMsg);} }/*** 波形輸出命令解析*/ static void waveCmd () {char *type = strtok(NULL, spaceCh);if (type == NULL) {showMsg(noEnoughParamMsg);return;}if (strstr(type, "square")) { // 命令wave squareWaveSelectType(WaveSquare);} else if (strstr(type, "start")) {WaveStartOutput();} else if (strstr(type, "stop")) {WaveStopOutput();} else {showMsg(noEnoughParamMsg);} }static void monitorPinCmd (void) {MonitorCmd * cmd;uint8_t pin;uint8_t isOn = 0;char * pinCh = strtok(NULL, spaceCh); // 解析引腳 pinnumif (pinCh == NULL) {showMsg(noEnoughParamMsg);return;} else {char *on_off;pin = atoi(pinCh);on_off = strtok(NULL, spaceCh); // 解析開關on/offif (on_off == NULL) {showMsg(noEnoughParamMsg);return;} else if (strstr(on_off, "on")) {isOn = 1;}cmd = MonitorAllocCmd();cmd->isAdd = isOn;cmd->target = MonitorExtIOPin;cmd->options.pin.pinNum = pin;MonitorSendCmd(cmd);} }static void monitorCPUCmd (void) {uint8_t isOn = 0;char * on_off = strtok(NULL, spaceCh); // monitor cpu on/offif (on_off == NULL) {showMsg(noEnoughParamMsg);return;} else if (strstr(on_off, "on")) {MonitorCmd * cmd = MonitorAllocCmd();char * percent = strtok(NULL, spaceCh); // monitor cpu on percentisOn = 1;if (percent != NULL) {float cpuPercent = (float)atof(percent);cmd->options.cpu.warning = 1;cmd->options.cpu.warnPercent = cpuPercent;} else {cmd->options.cpu.warning = 0;}cmd->isAdd = isOn;cmd->target = MonitorCPUUsage;MonitorSendCmd(cmd);} }/*** 波形輸出命令解析*/ static void monitorCmd (void) {char *type = strtok(NULL, spaceCh);if (type == NULL) {showMsg(noEnoughParamMsg);return;}if (strstr(type, "on")) { // monitor onMonitorOn();} else if (strstr(type, "off")) { // monitor offMonitorOff();} else if (strstr(type, "pin")) { // monitor pin num on/offif (MonitorIsOn()) {monitorPinCmd();} else {showMsg("Turn on Monitor first!\r\n");}} else if (strstr(type, "cpu")) { // monitor cpu on/offif (MonitorIsOn()) {monitorCPUCmd();} else {showMsg("Turn on Monitor first!\r\n");}} }/*** 未知命令處理*/ static void unknowCmd (void) {showMsg(unknownCmdMsg); }/*** 讀取一行數據,如果命令超過則截斷*/ static void readLine (char * buffer, uint32_t maxLen) {uint32_t index = 0;while (index < maxLen) {char ch;UartRead(&ch, 1);switch (ch) {case TERMINAL_BS: // 退格鍵if (index > 0) {buffer[index--] = '\0';showCh(TERMINAL_BS);showCh(TERMINAL_SPACE);showCh(TERMINAL_BS);}break;case TERMINAL_CR:showCh(TERMINAL_LF);default:showCh(ch);buffer[index++] = ch;if ((ch == '\n') || (ch == '\r') || (index >= maxLen)) {buffer[index] = '\0';return;}break;}} }/*** 解析命令*/ static void processCmd (char * cmdLine) {char * cmdStart;// 獲取開頭cmdStart = strtok(cmdLine, spaceCh);if (cmdStart == NULL) {return;}// 識別命令if (strstr(cmdStart, "extio")) {extioCmd();} else if (strstr(cmdStart, "wave")) {waveCmd();} else if (strstr(cmdStart, "promote")) {promoteCmd();} else if (strstr(cmdStart, "monitor")) {monitorCmd();} else {unknowCmd();} }/*** 解釋器任務* @param param*/ void cliTaskEntry (void * param) {static char cmdBuffer[CLI_CMD_BUFFER_SIZE];for (;;) {showPromote();readLine(cmdBuffer, sizeof(cmdBuffer));processCmd(cmdBuffer);} }/*** 命令解釋器設計*/ void CLIInit (void) {strcpy(promoteBuffer, ">>");tTaskInit(&cliTask, cliTaskEntry, (void *) 0x0, CLI_TASK_PRIO, cliTaskEnv, sizeof(cliTaskEnv)); }monitor.h:
/*** @brief 監控任務設計* @details* @author 01課堂 李述銅 http://01ketang.cc* @date 2017-06-01* @version 1.0* @copyright 版權所有,禁止用于商業用途*/#ifndef MONITOR_H #define MONITOR_H#include "tinyOS.h"#define MONITOR_TASK_PRIO 0 #define MONITOR_TASK_ENV_SIZE 512 #define MONITOR_MAX_CMD 10 #define REPORT_BUFFER_SIZE 128 #define MONITOR_DEFAULT_TIMEOUT 1000// 監控對像 typedef enum {MonitorCPUUsage,MonitorExtIOPin, }MonitorTarget;// 監控命令 typedef struct _MonitorCmd {tNode linkNode;uint8_t isAdd;MonitorTarget target;union MonitorOption{struct {uint8_t pinNum; // 管腳序號}pin;struct {uint8_t warning;float warnPercent;}cpu;}options; }MonitorCmd;void MonitorInit (void); void MonitorOn (void); void MonitorOff (void); uint8_t MonitorIsOn (void);MonitorCmd * MonitorAllocCmd (void); void MonitorFreeCmd (MonitorCmd * cmd); void MonitorSendCmd (MonitorCmd * cmd); void MonitorSetPeriod (uint32_t ms);#endif //PROJECT_MONITOR_Hmonitor.c:
/*** @brief 監控任務設計* @details* @author 01課堂 李述銅 http://01ketang.cc* @date 2017-06-01* @version 1.0* @copyright 版權所有,禁止用于商業用途*/ #include <string.h> #include <stdio.h> #include "monitor.h" #include "uart.h" #include "extio.h"static uint8_t monitorIsOn;__align(8) static tTaskStack monitorTaskEnv[MONITOR_TASK_ENV_SIZE]; static tTask monitorTask;static tMbox cmdMbox; static void * msgBuffer[MONITOR_MAX_CMD];static tMemBlock cmdMemBlock; static MonitorCmd cmdMem[MONITOR_MAX_CMD];static tList monitorCmdList;static uint32_t monitorPeriod; // 監控周期 static char reportBuffer[REPORT_BUFFER_SIZE];/*** 分配命令塊* @return*/ MonitorCmd * MonitorAllocCmd (void) {MonitorCmd * cmd = 0;tMemBlockWait(&cmdMemBlock, (void **)&cmd, 0);memset(cmd, 0, sizeof(MonitorCmd));tNodeInit(&cmd->linkNode);return cmd; }/*** 釋放命令塊* @param cmd*/ void MonitorFreeCmd (MonitorCmd * cmd) {tMemBlockNotify(&cmdMemBlock, cmd); }/*** 添加監控命令* @param cmd*/ void MonitorSendCmd (MonitorCmd * cmd) {tMboxNotify(&cmdMbox, cmd, tMBOXSendNormal); }/*** 設置監控周期* @param ms*/ void MonitorSetPeriod (uint32_t ms) {monitorPeriod = ms; }/*** 找到配置相同的命令* @param cmd* @return*/ static MonitorCmd * findCmd (MonitorCmd * cmd) {tNode * currNode;for (currNode = tListFirst(&monitorCmdList); currNode != (tNode *)0; currNode = tListNext(&monitorCmdList, currNode)) {MonitorCmd * currentCmd = (MonitorCmd *)tNodeParent(currNode, MonitorCmd, linkNode);if (currentCmd->target == cmd->target) {switch (currentCmd->target) {case MonitorCPUUsage:return currentCmd;case MonitorExtIOPin:if (currentCmd->options.pin.pinNum == cmd->options.pin.pinNum) {return currentCmd;}break;default:break;}}}return 0; }/*** 添加命令*/ static void procReceivedCmd (MonitorCmd * cmd) {MonitorCmd * existCmd = findCmd(cmd);if (cmd->isAdd) {if (existCmd) {tListRemove(&monitorCmdList, &existCmd->linkNode);MonitorFreeCmd(existCmd);}tListAddLast(&monitorCmdList, &cmd->linkNode);} else {if (existCmd) {tListRemove(&monitorCmdList, &existCmd->linkNode);MonitorFreeCmd(existCmd);}MonitorFreeCmd(cmd);} }static void showReportMsg (const char * msg) {UartWrite(msg, strlen(msg)); }static void reportCPUUsage (MonitorCmd * cmd) {float cpuUsage = tCpuUsageGet();sprintf(reportBuffer, "CPU usage:%lf\r\n", cpuUsage);showReportMsg(reportBuffer);if (cmd->options.cpu.warning) {if (cmd->options.cpu.warnPercent <= cpuUsage) {showReportMsg("Warning: CPU usage too high\r\n");}} }static void reportExtIOPin (MonitorCmd * cmd) {ExtIOState state;ExtIOPin pin = (ExtIOPin)cmd->options.pin.pinNum;if (pin >= ExtIOPinEnd) {return;}state = ExtIOGetState(pin);sprintf(reportBuffer, "ExtIO Pin %d:%d\r\n", pin, (state == ExtIOHigh) ? 1 : 0);showReportMsg(reportBuffer); }/*** 報告錯誤* @param cmd*/ static void reportTarget (void) {tNode * currNode;for (currNode = tListFirst(&monitorCmdList); currNode != NULL; currNode = tListNext(&monitorCmdList, currNode)) {MonitorCmd * currentCmd = (MonitorCmd *)tNodeParent(currNode, MonitorCmd, linkNode);switch (currentCmd->target) {case MonitorCPUUsage:reportCPUUsage(currentCmd);break;case MonitorExtIOPin:reportExtIOPin(currentCmd);break;}} }/*** 監控任務* @param param*/ void monitorTaskEntry (void * param) {for (;;) {uint32_t err;MonitorCmd * cmd;err = tMboxWait(&cmdMbox, (void **)&cmd, monitorPeriod / TINYOS_SYSTICK_MS);if (err == tErrorNoError) {procReceivedCmd(cmd);} else {reportTarget();}} }/*** 監控初始化*/ void MonitorInit (void) {monitorIsOn = 0; // 未開啟 }void MonitorOn (void) {if (monitorIsOn) {return;}monitorIsOn = 1;monitorPeriod = MONITOR_DEFAULT_TIMEOUT;tListInit(&monitorCmdList);tMboxInit(&cmdMbox, msgBuffer, MONITOR_MAX_CMD);tMemBlockInit(&cmdMemBlock, cmdMem, sizeof(MonitorCmd), MONITOR_MAX_CMD);tTaskInit(&monitorTask, monitorTaskEntry, (void *) 0x0, MONITOR_TASK_PRIO, monitorTaskEnv, sizeof(monitorTaskEnv)); }void MonitorOff (void) {if (monitorIsOn == 0) {return;}tTaskForceDelete(&monitorTask);monitorIsOn = 0; }uint8_t MonitorIsOn (void) {return monitorIsOn; }參考資料:
總結
- 上一篇: 外部事件的处理
- 下一篇: 入党后去当兵党员算数吗