gpio.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674
  1. /******************************************************************************
  2. 版权所有:
  3. 文件名称: gpio.c
  4. 文件版本: 01.01
  5. 创建作者: zhaoyang
  6. 创建日期: 2023-12-14
  7. 功能说明: gpio驱动程序。
  8. 其它说明:
  9. 修改记录:
  10. [new]-->applay
  11. B_DO_ADJ --> GPIOD_17 --> gpio113 预置返校
  12. B_DO_0 --> GPIOD_03 --> gpio99 预置
  13. B_DO_1 --> GPIOD_19 --> gpio115
  14. B_DO_2 --> GPIOD_02 --> gpio98
  15. B_DO_3 --> GPIOD_09 --> gpio105
  16. B_DO_4 --> GPIOD_18 --> gpio114
  17. B_DO_5 --> GPIOD_16 --> gpio112
  18. B_DO_6 --> GPIOD_07 --> gpio103
  19. B_DO_7 --> GPIOD_08 --> gpio104
  20. B_DO_8 --> GPIOD_06 --> gpio102
  21. T536 start ↓↓↓↓↓↓
  22. RUN_LED --> PB7 --> gpio39
  23. ERR_LED --> PF4 --> gpio164
  24. ESAM_PWR --> PL7 --> gpio159
  25. LINE_LOSS_SET --> PM5 --> gpio389
  26. T536 end ↑↑↑↑↑↑
  27. */
  28. /*------------------------------- 头文件 --------------------------------------
  29. */
  30. #include "bspconfig.h"
  31. #include "gpio.h"
  32. #include "head.h"
  33. #include <rtdm/gpio.h>
  34. /*------------------------------- 宏定义 --------------------------------------
  35. */
  36. #if CFG_BSP_DEBUG
  37. #define _GPIO_DEBUG
  38. #endif
  39. #define GPIO_LOW 0
  40. /*------------------------------ 全局变量 -------------------------------------
  41. */
  42. typedef enum
  43. {
  44. SYS_GPIO = 0,
  45. RTDM_GPIO = 1,
  46. } GPIO_TYPE;
  47. unsigned short kc_kout0_stu;
  48. extern uint32_t g_yx_buf[2]; // 预留64个遥信
  49. /*------------------------------ 函数声明 -------------------------------------
  50. */
  51. extern unsigned int change_di_ch(unsigned int di);
  52. int gpio_val_fd[DO_NUM];
  53. int gpio_dev_type[DO_NUM] = {
  54. SYS_GPIO,
  55. }; // 0:系统GPIO, 1:RTDM GPIO
  56. /* 开出gpio */
  57. const int gpio_val[DO_NUM] = {115, 98, 105, 114, 112, 103, 104, 102, 99, 113};
  58. // static int gpio_watchdog_val = 0;
  59. static int gpio_run_led_val = 0;
  60. /*------------------------------ 外部函数 -------------------------------------
  61. */
  62. int sysfs_gpio_unexport(int gpio)
  63. {
  64. char path[64];
  65. int fd;
  66. snprintf(path, sizeof(path), "/sys/class/gpio/unexport");
  67. fd = open(path, O_WRONLY);
  68. if (fd < 0)
  69. {
  70. perror("Failed to open unexport");
  71. return -1;
  72. }
  73. char buf[16];
  74. snprintf(buf, sizeof(buf), "%d", gpio);
  75. if (write(fd, buf, strlen(buf)) < 0)
  76. {
  77. perror("Failed to set GPIO");
  78. close(fd);
  79. return -1;
  80. }
  81. close(fd);
  82. return 0;
  83. }
  84. int sysfs_gpio_export(int gpio)
  85. {
  86. char path[64];
  87. int fd;
  88. // 检查是否已导出
  89. snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d", gpio);
  90. if (access(path, F_OK) == 0)
  91. {
  92. sysfs_gpio_unexport(gpio); // bugfix: 避免重复导出
  93. msleep(50); // 短暂等待让内核处理
  94. }
  95. snprintf(path, sizeof(path), "/sys/class/gpio/export");
  96. fd = open(path, O_WRONLY);
  97. if (fd < 0)
  98. {
  99. perror("Failed to open export");
  100. return -1;
  101. }
  102. char buf[16];
  103. snprintf(buf, sizeof(buf), "%d", gpio);
  104. if (write(fd, buf, strlen(buf)) < 0)
  105. {
  106. perror("Failed to export GPIO");
  107. close(fd);
  108. return -2;
  109. }
  110. close(fd);
  111. return 0;
  112. }
  113. int sysfs_gpio_set_direction(int gpio, int is_output)
  114. {
  115. char path[64];
  116. int fd;
  117. snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/direction", gpio);
  118. fd = open(path, O_WRONLY);
  119. if (fd < 0)
  120. {
  121. perror("Failed to open direction");
  122. return -1;
  123. }
  124. if (write(fd, is_output ? "out" : "in", is_output ? 3 : 2) < 0)
  125. {
  126. perror("Failed to set direction");
  127. close(fd);
  128. return -1;
  129. }
  130. close(fd);
  131. return 0;
  132. }
  133. int sysfs_gpio_set_edge_detect(int gpio, int edge)
  134. {
  135. char path[64];
  136. int fd;
  137. snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/edge", gpio);
  138. fd = open(path, O_WRONLY);
  139. if (fd < 0)
  140. {
  141. perror("Failed to open edge");
  142. close(fd);
  143. return -1;
  144. }
  145. if (write(fd, edge, strlen(edge)) < 0)
  146. {
  147. perror("Failed to set edge");
  148. close(fd);
  149. return -1;
  150. }
  151. close(fd);
  152. return 0;
  153. }
  154. int sysfs_gpio_set_value(int gpio, int value)
  155. {
  156. char path[64];
  157. int fd = -1;
  158. snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/value", gpio);
  159. fd = open(path, O_WRONLY);
  160. if (fd < 0)
  161. {
  162. perror("Failed to open value");
  163. return -1;
  164. }
  165. if (write(fd, value ? "1" : "0", 1) < 0)
  166. {
  167. perror("Failed to set value");
  168. close(fd);
  169. return -1;
  170. }
  171. return fd;
  172. }
  173. int sysfs_gpio_init(int gpio, int direction)
  174. {
  175. int ret;
  176. ret = sysfs_gpio_export(gpio);
  177. if (ret < 0)
  178. {
  179. dp_err_n_c("sysfs_gpio_export error ret = %d!", ret);
  180. return -1;
  181. }
  182. ret = sysfs_gpio_set_direction(gpio, direction);
  183. if (ret < 0)
  184. {
  185. dp_err_n_c("sysfs_gpio_set_direction error");
  186. }
  187. return sysfs_gpio_set_value(gpio, GPIO_LOW); // 初始化IO为低电平
  188. }
  189. int is_rtdm_device(int fd)
  190. {
  191. if (gpio_dev_type[fd] > SYS_GPIO)
  192. return 1;
  193. else if (gpio_dev_type[fd] == SYS_GPIO)
  194. return 0;
  195. else
  196. return -1;
  197. }
  198. int rt_write(int fd, char *buf, int len)
  199. {
  200. int value;
  201. if (len <= 0 || buf == NULL)
  202. {
  203. return -1;
  204. }
  205. if (is_rtdm_device(fd) == 1)
  206. {
  207. // Xenomai RTDM设备:需要转换为二进制值
  208. value = atoi(buf);
  209. if (value != 0 && value != 1)
  210. {
  211. dp_err_n_c("value :%d ERR, Please enter '0' or '1'", value);
  212. return -1;
  213. }
  214. return write(fd, &value, sizeof(value));
  215. }
  216. else
  217. {
  218. // 常规系统设备:直接传递字符串
  219. return write(fd, buf, len);
  220. }
  221. }
  222. int rt_read(int fd, char *buf, int len)
  223. {
  224. int ret = 0;
  225. if (is_rtdm_device(fd) == 1)
  226. {
  227. dp_info_n_c("fd = %d", fd);
  228. // Xenomai RTDM设备:读取二进制值
  229. int value = 0;
  230. // 从RTDM设备读取二进制状态(通常是4字节的int)
  231. ret = read(fd, &value, sizeof(value));
  232. dp_info_n_c("ret = %d", ret);
  233. if (ret != sizeof(value))
  234. {
  235. dp_err_n_c("Failed to read from RTDM device, ret=%d", ret);
  236. return -1;
  237. }
  238. // 将二进制值转换为字符'0'或'1'
  239. if (value == 0)
  240. {
  241. buf[0] = '0';
  242. }
  243. else if (value == 1)
  244. {
  245. buf[0] = '1';
  246. }
  247. else
  248. {
  249. dp_err_n_c("Unexpected value from RTDM device: %d", value);
  250. return -1;
  251. }
  252. buf[1] = '\0'; // 字符串结束符
  253. return 1; // 读取到的字符数
  254. }
  255. else
  256. {
  257. // 常规系统设备:直接读取字符串
  258. ret = read(fd, buf, len);
  259. dp_err_n_c("ret=%d", ret);
  260. if (ret < 0)
  261. {
  262. dp_err_n_c("Failed to read from regular device");
  263. return -1;
  264. }
  265. buf[ret] = '\0'; // 确保字符串正确结束
  266. // 移除可能的换行符
  267. if (ret > 0 && buf[ret - 1] == '\n')
  268. {
  269. buf[ret - 1] = '\0';
  270. ret--;
  271. }
  272. return ret; // 返回读取的字符数
  273. }
  274. }
  275. int rtdm_gpio_init(int gpio, int direction)
  276. {
  277. char path[64];
  278. int fd = -1, ret;
  279. int value = 1;
  280. snprintf(path, sizeof(path), "/dev/rtdm/3604000.pinctrl/gpio%d", gpio);
  281. fd = open(path, O_RDWR);
  282. if (fd < 0)
  283. {
  284. perror("open");
  285. return -1;
  286. }
  287. if (113 == gpio) /* 预置返校是开入 */
  288. {
  289. dp_info_n_c("gpio = %d, fd = %d", gpio, fd);
  290. ret = ioctl(fd, GPIO_RTIOC_DIR_IN, &value);
  291. }
  292. else
  293. {
  294. ret = ioctl(fd, GPIO_RTIOC_DIR_OUT, &value);
  295. }
  296. if (ret < 0)
  297. {
  298. perror("ioctl DIR_OUT");
  299. close(fd);
  300. return -1;
  301. }
  302. return fd;
  303. }
  304. int gpio_init(void)
  305. {
  306. #define GPIO_OUTPUT 1
  307. int i;
  308. for (i = 0; i < DO_NUM; i++)
  309. {
  310. gpio_val_fd[i] = rtdm_gpio_init(gpio_val[i], GPIO_OUTPUT);
  311. if (gpio_val_fd[i] < 0)
  312. {
  313. gpio_val_fd[i] = sysfs_gpio_init(gpio_val[i], GPIO_OUTPUT);
  314. dp_info_n_c("gpio_val_fd[%02d] = %d", i, gpio_val_fd[i]);
  315. if (gpio_val_fd[i] < 0)
  316. {
  317. dp_err_n_c("gpio_val_fd[%d] error", i);
  318. gpio_val_fd[i] = -1;
  319. gpio_dev_type[i] = -1;
  320. return -1;
  321. }
  322. }
  323. else
  324. {
  325. gpio_dev_type[i] = gpio_val_fd[i]; // 保存RTDM设备类型句柄,这里有风险,fd句柄可能为0
  326. }
  327. }
  328. msleep(10); // 延时10ms
  329. kc_kout0_stu = 0;
  330. for (i = DO_OUT1; i < DO_NUM; i++)
  331. {
  332. rt_write(gpio_val_fd[i], "1", 2);
  333. }
  334. return 0;
  335. }
  336. int gpio_exit(void)
  337. {
  338. int i;
  339. for (i = 0; i < DO_NUM; i++)
  340. {
  341. if (gpio_val_fd[i] >= 0)
  342. {
  343. close(gpio_val_fd[i]);
  344. gpio_val_fd[i] = -1;
  345. }
  346. sysfs_gpio_unexport(gpio_val[i]);
  347. }
  348. return 0;
  349. }
  350. /******************************************************************************
  351. 函数名称: gpio_get_di
  352. 函数版本: 01.01
  353. 创建作者:
  354. 创建日期: 2014-11-28
  355. 函数说明: 得到开入的状态
  356. 参数说明: 无
  357. 返回值: 返回开入的状态,每个bit代表一个开入量。
  358. 修改记录:
  359. */
  360. unsigned int gpio_get_di(void)
  361. {
  362. unsigned int dw = 0;
  363. dw = g_yx_buf[0]; // 这里保存的是共享内存的yx值,156us更新一次
  364. return change_di_ch(~dw); // 取反---因为没有短接时,值为1. 所以要取反为0才行
  365. }
  366. /******************************************************************************
  367. 函数名称: gpio_di_fj
  368. 函数版本: 01.01
  369. 创建作者:
  370. 创建日期: 2014-11-28
  371. 函数说明: 读取开出返校遥信值,控制板遥信为YX17~YX18
  372. YX17:选择, YX18:执行
  373. 参数说明: 无
  374. 返回值: 返回遥信值
  375. 修改记录:
  376. */
  377. #ifdef DO_KOUT_CHECK
  378. unsigned short gpio_di_fj(unsigned char index) //(void)
  379. #else
  380. unsigned short gpio_di_fj(void)
  381. #endif
  382. {
  383. unsigned int di = 0;
  384. unsigned short ret = 0;
  385. di = gpio_get_di();
  386. #ifdef DO_KOUT_CHECK
  387. ret = (unsigned short)((di >> index) & 0x0001);
  388. #else
  389. ret = (unsigned short)((di >> 23) & 0x0001);
  390. #endif
  391. return ret;
  392. }
  393. /**
  394. * @brief 读取预置返校的状态
  395. * @author lch (lch_work@foxmail.com)
  396. * @version 1.0
  397. * @date 20251229
  398. * @return * int
  399. * @retval none
  400. *
  401. * @warning none
  402. * @note none
  403. */
  404. int gpioio_get_perset_status(void)
  405. {
  406. char buf[2] = {0};
  407. int ret = 0;
  408. if (gpio_val_fd[DO_IN_PRESET] < 0)
  409. {
  410. dp_err_n_c("gpio_val_fd[DO_IN_PRESET] = %d, not initialized", gpio_val_fd[DO_IN_PRESET]);
  411. return -1;
  412. }
  413. ret = read(gpio_val_fd[DO_IN_PRESET], buf, sizeof(buf));
  414. if (ret > 0)
  415. {
  416. return buf[0] - '0'; // 字符转换为数字
  417. }
  418. return -1;
  419. }
  420. /******************************************************************************
  421. 函数名称: gpio_kout_do
  422. 函数版本: 01.01
  423. 创建作者:
  424. 创建日期: 2014-11-28
  425. 函数说明: 开出
  426. 参数说明: on: 1开出, 0回收
  427. kout: 那一路
  428. 返回值: 无
  429. 修改记录:
  430. */
  431. int gpio_kout_do(int on, unsigned int kout)
  432. {
  433. int l_ret = -1;
  434. if (kout > DO_OUT_PRESET)
  435. return;
  436. if (on)
  437. {
  438. l_ret = rt_write(gpio_val_fd[kout + DO_OUT0], "0", 2);
  439. // dp_info_n_c("kout = %d, on = %d, l_ret = %d", kout, on, l_ret);
  440. }
  441. else
  442. {
  443. l_ret = rt_write(gpio_val_fd[kout + DO_OUT0], "1", 2);
  444. // dp_info_n_c("kout = %d, on = %d, l_ret = %d", kout, on, l_ret);
  445. }
  446. return l_ret;
  447. }
  448. /******************************************************************************
  449. 函数名称: gpio_get_wirelessin
  450. 函数版本: 01.01
  451. 创建作者: sunxi
  452. 创建日期: 2008-09-16
  453. 函数说明: 得到无线遥控的状态。
  454. 参数说明: 无
  455. 返回值: 返回开入的状态,每个bit代表一个开入量。
  456. 修改记录:
  457. */
  458. unsigned int gpio_get_wirelessin(void)
  459. {
  460. register unsigned int dw = 0;
  461. return dw;
  462. }
  463. unsigned int gpio_get_version(void)
  464. {
  465. register unsigned int dw = 0;
  466. return dw;
  467. }
  468. unsigned int gpio_get_addr(void)
  469. {
  470. register unsigned int dw = 0;
  471. return dw;
  472. }
  473. void _led_run_err(void)
  474. {
  475. // 上电就亮错误灯,有错误就继续亮没有就熄灭
  476. static uint8 err_led = 2;
  477. if (rt_err_count())
  478. {
  479. // 错误指示灯常亮且运行熄灭
  480. if (!(err_led & 0x01))
  481. {
  482. err_led |= 1;
  483. // write(gpio_val_fd_other[ERR_LED], "0", 2);
  484. // write(gpio_val_fd_other[RUN_LED], "1", 2);
  485. }
  486. return;
  487. }
  488. if (err_led)
  489. {
  490. err_led = 0;
  491. // write(gpio_val_fd_other[ERR_LED], "1", 2);
  492. }
  493. // 运行指示灯,每隔1s改变状态一次
  494. if (!gpio_run_led_val)
  495. {
  496. gpio_run_led_val = 1;
  497. // write(gpio_val_fd_other[RUN_LED], "0", 2);
  498. }
  499. else
  500. {
  501. gpio_run_led_val = 0;
  502. // write(gpio_val_fd_other[RUN_LED], "1", 2);
  503. }
  504. }
  505. void esam_power_ctrl(int on)
  506. {
  507. // if (on)
  508. // write(gpio_val_fd_other[ESAM_PWR], "1", 2);
  509. // else
  510. // write(gpio_val_fd_other[ESAM_PWR], "0", 2);
  511. }
  512. /*------------------------------ 内部函数 -------------------------------------
  513. */
  514. /*------------------------------ 测试函数 -------------------------------------
  515. */
  516. #ifdef _GPIO_DEBUG
  517. #include "ustimer.h"
  518. #include "rt.h"
  519. int test_kc_function(void)
  520. {
  521. rt_write(gpio_val_fd[DO_OUT_PRESET], "0", 2); // 预置动作
  522. char gpio_state[2];
  523. int ret;
  524. sleep(1);
  525. #if (1)
  526. // 读取GPIO状态
  527. ret = rt_read(gpio_val_fd[DO_IN_PRESET], gpio_state, sizeof(gpio_state));
  528. printf("ret: %d\n", ret);
  529. if (ret > 0)
  530. {
  531. gpio_state[ret] = '\0'; // 添加字符串结束符
  532. printf("PRESET: %s\n", gpio_state); // 应该是"0"或"1"
  533. }
  534. #endif
  535. rt_write(gpio_val_fd[DO_OUT0], "0", 2);
  536. sleep(1);
  537. rt_write(gpio_val_fd[DO_OUT0], "1", 2);
  538. rt_write(gpio_val_fd[DO_OUT1], "0", 2);
  539. sleep(1);
  540. rt_write(gpio_val_fd[DO_OUT1], "1", 2);
  541. #if (0)
  542. rt_write(gpio_val_fd[DO_OUT2], "0", 2);
  543. sleep(5);
  544. rt_write(gpio_val_fd[DO_OUT2], "1", 2);
  545. rt_write(gpio_val_fd[DO_OUT3], "0", 2);
  546. sleep(5);
  547. rt_write(gpio_val_fd[DO_OUT3], "1", 2);
  548. #endif
  549. rt_write(gpio_val_fd[DO_OUT_PRESET], "1", 2); // 预置动作
  550. sleep(1);
  551. #if (1)
  552. // 读取GPIO状态
  553. ret = rt_read(gpio_val_fd[DO_IN_PRESET], gpio_state, sizeof(gpio_state));
  554. printf("ret: %d\n", ret);
  555. if (ret > 0)
  556. {
  557. gpio_state[ret] = '\0'; // 添加字符串结束符
  558. printf("PRESET: %s\n", gpio_state); // 应该是"0"或"1"
  559. }
  560. #endif
  561. #if (0)
  562. rt_write(gpio_val_fd[DO_OUT4], "0", 2);
  563. sleep(5);
  564. rt_write(gpio_val_fd[DO_OUT4], "1", 2);
  565. rt_write(gpio_val_fd[DO_OUT5], "0", 2);
  566. sleep(5);
  567. rt_write(gpio_val_fd[DO_OUT5], "1", 2);
  568. rt_write(gpio_val_fd[DO_OUT6], "0", 2);
  569. sleep(5);
  570. rt_write(gpio_val_fd[DO_OUT6], "1", 2);
  571. rt_write(gpio_val_fd[DO_OUT7], "0", 2);
  572. sleep(5);
  573. rt_write(gpio_val_fd[DO_OUT7], "1", 2);
  574. #endif
  575. }
  576. #endif