通用GPIO測試工具

爲了方便對GPIO驅動進行測試,特意開發了通用GPIO測試工具,該工具同時也可用於GPIO硬件測試和GPIO應用開發參考。

簡要說明

  • 命令行解析基於cmdParse模塊,這個模塊的功能和用法會單獨說明。
  • 命令每次只針對一個GPIO進行操作。
  • -id 選項指定了GPIO序號,選項參數可以是一個無符號整數,也可以是“gpio_port_pin”格式字符串(和SylixOS中GPIO序號宏定義中的格式類似,只不過那裏是宏定義常數,這裏是小寫字符串)。
  • -oper 選項指定了操作類型(operation type),可以是in/out/irq分別代表輸入模式,輸出模式和中斷模式。如果是輸出模式還可以後跟一個數字參數,指定輸出是高電平(非0)或低電平(0)。如果是中斷模式,後跟一個參數來指定觸發類型,high(高電平觸發)/low(低電平觸發)/rise(上升沿觸發)/fall(下降沿觸發)/edge(雙邊沿觸發)
  • -i選項指定動作時間間隔,單位是毫秒,默認是1000毫秒;-n選項指定動作重複次數,默認是一次。
  • 對於輸出模式如果執行次數不止一次,則每次輸出時電平會翻轉一次,便於讓LED閃爍或輸出某個頻率的方波。在這裏插入圖片描述在這裏插入圖片描述
  • -info選項用於顯示命令內部參數信息。
    在這裏插入圖片描述
  • -d [on/off] 選項用於控制是否打印運行信息。對於較高頻率的動作執行時一般要關閉調試信息。
  • -h 選項輸出幫助信息,主要是一些命令實例。
    在這裏插入圖片描述
  • help選項是個通用選項,會輸出相應命令的選項列表。
  • 在這裏插入圖片描述

程序源碼

/*********************************************************************************************************
**
**                                    中國軟件開源組織
**
**                                   嵌入式實時操作系統
**
**                                SylixOS(TM)  LW : long wing
**
**                               Copyright All Rights Reserved
**
**--------------文件信息--------------------------------------------------------------------------------
**
** 文   件   名: gpioAccessCmd.c
**
** 創   建   人: Hou.JinYu (侯進宇)
**
** 文件創建日期: 2019 年 10 月 17 日
**
** 描        述: 通用 GPIO 測試工具
*********************************************************************************************************/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#include "pthread.h"
#include "sys/gpiofd.h"
#include "cmdParse/cmdParse.h"
/*********************************************************************************************************
  操作模式
*********************************************************************************************************/
#define OPE_CLOSE               (0)                                     /*  關閉模式                    */
#define OPE_INPUT               (1)                                     /*  輸入模式                    */
#define OPE_OUTPUT              (2)                                     /*  輸出模式                    */
#define OPE_IRQ                 (3)                                     /*  中斷模式                    */
/*********************************************************************************************************
  設備配置參數結構
*********************************************************************************************************/
typedef struct {
    uint32_t                    uiEffective;                            /*  0無效,1有效                */
    uint32_t                    uiDisplayState;                         /*  過程顯示,0不顯示 1顯示     */
    uint32_t                    uiInterval;                             /*  運行間隔,單位毫秒          */
    uint32_t                    uiOperateNum;                           /*  計劃運行次數                */
    uint32_t                    uiOperateCount;                         /*  設計運行次數                */

    uint32_t                    uiGpioId;                               /*  gpio id                     */
    uint32_t                    uiOperate;                              /*  操作類型                    */
    uint32_t                    uiValue;                                /*  操作數值                    */
    uint32_t                    uiFlags;                                /*  gpio_flags                  */

    int32_t                     iFd;                                    /*  設備文件標識符              */
    pthread_t                   tid;                                    /*  運行線程ID                  */

} DEV_ARG_ST;
/*********************************************************************************************************
** 名稱: help
** 輸入: cmd        命令參數
**       opti       選項索引號
** 輸出: 錯誤碼,NONE成功,ERROR錯誤
** 說明: 幫助信息,列出參數列表信息
*********************************************************************************************************/
static  int  getHelp (command_st  *cmd, int opti)
{
    printf("Usage:  \n"
       "gpio  [options] [parameter]...\n"
       "gpio -id gpio_0_10 -opr in\n"
       "gpio -id gpio_0_10 -opr out 0/1\n"
       "gpio -id gpio_0_10 -opr irq high/low/rise/fall/edge\n"
       "gpio -help\n");

    return  (NONE);
}
/*********************************************************************************************************
** 名稱: getInfo
** 輸入: cmd        命令參數
**       opti       參數索引
** 輸出: 錯誤碼,NONE成功,ERROR錯誤
** 說明: 獲取 info 選項
*********************************************************************************************************/
static int  getInfo (command_st  *cmd, int opti)
{
    DEV_ARG_ST  *pArg;

    pArg = cmd->priv;
    printf("uiEffective    = %d\n",         pArg->uiEffective   );
    printf("uiDisplayState = %d\n",         pArg->uiDisplayState);
    printf("uiInterval     = %d\n",         pArg->uiInterval    );
    printf("uiOperateNum   = %d\n",         pArg->uiOperateNum  );
    printf("uiOperateCount = %d\n",         pArg->uiOperateCount);
    printf("uiGpioId       = %d\n",         pArg->uiGpioId      );
    printf("uiOperate      = %d\n",         pArg->uiOperate     );
    printf("uiValue        = %d\n",         pArg->uiValue       );
    printf("uiFlags        = %08x\n",       pArg->uiFlags       );
    printf("iFd            = %d\n",         pArg->iFd           );
    printf("tid            = %08x\n", (UINT)pArg->tid           );

    return  (ERROR_NONE);
}
/*********************************************************************************************************
** 名稱: getId
** 輸入: cmd        命令參數
**       opti       參數索引
** 輸出: 錯誤碼,NONE成功,ERROR錯誤
** 說明: 獲取 Id 選項
*********************************************************************************************************/
static int  getId (command_st  *cmd, int opti)
{
    option_st   *opt;
    DEV_ARG_ST  *pArg;

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

    if (opt->argc) {
        int  port;
        int  pin;

        if (2 == sscanf(cmd->argv[opt->index + 1], "gpio_%d_%d", &port, &pin)) {
            pArg->uiGpioId = port * 32 + pin;
        } else {
            pArg->uiGpioId = strtoul(cmd->argv[opt->index + 1], NULL, 0);
        }
    } else {
        printf("error!miss gpio id. -id xxx or -id gpio_x_y\n");
        return  (ERROR);
    }

    return  (NONE);
}
/*********************************************************************************************************
** 名稱: getIn
** 輸入: cmd        命令參數
**       opti       參數索引
** 輸出: 錯誤碼,NONE成功,ERROR錯誤
** 說明: 獲取 In 選項
*********************************************************************************************************/
static int  getOperate (command_st  *cmd, int opti)
{
    DEV_ARG_ST  *pArg;
    option_st   *opt;
    char        *type;
    char        *str;

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

    if (opt->argc > 0) {
        type = cmd->argv[opt->index + 1];
        if (strcasecmp(type, "in") == 0) {
            pArg->uiOperate = OPE_INPUT;
            pArg->uiFlags   = GPIO_FLAG_IN;
            pArg->uiValue   = 0;

        } else if (strcasecmp(type, "out") == 0) {
            pArg->uiOperate = OPE_OUTPUT;
            pArg->uiFlags   = GPIO_FLAG_OUT_INIT_LOW;
            pArg->uiValue   = 0;
            if (opt->argc > 1) {
                str = cmd->argv[opt->index + 2];
                if (strcasecmp(str, "0") == 0) {
                    pArg->uiFlags = GPIO_FLAG_OUT_INIT_LOW;
                    pArg->uiValue = 0;
                } else {
                    pArg->uiFlags = GPIO_FLAG_OUT_INIT_HIGH;
                    pArg->uiValue = 1;
                }
            }

        } else if (strcasecmp(type, "irq") == 0) {
            pArg->uiOperate = OPE_IRQ;
            pArg->uiFlags   = GPIO_FLAG_TRIG_FALL;
            pArg->uiValue   = 0;
            if (opt->argc > 1) {
                str = cmd->argv[opt->index + 2];
                if (strcasecmp(str, "high") == 0) {
                    pArg->uiFlags = GPIO_FLAG_TRIG_LEVEL | GPIO_FLAG_TRIG_RISE;
                } else if (strcasecmp(str, "low") == 0) {
                    pArg->uiFlags = GPIO_FLAG_TRIG_LEVEL | GPIO_FLAG_TRIG_FALL;
                } else if (strcasecmp(str, "rise") == 0) {
                    pArg->uiFlags = GPIO_FLAG_TRIG_RISE;
                } else if (strcasecmp(str, "fall") == 0) {
                    pArg->uiFlags = GPIO_FLAG_TRIG_FALL;
                } else if (strcasecmp(str, "edge") == 0) {
                    pArg->uiFlags = GPIO_FLAG_TRIG_FALL | GPIO_FLAG_TRIG_RISE;
                }
            }
        }
    }

    return  (NONE);
}
/*********************************************************************************************************
** 名稱: devPthread
** 輸入: pvArg       線程參數
** 輸出: 錯誤碼,NONE成功,ERROR錯誤
** 說明: 設備運行線程
*********************************************************************************************************/
static  void   *devPthread (void * pvArg)
{
    int          iFd;
    int          iError;
    uint8_t      value;
    DEV_ARG_ST  *pArg = (DEV_ARG_ST  *)pvArg;

    iFd = gpiofd(pArg->uiGpioId, O_RDWR, pArg->uiFlags);
    if (iFd < 0) {
        printf("open gpio_%d_%d failed!\n", pArg->uiGpioId / 32, pArg->uiGpioId % 32);
        return  (NULL);
    }

    pArg->iFd = iFd;
    pArg->uiOperateCount = 0;

    if (pArg->uiOperate == OPE_INPUT) {
        while(1) {
            iError = gpiofd_read(iFd, &value);
            if (iError < 0) {
                printf("gpio %d read error!\n", pArg->uiGpioId);
                break;
            }
            pArg->uiValue = value;
            if (pArg->uiDisplayState) {
                printf("gpio %d input %d\n", pArg->uiGpioId, pArg->uiValue);
            }

            pArg->uiOperateCount++;
            if (pArg->uiOperateCount >= pArg->uiOperateNum) {
                break;
            }

            usleep(pArg->uiInterval * 1000);
        }

    } else if (pArg->uiOperate == OPE_OUTPUT) {
        while(1) {
            value = pArg->uiValue;
            iError = gpiofd_write(iFd, value & 0x01);
            if (iError < 0) {
                printf("gpio %d write error!\n", pArg->uiGpioId);
                break;
            }
            if (pArg->uiDisplayState) {
                printf("gpio %d output %d\n", pArg->uiGpioId, pArg->uiValue);
            }
            usleep(pArg->uiInterval * 1000);

            pArg->uiOperateCount++;
            if (pArg->uiOperateCount >= pArg->uiOperateNum) {
                break;
            }

            pArg->uiValue = !pArg->uiValue;
        }

    } else if (pArg->uiOperate == OPE_IRQ) {
        fd_set           fdset;

        FD_ZERO(&fdset);
        while(1) {
            FD_SET(iFd, &fdset);

            iError = select(iFd + 1, &fdset, NULL, NULL, NULL);
            if (iError < 0) {
                printf("gpio %d select error! errno = %d\n", pArg->uiGpioId, iError);
                break;
            }
            if (pArg->uiDisplayState) {
                printf("gpio %d irq response. count = %u\n", pArg->uiGpioId, pArg->uiOperateCount);
            }
            pArg->uiOperateCount++;
            if (pArg->uiOperateCount >= pArg->uiOperateNum) {
                break;
            }
            usleep(pArg->uiInterval * 1000);
        }
    }

    close(pArg->iFd);
    pArg->iFd = -1;

    return  (NULL);
}
/*********************************************************************************************************
** 名稱: gpioTool
** 輸入: argc       參數個數
**       argv       參數列表
** 輸出: 錯誤碼,NONE成功,ERROR錯誤
** 說明: gpio 測試工具函數
*********************************************************************************************************/
static int gpioTool (int argc, char *argv[])
{
    DEV_ARG_ST  devArg = {
        .uiEffective    = 0,
        .uiDisplayState = 1,
        .uiInterval     = 1000,
        .uiOperateNum   = 1,
        .uiOperateCount = 0,
        .uiGpioId       = 0,
        .uiOperate      = 0,
        .uiValue        = 0,
        .uiFlags        = 0,
        .iFd            = -1,
        .tid            = 0,
    };
    option_st  optv[] = {
        {ATT_FUNC,        getHelp,                  "h",    "help info"},
        {ATT_FUNC,        getId,                    "id",   "gpio id, 32/gpio_1_0"},
        {ATT_FUNC,        getOperate,               "oper", "gpio operate type,in/out/irq"},
        {ATT_FUNC,        getInfo,                  "info", "print Info"},
        {ATT_TYPE_BOOL,   &devArg.uiDisplayState,   "d",    "display, on/off"},
        {ATT_TYPE_U32,    &devArg.uiOperateNum,     "n",    "set operate number"},
        {ATT_TYPE_U32,    &devArg.uiInterval,       "i",    "set Interval, ms"},

    };
    command_st      cmd;
    pthread_attr_t  attr;
    int             err;

    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);
    }

    pthread_attr_init(&attr);
    pthread_attr_setname(&attr, "t_gpioTest");
    pthread_create(&devArg.tid, &attr, devPthread, (void *)&devArg);

    return  (ERROR_NONE);
}
/*********************************************************************************************************
** 函數名稱: main
** 功能描述: 程序入口
** 輸    入: argc   參數個數
**           argv   參數列表
** 輸    出: ERROR_CODE
*********************************************************************************************************/
int main (int argc, char **argv)
{
    gpioTool(argc, argv);

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

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