监控任务设计

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 pin
        ExtIOPin 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 value
        ExtIOPin 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/out
        ExtIOPin 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 square
        WaveSelectType(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);       // 解析引脚 pinnum
    if (pinCh == NULL) {
        showMsg(noEnoughParamMsg);
        return;
    } else {
        char *on_off;

        pin = atoi(pinCh);
        on_off = strtok(NULL, spaceCh);         // 解析开关on/off
        if (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/off

    if (on_off == NULL) {
        showMsg(noEnoughParamMsg);
        return;
    } else if (strstr(on_off, "on")) {
        MonitorCmd * cmd = MonitorAllocCmd();

        char * percent = strtok(NULL, spaceCh); // monitor cpu on percent
        isOn = 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 on
        MonitorOn();
    } else if (strstr(type, "off")) {       // monitor off
        MonitorOff();
    } else if (strstr(type, "pin")) {       // monitor pin num on/off
        if (MonitorIsOn()) {
            monitorPinCmd();
        } else {
            showMsg("Turn on Monitor first!\r\n");
        }
    } else if (strstr(type, "cpu")) {      // monitor cpu on/off
        if (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_H

monitor.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;
}


参考资料:

  1. 手把手教你学用嵌入式操作系统

猜你喜欢

转载自blog.csdn.net/SlowIsFastLemon/article/details/106870316