You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
	
	
		
			343 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			C
		
	
		
		
			
		
	
	
			343 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			C
		
	
|   
											2 months ago
										 | /******************************************************************************
 | ||
|  |  * file    lib/hardware/hwgpio.c  | ||
|  |  * author  YuLiang | ||
|  |  * version 1.0.0 | ||
|  |  * date    24-Nov-2021 | ||
|  |  * brief   This file provides all the gpio operation functions. | ||
|  |  * | ||
|  |  ****************************************************************************** | ||
|  |  * Attention | ||
|  |  * | ||
|  |  * <h2><center>© COPYRIGHT(c) 2021 LandPower</center></h2> | ||
|  |  * | ||
|  |  * Redistribution and use in source and binary forms, with or without modification, | ||
|  |  * are permitted provided that the following conditions are met: | ||
|  |  *   1. Redistributions of source code must retain the above copyright notice, | ||
|  |  *      this list of conditions and the following disclaimer. | ||
|  |  *   2. Redistributions in binary form must reproduce the above copyright notice, | ||
|  |  *      this list of conditions and the following disclaimer in the documentation | ||
|  |  *      and/or other materials provided with the distribution. | ||
|  |  *   3. Neither the name of LandPower nor the names of its contributors may be used to  | ||
|  |  *      endorse or promote products derived from this software without specific | ||
|  |  *      prior written permission. | ||
|  |  * | ||
|  |  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
|  |  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
|  |  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
|  |  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | ||
|  |  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
|  |  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
|  |  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||
|  |  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | ||
|  |  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
|  |  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
|  |  * | ||
|  |  ******************************************************************************/ | ||
|  | 
 | ||
|  | /* Includes ------------------------------------------------------------------*/ | ||
|  | //#ifdef HAVE_CONFIG_H
 | ||
|  | #include "config.h"
 | ||
|  | //#endif
 | ||
|  | 
 | ||
|  | /* 标准C库头文件. */ | ||
|  | #include <unistd.h>
 | ||
|  | #include <sys/types.h>
 | ||
|  | #include <sys/stat.h>
 | ||
|  | #include <fcntl.h>
 | ||
|  | 
 | ||
|  | /* 用户代码头文件. */ | ||
|  | #include "hwgpio.h"
 | ||
|  | #include "cmd.h"
 | ||
|  | 
 | ||
|  | /* Private define ------------------------------------------------------------*/ | ||
|  | /* Private macro -------------------------------------------------------------*/ | ||
|  | /* Private typedef -----------------------------------------------------------*/ | ||
|  | /* Private variables ---------------------------------------------------------*/ | ||
|  | static array_t *gpios = NULL; | ||
|  | 
 | ||
|  | int32_t gpio_watcdog_idx; | ||
|  | 
 | ||
|  | /* Private function prototypes -----------------------------------------------*/ | ||
|  | 
 | ||
|  | /* Internal functions --------------------------------------------------------*/ | ||
|  | int32_t _gpio_name_get(uint16_t gpio, char *name) | ||
|  | { | ||
|  |     if (!name) | ||
|  |     { | ||
|  |         return E_NULL; | ||
|  |     } | ||
|  | 
 | ||
|  |     switch (gpio) | ||
|  |     { | ||
|  |     case GPIO_WATCHDONG: | ||
|  |         snprintf(name, DEV_NAME_STR_LEN, "watchdog"); | ||
|  |         break; | ||
|  |     default: | ||
|  |         snprintf(name, DEV_NAME_STR_LEN, "default"); | ||
|  |         break; | ||
|  |     } | ||
|  | 
 | ||
|  |     return E_NONE; | ||
|  | } | ||
|  | 
 | ||
|  | CMD(gpio_show, | ||
|  |     gpio_show_cmd, | ||
|  |     "show gpio", | ||
|  |     SHOW_STR | ||
|  |     "Gpios\n") | ||
|  | { | ||
|  |     uint16_t i = 0; | ||
|  |     char gpio_name[DEV_NAME_STR_LEN] = {0}; | ||
|  |     gpio_node_t *gpio_node = NULL; | ||
|  | 
 | ||
|  |     vty_out(vty, "GPIO NAME         DIR VALUE%s", VTY_NEWLINE); | ||
|  |     for(i = 0; i < array_active(gpios); i++) | ||
|  |     { | ||
|  |         gpio_node = array_lookup(gpios, i); | ||
|  |         if (!gpio_node) | ||
|  |         { | ||
|  |             continue; | ||
|  |         } | ||
|  | 
 | ||
|  |         if (gpio_node->curr_dir == GPIO_DIR_IN) | ||
|  |         { | ||
|  |             gpio_val_get(gpio_node->index, &gpio_node->curr_val); | ||
|  |         } | ||
|  | 
 | ||
|  |         _gpio_name_get(gpio_node->gpio, gpio_name); | ||
|  | 
 | ||
|  |         vty_out(vty, "%4d %-12s %-03s %d%s", gpio_node->gpio, gpio_name, gpio_node->curr_dir == GPIO_DIR_IN ? "in" : "out", | ||
|  |             gpio_node->curr_val, VTY_NEWLINE); | ||
|  |     } | ||
|  | 
 | ||
|  |     return CMD_SUCCESS; | ||
|  | } | ||
|  | 
 | ||
|  | /* Interface functions -------------------------------------------------------*/ | ||
|  | /* 根据 gpio 找到对应的结构体, 如果不存在, 返回NULL. */ | ||
|  | gpio_node_t *gpio_get_by_gpio(uint16_t gpio) | ||
|  | { | ||
|  |     uint16_t i = 0; | ||
|  |     gpio_node_t *gpio_node = NULL; | ||
|  | 
 | ||
|  |     for(i = 0; i < array_active(gpios); i++) | ||
|  |     { | ||
|  |         gpio_node = array_lookup(gpios, i); | ||
|  |         if (!gpio_node) | ||
|  |         { | ||
|  |             continue; | ||
|  |         } | ||
|  | 
 | ||
|  |         if (gpio_node->gpio == gpio) | ||
|  |         { | ||
|  |             return gpio_node; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     return NULL; | ||
|  | } | ||
|  | 
 | ||
|  | /* 根据数组 index 找到对应的结构体, 如果不存在, 返回 NULL. */ | ||
|  | gpio_node_t *gpio_get_by_index(uint16_t index) | ||
|  | { | ||
|  |     return (gpio_node_t*)array_lookup(gpios, index); | ||
|  | } | ||
|  | 
 | ||
|  | /* 设置gpio输出值 */ | ||
|  | int32_t gpio_val_set(uint16_t index, uint8_t value) | ||
|  | { | ||
|  |     int32_t fd = 0; | ||
|  |     char buf[40] = {0}; | ||
|  |     DBG(DBG_M_GPIO, "gpio index %d \r\n", index); | ||
|  |     gpio_node_t *gpio_node = gpio_get_by_index(index); | ||
|  |      | ||
|  |     /* 参数检查 */ | ||
|  |     if (!gpio_node) | ||
|  |     { | ||
|  |         DBG(DBG_M_GPIO, "gpio index %d is not found\r\n", index); | ||
|  |         return E_NOT_FOUND; | ||
|  |     } | ||
|  | 
 | ||
|  |     /* 只有out方向可以设置值 */ | ||
|  |     if (gpio_node->curr_dir != GPIO_DIR_OUT) | ||
|  |     { | ||
|  |         DBG(DBG_M_GPIO, "gpio %d direction is not out\r\n", gpio_node->gpio); | ||
|  |         return E_BAD_PARAM; | ||
|  |     } | ||
|  | 
 | ||
|  |     /* 如果值相等就不需要再操作了 */ | ||
|  |     if (gpio_node->curr_val == value) | ||
|  |     { | ||
|  |         return E_NONE; | ||
|  |     } | ||
|  | 
 | ||
|  |     /* 打开文件 */ | ||
|  |     snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/value", gpio_node->gpio); | ||
|  |     fd = open(buf, O_WRONLY); | ||
|  |     if (fd <= 0)  | ||
|  |     { | ||
|  |         DBG(DBG_M_GPIO, "Open %s error", buf);  | ||
|  |         return E_SYS_CALL; | ||
|  |     } | ||
|  | 
 | ||
|  |     /* 设置值 */ | ||
|  |     snprintf(buf, sizeof(buf), "%d", (value == 0) ? 0 : 1); | ||
|  |     if (write(fd, buf, 1) <= 0) | ||
|  |     { | ||
|  |         DBG(DBG_M_GPIO, "Write gpio %d value error", gpio_node->gpio);  | ||
|  |         return E_SYS_CALL; | ||
|  |     } | ||
|  |     close(fd); | ||
|  | 
 | ||
|  |     gpio_node->curr_val = value; | ||
|  |     return E_NONE; | ||
|  | } | ||
|  | 
 | ||
|  | /* 设置gpio输出值 */ | ||
|  | int32_t gpio_val_get(uint16_t index, uint8_t *value) | ||
|  | { | ||
|  |     int32_t fd = 0; | ||
|  |     char buf[40] = {0}; | ||
|  |     gpio_node_t *gpio_node = gpio_get_by_index(index); | ||
|  | 
 | ||
|  |     /* 参数检查 */ | ||
|  |     if (!gpio_node) | ||
|  |     { | ||
|  |         DBG(DBG_M_GPIO, "gpio index %d is not found\r\n", index); | ||
|  |         return E_NOT_FOUND; | ||
|  |     } | ||
|  | 
 | ||
|  |     /* out方向直接读取 */ | ||
|  |     if (GPIO_DIR_OUT == gpio_node->curr_dir) | ||
|  |     { | ||
|  |         *value = gpio_node->curr_val; | ||
|  |         return E_NONE; | ||
|  |     } | ||
|  | 
 | ||
|  |     /* 打开文件 */ | ||
|  |     snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/value", gpio_node->gpio); | ||
|  |     fd = open(buf, O_RDONLY); | ||
|  |     if (fd <= 0)  | ||
|  |     { | ||
|  |         DBG(DBG_M_GPIO, "Open %s error", buf);  | ||
|  |         return E_SYS_CALL; | ||
|  |     } | ||
|  | 
 | ||
|  |     /* 读取值 */ | ||
|  |     memset(buf, 0, sizeof(buf)); | ||
|  |     if (read(fd, buf, sizeof(buf) - 1) <= 0) | ||
|  |     { | ||
|  |         DBG(DBG_M_GPIO, "Read gpio %d value error", gpio_node->gpio);  | ||
|  |         return E_SYS_CALL; | ||
|  |     } | ||
|  |     close(fd); | ||
|  | 
 | ||
|  |     *value = strtol(buf, NULL, 10); | ||
|  |     return E_NONE; | ||
|  | } | ||
|  | 
 | ||
|  | /* 设置gpio方向 */ | ||
|  | int32_t gpio_dir_set(uint16_t index, uint8_t dir) | ||
|  | { | ||
|  |     int32_t fd = 0; | ||
|  |     char buf[40] = {0}; | ||
|  |     gpio_node_t *gpio_node = gpio_get_by_index(index); | ||
|  | 
 | ||
|  |     /* 参数检查 */ | ||
|  |     if (!gpio_node) | ||
|  |     { | ||
|  |         DBG(DBG_M_GPIO, "gpio index %d is not found\r\n", index); | ||
|  |         return E_NOT_FOUND; | ||
|  |     } | ||
|  | 
 | ||
|  |     /* 如果方向相等,不用继续操作 */ | ||
|  |     if (gpio_node->curr_dir == dir) | ||
|  |     { | ||
|  |         return E_NONE; | ||
|  |     } | ||
|  | 
 | ||
|  |     /* 打开文件 */ | ||
|  |     snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/direction", gpio_node->gpio); | ||
|  |     fd = open(buf, O_WRONLY); | ||
|  |     if (fd <= 0)  | ||
|  |     { | ||
|  |         DBG(DBG_M_GPIO, "Open %s error", buf);  | ||
|  |         return E_SYS_CALL; | ||
|  |     } | ||
|  | 
 | ||
|  |     /* 设置方向 */ | ||
|  |     snprintf(buf, sizeof(buf), "%s", (dir == GPIO_DIR_IN) ? "in" : "out"); | ||
|  |     if (write(fd, buf, strlen(buf)) <= 0) | ||
|  |     { | ||
|  |         DBG(DBG_M_GPIO, "Write gpio %d direction error", gpio_node->gpio);  | ||
|  |         return E_SYS_CALL; | ||
|  |     } | ||
|  |     close(fd); | ||
|  | 
 | ||
|  |     gpio_node->curr_dir = dir; | ||
|  |     return E_NONE; | ||
|  | } | ||
|  | 
 | ||
|  | /* 导出 GPIO, 返回值大于等于 0, 表示加入数组的 index; 小于 0 表示失败. */ | ||
|  | int32_t gpio_export(uint16_t gpio) | ||
|  | { | ||
|  |     int32_t fd = 0; | ||
|  |     char buf[40] = {0}; | ||
|  |     DBG(DBG_M_GPIO, "[%s %s:%d]gpio is %d \r\n", __FILE__, __func__, __LINE__, gpio); | ||
|  |     gpio_node_t *gpio_node = gpio_get_by_gpio(gpio); | ||
|  | 
 | ||
|  |     /* 如果找到表示已经 export. */ | ||
|  |     if (gpio_node) | ||
|  |     { | ||
|  |         return -1; | ||
|  |     } | ||
|  | 
 | ||
|  |     /* 文件不存在则导出, 存在不做操作. */ | ||
|  |     snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d", gpio); | ||
|  |     if (access(buf, 0) < 0) | ||
|  |     { | ||
|  |         /* 打开文件描述符 */ | ||
|  |         fd = open("/sys/class/gpio/export", O_WRONLY); | ||
|  |         if (fd <= 0)  | ||
|  |         { | ||
|  |             log_err(LOG_GPIO, "Open /sys/class/gpio/export error!");  | ||
|  |             return -2; | ||
|  |         } | ||
|  | 
 | ||
|  |         /* 导出gpio */ | ||
|  |         snprintf(buf, sizeof(buf), "%d", gpio); | ||
|  |         if (write(fd, buf, strlen(buf)) <= 0) | ||
|  |         { | ||
|  |             log_err(LOG_GPIO, "Write /sys/class/gpio/export(%d) error!", gpio);  | ||
|  |             return -3; | ||
|  |         } | ||
|  |         close(fd); | ||
|  |     } | ||
|  | 
 | ||
|  |     /* 添加结构体 */ | ||
|  |     gpio_node = XMALLOC_Q(MTYPE_GPIO, sizeof(gpio_node_t)); | ||
|  |     gpio_node->gpio = gpio; | ||
|  |     /* 默认值是不确定的 */ | ||
|  |     gpio_node->curr_val = 0xff; | ||
|  |     gpio_node->is_export = TRUE; | ||
|  |     gpio_node->index = array_append(gpios, gpio_node, MTYPE_GPIO); | ||
|  |      | ||
|  |     return gpio_node->index; | ||
|  | } | ||
|  | 
 | ||
|  | /* 初始化函数 */ | ||
|  | int32_t gpio_init(void) | ||
|  | { | ||
|  |     gpios = array_init(ARRAY_MIN_SIZE, MTYPE_GPIO); | ||
|  |     gpio_watcdog_idx = gpio_export(GPIO_WATCHDONG); | ||
|  |     if (gpio_watcdog_idx < 0) | ||
|  |     { | ||
|  |         DBG(DBG_M_GPIO, "ERROR return %d!\r\n", gpio_watcdog_idx); | ||
|  |         return E_BAD_PARAM; | ||
|  |     } | ||
|  |     LD_E_RETURN(DBG_M_GPIO, gpio_dir_set(gpio_watcdog_idx, GPIO_DIR_OUT)); | ||
|  | 
 | ||
|  |     return E_NONE; | ||
|  | } | ||
|  | /************************ (C) COPYRIGHT LandPower ***** END OF FILE ****************/ |