kmk_firmware/kmk/pins.py

100 lines
2.8 KiB
Python

from micropython import const
from kmk.consts import CIRCUITPYTHON, MICROPYTHON
PULL_UP = const(1)
PULL_DOWN = const(2)
try:
import board
import digitalio
PLATFORM = CIRCUITPYTHON
PIN_SOURCE = board
except ImportError:
import machine
PLATFORM = MICROPYTHON
PIN_SOURCE = machine.Pin.board
def get_pin(pin):
'''
Cross-platform method to find a pin by string.
The pin definitions are platform-dependent, but this provides
a way to say "I'm using pin D20" without rolling a D20 and
having to actually learn MicroPython/CircuitPython and the
differences in how they handle pinouts.
This also makes the keymap sanity checker actually work for
CircuitPython boards, since it's not possible in CPY to
define a module stub for `board` that uses Passthrough
natively (which is how the MicroPython stub worked originally)
'''
return getattr(PIN_SOURCE, pin)
class AbstractedDigitalPin:
def __init__(self, pin):
self.raw_pin = pin
if PLATFORM == CIRCUITPYTHON:
self.pin = digitalio.DigitalInOut(pin)
elif PLATFORM == MICROPYTHON:
self.pin = machine.Pin(pin)
else:
self.pin = pin
self.call_value = callable(self.pin.value)
def __repr__(self):
return 'AbstractedPin({})'.format(repr(self.raw_pin))
def switch_to_input(self, pull=None):
if PLATFORM == CIRCUITPYTHON:
if pull == PULL_UP:
return self.pin.switch_to_input(pull=digitalio.Pull.UP)
elif pull == PULL_DOWN:
return self.pin.switch_to_input(pull=digitalio.Pull.DOWN)
return self.pin.switch_to_input(pull=pull)
elif PLATFORM == MICROPYTHON:
if pull == PULL_UP:
return self.pin.init(machine.Pin.IN, machine.Pin.PULL_UP)
elif pull == PULL_DOWN:
return self.pin.init(machine.Pin.IN, machine.Pin.PULL_DOWN)
raise ValueError('only PULL_UP and PULL_DOWN supported on MicroPython')
raise NotImplementedError('switch_to_input not supported on platform')
def switch_to_output(self):
if PLATFORM == CIRCUITPYTHON:
return self.pin.switch_to_output()
elif PLATFORM == MICROPYTHON:
return self.pin.init(machine.Pin.OUT)
raise NotImplementedError('switch_to_output not supported on platform')
def value(self, value=None):
if value is None:
if self.call_value:
return self.pin.value()
return self.pin.value
if self.call_value:
return self.pin.value(value)
self.pin.value = value
return value
class PinLookup:
def __getattr__(self, attr):
return AbstractedDigitalPin(get_pin(attr))
Pin = PinLookup()