Merge master and reconcile tapdance with splits
This took a bit of brain surgery to firmware.py that deserves its own commit message beyond the default merge commit message - tl;dr though, it appears to work fine.
This commit is contained in:
105
kmk/firmware.py
105
kmk/firmware.py
@@ -34,8 +34,10 @@ import kmk.internal_state # isort:skip
|
||||
|
||||
# Thanks for sticking around. Now let's do real work, starting below
|
||||
|
||||
import busio
|
||||
import gc
|
||||
|
||||
import supervisor
|
||||
from kmk.consts import LeaderMode, UnicodeModes
|
||||
from kmk.hid import USB_HID
|
||||
from kmk.internal_state import InternalState
|
||||
@@ -59,6 +61,15 @@ class Firmware:
|
||||
|
||||
hid_helper = USB_HID
|
||||
|
||||
split_offsets = ()
|
||||
split_flip = False
|
||||
split_side = None
|
||||
split_type = None
|
||||
split_master_left = True
|
||||
is_master = None
|
||||
uart = None
|
||||
uart_flip = True
|
||||
|
||||
def __init__(self):
|
||||
self._state = InternalState(self)
|
||||
|
||||
@@ -75,12 +86,78 @@ class Firmware:
|
||||
self._state.remove_key(key)
|
||||
self._send_hid()
|
||||
|
||||
def _handle_matrix_report(self, update=None):
|
||||
'''
|
||||
Bulk processing of update code for each cycle
|
||||
:param update:
|
||||
'''
|
||||
if update is not None:
|
||||
self._state.matrix_changed(
|
||||
update[0],
|
||||
update[1],
|
||||
update[2],
|
||||
)
|
||||
|
||||
def _send_to_master(self, update):
|
||||
if self.split_master_left:
|
||||
update[1] += self.split_offsets[update[0]]
|
||||
else:
|
||||
update[1] -= self.split_offsets[update[0]]
|
||||
if self.uart is not None:
|
||||
self.uart.write(update)
|
||||
|
||||
def _receive_from_slave(self):
|
||||
if self.uart is not None and self.uart.in_waiting > 0:
|
||||
update = bytearray(self.uart.read(3))
|
||||
# Built in debug mode switch
|
||||
if update == b'DEB':
|
||||
# TODO Pretty up output
|
||||
print(self.uart.readline())
|
||||
return None
|
||||
return update
|
||||
|
||||
return None
|
||||
|
||||
def _send_debug(self, message):
|
||||
'''
|
||||
Prepends DEB and appends a newline to allow debug messages to
|
||||
be detected and handled differently than typical keypresses.
|
||||
:param message: Debug message
|
||||
'''
|
||||
if self.uart is not None:
|
||||
self.uart.write('DEB')
|
||||
self.uart.write(message, '\n')
|
||||
|
||||
def _master_half(self):
|
||||
return supervisor.runtime.serial_connected
|
||||
|
||||
def init_uart(self, tx=None, rx=None, timeout=20):
|
||||
if self._master_half():
|
||||
# If running with one wire, only receive on master
|
||||
if rx is None or self.uart_flip:
|
||||
return busio.UART(tx=rx, rx=None, timeout=timeout)
|
||||
else:
|
||||
return busio.UART(tx=tx, rx=rx, timeout=timeout)
|
||||
|
||||
else:
|
||||
return busio.UART(tx=tx, rx=rx, timeout=timeout)
|
||||
|
||||
def go(self):
|
||||
assert self.keymap, 'must define a keymap with at least one row'
|
||||
assert self.row_pins, 'no GPIO pins defined for matrix rows'
|
||||
assert self.col_pins, 'no GPIO pins defined for matrix columns'
|
||||
assert self.diode_orientation is not None, 'diode orientation must be defined'
|
||||
|
||||
self.is_master == self._master_half()
|
||||
|
||||
if self.split_flip and not self._master_half():
|
||||
self.col_pins = list(reversed(self.col_pins))
|
||||
|
||||
if self.split_side == "Left":
|
||||
self.split_master_left = self.is_master
|
||||
elif self.split_side == "Right":
|
||||
self.split_master_left = not self.is_master
|
||||
|
||||
self.matrix = MatrixScanner(
|
||||
cols=self.col_pins,
|
||||
rows=self.row_pins,
|
||||
@@ -95,17 +172,23 @@ class Firmware:
|
||||
print("Firin' lazers. Keyboard is booted.")
|
||||
|
||||
while True:
|
||||
matrix_report = self.matrix.scan_for_changes()
|
||||
state_changed = False
|
||||
|
||||
if matrix_report is not None:
|
||||
self._state.matrix_changed(
|
||||
matrix_report[0],
|
||||
matrix_report[1],
|
||||
matrix_report[2],
|
||||
)
|
||||
if self.split_type is not None and self._master_half:
|
||||
update = self._receive_from_slave()
|
||||
if update is not None:
|
||||
self._handle_matrix_report(update)
|
||||
state_changed = True
|
||||
|
||||
state_changed = True
|
||||
update = self.matrix.scan_for_changes()
|
||||
|
||||
if update is not None:
|
||||
if self._master_half():
|
||||
self._handle_matrix_report(update)
|
||||
state_changed = True
|
||||
else:
|
||||
# This keyboard is a slave, and needs to send data to master
|
||||
self._send_to_master(update)
|
||||
|
||||
if self._state.hid_pending:
|
||||
self._send_hid()
|
||||
@@ -118,12 +201,14 @@ class Firmware:
|
||||
state_changed = True
|
||||
|
||||
if self._state.macros_pending:
|
||||
# Blindly assume macros are going to change state, which is almost
|
||||
# always a safe assumption
|
||||
state_changed = True
|
||||
for macro in self._state.macros_pending:
|
||||
for key in macro(self):
|
||||
self._send_key(key)
|
||||
|
||||
self._state.resolve_macro()
|
||||
state_changed = True
|
||||
self._state.resolve_macro()
|
||||
|
||||
if self.debug_enabled and state_changed:
|
||||
print('New State: {}'.format(self._state._to_dict()))
|
||||
|
Reference in New Issue
Block a user