AirGPIO_1000.lua 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  1. --[[
  2. @module AirGPIO_1000
  3. @summary AirGPIO_1000应用功能模块
  4. @version 1.0
  5. @date 2025.10.21
  6. @author 沈园园
  7. @usage
  8. 本文件为AirGPIO_1000驱动配置文件,核心业务逻辑为:
  9. 1、配置主机和AirGPIO_1000之间的通信参数;
  10. 2、配置AirGPIO_1000上的扩展GPIO管脚功能;支持配置为输出,输入和中断三种模式;
  11. 本文件没有对外接口,直接require "AirGPIO_1000"就可以加载运行;
  12. ]]
  13. --本文件中的主机是指I2C主机,具体指Air780epm
  14. --本文件中的从机是指I2C从机,具体指AirGPIO_1000配件板上的IO扩展芯片
  15. local AirGPIO_1000 =
  16. {
  17. -- i2c_id:主机的i2c id;
  18. -- gpio_int_id:主机的GPIO中断引脚id;
  19. -- slave_address:从机地址;
  20. -- ints = --从机各个扩展IO配置为中断时的处理函数以及上一次的输入电平
  21. -- {
  22. -- [0x00] = {cb_func=, old_level=},
  23. -- [0x01] = {cb_func=, old_level=},
  24. -- [0x02] = {cb_func=, old_level=},
  25. -- [0x03] = {cb_func=, old_level=},
  26. -- [0x04] = {cb_func=, old_level=},
  27. -- [0x05] = {cb_func=, old_level=},
  28. -- [0x06] = {cb_func=, old_level=},
  29. -- [0x07] = {cb_func=, old_level=},
  30. -- [0x10] = {cb_func=, old_level=},
  31. -- [0x11] = {cb_func=, old_level=},
  32. -- [0x12] = {cb_func=, old_level=},
  33. -- [0x13] = {cb_func=, old_level=},
  34. -- [0x14] = {cb_func=, old_level=},
  35. -- [0x15] = {cb_func=, old_level=},
  36. -- [0x16] = {cb_func=, old_level=},
  37. -- [0x17] = {cb_func=, old_level=},
  38. -- }
  39. }
  40. -- 从机硬件上有三个引脚A0 A1 A2可以配置I2C从设备的地址
  41. -- 当A0 A1 A2都接地时的从设备基地址为(0x40 >> 1)
  42. -- A0 A1 A2有0到7一共八种排序组合,基地址+0/1/2/3/4/5/6/7即为八种从设备的地址
  43. -- AirGPIO_1000默认A0 A1 A2都接地,所以AirGPIO_1000的从设备地址默认也为(0x40 >> 1)
  44. local SALVE_ADDRESS_HIGH_4BIT = (0x40 >> 1)
  45. -- 寄存器地址
  46. local REG_INPUT_PORT_0 = 0x00 -- 输入端口0
  47. local REG_INPUT_PORT_1 = 0x01 -- 输入端口1
  48. local REG_OUTPUT_PORT_0 = 0x02 -- 输出端口0
  49. local REG_OUTPUT_PORT_1 = 0x03 -- 输出端口1
  50. local REG_POL_INV_0 = 0x04 -- 极性反转端口0
  51. local REG_POL_INV_1 = 0x05 -- 极性反转端口1
  52. local REG_CONFIG_0 = 0x06 -- 配置端口0
  53. local REG_CONFIG_1 = 0x07 -- 配置端口1
  54. -- 写入AirGPIO_1000的寄存器
  55. --reg:number类型;
  56. -- 表示AirGPIO_1000上的寄存器地址;
  57. -- 取值范围:0x00到0x07,参考本文件上方的寄存器地址列表;
  58. -- 必须传入,不允许为空;
  59. --value:number类型;
  60. -- 表示要写入到AirGPIO_1000寄存器中的数据;
  61. -- 取值范围:0x00到0xFF,1个字节的长度;
  62. -- 必须传入,不允许为空;
  63. --返回值:成功返回true,失败返回false
  64. local function write_register(reg, value)
  65. local data = {reg, value}
  66. local result = i2c.send(AirGPIO_1000.i2c_id, AirGPIO_1000.slave_address, data)
  67. return result
  68. end
  69. -- 读取AirGPIO_1000的寄存器
  70. --reg:number类型;
  71. -- 表示AirGPIO_1000上的寄存器地址;
  72. -- 取值范围:0x00到0x07,参考本文件上方的寄存器地址列表;
  73. -- 必须传入,不允许为空;
  74. --返回值:成功返回1个字节的number类型,失败返回nil
  75. local function read_register(reg)
  76. i2c.send(AirGPIO_1000.i2c_id, AirGPIO_1000.slave_address, reg)
  77. local data = i2c.recv(AirGPIO_1000.i2c_id, AirGPIO_1000.slave_address, 1)
  78. if data and #data == 1 then
  79. return string.byte(data, 1)
  80. end
  81. return nil
  82. end
  83. --主机上的中断引脚处理函数
  84. local function gpio_int_callback()
  85. log.info("gpio_int_callback")
  86. --在中断处理函数中不能直接执行耗时较长的动作
  87. --所以在此处publish一个"AirGPIO_1000_INT"消息
  88. --在其他位置订阅这个消息,进行异步处理
  89. --异步处理这个消息的函数可以直接执行耗时较长的动作
  90. sys.publish("AirGPIO_1000_INT")
  91. end
  92. --遍历用户扩展GPIO中断函数表,进行处理
  93. local function user_gpio_int_callback()
  94. if AirGPIO_1000.ints then
  95. --遍历用户扩展GPIO中断函数表
  96. for k,v in pairs(AirGPIO_1000.ints) do
  97. if v then
  98. --读取扩展GPIO的输入电平
  99. local cur_level = AirGPIO_1000.get(k)
  100. --如果输入电平和上一次输入电平不一致
  101. --则执行用户扩展GPIO中断函数
  102. if v.old_level~=cur_level then
  103. v.old_level = cur_level
  104. if v.cb_func then v.cb_func(k, cur_level) end
  105. end
  106. end
  107. end
  108. end
  109. end
  110. --订阅"AirGPIO_1000_INT"消息的处理函数user_gpio_int_callback
  111. --当其他位置publish "AirGPIO_1000_INT"消息时,会执行user_gpio_int_callback
  112. sys.subscribe("AirGPIO_1000_INT", user_gpio_int_callback)
  113. --检查AirGPIO_1000上的扩展GPIO ID是否有效
  114. --gpio_id:number类型;
  115. -- 表示AirGPIO_1000上的扩展GPIO ID;
  116. -- 取值范围:0x00到0x07,0x10到0x17,一共16种,分别对应16个扩展GPIO引脚;
  117. -- 必须传入,不允许为空;
  118. --返回值:有效返回true,无效返回false
  119. local function check_gpio_id_valid(gpio_id)
  120. return (gpio_id>=0x00 and gpio_id<=0x07 or gpio_id>=0x10 and gpio_id<=0x17)
  121. end
  122. --配置主机和AirGPIO_1000之间的通信参数;
  123. --i2c_id:number类型;
  124. -- 主机使用的I2C ID,用来控制AirGPIO_1000;
  125. -- 取值范围:仅支持0和1;
  126. -- 如果没有传入此参数,则默认为0;
  127. --int_id:number类型;
  128. -- 主机使用的中断引脚GPIO ID,和AirGPIO_1000上的INT引脚相连;
  129. -- AirGPIO_1000可以扩展出来16个GPIO,这些GPIO支持配置为输入;
  130. -- AirGPIO_1000上的任意一个输入GPIO的状态发生上升沿或者下降沿变化时,会通过INT引脚通知到主机的int_id中断引脚;
  131. -- 此时主机可以通过I2C接口立即读取AirGPIO_1000上配置为输入模式的扩展GPIO的电平状态,从而判断是哪些扩展GPIO的输入电平发生了变化;
  132. -- 取值范围:nil或者空,或者0到9,或者12到55,注意不要使用已经复用为其他功能的引脚;nil或者空时,表示不使用中断通知功能;
  133. -- 如果没有传入此参数,则默认为空,表示不使用中断通知功能;
  134. --返回值:成功返回true,失败返回false
  135. function AirGPIO_1000.init(i2c_id, gpio_int_id)
  136. --检查参数的合法性
  137. if not (i2c_id == 0 or i2c_id == 1) then
  138. log.error("AirGPIO_1000.init", "invalid i2c_id", i2c_id)
  139. return false
  140. end
  141. if not (gpio_int_id==nil or gpio_int_id>=0 and gpio_int_id<=9 or gpio_int_id>=12 and gpio_int_id<=55) then
  142. log.error("AirGPIO_1000.init", "invalid gpio_int_id", gpio_int_id)
  143. return false
  144. end
  145. AirGPIO_1000.i2c_id = i2c_id
  146. AirGPIO_1000.gpio_int_id = gpio_int_id
  147. --初始化I2C
  148. if i2c.setup(i2c_id, i2c.FAST) ~= 1 then
  149. log.error("AirGPIO_1000.init", "i2c.setup error", i2c_id)
  150. return false
  151. end
  152. --自动识别从设备地址
  153. --AirGPIO_1000上使用的TCA9555芯片有三个引脚,A2 A1 A0,可以配置三个bit的I2C从设备地址
  154. --从 0 0 0 到 1 1 1,也就是十进制的0到7,一共可以配置8种;
  155. --依次读取这8个从设备地址上的一个寄存器地址数据
  156. --如果返回应答数据,则从设备地址自动识别成功
  157. for i=0,7 do
  158. i2c.send(i2c_id, SALVE_ADDRESS_HIGH_4BIT+i, REG_INPUT_PORT_0)
  159. local data = i2c.recv(i2c_id, SALVE_ADDRESS_HIGH_4BIT+i, 1)
  160. if data~=nil then
  161. AirGPIO_1000.slave_address = SALVE_ADDRESS_HIGH_4BIT+i
  162. log.error("AirGPIO_1000.init", "slave_address", SALVE_ADDRESS_HIGH_4BIT+i, data:byte())
  163. break
  164. end
  165. end
  166. --自动识别从设备地址失败
  167. if not AirGPIO_1000.slave_address then
  168. log.error("AirGPIO_1000.init", "slave_address unknown")
  169. i2c.close(i2c_id)
  170. return false
  171. end
  172. --配置主机上的中断GPIO,用来实时检测从机上扩展GPIO的输入电平变化
  173. if gpio_int_id then
  174. gpio.setup(gpio_int_id, gpio_int_callback, gpio.PULLUP, gpio.FALLING)
  175. end
  176. return true
  177. end
  178. --关闭主机和AirGPIO_1000之间的通信;
  179. --返回值:成功返回true,失败返回false
  180. function AirGPIO_1000.deinit()
  181. --关闭主机I2C
  182. if AirGPIO_1000.i2c_id then
  183. i2c.close(AirGPIO_1000.i2c_id)
  184. AirGPIO_1000.i2c_id = nil
  185. AirGPIO_1000.slave_address = nil
  186. end
  187. --关闭主机中断GPIO
  188. if AirGPIO_1000.gpio_int_id then
  189. gpio.close(AirGPIO_1000.gpio_int_id)
  190. AirGPIO_1000.gpio_int_id = nil
  191. end
  192. --清空用户注册的扩展GPIO中断处理表
  193. if type(AirGPIO_1000.ints)=="table" then
  194. for k,v in pairs(AirGPIO_1000.ints) do
  195. AirGPIO_1000.ints[k] = nil
  196. end
  197. AirGPIO_1000.ints = nil
  198. end
  199. end
  200. --[[
  201. 配置AirGPIO_1000上的扩展GPIO管脚功能;
  202. 支持配置为输出,输入和中断三种模式;
  203. @api AirGPIO_1000.setup(gpio_id, gpio_mode)
  204. @number
  205. gpio_id
  206. 表示AirGPIO_1000上的扩展GPIO ID;
  207. 取值范围:0x00到0x07,0x10到0x17,一共16种,分别对应16个扩展GPIO引脚;
  208. 必须传入,不允许为空或者nil;
  209. @number or function or nil or 空
  210. gpio_mode
  211. number类型时,表示输出模式,取值范围为0和1,0表示默认输出低电平,1表示默认输出高电平;
  212. nil或者空类型时,表示输入模式;
  213. function类型时,表示中断模式,此function为中断回调函数,函数的定义格式如下:
  214. function cb_func(id, level)
  215. --id:表示触发中断的AirGPIO_1000上的扩展GPIO ID,取值范围为0x00到0x07,0x10到0x17,一共16种,分别对应16个扩展GPIO引脚;
  216. --level:触发中断后,某一时刻,扩展GPIO输入的电平状态,高电平为1, 低电平为0;并不是指触发中断的电平状态;
  217. end
  218. @return bool
  219. 成功返回true,失败返回false
  220. @usage
  221. -- GPIO ID 0x00配置为输出模式,默认输出低电平
  222. AirGPIO_1000.setup(0x00, 0)
  223. -- GPIO ID 0x11配置为输入模式
  224. AirGPIO_1000.setup(0x11)
  225. --P04引脚中断处理函数
  226. --id:0x04
  227. --level:触发中断后,某一时刻,扩展GPIO输入的电平状态,高电平为1, 低电平为0
  228. local function P04_int_cbfunc(id, level)
  229. log.info("P04_int_cbfunc", id, level)
  230. end
  231. -- GPIO ID 0x04配置为中断模式,中断处理函数为P04_int_cbfunc
  232. AirGPIO_1000.setup(0x04, P04_int_cbfunc)
  233. ]]
  234. function AirGPIO_1000.setup(gpio_id, gpio_mode)
  235. --检查参数的合法性
  236. if not check_gpio_id_valid(gpio_id) then
  237. log.error("AirGPIO_1000.setup", "invalid gpio_id", gpio_id)
  238. return false
  239. end
  240. if not (gpio_mode==0 or gpio_mode==1 or gpio_mode==nil or type(gpio_mode)=="function") then
  241. log.error("AirGPIO_1000.setup", "invalid gpio_mode", type(gpio_mode), gpio_mode)
  242. return false
  243. end
  244. log.info("AirGPIO_1000.setup", "enter", gpio_id, type(gpio_mode), gpio_mode)
  245. --根据扩展GPIO ID识别当前扩展GPIO使用的配置寄存器地址
  246. --0x0x开头的ID为REG_CONFIG_0,0x01开头的ID为REG_CONFIG_1
  247. local reg_addr = ((gpio_id>>4) == 0) and REG_CONFIG_0 or REG_CONFIG_1
  248. --读取从机中输出寄存器当前的值
  249. local reg_data = read_register(reg_addr)
  250. if reg_data==nil then
  251. log.error("AirGPIO_1000.setup", "read config register error", reg_addr)
  252. return false
  253. end
  254. local mask = 1<<(gpio_id&0x0F)
  255. local value
  256. --GPIO配置为输出模式
  257. if gpio_mode==0 or gpio_mode==1 then
  258. value = reg_data & (~mask)
  259. --GPIO配置为输入模式
  260. elseif gpio_mode==nil or type(gpio_mode)=="function" then
  261. value = reg_data | mask
  262. end
  263. --如果寄存器新值和旧值相比,发生变化
  264. --写新值到从机的配置寄存器中
  265. if reg_data~=value then
  266. if not write_register(reg_addr, value) then
  267. log.error("AirGPIO_1000.setup", "config write error", reg_addr, value)
  268. return false
  269. end
  270. end
  271. log.info("AirGPIO_1000.setup", "config", reg_addr, reg_data, value)
  272. --如果是中断模式,并且用户注册了中断处理函数
  273. if type(gpio_mode)=="function" then
  274. if AirGPIO_1000.ints==nil then
  275. AirGPIO_1000.ints = {}
  276. end
  277. if AirGPIO_1000.ints[gpio_id]==nil then
  278. AirGPIO_1000.ints[gpio_id] = {}
  279. end
  280. --存储中断处理函数
  281. AirGPIO_1000.ints[gpio_id].cb_func = gpio_mode
  282. --读取当前时刻GPIO的输入电平状态
  283. AirGPIO_1000.ints[gpio_id].old_level = AirGPIO_1000.get(gpio_id)
  284. end
  285. --如果配置的是输入模式或者中断模式,可以直接返回了
  286. if gpio_mode~=0 and gpio_mode~=1 then return true end
  287. --如果配置的输出模式,初始化输出的电平为gpio_mode
  288. if not AirGPIO_1000.set(gpio_id, gpio_mode) then
  289. log.error("AirGPIO_1000.setup", "output set error")
  290. return false
  291. end
  292. log.info("AirGPIO_1000.setup", "output", reg_addr, reg_data, value)
  293. return true
  294. end
  295. --设置AirGPIO_1000上配置为输出模式的扩展GPIO的输出电平
  296. --gpio_id:number类型;
  297. -- 表示AirGPIO_1000上的扩展GPIO ID;
  298. -- 取值范围:0x00到0x07,0x10到0x17,一共16种,分别对应16个扩展GPIO引脚;
  299. -- 必须传入,不允许为空;
  300. --output_level:number类型;
  301. -- 表示配置为输出模式的扩展GPIO对外输出的电平;
  302. -- 取值范围:0和1,0表示输出低电平,1表示输出高电平;
  303. -- 必须传入,不允许为空;
  304. --返回值:成功返回true,失败返回false
  305. function AirGPIO_1000.set(gpio_id, output_level)
  306. --检查参数的合法性
  307. if not check_gpio_id_valid(gpio_id) then
  308. log.error("AirGPIO_1000.set", "invalid gpio_id", gpio_id)
  309. return false
  310. end
  311. if not (output_level==0 or output_level==1) then
  312. log.error("AirGPIO_1000.set", "invalid output_level", type(output_level), output_level)
  313. return false
  314. end
  315. log.info("AirGPIO_1000.set", "enter", gpio_id, output_level)
  316. --根据扩展GPIO ID识别当前扩展GPIO使用的输出寄存器地址
  317. --0x0x开头的ID为REG_OUTPUT_PORT_0,0x01开头的ID为REG_OUTPUT_PORT_1
  318. local reg_addr = ((gpio_id>>4) == 0) and REG_OUTPUT_PORT_0 or REG_OUTPUT_PORT_1
  319. --读取从机中输出寄存器当前的值
  320. local reg_data = read_register(reg_addr)
  321. if reg_data==nil then
  322. log.error("AirGPIO_1000.set", "read output register error", reg_addr)
  323. return false
  324. end
  325. local mask = 1<<(gpio_id&0x0F)
  326. local value
  327. --输出低电平
  328. if output_level==0 then
  329. value = reg_data & (~mask)
  330. --输出高电平
  331. elseif output_level==1 then
  332. value = reg_data | mask
  333. end
  334. --如果寄存器新值和旧值相比,发生变化
  335. --写新值到从机的输出寄存器中
  336. if reg_data~=value then
  337. if not write_register(reg_addr, value) then
  338. log.error("AirGPIO_1000.set", "output write error", reg_addr, value)
  339. return false
  340. end
  341. end
  342. log.info("AirGPIO_1000.set", "output", reg_addr, reg_data, value)
  343. return true
  344. end
  345. --读取AirGPIO_1000上配置为输入或者中断模式的扩展GPIO的输入电平
  346. --gpio_id:number类型;
  347. -- 表示AirGPIO_1000上的扩展GPIO ID;
  348. -- 取值范围:0x00到0x07,0x10到0x17,一共16种,分别对应16个扩展GPIO引脚;
  349. -- 必须传入,不允许为空;
  350. --返回值:number类型,表示输入的电平,0表示低电平,1表示高电平;如果读取失败,返回false
  351. function AirGPIO_1000.get(gpio_id)
  352. --检查参数的合法性
  353. if not check_gpio_id_valid(gpio_id) then
  354. log.error("AirGPIO_1000.get", "invalid gpio_id", gpio_id)
  355. return false
  356. end
  357. --根据扩展GPIO ID识别当前扩展GPIO使用的输入寄存器地址
  358. --0x0x开头的ID为REG_INPUT_PORT_0,0x01开头的ID为REG_INPUT_PORT_1
  359. local reg_addr = ((gpio_id>>4) == 0) and REG_INPUT_PORT_0 or REG_INPUT_PORT_1
  360. --读取从机中输入寄存器当前的值
  361. local value = read_register(reg_addr)
  362. if not value then
  363. log.error("AirGPIO_1000.get", "read_register error", reg_addr)
  364. return false
  365. end
  366. --返回输入寄存器的值和GPIO对应的bit位的值
  367. return ((value>>(gpio_id&0x0F)) & 0x01)
  368. end
  369. --关闭AirGPIO_1000上的扩展GPIO功能
  370. --实际上是恢复为默认状态(配置为输入)
  371. --gpio_id:number类型;
  372. -- 表示AirGPIO_1000上的扩展GPIO ID;
  373. -- 取值范围:0x00到0x07,0x10到0x17,一共16种,分别对应16个扩展GPIO引脚;
  374. -- 必须传入,不允许为空;
  375. --返回值:成功返回true,失败返回false
  376. function AirGPIO_1000.close(gpio_id)
  377. local result = AirGPIO_1000.setup(gpio_id)
  378. if not result then
  379. log.error("AirGPIO_1000.close", "error", gpio_id)
  380. end
  381. return result
  382. end
  383. return AirGPIO_1000