Merge pull request #57 from KMKfw/topic-rotary-encoders-lol-reddit
Turn down for WHAT?! Rotary encoder support
This commit is contained in:
commit
3c5c95cfd7
@ -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')
|
|
@ -1,3 +1,7 @@
|
|||||||
|
CIRCUITPYTHON = 'CircuitPython'
|
||||||
|
MICROPYTHON = 'MicroPython'
|
||||||
|
|
||||||
|
|
||||||
class HIDReportTypes:
|
class HIDReportTypes:
|
||||||
KEYBOARD = 1
|
KEYBOARD = 1
|
||||||
MOUSE = 2
|
MOUSE = 2
|
||||||
|
76
kmk/common/macros/rotary_encoder.py
Normal file
76
kmk/common/macros/rotary_encoder.py
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
import math
|
||||||
|
|
||||||
|
from kmk.common.event_defs import (hid_report_event, keycode_down_event,
|
||||||
|
keycode_up_event)
|
||||||
|
from kmk.common.keycodes import Media
|
||||||
|
from kmk.common.rotary_encoder import RotaryEncoder
|
||||||
|
|
||||||
|
VAL_FALSE = False + 1
|
||||||
|
VAL_NONE = True + 2
|
||||||
|
VAL_TRUE = True + 1
|
||||||
|
VOL_UP_PRESS = keycode_down_event(Media.KC_AUDIO_VOL_UP)
|
||||||
|
VOL_UP_RELEASE = keycode_up_event(Media.KC_AUDIO_VOL_UP)
|
||||||
|
VOL_DOWN_PRESS = keycode_down_event(Media.KC_AUDIO_VOL_DOWN)
|
||||||
|
VOL_DOWN_RELEASE = keycode_up_event(Media.KC_AUDIO_VOL_DOWN)
|
||||||
|
|
||||||
|
|
||||||
|
class RotaryEncoderMacro:
|
||||||
|
def __init__(self, pos_pin, neg_pin, slop_history=1, slop_threshold=1):
|
||||||
|
self.encoder = RotaryEncoder(pos_pin, neg_pin)
|
||||||
|
self.max_history = slop_history
|
||||||
|
self.history = bytearray(slop_history)
|
||||||
|
self.history_idx = 0
|
||||||
|
self.history_threshold = math.floor(slop_threshold * slop_history)
|
||||||
|
|
||||||
|
def scan(self):
|
||||||
|
# Anti-slop logic
|
||||||
|
self.history[self.history_idx] = 0
|
||||||
|
|
||||||
|
reading = self.encoder.direction()
|
||||||
|
self.history[self.history_idx] = VAL_NONE if reading is None else reading + 1
|
||||||
|
|
||||||
|
self.history_idx += 1
|
||||||
|
|
||||||
|
if self.history_idx >= self.max_history:
|
||||||
|
self.history_idx = 0
|
||||||
|
|
||||||
|
nones = 0
|
||||||
|
trues = 0
|
||||||
|
falses = 0
|
||||||
|
|
||||||
|
for val in self.history:
|
||||||
|
if val == VAL_NONE:
|
||||||
|
nones += 1
|
||||||
|
elif val == VAL_TRUE:
|
||||||
|
trues += 1
|
||||||
|
elif val == VAL_FALSE:
|
||||||
|
falses += 1
|
||||||
|
|
||||||
|
if nones >= self.history_threshold:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if trues >= self.history_threshold:
|
||||||
|
return self.on_increase()
|
||||||
|
|
||||||
|
if falses >= self.history_threshold:
|
||||||
|
return self.on_decrease()
|
||||||
|
|
||||||
|
def on_decrease(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def on_increase(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class VolumeRotaryEncoder(RotaryEncoderMacro):
|
||||||
|
def on_decrease(self):
|
||||||
|
yield VOL_DOWN_PRESS
|
||||||
|
yield hid_report_event
|
||||||
|
yield VOL_DOWN_RELEASE
|
||||||
|
yield hid_report_event
|
||||||
|
|
||||||
|
def on_increase(self):
|
||||||
|
yield VOL_UP_PRESS
|
||||||
|
yield hid_report_event
|
||||||
|
yield VOL_UP_RELEASE
|
||||||
|
yield hid_report_event
|
@ -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)
|
@ -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()
|
||||||
|
57
kmk/common/rotary_encoder.py
Normal file
57
kmk/common/rotary_encoder.py
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
from kmk.common.pins import PULL_UP
|
||||||
|
|
||||||
|
|
||||||
|
class RotaryEncoder:
|
||||||
|
# Please don't ask. I don't know. All I know is bit_value
|
||||||
|
# works as expected. Here be dragons, etc. etc.
|
||||||
|
MIN_VALUE = False + 1 << 1 | True + 1
|
||||||
|
MAX_VALUE = True + 1 << 1 | True + 1
|
||||||
|
|
||||||
|
def __init__(self, pos_pin, neg_pin):
|
||||||
|
self.pos_pin = pos_pin
|
||||||
|
self.neg_pin = neg_pin
|
||||||
|
|
||||||
|
self.pos_pin.switch_to_input(pull=PULL_UP)
|
||||||
|
self.neg_pin.switch_to_input(pull=PULL_UP)
|
||||||
|
|
||||||
|
self.prev_bit_value = self.bit_value()
|
||||||
|
|
||||||
|
def value(self):
|
||||||
|
return (self.pos_pin.value(), self.neg_pin.value())
|
||||||
|
|
||||||
|
def bit_value(self):
|
||||||
|
'''
|
||||||
|
Returns 2, 3, 5, or 6 based on the state of the rotary encoder's two
|
||||||
|
bits. This is a total hack but it does what we need pretty efficiently.
|
||||||
|
Shrug.
|
||||||
|
'''
|
||||||
|
return self.pos_pin.value() + 1 << 1 | self.neg_pin.value() + 1
|
||||||
|
|
||||||
|
def direction(self):
|
||||||
|
'''
|
||||||
|
Compares the current rotary position against the last seen position.
|
||||||
|
|
||||||
|
Returns True if we're rotating "positively", False if we're rotating "negatively",
|
||||||
|
and None if no change could safely be detected for any reason (usually this
|
||||||
|
means the encoder itself did not change)
|
||||||
|
'''
|
||||||
|
new_value = self.bit_value()
|
||||||
|
rolling_under = self.prev_bit_value == self.MIN_VALUE and new_value == self.MAX_VALUE
|
||||||
|
rolling_over = self.prev_bit_value == self.MAX_VALUE and new_value == self.MIN_VALUE
|
||||||
|
increasing = new_value > self.prev_bit_value
|
||||||
|
decreasing = new_value < self.prev_bit_value
|
||||||
|
self.prev_bit_value = new_value
|
||||||
|
|
||||||
|
if rolling_over:
|
||||||
|
return True
|
||||||
|
elif rolling_under:
|
||||||
|
return False
|
||||||
|
|
||||||
|
if increasing:
|
||||||
|
return True
|
||||||
|
if decreasing:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Either no change, or not a type of change we can safely detect,
|
||||||
|
# so safely do nothing
|
||||||
|
return None
|
@ -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,
|
||||||
)
|
)
|
||||||
|
@ -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,
|
||||||
)
|
)
|
||||||
|
@ -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
|
||||||
|
@ -19,6 +19,9 @@ class Firmware:
|
|||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
logger.setLevel(log_level)
|
logger.setLevel(log_level)
|
||||||
|
|
||||||
|
import kmk_keyboard_user
|
||||||
|
self.encoders = getattr(kmk_keyboard_user, 'encoders', [])
|
||||||
|
|
||||||
self.hydrated = False
|
self.hydrated = False
|
||||||
|
|
||||||
self.store = Store(kmk_reducer, log_level=log_level)
|
self.store = Store(kmk_reducer, log_level=log_level)
|
||||||
@ -58,3 +61,10 @@ class Firmware:
|
|||||||
|
|
||||||
if update:
|
if update:
|
||||||
self.store.dispatch(update)
|
self.store.dispatch(update)
|
||||||
|
|
||||||
|
for encoder in self.encoders:
|
||||||
|
eupdate = encoder.scan()
|
||||||
|
|
||||||
|
if eupdate:
|
||||||
|
for event in eupdate:
|
||||||
|
self.store.dispatch(event)
|
||||||
|
@ -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
|
|
@ -5,9 +5,19 @@ 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)
|
||||||
|
|
||||||
|
def init(self, *args, **kwargs):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@property
|
||||||
|
def value(self):
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
class Passthrough:
|
class Passthrough:
|
||||||
def __getattr__(self, attr):
|
def __getattr__(self, attr):
|
||||||
@ -16,3 +26,13 @@ class Passthrough:
|
|||||||
|
|
||||||
class Pin:
|
class Pin:
|
||||||
board = Passthrough()
|
board = Passthrough()
|
||||||
|
IN = 'IN'
|
||||||
|
OUT = 'OUT'
|
||||||
|
PULL_DOWN = 'PULL_DOWN'
|
||||||
|
PULL_UP = 'PULL_UP'
|
||||||
|
|
||||||
|
def __call__(self, *args, **kwargs):
|
||||||
|
return self.board
|
||||||
|
|
||||||
|
def __getattr__(self, attr):
|
||||||
|
return getattr(self.board, attr)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
from kmk.common.consts import DiodeOrientation, UnicodeModes
|
from kmk.common.consts import DiodeOrientation, UnicodeModes
|
||||||
from kmk.common.keycodes import KC
|
from kmk.common.keycodes import KC
|
||||||
|
from kmk.common.macros.rotary_encoder import VolumeRotaryEncoder
|
||||||
from kmk.common.macros.simple import send_string, simple_key_sequence
|
from kmk.common.macros.simple import send_string, simple_key_sequence
|
||||||
from kmk.common.macros.unicode import unicode_string_sequence
|
from kmk.common.macros.unicode import unicode_string_sequence
|
||||||
from kmk.common.pins import Pin as P
|
from kmk.common.pins import Pin as P
|
||||||
@ -7,12 +8,18 @@ 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)
|
||||||
|
|
||||||
diode_orientation = DiodeOrientation.COLUMNS
|
diode_orientation = DiodeOrientation.COLUMNS
|
||||||
unicode_mode = UnicodeModes.LINUX
|
unicode_mode = UnicodeModes.LINUX
|
||||||
|
|
||||||
|
encoders = [
|
||||||
|
VolumeRotaryEncoder(P.A3, P.A2, 6, 0.6),
|
||||||
|
]
|
||||||
|
|
||||||
emoticons = AttrDict({
|
emoticons = AttrDict({
|
||||||
# Emojis
|
# Emojis
|
||||||
'BEER': r'🍺',
|
'BEER': r'🍺',
|
||||||
|
Loading…
Reference in New Issue
Block a user