Files
controller-wisetopdataserver/python/biopro/impl/gpio.py
T

537 lines
14 KiB
Python
Raw Normal View History

2021-12-20 14:52:55 +08:00
import abc
from time import sleep
from typing import Optional, List, Union, Callable
_RUNTIME_COMPILE = False
class P3Pin:
"""
**RPi3 pin usage**
=== =========== === ===========
pin func pin func
=== =========== === ===========
1 3.3V 2 5V
3 SDA(I2C) 4 5V
5 SCL(I2C) 6 GND
7 8 UART0_TXD
9 GND 10 UART0_RXD
11 RST(MEM) 12 UPS_A
13 REQ(MEM) 14 GND
15 BZY(MEM) 16 UPS_B
17 3.3V 18 SEL(MEM)
19 MOSI(SPI) 20 GND
21 MISO(SPI) 22 nRST
23 SCLK(SPI) 24 CS0(SPI)
25 GND 26
27 SD(EEPROM) 28 SC(EEPROM)
29 A2(UART) 30 GND
31 A1(UART) 32 WC(EEPROM)
33 A0(UART) 34 GND
35 LED_SDA 36 A2(74138)
37 LED_SCL 38 A1(74138)
39 GND 40 A0(74138)
=== =========== === ===========
"""
I2C_SDA = 3
I2C_SCL = 5
UART_TXD = 8
UART_RXD = 10
MEM_RST = 11
MEM_REQ = 13
MEM_BZY = 15
MEM_SEL = 18
UPS_ENABLE = 12
UPS_DETECT = 16
RESET = 22
SPI_MOSI = 19
SPI_MISO = 21
SPI_CLK = 23
SPI_CS0 = 24
UART_A0 = 33
UART_A1 = 31
UART_A2 = 29
MEM_A0 = 40
MEM_A1 = 38
MEM_A2 = 36
LED_SDA = 35
LED_SCL = 37
EEPROM_SDA = 27
EEPROM_SCL = 28
EEPROM_WC = 32
V33 = (1, 17)
V50 = (2, 4)
GND = (6, 9, 14, 25, 34, 39)
__slots__ = ()
class CC2650:
USE = 'MA'
__slots__ = ()
if CC2650.USE == 'LP':
CC2650.__doc__ = """
**CC2650 launch pad pin table**
=== ==============
dio func
=== ==============
2 UART_RXD
3 UART_TXD
4 DEBUG_1
5 DEBUG_2
6 LED_R
7 LED_G
8 spi_mosi
9 spi_miso
10 mem_rst
11 mem_bzy
12 mem_req
13 spi_clk
14 spi_cs
15 mem_sel
21 DEBUG_3
22 DEBUG_4
=== ==============
"""
elif CC2650.USE == 'MA':
CC2650.__doc__ = """
**CC2650 moda pin table**
=== === ==================
pin dio func
=== === ==================
1 GND
2 NC
3 GND
4 0 uart_tx
5 1 uart_rx
6 2 I2C_SCL
7 3 I2C_SDA
8 4 mem_rst
9 J_TMS
10 J_TCK
11 5 J_TDO
12 6 J_TDI
13 nRST
14 7
15 8 mem_sel
16 9 spi_cs
17 10 spi_clk
18 11 spi_mosi
19 12 spi_miso
20 13 mem_bzy
21 14 mem_req
22 Vdd
23 Vdd
24 NC
25 GND
26 EGP(GND)
27 EGP(GND)
28 EGP(GND)
29 EGP(GND)
=== === ==================
BoosterPack connector
=========== == == = =========== == == ===========
func J1 J1 | func J2 J2 func
=========== == == = =========== == == ===========
3.3V x | x GND
7 x | x 8 mem_sel
uart_tx 0 x | x 9 spi_cs
uart_rx 1 x | x x
2 x | x LP_RST
3 x | N_RST 11 spi_mosi
spi_clk 10 x | x 12 spi_miso
mem_rst 4 x | x 13 mem_bzy
5 x | x 14 mem_req
6 x | x LEGACY_RST
=========== == == = =========== == == ===========
"""
class GPIO:
"""
document page
https://sourceforge.net/p/raspberry-gpio-python/wiki/BasicUsage/
source code
https://github.com/Tieske/rpi-gpio/blob/master/source/py_gpio.c
**pins on RaspberryPi3**
======= =========== === === =========== ======
GPIO func pin pin func GPIO
======= =========== === === =========== ======
N/A 3.3V 1 2 5V N/A
GPIO2 SDA1(I2C) 3 4 5V N/A
GPIO3 SCL1(I2C) 5 6 GND N/A
GPIO4 GCLK 7 8 UART0_TXD GPIO14
N/A GND 9 10 UART0_RXD GPIO15
GPIO17 GEN0 11 12 GEN1 GPIO18
GPIO27 GEN2 13 14 GND N/A
GPIO22 GEN3 15 16 GEN4 GPIO23
N/A 3.3V 17 18 GEN5 GPIO24
GPIO10 MOSI(SPI) 19 20 GND N/A
GPIO9 MISO(SPI) 21 22 GEN6 GPIO25
GPIO11 SCLK(SPI) 23 24 GE0_N(SPI) GPIO8
N/A GND 25 26 GE1_N(SPI) GPIO7
EEPROM ID_SD 27 28 ID_SC EEPROM
GPIO5 N/A 29 30 GND N/A
GPIO6 N/A 31 32 GPIO12
GPIO13 N/A 33 34 GND N/A
GPIO19 N/A 35 36 N/A GPIO16
GPIO26 N/A 37 38 N/A GPIO20
N/A GND 39 40 N/A GPIO21
======= =========== === === =========== ======
"""
# Values
LOW = False
HIGH = True
# Modes
BCM = 11
BOARD = 10
# Pull
PUD_OFF = 20
PUD_DOWN = 21
PUD_UP = 22
# Edges
RISING = 31
FALLING = 32
BOTH = 33
# Functions
OUT = 0
IN = 1
SERIAL = 40
SPI = 41
I2C = 42
HARD_PWM = 43
UNKNOWN = -1
INSTANCE = None
__slots__ = ()
@classmethod
def _gpio_init(cls):
try:
import RPi.GPIO as _GPIO
_GPIO.setwarnings(False)
_GPIO.setmode(cls.BOARD)
except (RuntimeError, ImportError):
# not in the RaspberryPi3 environment
import fake_rpi
# all GPIO call just print to stdout
_GPIO = fake_rpi.RPi.GPIO
cls.INSTANCE = _GPIO
@classmethod
def get_instance(cls) -> 'GPIO':
if cls.INSTANCE is None:
cls._gpio_init()
return cls.INSTANCE
@classmethod
def setup(cls, channel: int, direction: int, initial: int = None, pull_up_down: int = None):
if direction == cls.IN:
cls.get_instance().setup(channel, direction, pull_up_down=pull_up_down)
else:
cls.get_instance().setup(channel, direction, initial=initial)
@classmethod
def PWM(cls, channel: int, frequency: float):
return cls.get_instance().PWM(channel, frequency)
@classmethod
def input(cls, channel: int) -> bool:
return cls.get_instance().input(channel)
@classmethod
def cleanup(cls, pin: Union[None, int, List[int]] = None):
if pin is None:
cls.get_instance().cleanup()
Pin.ALL.clear()
else:
cls.get_instance().cleanup(pin)
if isinstance(pin, int):
Pin.ALL = list(filter(lambda p: p.pin_number != pin, Pin.ALL))
else:
Pin.ALL = list(filter(lambda p: p.pin_number not in pin, Pin.ALL))
@classmethod
def output(cls, channel: Union[int, List[int]], state: Union[bool, List[bool]]):
cls.get_instance().output(channel, state)
@classmethod
def wait_for_edge(cls, channel: int, edge: int, timeout: int = None, bouncetime=1) -> Optional[int]:
return cls.get_instance().wait_for_edge(channel, edge, timeout=timeout, bouncetime=bouncetime)
@classmethod
def add_event_detect(cls,
channel: int,
edge: int,
callback: Callable[[int], None] = None,
bouncetime=1):
if callback is None:
cls.get_instance().add_event_detect(channel, edge, bouncetime=bouncetime)
else:
cls.get_instance().add_event_detect(channel, edge, callback, bouncetime)
@classmethod
def remove_event_detect(cls, channel: int):
cls.get_instance().remove_event_detect(channel)
@classmethod
def event_detected(cls, channel: int) -> bool:
return cls.get_instance().event_detected(channel)
@classmethod
def add_event_callback(cls, channel: int, callback: Callable[[int], None], bouncetime=0):
cls.get_instance().add_event_callback(channel, callback, bouncetime)
@classmethod
def gpio_function(cls, channel: int) -> int:
"""
https://sourceforge.net/p/raspberry-gpio-python/wiki/Checking%20function%20of%20GPIO%20channels/
:return: one of GPIO.IN, GPIO.OUT, GPIO.SPI, GPIO.I2C, GPIO.HARD_PWM, GPIO.SERIAL, GPIO.UNKNOWN
"""
return cls.get_instance().gpio_function(channel)
class Pin(metaclass=abc.ABCMeta):
ALL: List['Pin'] = []
__slots__ = '_pin_number',
def __init__(self, pin_number: int):
self._pin_number = pin_number
self.ALL.append(self)
@property
def pin_number(self) -> int:
return self._pin_number
def gpio_function(self) -> int:
return GPIO.gpio_function(self._pin_number)
def close(self):
GPIO.cleanup(self._pin_number)
@classmethod
def get_used(cls, pin_number: int) -> Optional['Pin']:
for p in cls.ALL:
if p._pin_number == pin_number:
return p
return None
class OutputPin(Pin):
"""
https://sourceforge.net/p/raspberry-gpio-python/wiki/Outputs/
"""
__slots__ = ('_state',)
def __init__(self, pin_number: int, initial=False):
super().__init__(pin_number)
GPIO.setup(pin_number, GPIO.OUT, initial=1 if initial else 0)
self._state = False
def __bool__(self):
return self._state
def __int__(self):
return 1 if self._state else 0
def output(self, value: bool):
self._state = value
if value:
GPIO.output(self._pin_number, GPIO.HIGH)
else:
GPIO.output(self._pin_number, GPIO.LOW)
def pulse(self, sleep_time: float = 0):
GPIO.output(self._pin_number, not self._state)
if sleep_time > 0:
sleep(sleep_time)
GPIO.output(self._pin_number, self._state)
def output_switch(self):
self.output(not self._state)
@classmethod
def get_used(cls, pin_number: int, initial=False) -> 'OutputPin':
pin = Pin.get_used(pin_number)
if pin is not None:
if not isinstance(pin, OutputPin):
raise RuntimeError('pin has set as output')
return pin
else:
return OutputPin(pin_number, initial)
class InputPin(Pin):
"""
https://sourceforge.net/p/raspberry-gpio-python/wiki/Inputs/
"""
__slots__ = ()
def __init__(self, pin_number: int, pull_up_down=False):
super().__init__(pin_number)
GPIO.setup(pin_number, GPIO.IN, pull_up_down=GPIO.PUD_UP if pull_up_down else GPIO.PUD_DOWN)
def __bool__(self):
return GPIO.input(self._pin_number) > 0
def __int__(self):
return GPIO.input(self._pin_number)
def input(self) -> int:
return GPIO.input(self._pin_number)
def wait_for_edge(self, edge: int, timeout: int = None, bouncetime=1) -> bool:
return GPIO.wait_for_edge(self._pin_number, edge, timeout=timeout, bouncetime=bouncetime) is not None
def add_event_detect(self, edge: int, callback: Callable[[int], None] = None, bouncetime=1):
GPIO.add_event_detect(self._pin_number, edge, callback, bouncetime)
def remove_event_detect(self):
GPIO.remove_event_detect(self._pin_number)
def event_detected(self) -> bool:
return GPIO.event_detected(self._pin_number)
def add_event_callback(self, callback: Callable[[int], None]):
GPIO.add_event_callback(self._pin_number, callback)
@classmethod
def get_used(cls, pin_number: int, pull_up_down=False) -> 'InputPin':
pin = Pin.get_used(pin_number)
if pin is not None:
if not isinstance(pin, InputPin):
raise RuntimeError('pin has set as output')
return pin
else:
return InputPin(pin_number, pull_up_down)
class PWMPin(Pin):
"""
https://sourceforge.net/p/raspberry-gpio-python/wiki/PWM/
"""
__slots__ = ('_instance', '_frequency', '_duty_cycle')
def __init__(self, pin_number: int, frequency: float, duty_cycle: int = 0):
super().__init__(pin_number)
self._instance = GPIO.PWM(pin_number, frequency)
self._frequency = frequency
self._duty_cycle = duty_cycle
@property
def frequency(self) -> float:
return self._frequency
@frequency.setter
def frequency(self, value: float):
if value <= 0:
raise ValueError('illegal frequency value : ' + str(value))
self._frequency = value
self._instance.ChangeFrequency(value)
@property
def duty_cycle(self) -> int:
return self._duty_cycle
@duty_cycle.setter
def duty_cycle(self, value: int):
if not (0 <= value <= 100):
raise ValueError('illegal duty cycle value : ' + str(value))
self._duty_cycle = value
self._instance.ChangeDutyCycle(value)
def start(self):
self._instance.start(self._duty_cycle)
def stop(self):
self._instance.stop()
if not _RUNTIME_COMPILE:
def hardware_test():
ret = {}
ret['pin'] = pin = [None for _ in range(40)]
ret['output'] = _o = []
ret['input'] = _i = []
for attr_name in dir(P3Pin):
if not attr_name.startswith('_'):
attr_value = getattr(P3Pin, attr_name)
if isinstance(attr_value, int):
p = attr_value - 1
pin[p] = attr_name
elif isinstance(attr_value, tuple):
for p in attr_value:
pin[p - 1] = attr_name
for p in Pin.ALL:
if isinstance(p, InputPin):
_i.append(p.pin_number)
elif isinstance(p, OutputPin):
_o.append(p.pin_number)
return ret
if __name__ == '__main__':
print(hardware_test())