gpio.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673
  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. ret = ioctl(fd, GPIO_RTIOC_DIR_IN, &value);
  290. }
  291. else
  292. {
  293. ret = ioctl(fd, GPIO_RTIOC_DIR_OUT, &value);
  294. }
  295. if (ret < 0)
  296. {
  297. perror("ioctl DIR_OUT");
  298. close(fd);
  299. return -1;
  300. }
  301. return fd;
  302. }
  303. int gpio_init(void)
  304. {
  305. #define GPIO_OUTPUT 1
  306. int i;
  307. for (i = 0; i < DO_NUM; i++)
  308. {
  309. gpio_val_fd[i] = rtdm_gpio_init(gpio_val[i], GPIO_OUTPUT);
  310. if (gpio_val_fd[i] < 0)
  311. {
  312. gpio_val_fd[i] = sysfs_gpio_init(gpio_val[i], GPIO_OUTPUT);
  313. dp_info_n_c("gpio_val_fd[%02d] = %d", i, gpio_val_fd[i]);
  314. if (gpio_val_fd[i] < 0)
  315. {
  316. dp_err_n_c("gpio_val_fd[%d] error", i);
  317. gpio_val_fd[i] = -1;
  318. gpio_dev_type[i] = -1;
  319. return -1;
  320. }
  321. }
  322. else
  323. {
  324. gpio_dev_type[i] = gpio_val_fd[i]; // 保存RTDM设备类型句柄,这里有风险,fd句柄可能为0
  325. }
  326. }
  327. msleep(10); // 延时10ms
  328. kc_kout0_stu = 0;
  329. for (i = DO_OUT1; i < DO_NUM; i++)
  330. {
  331. rt_write(gpio_val_fd[i], "1", 2);
  332. }
  333. return 0;
  334. }
  335. int gpio_exit(void)
  336. {
  337. int i;
  338. for (i = 0; i < DO_NUM; i++)
  339. {
  340. if (gpio_val_fd[i] >= 0)
  341. {
  342. close(gpio_val_fd[i]);
  343. gpio_val_fd[i] = -1;
  344. }
  345. sysfs_gpio_unexport(gpio_val[i]);
  346. }
  347. return 0;
  348. }
  349. /******************************************************************************
  350. 函数名称: gpio_get_di
  351. 函数版本: 01.01
  352. 创建作者:
  353. 创建日期: 2014-11-28
  354. 函数说明: 得到开入的状态
  355. 参数说明: 无
  356. 返回值: 返回开入的状态,每个bit代表一个开入量。
  357. 修改记录:
  358. */
  359. unsigned int gpio_get_di(void)
  360. {
  361. unsigned int dw = 0;
  362. dw = g_yx_buf[0]; // 这里保存的是共享内存的yx值,156us更新一次
  363. return change_di_ch(~dw); // 取反---因为没有短接时,值为1. 所以要取反为0才行
  364. }
  365. /******************************************************************************
  366. 函数名称: gpio_di_fj
  367. 函数版本: 01.01
  368. 创建作者:
  369. 创建日期: 2014-11-28
  370. 函数说明: 读取开出返校遥信值,控制板遥信为YX17~YX18
  371. YX17:选择, YX18:执行
  372. 参数说明: 无
  373. 返回值: 返回遥信值
  374. 修改记录:
  375. */
  376. #ifdef DO_KOUT_CHECK
  377. unsigned short gpio_di_fj(unsigned char index) //(void)
  378. #else
  379. unsigned short gpio_di_fj(void)
  380. #endif
  381. {
  382. unsigned int di = 0;
  383. unsigned short ret = 0;
  384. di = gpio_get_di();
  385. #ifdef DO_KOUT_CHECK
  386. ret = (unsigned short)((di >> index) & 0x0001);
  387. #else
  388. ret = (unsigned short)((di >> 23) & 0x0001);
  389. #endif
  390. return ret;
  391. }
  392. /**
  393. * @brief 读取预置返校的状态
  394. * @author lch (lch_work@foxmail.com)
  395. * @version 1.0
  396. * @date 20251229
  397. * @return * int
  398. * @retval none
  399. *
  400. * @warning none
  401. * @note none
  402. */
  403. int gpioio_get_perset_status(void)
  404. {
  405. char buf[2] = {0};
  406. int ret = 0;
  407. if (gpio_val_fd[DO_IN_PRESET] < 0)
  408. {
  409. dp_err_n_c("gpio_val_fd[DO_IN_PRESET] = %d, not initialized", gpio_val_fd[DO_IN_PRESET]);
  410. return -1;
  411. }
  412. ret = read(gpio_val_fd[DO_IN_PRESET], buf, sizeof(buf));
  413. if (ret > 0)
  414. {
  415. return buf[0] - '0'; // 字符转换为数字
  416. }
  417. return -1;
  418. }
  419. /******************************************************************************
  420. 函数名称: gpio_kout_do
  421. 函数版本: 01.01
  422. 创建作者:
  423. 创建日期: 2014-11-28
  424. 函数说明: 开出
  425. 参数说明: on: 1开出, 0回收
  426. kout: 那一路
  427. 返回值: 无
  428. 修改记录:
  429. */
  430. int gpio_kout_do(int on, unsigned int kout)
  431. {
  432. int l_ret = -1;
  433. if (kout > DO_OUT_PRESET)
  434. return;
  435. if (on)
  436. {
  437. l_ret = rt_write(gpio_val_fd[kout + DO_OUT0], "0", 2);
  438. // dp_info_n_c("kout = %d, on = %d, l_ret = %d", kout, on, l_ret);
  439. }
  440. else
  441. {
  442. l_ret = rt_write(gpio_val_fd[kout + DO_OUT0], "1", 2);
  443. // dp_info_n_c("kout = %d, on = %d, l_ret = %d", kout, on, l_ret);
  444. }
  445. return l_ret;
  446. }
  447. /******************************************************************************
  448. 函数名称: gpio_get_wirelessin
  449. 函数版本: 01.01
  450. 创建作者: sunxi
  451. 创建日期: 2008-09-16
  452. 函数说明: 得到无线遥控的状态。
  453. 参数说明: 无
  454. 返回值: 返回开入的状态,每个bit代表一个开入量。
  455. 修改记录:
  456. */
  457. unsigned int gpio_get_wirelessin(void)
  458. {
  459. register unsigned int dw = 0;
  460. return dw;
  461. }
  462. unsigned int gpio_get_version(void)
  463. {
  464. register unsigned int dw = 0;
  465. return dw;
  466. }
  467. unsigned int gpio_get_addr(void)
  468. {
  469. register unsigned int dw = 0;
  470. return dw;
  471. }
  472. void _led_run_err(void)
  473. {
  474. // 上电就亮错误灯,有错误就继续亮没有就熄灭
  475. static uint8 err_led = 2;
  476. if (rt_err_count())
  477. {
  478. // 错误指示灯常亮且运行熄灭
  479. if (!(err_led & 0x01))
  480. {
  481. err_led |= 1;
  482. // write(gpio_val_fd_other[ERR_LED], "0", 2);
  483. // write(gpio_val_fd_other[RUN_LED], "1", 2);
  484. }
  485. return;
  486. }
  487. if (err_led)
  488. {
  489. err_led = 0;
  490. // write(gpio_val_fd_other[ERR_LED], "1", 2);
  491. }
  492. // 运行指示灯,每隔1s改变状态一次
  493. if (!gpio_run_led_val)
  494. {
  495. gpio_run_led_val = 1;
  496. // write(gpio_val_fd_other[RUN_LED], "0", 2);
  497. }
  498. else
  499. {
  500. gpio_run_led_val = 0;
  501. // write(gpio_val_fd_other[RUN_LED], "1", 2);
  502. }
  503. }
  504. void esam_power_ctrl(int on)
  505. {
  506. // if (on)
  507. // write(gpio_val_fd_other[ESAM_PWR], "1", 2);
  508. // else
  509. // write(gpio_val_fd_other[ESAM_PWR], "0", 2);
  510. }
  511. /*------------------------------ 内部函数 -------------------------------------
  512. */
  513. /*------------------------------ 测试函数 -------------------------------------
  514. */
  515. #ifdef _GPIO_DEBUG
  516. #include "ustimer.h"
  517. #include "rt.h"
  518. int test_kc_function(void)
  519. {
  520. rt_write(gpio_val_fd[DO_OUT_PRESET], "0", 2); // 预置动作
  521. char gpio_state[2];
  522. int ret;
  523. sleep(1);
  524. #if (1)
  525. // 读取GPIO状态
  526. ret = rt_read(gpio_val_fd[DO_IN_PRESET], gpio_state, sizeof(gpio_state));
  527. printf("ret: %d\n", ret);
  528. if (ret > 0)
  529. {
  530. gpio_state[ret] = '\0'; // 添加字符串结束符
  531. printf("PRESET: %s\n", gpio_state); // 应该是"0"或"1"
  532. }
  533. #endif
  534. rt_write(gpio_val_fd[DO_OUT0], "0", 2);
  535. sleep(1);
  536. rt_write(gpio_val_fd[DO_OUT0], "1", 2);
  537. rt_write(gpio_val_fd[DO_OUT1], "0", 2);
  538. sleep(1);
  539. rt_write(gpio_val_fd[DO_OUT1], "1", 2);
  540. #if (0)
  541. rt_write(gpio_val_fd[DO_OUT2], "0", 2);
  542. sleep(5);
  543. rt_write(gpio_val_fd[DO_OUT2], "1", 2);
  544. rt_write(gpio_val_fd[DO_OUT3], "0", 2);
  545. sleep(5);
  546. rt_write(gpio_val_fd[DO_OUT3], "1", 2);
  547. #endif
  548. rt_write(gpio_val_fd[DO_OUT_PRESET], "1", 2); // 预置动作
  549. sleep(1);
  550. #if (1)
  551. // 读取GPIO状态
  552. ret = rt_read(gpio_val_fd[DO_IN_PRESET], gpio_state, sizeof(gpio_state));
  553. printf("ret: %d\n", ret);
  554. if (ret > 0)
  555. {
  556. gpio_state[ret] = '\0'; // 添加字符串结束符
  557. printf("PRESET: %s\n", gpio_state); // 应该是"0"或"1"
  558. }
  559. #endif
  560. #if (0)
  561. rt_write(gpio_val_fd[DO_OUT4], "0", 2);
  562. sleep(5);
  563. rt_write(gpio_val_fd[DO_OUT4], "1", 2);
  564. rt_write(gpio_val_fd[DO_OUT5], "0", 2);
  565. sleep(5);
  566. rt_write(gpio_val_fd[DO_OUT5], "1", 2);
  567. rt_write(gpio_val_fd[DO_OUT6], "0", 2);
  568. sleep(5);
  569. rt_write(gpio_val_fd[DO_OUT6], "1", 2);
  570. rt_write(gpio_val_fd[DO_OUT7], "0", 2);
  571. sleep(5);
  572. rt_write(gpio_val_fd[DO_OUT7], "1", 2);
  573. #endif
  574. }
  575. #endif