Refactor MatrixScanner to use enhanced Pins abstraction; add DEBUG_ENABLED to SAMD51 boards

This commit is contained in:
Josh Klar 2018-10-11 00:29:59 -07:00
parent 70db4ae84d
commit 3b0cd6c421
No known key found for this signature in database
GPG Key ID: 220F99BD7DB7A99E
10 changed files with 124 additions and 99 deletions

View File

@ -1,9 +0,0 @@
from kmk.common.consts import DiodeOrientation
class AbstractMatrixScanner():
def __init__(self, cols, rows, active_layers, diode_orientation=DiodeOrientation.COLUMNS):
raise NotImplementedError('Abstract implementation')
def scan_for_pressed(self):
raise NotImplementedError('Abstract implementation')

View File

@ -1,3 +1,7 @@
CIRCUITPYTHON = 'CircuitPython'
MICROPYTHON = 'MicroPython'
class HIDReportTypes: class HIDReportTypes:
KEYBOARD = 1 KEYBOARD = 1
MOUSE = 2 MOUSE = 2

View File

@ -1,11 +1,10 @@
import digitalio import digitalio
from kmk.common.abstract.matrix_scanner import AbstractMatrixScanner
from kmk.common.consts import DiodeOrientation from kmk.common.consts import DiodeOrientation
from kmk.common.event_defs import matrix_changed from kmk.common.event_defs import matrix_changed
class MatrixScanner(AbstractMatrixScanner): class MatrixScanner:
def __init__(self, cols, rows, diode_orientation=DiodeOrientation.COLUMNS): def __init__(self, cols, rows, diode_orientation=DiodeOrientation.COLUMNS):
# A pin cannot be both a row and column, detect this by combining the # A pin cannot be both a row and column, detect this by combining the
# two tuples into a set and validating that the length did not drop # two tuples into a set and validating that the length did not drop
@ -15,8 +14,8 @@ class MatrixScanner(AbstractMatrixScanner):
if len(unique_pins) != len(cols) + len(rows): if len(unique_pins) != len(cols) + len(rows):
raise ValueError('Cannot use a pin as both a column and row') raise ValueError('Cannot use a pin as both a column and row')
self.cols = [digitalio.DigitalInOut(pin) for pin in cols] self.cols = cols
self.rows = [digitalio.DigitalInOut(pin) for pin in rows] self.rows = rows
self.diode_orientation = diode_orientation self.diode_orientation = diode_orientation
self.last_pressed_len = 0 self.last_pressed_len = 0
@ -41,15 +40,15 @@ class MatrixScanner(AbstractMatrixScanner):
pressed = [] pressed = []
for oidx, opin in enumerate(self.outputs): for oidx, opin in enumerate(self.outputs):
opin.value = True opin.value(True)
for iidx, ipin in enumerate(self.inputs): for iidx, ipin in enumerate(self.inputs):
if ipin.value: if ipin.value():
pressed.append( pressed.append(
(oidx, iidx) if self.diode_orientation == DiodeOrientation.ROWS else (iidx, oidx) # noqa (oidx, iidx) if self.diode_orientation == DiodeOrientation.ROWS else (iidx, oidx) # noqa
) )
opin.value = False opin.value(False)
if len(pressed) != self.last_pressed_len: if len(pressed) != self.last_pressed_len:
self.last_pressed_len = len(pressed) self.last_pressed_len = len(pressed)

View File

@ -1,18 +1,22 @@
from micropython import const
from kmk.common.consts import CIRCUITPYTHON, MICROPYTHON
PULL_UP = const(1)
PULL_DOWN = const(2)
try: try:
import board import board
import digitalio
PLATFORM = 'CircuitPython' PLATFORM = CIRCUITPYTHON
PIN_SOURCE = board PIN_SOURCE = board
except ImportError: except ImportError:
import machine import machine
PLATFORM = 'MicroPython' PLATFORM = MICROPYTHON
PIN_SOURCE = machine.Pin.board PIN_SOURCE = machine.Pin.board
except ImportError:
from kmk.common.types import Passthrough
PLATFORM = 'Unit Testing'
PIN_SOURCE = Passthrough()
def get_pin(pin): def get_pin(pin):
@ -32,9 +36,64 @@ def get_pin(pin):
return getattr(PIN_SOURCE, pin) 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: class PinLookup:
def __getattr__(self, attr): def __getattr__(self, attr):
return get_pin(attr) return AbstractedDigitalPin(get_pin(attr))
Pin = PinLookup() Pin = PinLookup()

View File

@ -1,14 +1,24 @@
import sys import sys
from logging import WARNING
from kmk.circuitpython.hid import HIDHelper from kmk.circuitpython.hid import HIDHelper
from kmk.circuitpython.matrix import MatrixScanner
from kmk.common.consts import UnicodeModes from kmk.common.consts import UnicodeModes
from kmk.common.matrix import MatrixScanner
from kmk.firmware import Firmware from kmk.firmware import Firmware
def main(): def main():
from kmk_keyboard_user import cols, diode_orientation, keymap, rows import kmk_keyboard_user
cols = getattr(kmk_keyboard_user, 'cols')
diode_orientation = getattr(kmk_keyboard_user, 'diode_orientation')
keymap = getattr(kmk_keyboard_user, 'keymap')
rows = getattr(kmk_keyboard_user, 'rows')
DEBUG_ENABLE = getattr(kmk_keyboard_user, 'DEBUG_ENABLE', False)
if DEBUG_ENABLE:
from logging import DEBUG as log_level
else:
from logging import ERROR as log_level
try: try:
from kmk_keyboard_user import unicode_mode from kmk_keyboard_user import unicode_mode
@ -22,7 +32,7 @@ def main():
col_pins=cols, col_pins=cols,
diode_orientation=diode_orientation, diode_orientation=diode_orientation,
unicode_mode=unicode_mode, unicode_mode=unicode_mode,
log_level=WARNING, log_level=log_level,
matrix_scanner=MatrixScanner, matrix_scanner=MatrixScanner,
hid=HIDHelper, hid=HIDHelper,
) )

View File

@ -1,14 +1,24 @@
import sys import sys
from logging import WARNING
from kmk.circuitpython.hid import HIDHelper from kmk.circuitpython.hid import HIDHelper
from kmk.circuitpython.matrix import MatrixScanner
from kmk.common.consts import UnicodeModes from kmk.common.consts import UnicodeModes
from kmk.common.matrix import MatrixScanner
from kmk.firmware import Firmware from kmk.firmware import Firmware
def main(): def main():
from kmk_keyboard_user import cols, diode_orientation, keymap, rows import kmk_keyboard_user
cols = getattr(kmk_keyboard_user, 'cols')
diode_orientation = getattr(kmk_keyboard_user, 'diode_orientation')
keymap = getattr(kmk_keyboard_user, 'keymap')
rows = getattr(kmk_keyboard_user, 'rows')
DEBUG_ENABLE = getattr(kmk_keyboard_user, 'DEBUG_ENABLE', False)
if DEBUG_ENABLE:
from logging import DEBUG as log_level
else:
from logging import ERROR as log_level
try: try:
from kmk_keyboard_user import unicode_mode from kmk_keyboard_user import unicode_mode
@ -22,7 +32,7 @@ def main():
col_pins=cols, col_pins=cols,
diode_orientation=diode_orientation, diode_orientation=diode_orientation,
unicode_mode=unicode_mode, unicode_mode=unicode_mode,
log_level=WARNING, log_level=log_level,
matrix_scanner=MatrixScanner, matrix_scanner=MatrixScanner,
hid=HIDHelper, hid=HIDHelper,
) )

View File

@ -2,8 +2,8 @@ import sys
import gc import gc
from kmk.common.matrix import MatrixScanner
from kmk.firmware import Firmware from kmk.firmware import Firmware
from kmk.micropython.matrix import MatrixScanner
from kmk.micropython.pyb_hid import HIDHelper from kmk.micropython.pyb_hid import HIDHelper
@ -17,9 +17,9 @@ def main():
DEBUG_ENABLE = getattr(kmk_keyboard_user, 'DEBUG_ENABLE', False) DEBUG_ENABLE = getattr(kmk_keyboard_user, 'DEBUG_ENABLE', False)
if DEBUG_ENABLE: if DEBUG_ENABLE:
from logging import DEBUG from logging import DEBUG as log_level
else: else:
from logging import ERROR as DEBUG from logging import ERROR as log_level
# This will run out of ram at this point unless you manually GC # This will run out of ram at this point unless you manually GC
gc.collect() gc.collect()
@ -31,7 +31,7 @@ def main():
col_pins=cols, col_pins=cols,
diode_orientation=diode_orientation, diode_orientation=diode_orientation,
hid=HIDHelper, hid=HIDHelper,
log_level=DEBUG, log_level=log_level,
matrix_scanner=MatrixScanner, matrix_scanner=MatrixScanner,
) )
# This will run out of ram at this point unless you manually GC # This will run out of ram at this point unless you manually GC

View File

@ -1,63 +0,0 @@
import machine
from kmk.common.abstract.matrix_scanner import AbstractMatrixScanner
from kmk.common.consts import DiodeOrientation
from kmk.common.event_defs import matrix_changed
class MatrixScanner(AbstractMatrixScanner):
def __init__(self, cols, rows, active_layers, diode_orientation=DiodeOrientation.COLUMNS):
# A pin cannot be both a row and column, detect this by combining the
# two tuples into a set and validating that the length did not drop
#
# repr() hackery is because MicroPython Pin objects are not hashable.
# Technically we support passing either a string (hashable) or the
# Pin object directly here, so the hackaround is necessary.
unique_pins = {repr(c) for c in cols} | {repr(r) for r in rows}
if len(unique_pins) != len(cols) + len(rows):
raise ValueError('Cannot use a pin as both a column and row')
self.cols = [machine.Pin(pin) for pin in cols]
self.rows = [machine.Pin(pin) for pin in rows]
self.diode_orientation = diode_orientation
self.active_layers = active_layers
self.last_pressed_len = 0
if self.diode_orientation == DiodeOrientation.COLUMNS:
self.outputs = self.cols
self.inputs = self.rows
elif self.diode_orientation == DiodeOrientation.ROWS:
self.outputs = self.rows
self.inputs = self.cols
else:
raise ValueError('Invalid DiodeOrientation: {}'.format(
self.diode_orientation,
))
for pin in self.outputs:
pin.init(machine.Pin.OUT)
pin.off()
for pin in self.inputs:
pin.init(machine.Pin.IN, machine.Pin.PULL_DOWN)
pin.off()
def scan_for_pressed(self):
pressed = []
for oidx, opin in enumerate(self.outputs):
opin.value(1)
for iidx, ipin in enumerate(self.inputs):
if ipin.value():
pressed.append(
(oidx, iidx) if self.diode_orientation == DiodeOrientation.ROWS else (iidx, oidx) # noqa
)
opin.value(0)
if len(pressed) != self.last_pressed_len:
self.last_pressed_len = len(pressed)
return matrix_changed(pressed)
return None # The default, but for explicitness

View File

@ -5,9 +5,16 @@ class Anything:
def __init__(self, name): def __init__(self, name):
self.name = name self.name = name
def __call__(self, *args, **kwargs):
return self
def __repr__(self): def __repr__(self):
return 'Anything<{}>'.format(self.name) return 'Anything<{}>'.format(self.name)
@property
def value(self):
return None
class Passthrough: class Passthrough:
def __getattr__(self, attr): def __getattr__(self, attr):
@ -16,3 +23,9 @@ class Passthrough:
class Pin: class Pin:
board = Passthrough() board = Passthrough()
def __call__(self, *args, **kwargs):
return self.board
def __getattr__(self, attr):
return getattr(self.board, attr)

View File

@ -7,6 +7,8 @@ from kmk.common.types import AttrDict
from kmk.entrypoints.handwire.itsybitsy_m4_express import main from kmk.entrypoints.handwire.itsybitsy_m4_express import main
from kmk.firmware import Firmware from kmk.firmware import Firmware
DEBUG_ENABLE = True
cols = (P.A4, P.A5, P.D7) cols = (P.A4, P.A5, P.D7)
rows = (P.D12, P.D11, P.D10) rows = (P.D12, P.D11, P.D10)