通用uart测试工具

为了方便对UART驱动进行测试,特意开发了通用UART测试工具,该工具同时也可用于UART硬件测试和UART应用开发参考。

简要说明

  • 命令行解析基于cmdParse模块,这个模块的功能和用法会单独说明。
  • 命令每次只针对一个UART端口进行操作。
  • 该命令运行后会创建3个执行线程,接收线程,反射线程和发送线程。
  • -help 选项是个通用选项,会输出相应命令的选项列表。
  • -info 选项用于打印命令默认运行参数。
  • -f 选项指定UART设备文件名称,使用 ll /dev/ 命令可以查看当前系统有哪些串口设备。
  • -d [on/off] 选项用于控制是否打印运行信息。对于较高频率的动作执行时一般要关闭调试信息。
  • -e [on/off]选项用于控制是否开启接收反射功能。开启后会把收到的数据原样发送出去。
  • -b 选项用于设置串口波特率,默认为115200。
  • -o 选项用于设置串口校验方式,默认无校验。
  • -i 选项用于设置发送间隔,单位是毫秒,默认为1000毫秒。
  • -n 选项用于设置发送次数。
  • -w 选项用于设置发送数据内容。后跟uint8_t类型数据数组。

命令执行

显示选项列表
在这里插入图片描述

显示命令默认配置
在这里插入图片描述

只接收数据
只接收数据

接收并反射数据

在这里插入图片描述

发送数据
在这里插入图片描述

程序源码

/*********************************************************************************************************
**
**                                    中国软件开源组织
**
**                                   嵌入式实时操作系统
**
**                                SylixOS(TM)  LW : long wing
**
**                               Copyright All Rights Reserved
**
**--------------文件信息--------------------------------------------------------------------------------
**
** 文   件   名: uartAccessCmd.c
**
** 创   建   人: Hou.JinYu (侯进宇)
**
** 文件创建日期: 2017 年 10 月 17 日
**
** 描        述: 通用串口测试工具
*********************************************************************************************************/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "cmdParse/cmdParse.h"
/*********************************************************************************************************
  宏定义
*********************************************************************************************************/
#define CFG_DEFAULT_BUF_SIZE                (64)                        /*  默认缓存大小                */
#define CFG_DEFAULT_BUF_COUNT               (32)                        /*  默认缓存个数                */
/*********************************************************************************************************
  宏函数
*********************************************************************************************************/
#if 1
#define PRINT_DEBUG(fmt, ...)     do {printf(fmt, ##__VA_ARGS__);} while (0)
#else
#define PRINT_DEBUG(fmt, ...)
#endif

#define PRINT_ERROR(fmt, ...)     do {printf("[ERROR]%s:%d---", __FILE__, __LINE__); \
                                      printf(fmt, ##__VA_ARGS__);  } while (0)

#define PRINT_DATA_UINT8(ptr, len, fmt, ...)                            \
                do {UINT  j;                                            \
                    printf(fmt, ##__VA_ARGS__);                         \
                    for (j = 0; j < (len); j++) {                       \
                        if ((j & 0x0f) == 0) {printf("\r\n[%04x]", j);} \
                        printf(" %02x", ((UINT8 *)ptr)[j]);             \
                    } printf("\n");} while (0)
/*********************************************************************************************************
  设备配置参数结构
*********************************************************************************************************/
typedef struct {
    UINT32                      uiEchoState;                            /*  0 不反射 1反射接收的数据    */
    UINT32                      uiDisplayState;                         /*  0 不显示收发数据 1显示      */
    INT                         iFd;                                    /*  设备文件标识符              */
    pthread_t                   tidRecv;                                /*  接收线程ID                  */
    pthread_t                   tidEcho;                                /*  反射线程ID                  */
    pthread_t                   tidSend;                                /*  发送线程ID                  */
    LW_OBJECT_HANDLE            hQueueSend;                             /*  消息队列句柄                */
    CHAR                        cFileName[64];                          /*  波特率                      */
    UINT32                      uiBaud;                                 /*  波特率                      */
    UINT32                      uiOption;                               /*  硬件选项                    */
    UINT32                      uiRecvCount;                            /*  串口接收数据计数            */
    UINT32                      uiEchoCount;                            /*  串口反射数据计数            */
    UINT32                      uiSendCount;                            /*  串口发送数据计数            */

    UINT32                      uiSendInterval;                         /*  发送间隔,单位毫秒          */
    UINT32                      uiSendNumber;                           /*  串口发送次数                */
    INT32                       uiBufLength;                            /*  缓冲区有效数据长度          */
    UINT8                       ucBuf[CFG_DEFAULT_BUF_SIZE];            /*  缓冲区                      */

} DEV_ARG_ST;
/*********************************************************************************************************
** 名称: getInfo
** 输入: cmd        命令参数
**       opti       参数索引
** 输出: 错误码,NONE成功,ERROR错误
** 说明: 获取 info 选项
*********************************************************************************************************/
static int  getInfo (command_st  *cmd, int opti)
{
    DEV_ARG_ST  *pArg;

    pArg = cmd->priv;

    printf("echo     = %d\n", pArg->uiEchoState);
    printf("display  = %d\n", pArg->uiDisplayState);
    printf("iFd      = %d\n", pArg->iFd);
    printf("tidRecv  = %08x\n", (UINT)pArg->tidRecv);
    printf("tidEcho  = %08x\n", (UINT)pArg->tidEcho);
    printf("tidSend  = %08x\n", (UINT)pArg->tidSend);
    printf("file     = %s\n", pArg->cFileName);
    printf("uiBaud   = %d\n", pArg->uiBaud);
    printf("uiOption = %08x\n", pArg->uiOption);
    printf("recvCount= %d\n", pArg->uiRecvCount);
    printf("echoCount= %d\n", pArg->uiEchoCount);
    printf("sendCount= %d\n", pArg->uiSendCount);
    printf("interval = %d\n", pArg->uiSendInterval);
    printf("number   = %d\n", pArg->uiSendNumber);
    printf("uiLength = %d\n", pArg->uiBufLength);

    if (pArg->uiBufLength) {
        PRINT_DATA_UINT8(pArg->ucBuf, pArg->uiBufLength, "send data :");
    }

    return  (ERROR);
}
/*********************************************************************************************************
** 名称: getClose
** 输入: cmd        命令参数
**       opti       参数索引
** 输出: 错误码,NONE成功,ERROR错误
** 说明: 获取 Option 选项
*********************************************************************************************************/
static int  getOption (command_st  *cmd, int opti)
{
    option_st   *opt;
    DEV_ARG_ST  *pArg;
    char        *str;

    pArg = cmd->priv;
    opt  = &cmd->optv[opti];

    if (opt->argc <= 0) {
        return  (NONE);
    }

    str = cmd->argv[opt->index + 1];
    if (strcmp(str, "none") == 0) {
        pArg->uiOption = CREAD | CS8;
    } else if (strcmp(str, "odd") == 0) {
        pArg->uiOption = CREAD | CS8 | PARENB | PARODD;
    } else if (strcmp(str, "even") == 0) {
        pArg->uiOption = CREAD | CS8 | PARENB;
    } else {
        pArg->uiOption = strtoul(str, NULL, 0);
    }

    return  (NONE);
}
/*********************************************************************************************************
** 名称: devPthreadRecv
** 描述: 串口接收线程
** 输入: pvArg       参数结构
** 输出: ERROR_CODE
*********************************************************************************************************/
static  void   *devPthreadRecv (void * pvArg)
{
    INT          res;
    UINT8        buf[CFG_DEFAULT_BUF_SIZE];
    DEV_ARG_ST  *pArg = (DEV_ARG_ST  *)pvArg;

    while(1) {
        res = read(pArg->iFd, buf, sizeof(buf));
        if (res > 0) {                                                  /*  接收数据                    */
            pArg->uiRecvCount += res;
            if (pArg->uiEchoState) {
                Lw_MsgQueue_SendEx2(pArg->hQueueSend,
                                    (PVOID)buf,
                                    res,
                                    LW_OPTION_NOT_WAIT,
                                    LW_OPTION_DEFAULT);

            }

            if (pArg->uiDisplayState) {
                PRINT_DATA_UINT8(buf, res, "[uart %s] recv %d byte, data :", pArg->cFileName, res);
            }

        } else {
            PRINT_ERROR("read err,res = %d \n", res);
            break;
        }
    }

    return  (NULL);
}
/*********************************************************************************************************
** 名称: devPthreadEcho
** 描述: 串口反射线程
** 输入: pvArg       参数结构
** 输出: ERROR_CODE
*********************************************************************************************************/
static  void   *devPthreadEcho (void * pvArg)
{
    INT          res;
    size_t       txLen;
    UINT8        buf[CFG_DEFAULT_BUF_SIZE];
    DEV_ARG_ST  *pArg = (DEV_ARG_ST  *)pvArg;

    while(1) {
        res = Lw_MsgQueue_Receive(pArg->hQueueSend,
                                  buf,
                                  CFG_DEFAULT_BUF_SIZE,
                                  &txLen,
                                  LW_OPTION_WAIT_INFINITE);


        if (res < 0) {
            PRINT_ERROR("Lw_MsgQueue_Receive,res = %d", res);
            break;
        } else {                                                        /*  接收数据                    */
            if (pArg->uiDisplayState) {
                pArg->uiEchoCount += txLen;
                write(pArg->iFd, buf, txLen);
                PRINT_DATA_UINT8(buf, txLen, "[uart %s] echo %d byte, data :", pArg->cFileName, txLen);
            }
        }
    }

    return  (NULL);
}
/*********************************************************************************************************
** 名称: devPthreadSend
** 描述: 串口发送线程
** 输入: pvArg       参数结构
** 输出: ERROR_CODE
*********************************************************************************************************/
static  void   *devPthreadSend (void * pvArg)
{
    DEV_ARG_ST  *pArg = (DEV_ARG_ST  *)pvArg;

    while(pArg->uiBufLength && pArg->uiSendNumber--) {
        if (pArg->uiDisplayState) {
            PRINT_DATA_UINT8(pArg->ucBuf, pArg->uiBufLength,
                            "[uart %s] send %d byte, data :", pArg->cFileName, pArg->uiBufLength);
        }

        pArg->uiSendCount += pArg->uiBufLength;
        write(pArg->iFd, pArg->ucBuf, pArg->uiBufLength);

        usleep(pArg->uiSendInterval * 1000);
    }

    return  (NULL);
}
/*********************************************************************************************************
** 名称: main 
** 输入: argc       参数个数
**       argv       参数列表
** 输出: 错误码,NONE成功,ERROR错误
** 说明: 通用串口测试工具
*********************************************************************************************************/
static int uartTool (int argc, char *argv[])
{
    DEV_ARG_ST  devArg = {
        .uiEchoState    = 0,
        .uiDisplayState = 1,
        .iFd            = -1,
        .cFileName      = "/dev/ttyS1",
        .uiBaud         = SIO_BAUD_115200,
        .uiOption       = CREAD | CS8,
        .uiRecvCount    = 0,
        .uiEchoCount    = 0,
        .uiSendCount    = 0,
        .uiSendInterval = 1000,
        .uiSendNumber   = 0,
        .uiBufLength    = 0,
        .ucBuf          = { 0 },
    };
    option_st  optv[] = {
        {ATT_BUF_SIZE(sizeof(devArg.cFileName)) |
         ATT_TYPE_SBUF, &devArg.cFileName,      "f",      "set uart device file name"},
        {ATT_TYPE_BOOL, &devArg.uiDisplayState, "d",      "set dispaly state"},
        {ATT_TYPE_BOOL, &devArg.uiEchoState,    "e",      "set echo state"},
        {ATT_TYPE_U32,  &devArg.uiBaud,         "b",      "set baudrate"},
        {ATT_FUNC,      getOption,              "o",      "set option, none/odd/even/0x0e"},
        {ATT_TYPE_U32,  &devArg.uiSendInterval, "i",      "set send interval, ms"},
        {ATT_TYPE_U32,  &devArg.uiSendNumber,   "n",      "set send number"},
        {ATT_ARRAY(GET_ARRAY_COUNT(devArg.ucBuf)) |
         ATT_TYPE_U8,   &devArg.ucBuf,          "w",      "set send data", &devArg.uiBufLength},
        {ATT_FUNC,      getInfo,                "info",   "print cmd info"},
    };
    command_st      cmd;
    DEV_ARG_ST     *pArg = &devArg;
    int             err;
    LW_CLASS_THREADATTR  hThreadAttr;


    cmd.argc = argc;
    cmd.argv = argv;
    cmd.optc = GET_OPTC(optv);
    cmd.optv = optv;
    cmd.priv = &devArg;

    err = cmdParse(&cmd);
    if (err != NONE) {
        return  (err);
    }

    pArg->hQueueSend = Lw_MsgQueue_Create(
        "uartQueue",
        CFG_DEFAULT_BUF_COUNT,
        CFG_DEFAULT_BUF_SIZE,
        LW_OPTION_WAIT_FIFO | LW_OPTION_OBJECT_LOCAL,
        NULL);

    pArg->iFd = open(pArg->cFileName, O_RDWR, 0666);
    if (pArg->iFd < 0) {
        PRINT_ERROR("open device [%s] faild\n", pArg->cFileName);
        return  (PX_ERROR);
    }

    ioctl(pArg->iFd, FIOFLUSH, NULL);                                   /*  清空设备收发缓冲区          */
    if (ioctl(pArg->iFd, SIO_BAUD_SET, pArg->uiBaud) != ERROR_NONE) {
        PRINT_ERROR("set baudrate faild\n");
        close(pArg->iFd);
        return  (PX_ERROR);
    }
    if (ioctl(pArg->iFd, SIO_HW_OPTS_SET, pArg->uiOption) != ERROR_NONE) {
        PRINT_ERROR("set opt faild\n");
        close(pArg->iFd);
        return  (PX_ERROR);
    }

    Lw_ThreadAttr_Build(&hThreadAttr, 4 * LW_CFG_KB_SIZE, LW_PRIO_NORMAL + 0, 0, (void *)pArg);
    Lw_Thread_Create("t_uartRecv", devPthreadRecv, &hThreadAttr, &pArg->tidRecv);
    Lw_ThreadAttr_Build(&hThreadAttr, 4 * LW_CFG_KB_SIZE, LW_PRIO_NORMAL + 1, 0, (void *)pArg);
    Lw_Thread_Create("t_uartEcho", devPthreadEcho, &hThreadAttr, &pArg->tidEcho);
    Lw_ThreadAttr_Build(&hThreadAttr, 4 * LW_CFG_KB_SIZE, LW_PRIO_NORMAL + 2, 0, (void *)pArg);
    Lw_Thread_Create("t_uartSend", devPthreadSend, &hThreadAttr, &pArg->tidSend);

    Lw_Thread_Join(pArg->tidRecv, NULL);
    Lw_Thread_Join(pArg->tidEcho, NULL);

    return  (ERROR_NONE);
}
/*********************************************************************************************************
  END
*********************************************************************************************************/

发布了39 篇原创文章 · 获赞 6 · 访问量 5062

猜你喜欢

转载自blog.csdn.net/ScilogyHunter/article/details/104361632