From 49da93e43628f9333cb8501c48850047bc0b33e3 Mon Sep 17 00:00:00 2001 From: Kyle Brown Date: Fri, 19 Oct 2018 02:22:22 -0700 Subject: [PATCH 1/6] Basic uart split support. Still need docs and testing --- kmk/firmware.py | 89 +++++++++++++++++++++-------- user_keymaps/kdb424/klanck.py | 4 +- user_keymaps/kdb424/levinson_m4.py | 90 ++++++++++++++++++++++++++++++ 3 files changed, 158 insertions(+), 25 deletions(-) create mode 100644 user_keymaps/kdb424/levinson_m4.py diff --git a/kmk/firmware.py b/kmk/firmware.py index 389321d..363f46a 100644 --- a/kmk/firmware.py +++ b/kmk/firmware.py @@ -35,6 +35,9 @@ import kmk.internal_state # isort:skip # Thanks for sticking around. Now let's do real work, starting below import gc +import supervisor +import board +import busio from kmk.consts import LeaderMode, UnicodeModes from kmk.hid import USB_HID @@ -59,6 +62,10 @@ class Firmware: hid_helper = USB_HID + split_type = None + split_offsets = () + split_master_left = True + def __init__(self): self._state = InternalState(self) @@ -75,6 +82,54 @@ class Firmware: self._state.force_keycode_up(key) self._send_hid() + def _handle_update(self, update): + if self.split_type is not None and not self.split_master_left: + update[1] += self.split_offsets[update[1]] + + if update is not None: + self._state.matrix_changed( + update[0], + update[1], + update[2], + ) + + if self._state.hid_pending: + self._send_hid() + + for key in self._state.pending_keys: + self._send_key(key) + self._state.pending_key_handled() + + if self._state.macro_pending: + for key in self._state.macro_pending(self): + self._send_key(key) + + self._state.resolve_macro() + + if self.debug_enabled: + print('New State: {}'.format(self._state._to_dict())) + + def _send_to_master(self, update): + if self.split_type == "UART": + if self.uart is None: + self.uart = busio.UART(board.TX, board.RX, timeout=0) + + # Update column with offset + if self.split_master_left: + update[1] += self.split_offsets[update[1]] + + self.uart.write(update) + + def _receive_from_slave(self): + if self.split_type == "UART": + if self.uart is None: + self.uart = busio.UART(board.TX, board.RX, timeout=0) + + update = self.uart.read() + return update + + return None + 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' @@ -95,30 +150,18 @@ class Firmware: print("Firin' lazers. Keyboard is booted.") while True: - update = self.matrix.scan_for_changes() - if update is not None: - self._state.matrix_changed( - update[0], - update[1], - update[2], - ) + if self.split_type is not None: + update = self._receive_from_slave() + if update is not None: + self._handle_update(update) - if self._state.hid_pending: - self._send_hid() + for update in self.matrix.scan_for_changes(): + # Abstract this later. Bluetooth will fail here + if supervisor.runtime.serial_connected: + self._handle_update(update) - if self.debug_enabled: - print('New State: {}'.format(self._state._to_dict())) - - self._state.process_timeouts() - - for key in self._state.pending_keys: - self._send_key(key) - self._state.pending_key_handled() - - if self._state.macro_pending: - for key in self._state.macro_pending(self): - self._send_key(key) - - self._state.resolve_macro() + else: + # This keyboard is a slave, and needs to send data to master + self._send_to_master(update) gc.collect() diff --git a/user_keymaps/kdb424/klanck.py b/user_keymaps/kdb424/klanck.py index 8d3c9f4..fe593ab 100644 --- a/user_keymaps/kdb424/klanck.py +++ b/user_keymaps/kdb424/klanck.py @@ -16,9 +16,9 @@ keyboard.diode_orientation = DiodeOrientation.COLUMNS # ------------------User level config variables --------------------------------------- keyboard.unicode_mode = UnicodeModes.LINUX -keyboard.tap_time = 900 +keyboard.tap_time = 350 keyboard.leader_timeout = 2000 -keyboard.debug_enabled = True +keyboard.debug_enabled = False emoticons = compile_unicode_string_sequences({ # Emoticons, but fancier diff --git a/user_keymaps/kdb424/levinson_m4.py b/user_keymaps/kdb424/levinson_m4.py new file mode 100644 index 0000000..8d3c9f4 --- /dev/null +++ b/user_keymaps/kdb424/levinson_m4.py @@ -0,0 +1,90 @@ +from kmk.consts import DiodeOrientation, UnicodeModes +from kmk.keycodes import KC +from kmk.keycodes import generate_leader_dictionary_seq as glds +from kmk.macros.simple import send_string +from kmk.macros.unicode import compile_unicode_string_sequences +from kmk.mcus.circuitpython_samd51 import Firmware +from kmk.pins import Pin as P +from kmk.types import AttrDict + +keyboard = Firmware() + +keyboard.col_pins = (P.A0, P.A1, P.A2, P.A3, P.A4, P.A5, P.SCK, P.MOSI, P.MISO, P.RX, P.TX, P.D4) +keyboard.row_pins = (P.D10, P.D11, P.D12, P.D13) +keyboard.diode_orientation = DiodeOrientation.COLUMNS + + +# ------------------User level config variables --------------------------------------- +keyboard.unicode_mode = UnicodeModes.LINUX +keyboard.tap_time = 900 +keyboard.leader_timeout = 2000 +keyboard.debug_enabled = True + +emoticons = compile_unicode_string_sequences({ + # Emoticons, but fancier + 'ANGRY_TABLE_FLIP': r'(ノಠ痊ಠ)ノ彡┻━┻', + 'CHEER': r'+。:.゚ヽ(´∀。)ノ゚.:。+゚゚+。:.゚ヽ(*´∀)ノ゚.:。+゚', + 'TABLE_FLIP': r'(╯°□°)╯︵ ┻━┻', + 'WAT': r'⊙.☉', + 'FF': r'凸(゚Д゚#)', + 'F': r'( ̄^ ̄)凸', + 'MEH': r'╮( ̄_ ̄)╭', + 'YAY': r'o(^▽^)o', +}) + +# ---------------------- Leader Key Macros -------------------------------------------- + +keyboard.leader_dictionary = { + glds('flip'): emoticons.ANGRY_TABLE_FLIP, + glds('cheer'): emoticons.CHEER, + glds('wat'): emoticons.WAT, + glds('ff'): emoticons.FF, + glds('f'): emoticons.F, + glds('meh'): emoticons.MEH, + glds('yay'): emoticons.YAY, +} + +WPM = send_string("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Bibendum arcu vitae elementum curabitur vitae nunc sed. Facilisis sed odio morbi quis.") + +# ---------------------- Keymap --------------------------------------------------------- + +keyboard.keymap = [ + [ + # Default + [KC.GESC, KC.QUOTE, KC.COMMA, KC.DOT, KC.P, KC.Y, KC.F, KC.G, KC.C, KC.R, KC.L, KC.BKSP], + [KC.TAB, KC.A, KC.O, KC.E, KC.U, KC.I, KC.D, KC.H, KC.T, KC.N, KC.S, KC.ENT], + [KC.LSFT, KC.SCLN, KC.Q, KC.J, KC.K, KC.X, KC.B, KC.M, KC.W, KC.V, KC.Z, KC.SLSH], + [KC.LCTRL, KC.LGUI, KC.LALT, KC.LEAD, KC.MO(2), KC.LT(3, KC.SPC), KC.LT(3, KC.SPC), KC.MO(4), KC.LEFT, KC.DOWN, KC.UP, KC.RIGHT], + ], + [ + # Gaming + [KC.TAB, KC.QUOT, KC.COMM, KC.DOT, KC.P, KC.Y, KC.F, KC.G, KC.C, KC.R, KC.L, KC.BKSP], + [KC.ESC, KC.A, KC.O, KC.E, KC.U, KC.I, KC.D, KC.H, KC.T, KC.N, KC.S, KC.ENT], + [KC.LSFT, KC.SCLN, KC.Q, KC.J, KC.K, KC.X, KC.B, KC.M, KC.W, KC.V, KC.Z, KC.SLSH], + [KC.LCTRL, KC.LGUI, KC.LALT, KC.F1, KC.F2, KC.SPC, KC.SPC, KC.MO(4), KC.LEFT, KC.DOWN, KC.UP, KC.RIGHT], + ], + [ + # Raise1 + [KC.TILD, KC.EXLM, KC.AT, KC.HASH, KC.DLR, KC.PERC, KC.CIRC, KC.AMPR, KC.ASTR, KC.LPRN, KC.RPRN, KC.DEL], + [KC.TRNS, KC.NO, KC.NO, KC.NO, KC.NO, KC.NO, KC.NO, KC.NO, KC.NO, KC.LBRC, KC.RBRC, KC.BSLS], + [KC.TRNS, KC.NO, KC.NO, KC.NO, KC.NO, KC.NO, KC.NO, KC.NO, KC.INS, KC.PGDN, KC.PGUP, KC.MINS], + [KC.RESET, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.NO, KC.NO, KC.EQL, KC.HOME, KC.VOLD, KC.VOLU, KC.END], + ], + [ + # Raise2 + [KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.N7, KC.N8, KC.N9, KC.BKSP], + [KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.N4, KC.N5, KC.N6, KC.NO], + [KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.N1, KC.N2, KC.N3, KC.NO], + [KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.N0, KC.N0, KC.PDOT, KC.ENT], + ], + [ + # Raise3 + [WPM, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.F10, KC.F11, KC.F12, KC.LSHIFT(KC.INS)], + [KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.F7, KC.F8, KC.F9, KC.NO], + [KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.F4, KC.F5, KC.F6, KC.NO], + [KC.DF(0), KC.DF(1), KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.F1, KC.F2, KC.F3, KC.NO], + ], +] + +if __name__ == '__main__': + keyboard.go() From af3eccd7155c6153cbc8b8b1a8abd0a12182151a Mon Sep 17 00:00:00 2001 From: Kyle Brown Date: Fri, 19 Oct 2018 03:36:24 -0700 Subject: [PATCH 2/6] First keys on slave half actually type! Still needs a bit of work --- kmk/firmware.py | 32 +++++++++++++++++------------- user_keymaps/kdb424/levinson_m4.py | 6 ++++-- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/kmk/firmware.py b/kmk/firmware.py index 363f46a..7c3f003 100644 --- a/kmk/firmware.py +++ b/kmk/firmware.py @@ -65,6 +65,7 @@ class Firmware: split_type = None split_offsets = () split_master_left = True + uart = None def __init__(self): self._state = InternalState(self) @@ -83,8 +84,8 @@ class Firmware: self._send_hid() def _handle_update(self, update): - if self.split_type is not None and not self.split_master_left: - update[1] += self.split_offsets[update[1]] + # if self.split_type is not None and not self.split_master_left: + # update[1] += self.split_offsets[update[1]] if update is not None: self._state.matrix_changed( @@ -112,20 +113,20 @@ class Firmware: def _send_to_master(self, update): if self.split_type == "UART": if self.uart is None: - self.uart = busio.UART(board.TX, board.RX, timeout=0) + self.uart = busio.UART(board.TX, board.RX, timeout=1) # Update column with offset - if self.split_master_left: - update[1] += self.split_offsets[update[1]] + # if self.split_master_left: + # update[1] += self.split_offsets[update[1]] self.uart.write(update) def _receive_from_slave(self): if self.split_type == "UART": if self.uart is None: - self.uart = busio.UART(board.TX, board.RX, timeout=0) + self.uart = busio.UART(board.TX, board.RX, timeout=1) - update = self.uart.read() + update = self.uart.read(nbytes=3) return update return None @@ -150,18 +151,21 @@ class Firmware: print("Firin' lazers. Keyboard is booted.") while True: - if self.split_type is not None: + if self.split_type is not None and supervisor.runtime.serial_connected: update = self._receive_from_slave() + print(str(update)) if update is not None: self._handle_update(update) for update in self.matrix.scan_for_changes(): - # Abstract this later. Bluetooth will fail here - if supervisor.runtime.serial_connected: - self._handle_update(update) + if update is not None: + # Abstract this later. Bluetooth will fail here + if supervisor.runtime.serial_connected: + if update is not None: + self._handle_update(update) - else: - # This keyboard is a slave, and needs to send data to master - self._send_to_master(update) + else: + # This keyboard is a slave, and needs to send data to master + self._send_to_master(update) gc.collect() diff --git a/user_keymaps/kdb424/levinson_m4.py b/user_keymaps/kdb424/levinson_m4.py index 8d3c9f4..3084822 100644 --- a/user_keymaps/kdb424/levinson_m4.py +++ b/user_keymaps/kdb424/levinson_m4.py @@ -9,8 +9,8 @@ from kmk.types import AttrDict keyboard = Firmware() -keyboard.col_pins = (P.A0, P.A1, P.A2, P.A3, P.A4, P.A5, P.SCK, P.MOSI, P.MISO, P.RX, P.TX, P.D4) -keyboard.row_pins = (P.D10, P.D11, P.D12, P.D13) +keyboard.col_pins = (P.D10, P.D9, P.D7, P.D5, P.A4, P.A5) +keyboard.row_pins = (P.A0, P.A1, P.A2, P.A3) keyboard.diode_orientation = DiodeOrientation.COLUMNS @@ -19,6 +19,8 @@ keyboard.unicode_mode = UnicodeModes.LINUX keyboard.tap_time = 900 keyboard.leader_timeout = 2000 keyboard.debug_enabled = True +keyboard.split_type = "UART" +keyboard.split_offsets = [5, 5, 5, 5] emoticons = compile_unicode_string_sequences({ # Emoticons, but fancier From 8d3e4e0a63513ff857022f28d222ebed4ee33d88 Mon Sep 17 00:00:00 2001 From: Kyle Brown Date: Fri, 19 Oct 2018 12:17:47 -0700 Subject: [PATCH 3/6] Fully working split. Needs further testing --- kmk/firmware.py | 21 +++++++++++++-------- user_keymaps/kdb424/levinson_m4.py | 3 ++- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/kmk/firmware.py b/kmk/firmware.py index 7c3f003..5c2387b 100644 --- a/kmk/firmware.py +++ b/kmk/firmware.py @@ -64,6 +64,7 @@ class Firmware: split_type = None split_offsets = () + split_flip = True split_master_left = True uart = None @@ -86,6 +87,7 @@ class Firmware: def _handle_update(self, update): # if self.split_type is not None and not self.split_master_left: # update[1] += self.split_offsets[update[1]] + print(update[1]) if update is not None: self._state.matrix_changed( @@ -115,9 +117,6 @@ class Firmware: if self.uart is None: self.uart = busio.UART(board.TX, board.RX, timeout=1) - # Update column with offset - # if self.split_master_left: - # update[1] += self.split_offsets[update[1]] self.uart.write(update) @@ -126,8 +125,11 @@ class Firmware: if self.uart is None: self.uart = busio.UART(board.TX, board.RX, timeout=1) - update = self.uart.read(nbytes=3) - return update + if self.uart.in_waiting > 0: + update = bytearray(self.uart.read()) + if self.split_master_left: + update[1] += self.split_offsets[update[0]] + return update return None @@ -137,6 +139,9 @@ class Firmware: assert self.col_pins, 'no GPIO pins defined for matrix columns' assert self.diode_orientation is not None, 'diode orientation must be defined' + if self.split_flip and not supervisor.runtime.serial_connected: + self.col_pins = list(reversed(self.col_pins)) + self.matrix = MatrixScanner( cols=self.col_pins, rows=self.row_pins, @@ -153,16 +158,16 @@ class Firmware: while True: if self.split_type is not None and supervisor.runtime.serial_connected: update = self._receive_from_slave() - print(str(update)) if update is not None: + print(str(update)) self._handle_update(update) for update in self.matrix.scan_for_changes(): if update is not None: # Abstract this later. Bluetooth will fail here if supervisor.runtime.serial_connected: - if update is not None: - self._handle_update(update) + print(str(update)) + self._handle_update(update) else: # This keyboard is a slave, and needs to send data to master diff --git a/user_keymaps/kdb424/levinson_m4.py b/user_keymaps/kdb424/levinson_m4.py index 3084822..661d530 100644 --- a/user_keymaps/kdb424/levinson_m4.py +++ b/user_keymaps/kdb424/levinson_m4.py @@ -20,7 +20,8 @@ keyboard.tap_time = 900 keyboard.leader_timeout = 2000 keyboard.debug_enabled = True keyboard.split_type = "UART" -keyboard.split_offsets = [5, 5, 5, 5] +keyboard.split_flip = True +keyboard.split_offsets = [6, 6, 6, 6] emoticons = compile_unicode_string_sequences({ # Emoticons, but fancier From 744d7c1f5d9753a5a4adce54164e51ed56fc021b Mon Sep 17 00:00:00 2001 From: Kyle Brown Date: Fri, 19 Oct 2018 19:01:39 -0700 Subject: [PATCH 4/6] Needs docs, but is basically complete. #3 --- kmk/firmware.py | 51 ++++++++++++++++-------------- user_keymaps/kdb424/levinson_m4.py | 4 +++ 2 files changed, 31 insertions(+), 24 deletions(-) diff --git a/kmk/firmware.py b/kmk/firmware.py index 5c2387b..9cf9fdd 100644 --- a/kmk/firmware.py +++ b/kmk/firmware.py @@ -34,11 +34,11 @@ import kmk.internal_state # isort:skip # Thanks for sticking around. Now let's do real work, starting below -import gc -import supervisor import board import busio +import gc +import supervisor from kmk.consts import LeaderMode, UnicodeModes from kmk.hid import USB_HID from kmk.internal_state import InternalState @@ -62,11 +62,11 @@ class Firmware: hid_helper = USB_HID - split_type = None split_offsets = () - split_flip = True + split_flip = False split_master_left = True uart = None + uart_flip = False def __init__(self): self._state = InternalState(self) @@ -85,10 +85,6 @@ class Firmware: self._send_hid() def _handle_update(self, update): - # if self.split_type is not None and not self.split_master_left: - # update[1] += self.split_offsets[update[1]] - print(update[1]) - if update is not None: self._state.matrix_changed( update[0], @@ -113,33 +109,41 @@ class Firmware: print('New State: {}'.format(self._state._to_dict())) def _send_to_master(self, update): - if self.split_type == "UART": - if self.uart is None: - self.uart = busio.UART(board.TX, board.RX, timeout=1) + if self.uart is not None: + if self.split_master_left: + update[1] += self.split_offsets[update[0]] self.uart.write(update) def _receive_from_slave(self): - if self.split_type == "UART": - if self.uart is None: - self.uart = busio.UART(board.TX, board.RX, timeout=1) - - if self.uart.in_waiting > 0: - update = bytearray(self.uart.read()) - if self.split_master_left: - update[1] += self.split_offsets[update[0]] - return update + if self.uart is not None and self.uart.in_waiting > 0: + update = bytearray(self.uart.read()) + return update return None + def _master_half(self): + return supervisor.runtime.serial_connected + + def init_uart(self, tx=None, rx=None, timeout=1): + 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' - if self.split_flip and not supervisor.runtime.serial_connected: + if self.split_flip and not self._master_half(): self.col_pins = list(reversed(self.col_pins)) self.matrix = MatrixScanner( @@ -156,7 +160,7 @@ class Firmware: print("Firin' lazers. Keyboard is booted.") while True: - if self.split_type is not None and supervisor.runtime.serial_connected: + if self.split_type is not None and self._master_half: update = self._receive_from_slave() if update is not None: print(str(update)) @@ -165,8 +169,7 @@ class Firmware: for update in self.matrix.scan_for_changes(): if update is not None: # Abstract this later. Bluetooth will fail here - if supervisor.runtime.serial_connected: - print(str(update)) + if self._master_half(): self._handle_update(update) else: diff --git a/user_keymaps/kdb424/levinson_m4.py b/user_keymaps/kdb424/levinson_m4.py index 661d530..2c53c03 100644 --- a/user_keymaps/kdb424/levinson_m4.py +++ b/user_keymaps/kdb424/levinson_m4.py @@ -1,3 +1,6 @@ +import board +import busio + from kmk.consts import DiodeOrientation, UnicodeModes from kmk.keycodes import KC from kmk.keycodes import generate_leader_dictionary_seq as glds @@ -22,6 +25,7 @@ keyboard.debug_enabled = True keyboard.split_type = "UART" keyboard.split_flip = True keyboard.split_offsets = [6, 6, 6, 6] +keyboard.uart = keyboard.init_uart(tx=board.TX, rx=board.RX) emoticons = compile_unicode_string_sequences({ # Emoticons, but fancier From 2b28b99503e96e30b242f11a4d47bcc40dcfb097 Mon Sep 17 00:00:00 2001 From: Kyle Brown Date: Thu, 25 Oct 2018 23:00:11 -0700 Subject: [PATCH 5/6] Finalize docs, and unbreak failed rebase --- docs/split_keyboards.md | 38 ++++++++++++++++++++++++ kmk/firmware.py | 47 +++++++++++++++++++----------- user_keymaps/kdb424/levinson_m4.py | 5 ++-- 3 files changed, 71 insertions(+), 19 deletions(-) create mode 100644 docs/split_keyboards.md diff --git a/docs/split_keyboards.md b/docs/split_keyboards.md new file mode 100644 index 0000000..ea83ac7 --- /dev/null +++ b/docs/split_keyboards.md @@ -0,0 +1,38 @@ +# Split Keyboards +Split keyboards are mostly the same as unsplit and very easy to adapt a keymap for. Currently +UART is supported, though other modes will come later such as Bluetooth and i2c. + +Useful config options: +```python +keyboard.split_type = "UART" # Sets split mode to UART +keyboard.split_flip = True # If your boards are identical but one is flipped, this option is for you +keyboard.split_offsets = [6, 6, 6, 6] # This is the how many keys are on each column on the "Master" half +``` + +## Master Half +Choosing the master half can be done one of 2 ways. You can set this true or false if you only pleg in on one side. +```python +keyboard.split_master_left = True +``` + +## EE HANDS +If you want to plug in on either side, it can be done fairly easily but requires setup. + +On each half of your keyboard make a file called kmk_side.py and add one of these lines to the file +depending on where each piece is physically located. +```python +split_side = "Left" +OR +split_side = "Right" +``` + +and then in your keymap, add the line +```python +from kmk_side import split_side +``` + +# UART +To enable uart it's as simple as adding this line, of course changing the pin +```python +keyboard.uart = keyboard.init_uart(tx=board.SCL) +``` diff --git a/kmk/firmware.py b/kmk/firmware.py index 9cf9fdd..c21de5c 100644 --- a/kmk/firmware.py +++ b/kmk/firmware.py @@ -34,7 +34,6 @@ import kmk.internal_state # isort:skip # Thanks for sticking around. Now let's do real work, starting below -import board import busio import gc @@ -66,7 +65,7 @@ class Firmware: split_flip = False split_master_left = True uart = None - uart_flip = False + uart_flip = True def __init__(self): self._state = InternalState(self) @@ -92,8 +91,13 @@ class Firmware: update[2], ) - if self._state.hid_pending: - self._send_hid() + if self._state.hid_pending: + self._send_hid() + + if self.debug_enabled: + print('New State: {}'.format(self._state._to_dict())) + + self._state.process_timeouts() for key in self._state.pending_keys: self._send_key(key) @@ -105,9 +109,6 @@ class Firmware: self._state.resolve_macro() - if self.debug_enabled: - print('New State: {}'.format(self._state._to_dict())) - def _send_to_master(self, update): if self.uart is not None: @@ -118,7 +119,9 @@ class Firmware: def _receive_from_slave(self): if self.uart is not None and self.uart.in_waiting > 0: - update = bytearray(self.uart.read()) + update = bytearray(self.uart.read(3)) + if self.split_master_left: + update[1] -= self.split_offsets[update[0]] return update return None @@ -146,6 +149,17 @@ class Firmware: if self.split_flip and not self._master_half(): self.col_pins = list(reversed(self.col_pins)) + if self.split_side == "Left": + if supervisor.runtime.serial_connected: + self.split_master_left = True + else: + self.split_master_left = False + else: + if supervisor.runtime.serial_connected: + self.split_master_left = False + else: + self.split_master_left = True + self.matrix = MatrixScanner( cols=self.col_pins, rows=self.row_pins, @@ -163,17 +177,16 @@ class Firmware: if self.split_type is not None and self._master_half: update = self._receive_from_slave() if update is not None: - print(str(update)) self._handle_update(update) - for update in self.matrix.scan_for_changes(): - if update is not None: - # Abstract this later. Bluetooth will fail here - if self._master_half(): - self._handle_update(update) + update = self.matrix.scan_for_changes() - else: - # This keyboard is a slave, and needs to send data to master - self._send_to_master(update) + if update is not None: + if self._master_half(): + self._handle_update(update) + + else: + # This keyboard is a slave, and needs to send data to master + self._send_to_master(update) gc.collect() diff --git a/user_keymaps/kdb424/levinson_m4.py b/user_keymaps/kdb424/levinson_m4.py index 2c53c03..9560964 100644 --- a/user_keymaps/kdb424/levinson_m4.py +++ b/user_keymaps/kdb424/levinson_m4.py @@ -19,13 +19,14 @@ keyboard.diode_orientation = DiodeOrientation.COLUMNS # ------------------User level config variables --------------------------------------- keyboard.unicode_mode = UnicodeModes.LINUX -keyboard.tap_time = 900 +keyboard.tap_time = 350 keyboard.leader_timeout = 2000 -keyboard.debug_enabled = True +keyboard.debug_enabled = False keyboard.split_type = "UART" keyboard.split_flip = True keyboard.split_offsets = [6, 6, 6, 6] keyboard.uart = keyboard.init_uart(tx=board.TX, rx=board.RX) +keyboard.uart_flip = False emoticons = compile_unicode_string_sequences({ # Emoticons, but fancier From 15fea0189b9265fc60e819eb158f70277796afd0 Mon Sep 17 00:00:00 2001 From: Kyle Brown Date: Fri, 26 Oct 2018 14:26:15 -0700 Subject: [PATCH 6/6] Added remote debugger and cleaned up several things Looks good to merge --- .gitignore | 3 ++ docs/split_keyboards.md | 2 +- kmk/firmware.py | 47 ++++++++++++++++++++---------- user_keymaps/kdb424/levinson_m4.py | 17 ++++++----- 4 files changed, 44 insertions(+), 25 deletions(-) diff --git a/.gitignore b/.gitignore index 3e4a0f3..5e7a62f 100644 --- a/.gitignore +++ b/.gitignore @@ -112,3 +112,6 @@ venv.bak/ # Pycharms cruft .idea + +# Personal dev scripts +.scripts diff --git a/docs/split_keyboards.md b/docs/split_keyboards.md index ea83ac7..67b421f 100644 --- a/docs/split_keyboards.md +++ b/docs/split_keyboards.md @@ -4,7 +4,6 @@ UART is supported, though other modes will come later such as Bluetooth and i2c. Useful config options: ```python -keyboard.split_type = "UART" # Sets split mode to UART keyboard.split_flip = True # If your boards are identical but one is flipped, this option is for you keyboard.split_offsets = [6, 6, 6, 6] # This is the how many keys are on each column on the "Master" half ``` @@ -34,5 +33,6 @@ from kmk_side import split_side # UART To enable uart it's as simple as adding this line, of course changing the pin ```python +keyboard.split_type = "UART" keyboard.uart = keyboard.init_uart(tx=board.SCL) ``` diff --git a/kmk/firmware.py b/kmk/firmware.py index c21de5c..b7d05d4 100644 --- a/kmk/firmware.py +++ b/kmk/firmware.py @@ -63,7 +63,9 @@ class Firmware: split_offsets = () split_flip = False + split_side = None split_master_left = True + is_master = None uart = None uart_flip = True @@ -84,6 +86,10 @@ class Firmware: self._send_hid() def _handle_update(self, update): + ''' + Bulk processing of update code for each cycle + :param update: + ''' if update is not None: self._state.matrix_changed( update[0], @@ -110,26 +116,39 @@ class Firmware: self._state.resolve_macro() 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: - - if self.split_master_left: - update[1] += self.split_offsets[update[0]] - 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)) - if self.split_master_left: - update[1] -= self.split_offsets[update[0]] + # 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=1): + 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: @@ -146,19 +165,15 @@ class Firmware: 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": - if supervisor.runtime.serial_connected: - self.split_master_left = True - else: - self.split_master_left = False - else: - if supervisor.runtime.serial_connected: - self.split_master_left = False - else: - self.split_master_left = True + 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, diff --git a/user_keymaps/kdb424/levinson_m4.py b/user_keymaps/kdb424/levinson_m4.py index 9560964..b20f8ce 100644 --- a/user_keymaps/kdb424/levinson_m4.py +++ b/user_keymaps/kdb424/levinson_m4.py @@ -1,7 +1,7 @@ import board import busio -from kmk.consts import DiodeOrientation, UnicodeModes +from kmk.consts import DiodeOrientation, LeaderMode, UnicodeModes from kmk.keycodes import KC from kmk.keycodes import generate_leader_dictionary_seq as glds from kmk.macros.simple import send_string @@ -16,17 +16,18 @@ keyboard.col_pins = (P.D10, P.D9, P.D7, P.D5, P.A4, P.A5) keyboard.row_pins = (P.A0, P.A1, P.A2, P.A3) keyboard.diode_orientation = DiodeOrientation.COLUMNS - -# ------------------User level config variables --------------------------------------- -keyboard.unicode_mode = UnicodeModes.LINUX -keyboard.tap_time = 350 -keyboard.leader_timeout = 2000 -keyboard.debug_enabled = False keyboard.split_type = "UART" keyboard.split_flip = True keyboard.split_offsets = [6, 6, 6, 6] -keyboard.uart = keyboard.init_uart(tx=board.TX, rx=board.RX) keyboard.uart_flip = False +keyboard.uart = keyboard.init_uart(tx=board.TX, rx=board.RX) + +# ------------------User level config variables --------------------------------------- +keyboard.leader_mode = LeaderMode.TIMEOUT +keyboard.unicode_mode = UnicodeModes.LINUX +keyboard.tap_time = 150 +keyboard.leader_timeout = 2000 +keyboard.debug_enabled = True emoticons = compile_unicode_string_sequences({ # Emoticons, but fancier