通用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
*********************************************************************************************************/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章