opio 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610
  1. #!/usr/bin/python3
  2. # TODO: add 'out' and 'in' as almost-synonyms for 'write' and 'read'
  3. """
  4. This is a clone of the 'gpio/WiringPi' project, written specifically for the
  5. OrangePi i96.
  6. Not all of gpio is re-implemented. The 'mode' command allows the user to
  7. select any pin a GPIO or its special-funtion (i2c, spi, uart, pcm, etc)
  8. Pat Beirne <patb@pbeirne.com>
  9. Implemented:
  10. gpio read <gpio pin number> => displays a value, returns 0 on success
  11. gpio write <gpio pin number> <value> # set a pin high or low
  12. gpio mode [in | out | alt] # set the pin for in/out or special-function
  13. gpio readall # display all current pin settings
  14. # and the pin assignments on the 40 pin i96
  15. gpio readallx # similar to above, but shows RDA pinout
  16. gpio exports # simply dump the state of all the exports
  17. # which exist
  18. gpio leds # like readall, but for LEDs, switches
  19. # and other on-board devices
  20. NOTE: pin numbers are always gpio numbers.
  21. use 'readall' to see the connector assignment
  22. By default, the 'mode' function will create/delete an export. By default,
  23. the 'read' and 'write' function will set the mode and create an export.
  24. To disable this default, use the '-d' option.
  25. Variable plan: functions which are "is_" or "has_" return boolean
  26. functions which involve 'in' 'out' 'alt' pass-&-return strings
  27. functions which involve values pass-&-return ints....-1 means invalid
  28. gpio is always a short int
  29. Attack plan:
  30. mode set: check iomux, then create-&-use export
  31. -d set: check iomux, then low-level set
  32. read: check iomux, then check export, then use export
  33. -d: check iomux, then low-level read
  34. write: check iomux, then check export then set mode=out then use export
  35. -d: check iomux, then set direction=out, tne low-level write
  36. NOTE: 'read' and 'write' will auto-set the GPIO mode and disable 'alt'
  37. NOTE: 'read' and 'write' will auto-set the GPIO mode and disable 'alt'
  38. Classes: GPIO to access a pin through the export-gpio methods
  39. GPIO_DIRECT to access only through low-level calls
  40. read/write/mode will use GPIO unless the -d flag is used
  41. exports will always use GPIO
  42. readall/readallx/leds will use GPIO_DIRECT
  43. """
  44. from mmap import mmap
  45. from struct import pack, unpack
  46. import os, sys, argparse, pathlib, re, logging
  47. VERSION = "2.1"
  48. ############ board specific
  49. class Board:
  50. def __init__(self,full_name,short_name,config_file):
  51. self.name = full_name
  52. self.short_name = short_name
  53. self.config_file = config_file
  54. def __repr__(self):
  55. return self.name
  56. board_i96 = Board("OrangePi i96", "OrangePi i96", "/etc/OrangePi-i96")
  57. board_2g = Board("OrangePi 2G-IOT","OrgPi 2G-iot", "/etc/OrangePi-2g-iot")
  58. # pins, arranged according to i96 connector
  59. # i96 label, rda_port number, pio number, rda special function
  60. board_i96.PINS = (
  61. ("GND", "", -1, "", ""), # 1
  62. ("GND", "", -1, "", ""),
  63. ("UART2.CTS", "B8", 40, "CTS", "ttyS1.cts"),
  64. ("PWR_BTN_N", "", -1, "", ""),
  65. ("UART2.TX", "C8", 104, "TX", "ttyS1.tx"),
  66. ("RST_BTN_N", "", -1, "1.4v", ""),
  67. ("UART2.RX", "C7", 103, "RX", "ttyS1.rx"),
  68. ("SPI2.CLK", "A2", 2, "CLK","spi2.clk"),
  69. ("UART2.RTS", "B9", 41, "RTS","ttyS1.rts"),
  70. ("SPI2.DI", "A4", 4, "DI", "spi2.di"), # 10
  71. ("UART1.TX", "A14", 14, "TX", "ttyS0.tx"),
  72. ("SPI2.CS", "A6", 6, "CS", "spi2.cs"),
  73. ("UART1.RX", "C6", 102, "RX", "ttyS0.rx"),
  74. ("SPI2.DO", "A3", 3, "DO", "spi2.do"),
  75. ("I2C2.SCL", "A0", 0, "SCL", "i2c-1.scl"),
  76. ("I2S.LRCK", "A10", 10, "LRCK", "pcm.fp"),
  77. ("I2C2.SDA", "A1", 1, "SDA", "i2c-1.sda"),
  78. ("I2S.BCK", "A9", 9, "BCK", "pcm.clk"),
  79. ("I2C3.SCL", "B6", 38, "SCL", "i2c-2.scl"),
  80. ("I2S.DO", "A13", 13, "DO", "pcm.do"), # 20
  81. ("I2C3.SDA", "B7", 39, "SDA", "i2c-2.sda"),
  82. ("I2S.DI", "A11", 11, "DI", "pcm.di"),
  83. ("GPIO.A", "A15", 15, "CTS", "ttyS0.cts"),
  84. ("GPIO.B", "A20", 20, "LCD", "lcd"),
  85. ("GPIO.C", "B24", 56, "ROM", "n/a"),
  86. ("GPIO.D", "D2", 66, "CTS", "ttyS2.cts"),
  87. ("GPIO.E", "D3", 67, "RTS", "ttyS2.rts"),
  88. ("GPIO.F", "A22", 22, "LCD", "lcd"),
  89. ("GPIO.G", "A30", 30, "LCD", "lcd"),
  90. ("GPIO.H", "A29", 29, "LCD", "lcd"), # 30
  91. ("GPIO.I", "A28", 28, "LCD", "lcd"),
  92. ("GPIO.J", "A27", 27, "LCD", "lcd"),
  93. ("GPIO.K", "A26", 26, "LCD", "lcd"),
  94. ("GPIO.L", "A25", 25, "LCD", "lcd"),
  95. ("V_PAD", "", -1, "1.8v", ""),
  96. ("SYS_DCIN", "", -1, "n/c", ""),
  97. ("VDD_IN", "", -1, "5V", ""),
  98. ("SYS_DCIN", "", -1, "n/c", ""),
  99. ("GND", "", -1, "", ""),
  100. ("GND", "", -1, "", "") # 40
  101. )
  102. deleted_board_2g_14_PINS = (
  103. ("VCC", "", -1,""),
  104. ("I2C1.SDA", "B31", 63, "SDA"),
  105. ("I2C1.SCL", "B30", 62, "SCL"),
  106. ("GPIO.B24", "B24", 56, ""),
  107. ("GND", "", -1, ""),
  108. ("UART1.RX", "C6", 102, "RX"),
  109. ("UART1.TX", "A14", 14, "TX"),
  110. ("UART1.CT", "A15", 15,"CTS"),
  111. ("VCC", "", -1,""),
  112. ("SPI2.DI", "A4", 4, "DI"), #10
  113. ("SPI2.DIO", "A3", 3, "DIO"),
  114. ("SPI2.CLK", "A2", 2, "CLK"),
  115. ("GND", "", -1, ""),
  116. ("I2C2.SDA", "A1", 1, ""),
  117. ("GPIO.C26", "C26", 122, "SIM"),
  118. ("GPIO.C27", "C27", 123, "SIM"),
  119. ("GPIO.C28", "C28", 124, "LCD"),
  120. ("GPIO.C29", "C29", 125, "LCD"),
  121. ("GPIO.C30", "C30", 126, "LCD"),
  122. ("GND", "", -1, ""), #20
  123. ("I2C3.SDA", "B7", 39, "SDA"),
  124. ("I2C3.SCL", "B6", 38, "SCL"),
  125. ("UART2.CT", "B8", 40, "CTS"),
  126. ("GND", "", -1, ""),
  127. ("UART2.RT", "B9", 41, "RTS"),
  128. ("GND", "", -1, ""),
  129. ("I2C2.SCL", "A0", 0, "SCL"),
  130. ("SPI2.CS0", "A5", 5, "CS0"),
  131. ("SPI2.CS1", "A6", 6, "CS1"),
  132. ("UART1.RT", "A16", 16, "RTS"), #30
  133. ("GND", "", -1, ""),
  134. ("GPIO.C25", "C25", 121, "SIM"),
  135. ("GPIO.C5", "C5", 101, ""),
  136. ("GND", "", -1, ""),
  137. ("GPIO.B5", "B5", 37, ""),
  138. ("UART2.RX", "C7", 103,""),
  139. ("UART2.TX", "C8", 104,""),
  140. ("GND", "", -1, ""),
  141. ("VCC", "", -1,""),
  142. ("VCC", "", -1,""), #40
  143. )
  144. board_2g.PINS = (
  145. ("V_PAD", "", -1, "2.8v", ""),
  146. ("VDD_IN", "", -1, "5V", ""),
  147. ("I2C1.SDA", "B31", 63, "SDA","i2c-0.sda"),
  148. ("VDD_IN", "", -1, "5V", ""),
  149. ("I2C1.SCL", "B30", 62, "SCL", "i2c-0.scl"),
  150. ("GND", "", -1, "", ""),
  151. ("GPIO.B24", "B24", 56, "", ""),
  152. ("UART2.TX", "C8", 104,"", "ttyS1.tx"),
  153. ("GND", "", -1, "", ""),
  154. ("UART2.RX", "C7", 103,"", "ttyS1.rx"), #10
  155. ("UART1.RX", "C6", 102, "RX", "ttyS0.rx"),
  156. ("GPIO.B5", "B5", 37, "", ""),
  157. ("UART1.TX", "A14", 14, "TX", "ttyS0.tx"),
  158. ("GND", "", -1, "", ""),
  159. ("UART1.CT", "A15", 15,"CTS", "ttyS0.cts"),
  160. ("GPIO.C5", "C5", 101, "", "",""),
  161. ("V_PAD", "", -1, "2.8v", ""),
  162. ("GPIO.C25", "C25", 121, "SIM", ""),
  163. ("SPI2.DI", "A4", 4, "DI", "spi-1.di"),
  164. ("GND", "", -1, "", ""), #20
  165. ("SPI2.DIO", "A3", 3, "DIO", "spi-1.do"),
  166. ("UART1.RT", "A16", 16, "RTS", "ttyS0.rts"),
  167. ("SPI2.CLK", "A2", 2, "CLK", "spi-1.clk"),
  168. ("SPI2.CS0", "A5", 5, "CS0", "spi-1.cs"),
  169. ("GND", "", -1, "", ""),
  170. ("SPI2.CS1", "A6", 6, "CS1", "spi-1.cs1"),
  171. ("I2C2.SDA", "A1", 1, "", "i2c-1.sda"),
  172. ("I2C2.SCL", "A0", 0, "SCL", "i2c-1.scl"),
  173. ("GPIO.C26", "C26", 122, "SIM", ""),
  174. ("GND", "", -1, "", ""), #30
  175. ("GPIO.C27", "C27", 123, "SIM", ""),
  176. ("UART2.RT", "B9", 41, "RTS", "ttyS1.rts"),
  177. ("GPIO.C28", "C28", 124, "LCD", "lcd"),
  178. ("GND", "", -1, "", ""),
  179. ("GPIO.C29", "C29", 125, "LCD", "lcd"),
  180. ("UART2.CT", "B8", 40, "CTS", "ttyS1.cts"),
  181. ("GPIO.C30", "C30", 126, "LCD", "lcd"),
  182. ("I2C3.SCL", "B6", 38, "SCL", "i2c2-scl"),
  183. ("GND", "", -1, "", ""),
  184. ("I2C3.SDA", "B7", 39, "SDA", "i2c2-sda"), #40
  185. )
  186. board_2g.other = (
  187. )
  188. board_i96.other = (
  189. ("LED2", "C30", 126, ""),
  190. ("LED3", "C29", 125, ""),
  191. ("LED5", "C5", 101, ""),
  192. ("J2", "C2", 98, "boot sd"),
  193. ("OTGPWR","A17",17,""),
  194. # ("DBG_TX","D1",65,"TX"),
  195. # ("DBG_RX","D0",64,"RX"),
  196. )
  197. ########################## cpu specific
  198. class Cpu:
  199. def __init__(self,name):
  200. self.name = name
  201. RDA_PORTC_IOMUX = 0x11a09008
  202. RDA_PORTA_IOMUX = 0x11a0900c
  203. RDA_PORTB_IOMUX = 0x11a09010
  204. RDA_PORTD_IOMUX = 0x11a09014
  205. cpu_rda = Cpu("RDA8810")
  206. cpu_rda.IOMUX_ADDRESSES = (RDA_PORTA_IOMUX, RDA_PORTB_IOMUX, RDA_PORTD_IOMUX, RDA_PORTC_IOMUX)
  207. cpu = cpu_rda
  208. GPIO_PER_PORT = 32
  209. PAGE_MASK = ~0xFFF
  210. PAGE_OFFSET = 0xFFF
  211. SYS_PATH = "/sys/class/gpio/"
  212. def pin_has_export(gpio):
  213. return pathlib.Path('/sys/class/gpio/gpio{}'.format(gpio)).exists()
  214. #################### memory access
  215. def mem_set(address, bitmask, value):
  216. try:
  217. with open("/dev/mem","w+b") as m:
  218. mem = mmap(m.fileno(), 32, offset = address & PAGE_MASK)
  219. address &= PAGE_OFFSET
  220. data = unpack("<L",mem[address:address+4])[0]
  221. logging.debug("mem_set: current data is {} mask is {} value is {}".format(hex(data),hex(bitmask),value))
  222. if value:
  223. data |= bitmask
  224. else:
  225. data &= ~bitmask
  226. logging.debug("mem_set: resulting data is {}".format(hex(data)))
  227. mem[address:address+4] = pack("<L",data)
  228. except PermissionError:
  229. print("failed to open /dev/mem.....you must execute this script as root")
  230. def mem_get(address, bitmask):
  231. try:
  232. with open("/dev/mem","r+b") as m:
  233. mem = mmap(m.fileno(), 32, offset = address & PAGE_MASK)
  234. address &= PAGE_OFFSET
  235. return unpack("<L",mem[address:address+4])[0] & bitmask
  236. except PermissionError:
  237. print("failed to open /dev/mem.....you must execute this script as root")
  238. ############################ pin access
  239. """ decide which kind of GPIO """
  240. def GPIO_factory(gpio,direct):
  241. if direct:
  242. return GPIO_DIRECT(gpio)
  243. else:
  244. return GPIO(gpio)
  245. """ via the gpio/export system """
  246. class GPIO:
  247. ''' this object owns a pin, assures it has an export and accesses it through the gpio-export mechanism'''
  248. def __init__(self, gpio):
  249. self.gpio = gpio
  250. self.set_iomux(True)
  251. create_export(gpio)
  252. def get(self):
  253. logging.debug("GPIO.get")
  254. # we don't care about the export/direction
  255. with open(SYS_PATH + "gpio{}/value".format(self.gpio)) as f:
  256. r = int(f.read())
  257. logging.debug("pin_read of {} returns {}".format(self.gpio,r))
  258. return r
  259. def set(self, value):
  260. logging.debug("GPIO.set {} {}".format(self.gpio, value))
  261. self.set_mode('out')
  262. with open(SYS_PATH + "gpio{}/value".format(self.gpio),"w+b") as f:
  263. f.write(bytes(str(value),"utf-8"))
  264. def set_mode(self,mode_string):
  265. with open('/sys/class/gpio/gpio{}/direction'.format(self.gpio),'w') as f:
  266. f.write(mode_string)
  267. def get_mode_value(self):
  268. with open('/sys/class/gpio/gpio{}/direction'.format(self.gpio)) as f:
  269. return f.read().strip(), self.get()
  270. def set_iomux(self, gpio_mode):
  271. ''' set value=True for this pin to be GPIO,
  272. False for this pin to be special function'''
  273. logging.debug("GPIO: set iomux for pin {} to {}".format(self.gpio,gpio_mode))
  274. port_group = self.gpio // GPIO_PER_PORT
  275. port_offset = self.gpio % GPIO_PER_PORT
  276. mem_set(cpu.IOMUX_ADDRESSES[port_group], 1 << port_offset, gpio_mode)
  277. if gpio_mode == False:
  278. logging.debug("GPIO.set_iomux with mode {}".format(gpio_mode))
  279. remove_export(self.gpio)
  280. def get_iomux(self):
  281. ''' returns 1 when it's in GPIO mode, 0 for alt mode '''
  282. logging.debug("GPIO check the IOMUX for gpio {}".format(self.gpio))
  283. port_group = self.gpio // GPIO_PER_PORT
  284. port_offset = self.gpio % GPIO_PER_PORT
  285. logging.debug("check IOMUX at address {}".format(hex(cpu.IOMUX_ADDRESSES[port_group])))
  286. return mem_get(cpu.IOMUX_ADDRESSES[port_group], 1 << port_offset)
  287. def __repr__(self):
  288. return("gpio"+str(self.gpio))
  289. class GPIO_DIRECT(GPIO):
  290. def __init__(self,gpio):
  291. self.gpio = gpio
  292. def set(self,value):
  293. logging.debug("GPIO_DIRECT.set {} value: {}".format(self.gpio,value))
  294. if self.get_iomux()==0:
  295. self.set_iomux(1)
  296. self.set_mode('out')
  297. low_level_write(self.gpio,IO_DATA,value)
  298. def get(self):
  299. if self.get_iomux() == 0:
  300. self.set_iomux(1)
  301. self.set_mode('in')
  302. return low_level_read(self.gpio,IO_DATA)
  303. def get_mode_value(self):
  304. iomux = self.get_iomux()
  305. if not iomux:
  306. return 'alt','?'
  307. d = low_level_read(self.gpio, IO_DIR)
  308. m = 'in' if d else 'out'
  309. if not pin_has_export(self.gpio):
  310. m = m+'*'
  311. return m, low_level_read(self.gpio,IO_DATA)
  312. def set_mode(self, mode_string):
  313. low_level_set_mode(self.gpio, mode_string);
  314. def set_iomux(self, gpio_mode):
  315. super().set_iomux(gpio_mode)
  316. def create_export(gpio):
  317. ''' make sure this gpio has an export set in the /sys/class/gpio dir '''
  318. if not pin_has_export(gpio):
  319. with open(SYS_PATH + 'export','w') as f:
  320. f.write(str(gpio))
  321. if not pin_has_export(gpio):
  322. print("could not create the gpio-export for pin {}".format(gpio))
  323. print("perhaps you should run this program as root")
  324. sys.exit(1)
  325. return
  326. def remove_export(gpio):
  327. if pin_has_export(gpio):
  328. with open(SYS_PATH + 'unexport','w') as f:
  329. f.write(str(gpio))
  330. return
  331. ################## low level pin control ################
  332. """ bypass the gpio/export system """
  333. PORTA_IOBASE = 0x20930000
  334. PORTB_IOBASE = 0x20931000
  335. PORTC_IOBASE = 0x11a08000
  336. PORTD_IOBASE = 0x20932000
  337. IOBASE_ADDRESSES = (PORTA_IOBASE, PORTB_IOBASE, PORTD_IOBASE, PORTC_IOBASE)
  338. IO_DIR = 0 # [0=out,1=in] +0 direct access, +4 = clr-reg(out), +8 = set-reg(in)
  339. IO_DATA = 0xc # +0 direct access, +4 for set-reg, +8 for clr-reg
  340. def low_level_read(gpio, address_offset):
  341. port_group = gpio // GPIO_PER_PORT
  342. port_offset = gpio % GPIO_PER_PORT
  343. address = IOBASE_ADDRESSES[port_group] + address_offset
  344. r = mem_get(address, 1 << port_offset)
  345. logging.debug("low_level_read of address {} and bit {} returns {}".format(hex(address),port_offset,hex(r)))
  346. return 1 if r else 0
  347. def low_level_write(gpio, address_offset, data):
  348. port_group = gpio // GPIO_PER_PORT
  349. port_offset = gpio % GPIO_PER_PORT
  350. address = IOBASE_ADDRESSES[port_group] + address_offset
  351. mem_set(address, 1 << port_offset, data)
  352. def low_level_set_mode(gpio, mode):
  353. if mode == 'alt':
  354. print("illegal call to low_level_set_mode")
  355. sys.exit(1)
  356. low_level_write(gpio, IO_DIR, 0 if mode=='out' else 1)
  357. def low_level_get_mode(gpio):
  358. return low_level_read(gpio, IO_DIR)
  359. ######################### detect board ###################
  360. # the 2gio has the B3 pin pulled up
  361. # the i96 board leaves the B3 pin floating
  362. B3 = 35
  363. def board_auto_sense():
  364. low_level_set_mode(B3, "out")
  365. low_level_write(B3, IO_DATA, 1)
  366. low_level_set_mode(B3, "in")
  367. a = low_level_read(B3, IO_DATA)
  368. low_level_set_mode(B3, "out")
  369. low_level_write(B3, IO_DATA, 0)
  370. low_level_set_mode(B3, "in")
  371. b = low_level_read(B3, IO_DATA)
  372. board = board_2g if b else board_i96
  373. print("Board auto-detect found {}. To skip auto-detect, create a file named {}".format(board.short_name,board.config_file))
  374. return board
  375. ########################### actions #######################
  376. def do_readall():
  377. exports_dirty = False
  378. print("""
  379. +-----+-----+----------+------+-+ {} +-+------+----------+-----+-----+
  380. | gpio| alt | i96 Name | Mode | V | Physical | V | Mode | i96 Name | alt | gpio|
  381. +-----+-----+----------+------+---+----++----+---+------+----------+-----+-----+""".format(
  382. board.short_name))
  383. for i in range(20):
  384. left_gpio = board.PINS[2*i][2]
  385. if left_gpio != -1:
  386. left_g = GPIO_DIRECT(left_gpio)
  387. left_mode, left_value = left_g.get_mode_value()
  388. left_gpio_str = str(left_gpio)
  389. if '*' in left_mode: exports_dirty = True
  390. else:
  391. left_gpio_str = left_mode = left_value = ""
  392. right_gpio = board.PINS[2*i+1][2]
  393. if right_gpio != -1:
  394. right_g = GPIO_DIRECT(right_gpio)
  395. right_mode, right_value = right_g.get_mode_value()
  396. right_gpio_str = str(right_gpio)
  397. if '*' in right_mode: exports_dirty = True
  398. else:
  399. right_gpio_str = right_mode = right_value = ""
  400. left_value,right_value = str(left_value),str(right_value)
  401. print("| {:3s} | {:4s}| {:9s}| {:4s} | {:1s} | {:2d} || {:2d} | {:1s} | {:4s} | {:9s}| {:4s}| {:3s} |".format(
  402. left_gpio_str,board.PINS[2*i][3],board.PINS[2*i][0],
  403. left_mode,left_value,2*i+1,
  404. 2*i+2,right_value,right_mode,board.PINS[2*i+1][0],
  405. board.PINS[2*i+1][3],right_gpio_str))
  406. print("+-----+-----+----------+------+---+----++----+---+------+----------+-----+-----+")
  407. if exports_dirty:
  408. print("Note: *these pins are set to GPIO mode but do NOT have exports in /sys/class/gpio")
  409. def do_exports():
  410. print("GPIO Pins Mode Value Located")
  411. for f in os.listdir(SYS_PATH):
  412. if re.match('gpio\d',f):
  413. gpio = GPIO(int(f[4:]))
  414. m,v = gpio.get_mode_value()
  415. iop = ""
  416. for i in range(len(board.PINS)):
  417. if board.PINS[i][2]==gpio.gpio:
  418. iop = (board.short_name + " I/O: {}").format(i+1)
  419. break
  420. for i in range(len(board.other)):
  421. if board.other[i][2]==gpio:
  422. iop = board.other[i][0]
  423. break
  424. print("{:>9s} {:3} {:<6} {}".format(f,m,v,iop))
  425. def do_leds():
  426. print("+------+-------+------+-----+")
  427. print("| gpio | func | mode |value|")
  428. print("+------+-------+------+-----+")
  429. for p in board.other:
  430. #print("led function:", p)
  431. g = GPIO_DIRECT(p[2])
  432. m,v = g.get_mode_value()
  433. print("| {:3} | {:6}| {:4} | {:1} |".format(
  434. p[2],p[0],m,v))
  435. print("+------+-------+------+-----+")
  436. def do_read():
  437. logging.debug("do_read: %d",args.gpio)
  438. gpio = args.gpio
  439. g = GPIO_factory(gpio,args.direct)
  440. print(g.get())
  441. def do_write():
  442. logging.debug("do_write: %d %s",args.gpio, args.extra)
  443. gpio = args.gpio
  444. g = GPIO_factory(gpio, args.direct)
  445. if args.extra in ('1', 'on', 'ON'):
  446. v = 1
  447. elif args.extra in ('0', 'off', 'OFF'):
  448. v = 0
  449. else:
  450. print("the 'write' command requires a 2nd argument, either 0 or 1")
  451. sys.exit(1)
  452. g.set(v)
  453. def do_mode():
  454. logging.info("do_mode %d %s", args.gpio, args.extra)
  455. logging.info("the -d flag is {}".format(args.direct))
  456. if not args.gpio or args.gpio<0 or args.gpio>127:
  457. print("the {} command requires a gpio number".format(args.cmd))
  458. sys.exit(1)
  459. if args.extra == None:
  460. m,v = GPIO_DIRECT(args.gpio).get_mode_value()
  461. print(m)
  462. return
  463. if args.extra == "alt":
  464. args.direct = True
  465. gpio = GPIO_factory(args.gpio,args.direct)
  466. if args.extra in ('in','out'):
  467. logging.info("set mode: %s",args.extra)
  468. gpio.set_iomux(True)
  469. gpio.set_mode(args.extra)
  470. elif args.extra=='alt':
  471. logging.info("set alt mode")
  472. gpio.set_iomux(False)
  473. def do_readallx():
  474. exports_dirty = False
  475. print("""
  476. +-----+-----+----------+------+-+ {} +-+------+----------+-----+-----+
  477. | gpio| RDA | alt name | Mode | V | Physical | V | Mode | alt name | RDA | gpio|
  478. +-----+-----+----------+------+---+----++----+---+------+----------+-----+-----+""".format(
  479. board.short_name))
  480. for i in range(20):
  481. left_gpio = board.PINS[2*i][2]
  482. if left_gpio != -1:
  483. left_g = GPIO_DIRECT(left_gpio)
  484. left_mode, left_value = left_g.get_mode_value()
  485. left_gpio_str = str(left_gpio)
  486. if '*' in left_mode: exports_dirty = True
  487. else:
  488. left_gpio_str = left_mode = left_value = ""
  489. right_gpio = board.PINS[2*i+1][2]
  490. if right_gpio != -1:
  491. right_g = GPIO_DIRECT(right_gpio)
  492. right_mode, right_value = right_g.get_mode_value()
  493. right_gpio_str = str(right_gpio)
  494. if '*' in right_mode: exports_dirty = True
  495. else:
  496. right_gpio_str = right_mode = right_value = ""
  497. left_value,right_value = str(left_value),str(right_value)
  498. print("| {:3s} | {:4s}| {:9s}| {:4s} | {:1s} | {:2d} || {:2d} | {:1s} | {:4s} | {:9s}| {:4s}| {:3s} |".format(
  499. left_gpio_str,board.PINS[2*i][1],board.PINS[2*i][4],
  500. left_mode,left_value,2*i+1,
  501. 2*i+2,right_value,right_mode,board.PINS[2*i+1][4],
  502. board.PINS[2*i+1][1],right_gpio_str))
  503. print("+-----+-----+----------+------+---+----++----+---+------+----------+-----+-----+")
  504. if exports_dirty:
  505. print("Note: *these pins are set to GPIO mode but do NOT have exports in /sys/class/gpio")
  506. print("Note: the alt names are based on the Linux naming scheme")
  507. args = None
  508. if __name__ == "__main__":
  509. #logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)
  510. #logging.basicConfig(stream=sys.stderr, level=logging.INFO)
  511. parser = argparse.ArgumentParser(description = "Access GPIO on the OrangePi RDA boards")
  512. parser.add_argument('-v','--version', action='version',
  513. version="opio "+VERSION+" -- python rewrite of gpio; by Pat Beirne")
  514. parser.add_argument('cmd',help="one of: read, write, mode, readall, readallx")
  515. parser.add_argument('gpio',nargs='?',type=int,help="gpio number 0...126")
  516. parser.add_argument('extra',nargs='?')
  517. parser.add_argument('-d',"--direct",help="use low-level access",action="store_true")
  518. parser.add_argument('-2',"--op2giot",help="configure for OrangePi 2G-iot [disable auto-detect]",action="store_true")
  519. parser.add_argument('-9',"--i96",help="configure for OrangePi i96 [disable auto-detect]",action="store_true")
  520. args = parser.parse_args()
  521. if pathlib.Path(board_2g.config_file).exists() or args.op2giot:
  522. board = board_2g
  523. elif pathlib.Path(board_i96.config_file).exists() or args.i96:
  524. board = board_i96
  525. else:
  526. board = board_auto_sense()
  527. switcher = {"readall":do_readall,
  528. "readallx":do_readallx,
  529. "status":do_readall,
  530. "statusx":do_readallx,
  531. "leds":do_leds,
  532. "mode":do_mode,
  533. "read":do_read,
  534. "write":do_write,
  535. "exports":do_exports}
  536. f = switcher.get(args.cmd)
  537. if not f:
  538. print("the available commands are:", ", ".join(sorted(list(switcher.keys()))))
  539. print("function",args.cmd,"not found")
  540. sys.exit(1)
  541. f()