ch423s.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  1. /**
  2. * @file ch423s.c
  3. * @brief
  4. * @author lch (lch_work@foxmail.com)
  5. * @version 1.0
  6. * @date 20251224
  7. *
  8. * @copyright Copyright (c) 2025 by OLE, All Rights Reserved.
  9. *
  10. * @par 修改日志:
  11. * <table>
  12. * <tr><th>Date <th>Version <th>Author <th>Description
  13. * <tr><td>20251224 <td>2.0 <td>test <td>内容
  14. * </table>
  15. */
  16. #include <fcntl.h>
  17. #include <sys/ioctl.h>
  18. #include <linux/i2c.h>
  19. #include <linux/i2c-dev.h>
  20. #include <errno.h>
  21. #include "head.h"
  22. #include "ch423s.h"
  23. #if defined IO_CHIP_CH423S
  24. /* 设置系统参数命令 */
  25. #define CH423_SYS_CMD 0x48 // 设置系统参数命令,默认方式
  26. #define BIT_SLEEP 0x30 // 低功耗睡眠控制 0正常工作 1睡眠模式
  27. #define BIT_INTENS 0x20 // 动态显示驱动亮度控制
  28. #define BIT_OD_OE 0x10 // 输出引脚 OC15~OC0 开漏输出使能 0推挽输出低电平和高电平 1开漏输出低电平和不输出
  29. #define BIT_X_INT 0x08 // 使能输入电平变化中断 0禁止输入电平变化中断 为1并且DEC_H为0允许从OC15引脚输出电平变化中断
  30. #define BIT_DEC_H 0x04 // 控制开漏输出引脚高8位的片选译码 0通用输出 1分时显示扫描计数器译码后
  31. #define BIT_DEC_L 0x02 // 控制开漏输出引脚低8位的片选译码 0通用输出 1分时显示扫描计数器译码后
  32. #define BIT_IO_OE 0x01 // 控制双向输入输出引脚的三态输出 0禁止输出 1允许输出
  33. /* 设置低8位开漏输出命令 */
  34. #define CH423_OC_L_CMD 0x44 // 设置低8位开漏输出命令,默认方式
  35. #define BIT_OC0_L_DAT 0x01 // OC0为0则使引脚输出低电平,为1则引脚不输出
  36. #define BIT_OC1_L_DAT 0x02 // OC1为0则使引脚输出低电平,为1则引脚不输出
  37. #define BIT_OC2_L_DAT 0x04 // OC2为0则使引脚输出低电平,为1则引脚不输出
  38. #define BIT_OC3_L_DAT 0x08 // OC3为0则使引脚输出低电平,为1则引脚不输出
  39. #define BIT_OC4_L_DAT 0x10 // OC4为0则使引脚输出低电平,为1则引脚不输出
  40. #define BIT_OC5_L_DAT 0x20 // OC5为0则使引脚输出低电平,为1则引脚不输出
  41. #define BIT_OC6_L_DAT 0x40 // OC6为0则使引脚输出低电平,为1则引脚不输出
  42. #define BIT_OC7_L_DAT 0x80 // OC7为0则使引脚输出低电平,为1则引脚不输出
  43. /* 设置高8位开漏输出命令 */
  44. #define CH423_OC_H_CMD 0x46 // 设置低8位开漏输出命令,默认方式
  45. #define BIT_OC8_L_DAT 0x01 // OC8为0则使引脚输出低电平,为1则引脚不输出
  46. #define BIT_OC9_L_DAT 0x02 // OC9为0则使引脚输出低电平,为1则引脚不输出
  47. #define BIT_OC10_L_DAT 0x04 // OC10为0则使引脚输出低电平,为1则引脚不输出
  48. #define BIT_OC11_L_DAT 0x08 // OC11为0则使引脚输出低电平,为1则引脚不输出
  49. #define BIT_OC12_L_DAT 0x10 // OC12为0则使引脚输出低电平,为1则引脚不输出
  50. #define BIT_OC13_L_DAT 0x20 // OC13为0则使引脚输出低电平,为1则引脚不输出
  51. #define BIT_OC14_L_DAT 0x40 // OC14为0则使引脚输出低电平,为1则引脚不输出
  52. #define BIT_OC15_L_DAT 0x80 // OC15为0则使引脚输出低电平,为1则引脚不输出
  53. /* 设置双向输入输出命令 */
  54. #define CH423_SET_IO_CMD 0x60 // 设置双向输入输出命令,默认方式
  55. #define BIT_IO0_DAT 0x01 // 写入双向输入输出引脚的输出寄存器,当IO_OE=1,IO0为0输出低电平,为1输出高电平
  56. #define BIT_IO1_DAT 0x02 // 写入双向输入输出引脚的输出寄存器,当IO_OE=1,IO1为0输出低电平,为1输出高电平
  57. #define BIT_IO2_DAT 0x04 // 写入双向输入输出引脚的输出寄存器,当IO_OE=1,IO2为0输出低电平,为1输出高电平
  58. #define BIT_IO3_DAT 0x08 // 写入双向输入输出引脚的输出寄存器,当IO_OE=1,IO3为0输出低电平,为1输出高电平
  59. #define BIT_IO4_DAT 0x10 // 写入双向输入输出引脚的输出寄存器,当IO_OE=1,IO4为0输出低电平,为1输出高电平
  60. #define BIT_IO5_DAT 0x20 // 写入双向输入输出引脚的输出寄存器,当IO_OE=1,IO5为0输出低电平,为1输出高电平
  61. #define BIT_IO6_DAT 0x40 // 写入双向输入输出引脚的输出寄存器,当IO_OE=1,IO6为0输出低电平,为1输出高电平
  62. #define BIT_IO7_DAT 0x80 // 写入双向输入输出引脚的输出寄存器,当IO_OE=1,IO7为0输出低电平,为1输出高电平
  63. /**< led配置结构体 */
  64. struct t_config_led
  65. {
  66. uint8_t uc_port;
  67. uint8_t uc_pin;
  68. uint8_t uc_en; /**< 使能标志 */
  69. uint8_t uc_mode; /**< 模式 0灭 1亮 2闪烁 */
  70. uint8_t uc_state; /**< 目前状态 */
  71. uint32_t ul_time; /**< 翻转时间 */
  72. uint32_t ul_count; /**< 翻转计时 */
  73. };
  74. static struct t_config_led mst_led_cfg[LED_MAX_NUM] =
  75. {
  76. {CH423_OC_L_CMD, 0, 0, 0, 0, 0},
  77. {CH423_OC_L_CMD, 1, 0, 0, 0, 0},
  78. {CH423_OC_L_CMD, 2, 0, 0, 0, 0},
  79. {CH423_OC_L_CMD, 3, 0, 0, 0, 0},
  80. {CH423_OC_L_CMD, 4, 0, 0, 0, 0},
  81. {CH423_OC_L_CMD, 5, 0, 0, 0, 0},
  82. {CH423_OC_L_CMD, 6, 0, 0, 0, 0},
  83. {CH423_OC_L_CMD, 7, 0, 0, 0, 0},
  84. {CH423_OC_H_CMD, 8, 0, 0, 0, 0},
  85. {CH423_OC_H_CMD, 9, 0, 0, 0, 0},
  86. {CH423_OC_H_CMD, 10, 0, 0, 0, 0},
  87. {CH423_OC_H_CMD, 11, 0, 0, 0, 0},
  88. {CH423_OC_H_CMD, 12, 0, 0, 0, 0},
  89. {CH423_OC_H_CMD, 13, 0, 0, 0, 0},
  90. {CH423_OC_H_CMD, 14, 0, 0, 0, 0},
  91. {CH423_OC_H_CMD, 15, 0, 0, 0, 0},
  92. {CH423_SET_IO_CMD, 16, 0, 0, 0, 0},
  93. {CH423_SET_IO_CMD, 17, 0, 0, 0, 0},
  94. {CH423_SET_IO_CMD, 18, 0, 0, 0, 0},
  95. {CH423_SET_IO_CMD, 19, 0, 0, 0, 0},
  96. {CH423_SET_IO_CMD, 20, 0, 0, 0, 0},
  97. {CH423_SET_IO_CMD, 21, 0, 0, 0, 0},
  98. {CH423_SET_IO_CMD, 22, 0, 0, 0, 0},
  99. {CH423_SET_IO_CMD, 23, 0, 0, 0, 0},
  100. };
  101. #define I2C_DEV "/dev/i2c-5"
  102. static int sl_ch423s_fd = -1, sl_ch423s_init = -1;
  103. static uint32_t sul_io_status = 0xffffff;
  104. static uint8_t msuc_test_flag = 0;
  105. /**
  106. * @brief
  107. * @author lch (lch_work@foxmail.com)
  108. * @version 1.0
  109. * @date 20251224
  110. * @param[in/out] {uint8_t} _uc_cmd 命令
  111. * @param[in/out] {uint8_t} _uc_state 状态
  112. * @return * int
  113. * @retval none
  114. *
  115. * @warning none
  116. * @note 注意这个原件没有固定的iic地址 抓数据发现 命令 + 数据 就可以操作
  117. */
  118. static int ch423_write_data(uint8_t _uc_cmd, uint8_t _uc_state)
  119. {
  120. /* 使用寄存器地址来寻址 */
  121. if (ioctl(sl_ch423s_fd, I2C_SLAVE, _uc_cmd >> 1) < 0)
  122. {
  123. dp_err_n_c("Failed to set I2C slave address: %s\n", strerror(errno));
  124. return -1;
  125. }
  126. if (write(sl_ch423s_fd, &_uc_state, 1) != 1)
  127. {
  128. dp_err_n_c("Failed to write data: %s", strerror(errno));
  129. return -2;
  130. }
  131. return 0;
  132. }
  133. /**
  134. * @brief
  135. * @author lch (lch_work@foxmail.com)
  136. * @version 1.0
  137. * @date 20251224
  138. * @param[in/out] {uint8_t} _uc_idx
  139. * @param[in/out] {uint8_t} _uc_state
  140. * @return * void
  141. * @retval none
  142. *
  143. * @warning none
  144. * @note none
  145. */
  146. static void ch423s_updata_port_status(uint8_t _uc_idx, uint8_t _uc_state)
  147. {
  148. uint32_t ul_data_1 = 0, ul_data_2 = 0;
  149. ul_data_1 = sul_io_status;
  150. if ((sul_io_status >> _uc_idx) & 0x01)
  151. {
  152. sul_io_status ^= (1 << _uc_idx);
  153. }
  154. ul_data_2 = sul_io_status;
  155. /* 重新设置 */
  156. sul_io_status |= _uc_state ? (0 << _uc_idx) : (1 << _uc_idx);
  157. // dp_err_n_c_rt("ul_data_1 = 0x%06x, ul_data_2 = 0x%06x, sul_io_status = 0x%06x\r\n", ul_data_1, ul_data_1, sul_io_status);
  158. }
  159. /**
  160. * @brief 定时更新gpio状态
  161. * @author lch (lch_work@foxmail.com)
  162. * @version 1.0
  163. * @date 20251224
  164. * @return * int
  165. * @retval none
  166. *
  167. * @warning none
  168. * @note none
  169. */
  170. int ch423sio_updata_status_ontime(void)
  171. {
  172. uint8_t uca_state[3] = {0};
  173. int l_ret = 0;
  174. uca_state[0] = (uint8_t)(sul_io_status & 0xff);
  175. (0 == ch423_write_data(CH423_OC_L_CMD, uca_state[0])) ? l_ret : l_ret--;
  176. uca_state[1] = (uint8_t)((sul_io_status >> 8) & 0xff);
  177. (0 == ch423_write_data(CH423_OC_H_CMD, uca_state[1])) ? l_ret : l_ret--;
  178. uca_state[2] = (uint8_t)((sul_io_status >> 16) & 0xff);
  179. (0 == ch423_write_data(CH423_SET_IO_CMD, uca_state[2])) ? l_ret : l_ret--;
  180. return l_ret;
  181. }
  182. /**
  183. * @brief 设置io状态
  184. * @author lch (lch_work@foxmail.com)
  185. * @version 1.0
  186. * @date 20251224
  187. * @param[in/out] {uint8_t} _uc_idx 下标
  188. * @param[in/out] {uint8_t} _uc_state 电平状态
  189. * @return * int
  190. * @retval none
  191. *
  192. * @warning none
  193. * @note none
  194. */
  195. int ch423sio_set_io(uint8_t _uc_idx, uint8_t _uc_state)
  196. {
  197. if (_uc_idx >= LED_MAX_NUM || sl_ch423s_init < 0 || _uc_state > 1)
  198. {
  199. return -1;
  200. }
  201. switch (mst_led_cfg[_uc_idx].uc_port)
  202. {
  203. case CH423_OC_L_CMD:
  204. ch423s_updata_port_status(mst_led_cfg[_uc_idx].uc_pin, _uc_state);
  205. break;
  206. case CH423_OC_H_CMD:
  207. ch423s_updata_port_status(mst_led_cfg[_uc_idx].uc_pin, _uc_state);
  208. break;
  209. case CH423_SET_IO_CMD:
  210. ch423s_updata_port_status(mst_led_cfg[_uc_idx].uc_pin, _uc_state);
  211. break;
  212. default:
  213. return -2;
  214. break;
  215. }
  216. return 0;
  217. }
  218. /**
  219. * @brief 设置io状态
  220. * @author lch (lch_work@foxmail.com)
  221. * @version 1.0
  222. * @date 20251224
  223. * @param[in/out] {uint8_t} _uc_idx 下标
  224. * @param[in/out] {uint8_t} _uc_state 电平状态
  225. * @return * int
  226. * @retval none
  227. *
  228. * @warning none
  229. * @note none
  230. */
  231. int ch423sio_set_ioupdata(uint8_t _uc_idx, uint8_t _uc_state)
  232. {
  233. int ret = -1;
  234. uint8_t io_val[3] = {0};
  235. if (_uc_idx >= LED_MAX_NUM || sl_ch423s_init < 0 || _uc_state > 1)
  236. {
  237. dp_err_n_c("_uc_idx = %d, sl_ch423s_init = %d, _uc_state = %d", _uc_idx, sl_ch423s_init, _uc_state);
  238. return -1;
  239. }
  240. switch (mst_led_cfg[_uc_idx].uc_port)
  241. {
  242. case CH423_OC_L_CMD:
  243. ch423s_updata_port_status(mst_led_cfg[_uc_idx].uc_pin, _uc_state);
  244. io_val[0] = (uint8_t)(sul_io_status & 0xff);
  245. ret = ch423_write_data(CH423_OC_L_CMD, io_val[0]);
  246. break;
  247. case CH423_OC_H_CMD:
  248. ch423s_updata_port_status(mst_led_cfg[_uc_idx].uc_pin, _uc_state);
  249. io_val[1] = (uint8_t)((sul_io_status & 0xff00) >> 8);
  250. ret = ch423_write_data(CH423_OC_H_CMD, io_val[1]);
  251. break;
  252. case CH423_SET_IO_CMD:
  253. ch423s_updata_port_status(mst_led_cfg[_uc_idx].uc_pin, _uc_state);
  254. io_val[2] = (uint8_t)((sul_io_status & 0xff0000) >> 16);
  255. ret = ch423_write_data(CH423_SET_IO_CMD, io_val[2]);
  256. break;
  257. default:
  258. return -2;
  259. break;
  260. }
  261. return ret;
  262. }
  263. /**
  264. * @brief io测试
  265. * @author lch (lch_work@foxmail.com)
  266. * @version 1.0
  267. * @date 20251230
  268. * @return * int
  269. * @retval none
  270. *
  271. * @warning none
  272. * @note none
  273. */
  274. static int ch423sio_run_test(void)
  275. {
  276. int i = 0;
  277. for (i = 0; i < LED_MAX_NUM; i++)
  278. {
  279. ch423sio_set_ioupdata(i, 1);
  280. usleep(1000 * 50);
  281. }
  282. usleep(1000 * 100);
  283. for (i = (LED_MAX_NUM - 1); i >= 0; i--)
  284. {
  285. ch423sio_set_ioupdata(i, 0);
  286. usleep(1000 * 50);
  287. }
  288. usleep(1000 * 100);
  289. for (i = 0; i < LED_MAX_NUM; i++)
  290. {
  291. ch423sio_set_ioupdata(i, 1);
  292. }
  293. usleep(1000 * 100);
  294. for (i = 0; i < LED_MAX_NUM; i++)
  295. {
  296. ch423sio_set_ioupdata(i, 0);
  297. }
  298. usleep(1000 * 100);
  299. return 0;
  300. }
  301. /**
  302. * @brief 初始化设备
  303. * @author lch (lch_work@foxmail.com)
  304. * @version 1.0
  305. * @date 20251224
  306. * @return * int
  307. * @retval none
  308. *
  309. * @warning none
  310. * @note none
  311. */
  312. int ch423sio_init_dev(void)
  313. {
  314. // 打开I2C设备
  315. sl_ch423s_fd = open(I2C_DEV, O_RDWR);
  316. if (sl_ch423s_fd < 0)
  317. {
  318. dp_err_n_c_rt("Failed to open I2C device %s: %s", I2C_DEV, strerror(errno));
  319. return -1;
  320. }
  321. ch423_write_data(CH423_SYS_CMD, BIT_IO_OE); /* 将IO7~IO0设置为输出 其它参数使用默认值 */
  322. ch423_write_data(CH423_OC_L_CMD, 0xff);
  323. ch423_write_data(CH423_OC_H_CMD, 0xff);
  324. ch423_write_data(CH423_SET_IO_CMD, 0xff);
  325. sl_ch423s_init = 0;
  326. ch423sio_run_test();
  327. return 0;
  328. }
  329. /**
  330. * @brief 关闭句柄
  331. * @author lch (lch_work@foxmail.com)
  332. * @version 1.0
  333. * @date 20251224
  334. * @return * int
  335. * @retval none
  336. *
  337. * @warning none
  338. * @note none
  339. */
  340. int ch423sio_exit_dev(void)
  341. {
  342. if (sl_ch423s_fd >= 0)
  343. {
  344. close(sl_ch423s_fd);
  345. sl_ch423s_fd = -1;
  346. }
  347. return 0;
  348. }
  349. /**
  350. * @brief 控制led驱动
  351. *
  352. * @param[in] {uint8_t} _uc_idx 硬件地址
  353. * @param[in] {uint8_t} _uc_set 模式 0灭 1亮
  354. */
  355. static void ch423_control_drive(uint8_t _uc_idx, uint8_t _uc_set)
  356. {
  357. if (_uc_idx >= LED_MAX_NUM || _uc_set >= e_io_mode_max)
  358. return;
  359. switch (_uc_set)
  360. {
  361. case e_io_mode_off:
  362. ch423sio_set_io(_uc_idx, e_io_mode_off);
  363. mst_led_cfg[_uc_idx].uc_state = e_io_mode_off;
  364. break;
  365. case e_io_mode_on:
  366. ch423sio_set_io(_uc_idx, e_io_mode_on);
  367. mst_led_cfg[_uc_idx].uc_state = e_io_mode_on;
  368. break;
  369. default:
  370. return;
  371. break;
  372. }
  373. }
  374. /**
  375. * @brief 切换led模式
  376. *
  377. * @details 闪烁模式一直在计时,uc_en使能标志不会清零
  378. */
  379. void ch423sio_handle_mode(void)
  380. {
  381. uint8_t uc_updata = 0;
  382. #if (0) /* 测试打印代码 */
  383. static uint64_t sull_printf_led = 0;
  384. if (sull_printf_led++ >= (10 * 10))
  385. {
  386. sull_printf_led = 0;
  387. dp_info_n_c("dTCounter = %d", dTCounter);
  388. for (uint8_t j = 0; j < LED_MAX_NUM; j++)
  389. {
  390. dp_info_n_c("[%02d] uc_en = %d, mode = %d, state = %d, ul_time = %d, ul_count = %d",
  391. j,
  392. mst_led_cfg[j].uc_en,
  393. mst_led_cfg[j].uc_mode,
  394. mst_led_cfg[j].uc_state,
  395. mst_led_cfg[j].ul_time,
  396. mst_led_cfg[j].ul_count);
  397. }
  398. }
  399. #endif
  400. for (uint8_t i = 0; i < LED_MAX_NUM; i++)
  401. {
  402. if (mst_led_cfg[i].uc_en == 0)
  403. continue;
  404. mst_led_cfg[i].ul_count += 100;
  405. if (mst_led_cfg[i].ul_count > mst_led_cfg[i].ul_time)
  406. {
  407. mst_led_cfg[i].ul_count = 0;
  408. uc_updata = 1;
  409. if (mst_led_cfg[i].uc_mode != e_io_mode_shine)
  410. {
  411. mst_led_cfg[i].uc_en = 0;
  412. ch423_control_drive(i, mst_led_cfg[i].uc_mode);
  413. }
  414. else
  415. {
  416. if (e_io_mode_on == mst_led_cfg[i].uc_state)
  417. {
  418. ch423_control_drive(i, e_io_mode_off);
  419. }
  420. else
  421. {
  422. ch423_control_drive(i, e_io_mode_on);
  423. }
  424. }
  425. }
  426. }
  427. if (1 == uc_updata)
  428. {
  429. ch423sio_updata_status_ontime();
  430. }
  431. }
  432. /**
  433. * @brief
  434. *
  435. * @param[in] {uint8_t} _uc_idx led映射
  436. * @param[in] {enum e_mode_ch423} _e_mode 模式 0灭 1亮 2闪烁
  437. * @param[in] {uint32_t} _ul_time 闪烁时间
  438. * @return int
  439. * @retval 0设置模式成功
  440. * @details none
  441. */
  442. int ch423sio_control_state(uint8_t _uc_idx, enum e_mode_ch423 _e_mode, uint32_t _ul_time)
  443. {
  444. if (_uc_idx >= LED_MAX_NUM || _e_mode >= e_io_mode_max)
  445. return -1;
  446. mst_led_cfg[_uc_idx].uc_en = 1;
  447. mst_led_cfg[_uc_idx].uc_mode = _e_mode;
  448. if (_e_mode == e_io_mode_shine)
  449. mst_led_cfg[_uc_idx].ul_time = _ul_time;
  450. return 0;
  451. }
  452. #endif /* TMP_CHIP_AHT20 */