537 lines
14 KiB
Python
537 lines
14 KiB
Python
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())
|