爲了方便對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
*********************************************************************************************************/