You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							89 lines
						
					
					
						
							2.4 KiB
						
					
					
				
			
		
		
	
	
							89 lines
						
					
					
						
							2.4 KiB
						
					
					
				| import os
 | |
| import fcntl
 | |
| import ctypes
 | |
| from functools import cache
 | |
| 
 | |
| def gpio_init(pin: int, output: bool) -> None:
 | |
|   try:
 | |
|     with open(f"/sys/class/gpio/gpio{pin}/direction", 'wb') as f:
 | |
|       f.write(b"out" if output else b"in")
 | |
|   except Exception as e:
 | |
|     print(f"Failed to set gpio {pin} direction: {e}")
 | |
| 
 | |
| def gpio_set(pin: int, high: bool) -> None:
 | |
|   try:
 | |
|     with open(f"/sys/class/gpio/gpio{pin}/value", 'wb') as f:
 | |
|       f.write(b"1" if high else b"0")
 | |
|   except Exception as e:
 | |
|     print(f"Failed to set gpio {pin} value: {e}")
 | |
| 
 | |
| def gpio_read(pin: int) -> bool | None:
 | |
|   val = None
 | |
|   try:
 | |
|     with open(f"/sys/class/gpio/gpio{pin}/value", 'rb') as f:
 | |
|       val = bool(int(f.read().strip()))
 | |
|   except Exception as e:
 | |
|     print(f"Failed to set gpio {pin} value: {e}")
 | |
| 
 | |
|   return val
 | |
| 
 | |
| def gpio_export(pin: int) -> None:
 | |
|   if os.path.isdir(f"/sys/class/gpio/gpio{pin}"):
 | |
|     return
 | |
| 
 | |
|   try:
 | |
|     with open("/sys/class/gpio/export", 'w') as f:
 | |
|       f.write(str(pin))
 | |
|   except Exception:
 | |
|     print(f"Failed to export gpio {pin}")
 | |
| 
 | |
| @cache
 | |
| def get_irq_action(irq: int) -> list[str]:
 | |
|   try:
 | |
|     with open(f"/sys/kernel/irq/{irq}/actions") as f:
 | |
|       actions = f.read().strip().split(',')
 | |
|       return actions
 | |
|   except FileNotFoundError:
 | |
|     return []
 | |
| 
 | |
| def get_irqs_for_action(action: str) -> list[str]:
 | |
|   ret = []
 | |
|   with open("/proc/interrupts") as f:
 | |
|     for l in f.readlines():
 | |
|       irq = l.split(':')[0].strip()
 | |
|       if irq.isdigit() and action in get_irq_action(irq):
 | |
|         ret.append(irq)
 | |
|   return ret
 | |
| 
 | |
| # *** gpiochip ***
 | |
| 
 | |
| class gpioevent_data(ctypes.Structure):
 | |
|   _fields_ = [
 | |
|     ("timestamp", ctypes.c_uint64),
 | |
|     ("id", ctypes.c_uint32),
 | |
|   ]
 | |
| 
 | |
| class gpioevent_request(ctypes.Structure):
 | |
|   _fields_ = [
 | |
|     ("lineoffset", ctypes.c_uint32),
 | |
|     ("handleflags", ctypes.c_uint32),
 | |
|     ("eventflags", ctypes.c_uint32),
 | |
|     ("label", ctypes.c_char * 32),
 | |
|     ("fd", ctypes.c_int)
 | |
|   ]
 | |
| 
 | |
| def gpiochip_get_ro_value_fd(label: str, gpiochip_id: int, pin: int) -> int:
 | |
|   GPIOEVENT_REQUEST_BOTH_EDGES = 0x3
 | |
|   GPIOHANDLE_REQUEST_INPUT = 0x1
 | |
|   GPIO_GET_LINEEVENT_IOCTL = 0xc030b404
 | |
| 
 | |
|   rq = gpioevent_request()
 | |
|   rq.lineoffset = pin
 | |
|   rq.handleflags = GPIOHANDLE_REQUEST_INPUT
 | |
|   rq.eventflags = GPIOEVENT_REQUEST_BOTH_EDGES
 | |
|   rq.label = label.encode('utf-8')[:31] + b'\0'
 | |
| 
 | |
|   fd = os.open(f"/dev/gpiochip{gpiochip_id}", os.O_RDONLY)
 | |
|   fcntl.ioctl(fd, GPIO_GET_LINEEVENT_IOCTL, rq)
 | |
|   os.close(fd)
 | |
|   return int(rq.fd)
 | |
| 
 |