/****************************************************************************** 版权所有: 文件名称: gpio.c 文件版本: 01.01 创建作者: zhaoyang 创建日期: 2023-12-14 功能说明: gpio驱动程序。 其它说明: 修改记录: [new]-->applay B_DO_ADJ --> GPIOD_17 --> gpio113 预置返校 B_DO_0 --> GPIOD_03 --> gpio99 预置 B_DO_1 --> GPIOD_19 --> gpio115 B_DO_2 --> GPIOD_02 --> gpio98 B_DO_3 --> GPIOD_09 --> gpio105 B_DO_4 --> GPIOD_18 --> gpio114 B_DO_5 --> GPIOD_16 --> gpio112 B_DO_6 --> GPIOD_07 --> gpio103 B_DO_7 --> GPIOD_08 --> gpio104 B_DO_8 --> GPIOD_06 --> gpio102 M1 开入 --> GPIOI_11 --> gpio267 M3 采样 --> GPIOI_10 --> gpio266 M4 开出 --> GPIOA_02 --> gpio2 T536 start ↓↓↓↓↓↓ RUN_LED --> PB7 --> gpio39 ERR_LED --> PF4 --> gpio164 ESAM_PWR --> PL7 --> gpio159 LINE_LOSS_SET --> PM5 --> gpio389 T536 end ↑↑↑↑↑↑ */ /*------------------------------- 头文件 -------------------------------------- */ #include "bspconfig.h" #include "gpio.h" #include "head.h" #include /*------------------------------- 宏定义 -------------------------------------- */ #if CFG_BSP_DEBUG #define _GPIO_DEBUG #endif #define GPIO_LOW 0 #define GPIO_INPUT 0 #define GPIO_OUTPUT 1 #define NEW_GOIO_VERSION 1 /*------------------------------ 全局变量 ------------------------------------- */ typedef enum { SYS_GPIO = 0, RTDM_GPIO = 1, } GPIO_TYPE; unsigned short kc_kout0_stu; extern uint32_t g_yx_buf[2]; // 预留64个遥信 /*------------------------------ 函数声明 ------------------------------------- */ extern unsigned int change_di_ch(unsigned int di); #if (0 == NEW_GOIO_VERSION) int gpio_val_fd[DO_NUM]; int gpio_dev_type[DO_NUM] = { SYS_GPIO, }; // 0:系统GPIO, 1:RTDM GPIO /* 开出gpio */ const int gpio_val[DO_NUM] = {115, 98, 105, 114, 112, 103, 104, 102, 99, 113}; #else struct t_goio_cfg { int l_pin_num; // 引脚号 int l_pin_fd; // 句柄 int l_pin_type; // 类型 0:系统GPIO, 1:RTDM GPIO int l_pin_dir; // 方向 GPIO_INPUT 0 输入, GPIO_OUTPUT 1 输出 }; static struct t_goio_cfg mst_gpio_cfg[GPIO_NUM_TOTAL] = { {115, -1, -1, GPIO_OUTPUT}, {98, -1, -1, GPIO_OUTPUT}, {105, -1, -1, GPIO_OUTPUT}, {114, -1, -1, GPIO_OUTPUT}, {112, -1, -1, GPIO_OUTPUT}, {103, -1, -1, GPIO_OUTPUT}, {104, -1, -1, GPIO_OUTPUT}, {102, -1, -1, GPIO_OUTPUT}, {99, -1, -1, GPIO_OUTPUT}, {113, -1, -1, GPIO_INPUT}, {267, -1, -1, GPIO_INPUT}, {266, -1, -1, GPIO_INPUT}, {2, -1, -1, GPIO_INPUT}, }; #endif // static int gpio_watchdog_val = 0; static int gpio_run_led_val = 0; /*------------------------------ 外部函数 ------------------------------------- */ int sysfs_gpio_unexport(int gpio) { char path[64]; int fd; snprintf(path, sizeof(path), "/sys/class/gpio/unexport"); fd = open(path, O_WRONLY); if (fd < 0) { perror("Failed to open unexport"); return -1; } char buf[16]; snprintf(buf, sizeof(buf), "%d", gpio); if (write(fd, buf, strlen(buf)) < 0) { perror("Failed to set GPIO"); close(fd); return -1; } close(fd); return 0; } int sysfs_gpio_export(int gpio) { char path[64]; int fd; // 检查是否已导出 snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d", gpio); if (access(path, F_OK) == 0) { sysfs_gpio_unexport(gpio); // bugfix: 避免重复导出 msleep(50); // 短暂等待让内核处理 } snprintf(path, sizeof(path), "/sys/class/gpio/export"); fd = open(path, O_WRONLY); if (fd < 0) { perror("Failed to open export"); return -1; } char buf[16]; snprintf(buf, sizeof(buf), "%d", gpio); if (write(fd, buf, strlen(buf)) < 0) { perror("Failed to export GPIO"); close(fd); return -2; } close(fd); return 0; } int sysfs_gpio_set_direction(int gpio, int is_output) { char path[64]; int fd; snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/direction", gpio); fd = open(path, O_WRONLY); if (fd < 0) { perror("Failed to open direction"); return -1; } if (write(fd, is_output ? "out" : "in", is_output ? 3 : 2) < 0) { perror("Failed to set direction"); close(fd); return -1; } close(fd); return 0; } int sysfs_gpio_set_edge_detect(int gpio, int edge) { char path[64]; int fd; snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/edge", gpio); fd = open(path, O_WRONLY); if (fd < 0) { perror("Failed to open edge"); close(fd); return -1; } if (write(fd, edge, strlen(edge)) < 0) { perror("Failed to set edge"); close(fd); return -1; } close(fd); return 0; } int sysfs_gpio_set_value(int gpio, int value) { char path[64]; int fd = -1; snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/value", gpio); fd = open(path, O_WRONLY); if (fd < 0) { perror("Failed to open value"); return -1; } if (write(fd, value ? "1" : "0", 1) < 0) { perror("Failed to set value"); close(fd); return -1; } return fd; } int sysfs_gpio_get_value(int gpio) { char path[64]; int fd = -1; int value = 0; snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/value", gpio); fd = open(path, O_RDONLY); if (fd < 0) { perror("Failed to open value"); return -1; } if (read(fd, value, 1) < 0) { perror("Failed to get value"); close(fd); return -1; } return fd; } int sysfs_gpio_init(int gpio, int direction) { int ret; ret = sysfs_gpio_export(gpio); if (ret < 0) { dp_err_n_c("sysfs_gpio_export error ret = %d!", ret); return -1; } ret = sysfs_gpio_set_direction(gpio, direction); if (ret < 0) { dp_err_n_c("sysfs_gpio_set_direction error"); } if (GPIO_INPUT == direction) { return sysfs_gpio_get_value(gpio); } else { return sysfs_gpio_set_value(gpio, GPIO_LOW); // 初始化IO为低电平 } } int is_rtdm_device(int fd) { #if (0 == NEW_GOIO_VERSION) if (gpio_dev_type[fd] > SYS_GPIO) return 1; else if (gpio_dev_type[fd] == SYS_GPIO) return 0; else return -1; #else if (mst_gpio_cfg[fd].l_pin_type > SYS_GPIO) return 1; else if (mst_gpio_cfg[fd].l_pin_type == SYS_GPIO) return 0; else return -1; #endif } int rt_write(int fd, char *buf, int len) { int value; if (len <= 0 || buf == NULL) { return -1; } if (is_rtdm_device(fd) == 1) { value = atoi(buf); if (value != 0 && value != 1) { dp_err_n_c("value :%d ERR, Please enter '0' or '1'", value); return -1; } return write(fd, &value, sizeof(value)); } else { return write(fd, buf, len); } } int rt_read(int _l_fd, int *_l_state, int len) { int ret = 0, l_val = -1; if (is_rtdm_device(_l_fd) == 1) { ret = read(_l_fd, &l_val, sizeof(l_val)); if (ret < 0 || ret != sizeof(l_val)) { dp_err_n_c("Failed to read from RTDM device, ret=%d", ret); return -1; } *_l_state = l_val; } else { ret = read(_l_fd, &l_val, len); dp_err_n_c("ret=%d", ret); if (ret < 0) { dp_err_n_c("Failed to read from regular device"); return -1; } *_l_state = l_val; } return ret; } int rtdm_gpio_init(int gpio, int direction) { char path[64]; int fd = -1, ret; int value = 1; snprintf(path, sizeof(path), "/dev/rtdm/3604000.pinctrl/gpio%d", gpio); if (GPIO_INPUT == direction) { fd = open(path, O_RDWR | O_NONBLOCK); } else { fd = open(path, O_RDWR); } if (fd < 0) { dp_err_n_c("gpio [%d] open error", gpio); perror("open"); return -1; } if (GPIO_INPUT == direction) { ret = ioctl(fd, GPIO_RTIOC_DIR_IN, &value); } else { ret = ioctl(fd, GPIO_RTIOC_DIR_OUT, &value); } if (ret < 0) { dp_err_n_c("gpio [%d] ioctl error", gpio); perror("gpio ioctl err"); close(fd); return -1; } return fd; } int gpio_init(void) { int i; #if (0 == NEW_GOIO_VERSION) for (i = 0; i < DO_NUM; i++) { gpio_val_fd[i] = rtdm_gpio_init(gpio_val[i], GPIO_OUTPUT); if (gpio_val_fd[i] < 0) { gpio_val_fd[i] = sysfs_gpio_init(gpio_val[i], GPIO_OUTPUT); dp_info_n_c("gpio_val_fd[%02d] = %d", i, gpio_val_fd[i]); if (gpio_val_fd[i] < 0) { dp_err_n_c("gpio_val_fd[%d] error", i); gpio_val_fd[i] = -1; gpio_dev_type[i] = -1; return -1; } } else { gpio_dev_type[i] = gpio_val_fd[i]; // 保存RTDM设备类型句柄,这里有风险,fd句柄可能为0 } } msleep(10); // 延时10ms kc_kout0_stu = 0; for (i = DO_OUT1; i < DO_NUM; i++) { rt_write(gpio_val_fd[i], "1", 2); } return 0; #else for (i = 0; i < GPIO_NUM_TOTAL; i++) { mst_gpio_cfg[i].l_pin_fd = rtdm_gpio_init(mst_gpio_cfg[i].l_pin_num, mst_gpio_cfg[i].l_pin_dir); if (mst_gpio_cfg[i].l_pin_fd < 0) { mst_gpio_cfg[i].l_pin_fd = sysfs_gpio_init(mst_gpio_cfg[i].l_pin_num, mst_gpio_cfg[i].l_pin_dir); if (mst_gpio_cfg[i].l_pin_fd < 0) { dp_err_n_c("mst_gpio_cfg[%d].l_pin_fd error", i); mst_gpio_cfg[i].l_pin_fd = -1; mst_gpio_cfg[i].l_pin_type = -1; return -1; } } else { mst_gpio_cfg[i].l_pin_type = mst_gpio_cfg[i].l_pin_fd; // 保存RTDM设备类型句柄,这里有风险,fd句柄可能为0 } } msleep(10); // 延时10ms kc_kout0_stu = 0; for (i = 0; i < (DO_NUM - 1); i++) { rt_write(mst_gpio_cfg[i].l_pin_fd, "1", 2); } return 0; #endif } int gpio_exit(void) { int i; for (i = 0; i < DO_NUM; i++) { #if (0 == NEW_GOIO_VERSION) if (gpio_val_fd[i] >= 0) { close(gpio_val_fd[i]); gpio_val_fd[i] = -1; } sysfs_gpio_unexport(gpio_val[i]); #else if (mst_gpio_cfg[i].l_pin_fd >= 0) { close(mst_gpio_cfg[i].l_pin_fd); mst_gpio_cfg[i].l_pin_fd = -1; } sysfs_gpio_unexport(mst_gpio_cfg[i].l_pin_num); #endif } return 0; } /****************************************************************************** 函数名称: gpio_get_di 函数版本: 01.01 创建作者: 创建日期: 2014-11-28 函数说明: 得到开入的状态 参数说明: 无 返回值: 返回开入的状态,每个bit代表一个开入量。 修改记录: */ unsigned int gpio_get_di(void) { unsigned int dw = 0; dw = g_yx_buf[0]; // 这里保存的是共享内存的yx值,156us更新一次 return change_di_ch(~dw); // 取反---因为没有短接时,值为1. 所以要取反为0才行 } /****************************************************************************** 函数名称: gpio_di_fj 函数版本: 01.01 创建作者: 创建日期: 2014-11-28 函数说明: 读取开出返校遥信值,控制板遥信为YX17~YX18 YX17:选择, YX18:执行 参数说明: 无 返回值: 返回遥信值 修改记录: */ #ifdef DO_KOUT_CHECK unsigned short gpio_di_fj(unsigned char index) //(void) #else unsigned short gpio_di_fj(void) #endif { unsigned int di = 0; unsigned short ret = 0; di = gpio_get_di(); #ifdef DO_KOUT_CHECK ret = (unsigned short)((di >> index) & 0x0001); #else ret = (unsigned short)((di >> 23) & 0x0001); #endif return ret; } /** * @brief 读取gpio的状态 * @author lch (lch_work@foxmail.com) * @version 1.0 * @date 20260311 * @param[in/out] {uint8_t} _uc_idx 下标 * @return * int * @retval none * * @warning none * @note none */ int gpioio_get_gpio_status(uint8_t _uc_idx) { int ret, l_io_state = 0; if (_uc_idx < DO_IN_PRESET || _uc_idx > GPIO_INT_M4) return -1; ret = rt_read(mst_gpio_cfg[_uc_idx].l_pin_fd, &l_io_state, sizeof(l_io_state)); if (ret < 0) { dp_err_n_c("l_io_state: %d\r\n", l_io_state); return -2; } return l_io_state; } /****************************************************************************** 函数名称: gpio_kout_do 函数版本: 01.01 创建作者: 创建日期: 2014-11-28 函数说明: 开出 参数说明: on: 1开出, 0回收 kout: 那一路 返回值: 无 修改记录: */ int gpio_kout_do(int on, unsigned int kout) { int l_ret = -1; if (kout > DO_OUT_PRESET) return; #if (0 == NEW_GOIO_VERSION) if (on) { l_ret = rt_write(gpio_val_fd[kout + DO_OUT0], "0", 2); // dp_info_n_c("kout = %d, on = %d, l_ret = %d", kout, on, l_ret); } else { l_ret = rt_write(gpio_val_fd[kout + DO_OUT0], "1", 2); // dp_info_n_c("kout = %d, on = %d, l_ret = %d", kout, on, l_ret); } #else if (on) { l_ret = rt_write(mst_gpio_cfg[kout + DO_OUT0].l_pin_fd, "0", 2); // dp_info_n_c("kout = %d, on = %d, l_ret = %d", kout, on, l_ret); } else { l_ret = rt_write(mst_gpio_cfg[kout + DO_OUT0].l_pin_fd, "1", 2); // dp_info_n_c("kout = %d, on = %d, l_ret = %d", kout, on, l_ret); } #endif return l_ret; } /****************************************************************************** 函数名称: gpio_get_wirelessin 函数版本: 01.01 创建作者: sunxi 创建日期: 2008-09-16 函数说明: 得到无线遥控的状态。 参数说明: 无 返回值: 返回开入的状态,每个bit代表一个开入量。 修改记录: */ unsigned int gpio_get_wirelessin(void) { register unsigned int dw = 0; return dw; } unsigned int gpio_get_version(void) { register unsigned int dw = 0; return dw; } unsigned int gpio_get_addr(void) { register unsigned int dw = 0; return dw; } void _led_run_err(void) { // 上电就亮错误灯,有错误就继续亮没有就熄灭 static uint8 err_led = 2; if (rt_err_count()) { // 错误指示灯常亮且运行熄灭 if (!(err_led & 0x01)) { err_led |= 1; // write(gpio_val_fd_other[ERR_LED], "0", 2); // write(gpio_val_fd_other[RUN_LED], "1", 2); } return; } if (err_led) { err_led = 0; // write(gpio_val_fd_other[ERR_LED], "1", 2); } // 运行指示灯,每隔1s改变状态一次 if (!gpio_run_led_val) { gpio_run_led_val = 1; // write(gpio_val_fd_other[RUN_LED], "0", 2); } else { gpio_run_led_val = 0; // write(gpio_val_fd_other[RUN_LED], "1", 2); } } void esam_power_ctrl(int on) { // if (on) // write(gpio_val_fd_other[ESAM_PWR], "1", 2); // else // write(gpio_val_fd_other[ESAM_PWR], "0", 2); } /*------------------------------ 内部函数 ------------------------------------- */ /*------------------------------ 测试函数 ------------------------------------- */ #if (0) int test_read_pin(void) { int ret, l_io_state = 0; dp_info_n_c("test_read_pin!"); ret = rt_read(mst_gpio_cfg[GPIO_INT_M1].l_pin_fd, &l_io_state, sizeof(l_io_state)); dp_info_n_c("ret: %d", ret); if (ret > 0) { dp_info_n_c("l_io_state: %d\r\n", l_io_state); } else { dp_err_n_c("l_io_state: %d\r\n", l_io_state); } ret = rt_read(mst_gpio_cfg[GPIO_INT_M3].l_pin_fd, &l_io_state, sizeof(l_io_state)); dp_info_n_c("ret: %d", ret); if (ret > 0) { dp_info_n_c("l_io_state: %d\r\n", l_io_state); } else { dp_err_n_c("l_io_state: %d\r\n", l_io_state); } ret = rt_read(mst_gpio_cfg[GPIO_INT_M4].l_pin_fd, &l_io_state, sizeof(l_io_state)); dp_info_n_c("ret: %d", ret); if (ret > 0) { dp_info_n_c("l_io_state: %d\r\n", l_io_state); } else { dp_err_n_c("l_io_state: %d\r\n", l_io_state); } } #endif