Clean some code up; force GC on every cycle

This commit is contained in:
Josh Klar 2019-07-12 16:38:50 -07:00
parent 2947f81489
commit 17094a2988
No known key found for this signature in database
GPG Key ID: A4A0C7B4E8EEE222
4 changed files with 72 additions and 90 deletions

View File

@ -50,6 +50,7 @@ import kmk.internal_state # isort:skip
# Thanks for sticking around. Now let's do real work, starting below # Thanks for sticking around. Now let's do real work, starting below
from kmk.kmktime import sleep_ms
from kmk.util import intify_coordinate as ic from kmk.util import intify_coordinate as ic
@ -156,13 +157,18 @@ class Firmware:
) )
def _print_debug_cycle(self, init=False): def _print_debug_cycle(self, init=False):
pre_alloc = gc.mem_alloc()
pre_free = gc.mem_free()
if self.debug_enabled: if self.debug_enabled:
if init: if init:
print('KMKInit()') print('KMKInit()')
print(self) print(self)
print(self._state) print(self._state)
print('GCStats(alloc={} free={})'.format( print('GCStats(pre_alloc={} pre_free={} alloc={} free={})'.format(
pre_alloc,
pre_free,
gc.mem_alloc(), gc.mem_alloc(),
gc.mem_free(), gc.mem_free(),
)) ))
@ -222,21 +228,8 @@ class Firmware:
self.uart.write('DEB') self.uart.write('DEB')
self.uart.write(message, '\n') self.uart.write(message, '\n')
def _master_half(self):
if self.is_master is not None:
return self.is_master
# Working around https://github.com/adafruit/circuitpython/issues/1769
try:
self._hid_helper_inst.create_report([]).send()
self.is_master = True
except OSError:
self.is_master = False
return self.is_master
def init_uart(self, pin, timeout=20): def init_uart(self, pin, timeout=20):
if self._master_half(): if self.is_master:
return busio.UART(tx=None, rx=pin, timeout=timeout) return busio.UART(tx=None, rx=pin, timeout=timeout)
else: else:
return busio.UART(tx=pin, rx=None, timeout=timeout) return busio.UART(tx=pin, rx=None, timeout=timeout)
@ -250,13 +243,27 @@ class Firmware:
self._hid_helper_inst = self.hid_helper() self._hid_helper_inst = self.hid_helper()
# Split keyboard Init # Split keyboard Init
if self.split_flip and not self._master_half(): if self.split_type is not None:
self.col_pins = list(reversed(self.col_pins)) try:
# Working around https://github.com/adafruit/circuitpython/issues/1769
self._hid_helper_inst.create_report([]).send()
self.is_master = True
if self.split_side == "Left": # Sleep 2s so master portion doesn't "appear" to boot quicker than
self.split_master_left = self._master_half() # dependent portions (which will take ~2s to time out on the HID send)
elif self.split_side == "Right": sleep_ms(2000)
self.split_master_left = not self._master_half() except OSError:
self.is_master = False
if self.split_flip and not self.is_master:
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
else:
self.is_master = True
if self.uart_pin is not None: if self.uart_pin is not None:
self.uart = self.init_uart(self.uart_pin) self.uart = self.init_uart(self.uart_pin)
@ -278,12 +285,17 @@ class Firmware:
if not isinstance(k, tuple): if not isinstance(k, tuple):
del self.leader_dictionary[k] del self.leader_dictionary[k]
gc.collect()
self._print_debug_cycle(init=True) self._print_debug_cycle(init=True)
while True: while True:
# Generally speaking, the less stuff GC has to clean out,
# the faster it'll run. Start every cycle with a clean
# garbage bin to avoid random hiccups during keypress handling
gc.collect()
state_changed = False state_changed = False
if self.split_type is not None and self._master_half: if self.split_type is not None and self.is_master:
update = self._receive_from_slave() update = self._receive_from_slave()
if update is not None: if update is not None:
self._handle_matrix_report(update) self._handle_matrix_report(update)
@ -292,7 +304,7 @@ class Firmware:
update = self.matrix.scan_for_changes() update = self.matrix.scan_for_changes()
if update is not None: if update is not None:
if self._master_half(): if self.is_master:
self._handle_matrix_report(update) self._handle_matrix_report(update)
state_changed = True state_changed = True
else: else:

View File

@ -144,7 +144,6 @@ class InternalState:
return self.process_key(kc_changed, is_pressed, int_coord, (row, col)) return self.process_key(kc_changed, is_pressed, int_coord, (row, col))
def process_key(self, key, is_pressed, coord_int=None, coord_raw=None): def process_key(self, key, is_pressed, coord_int=None, coord_raw=None):
if self.tapping and not isinstance(key.meta, TapDanceKeyMeta): if self.tapping and not isinstance(key.meta, TapDanceKeyMeta):
self._process_tap_dance(key, is_pressed) self._process_tap_dance(key, is_pressed)
else: else:

32
kmk/key_validators.py Normal file
View File

@ -0,0 +1,32 @@
from kmk.types import (KeySeqSleepMeta, LayerKeyMeta, ModTapKeyMeta,
TapDanceKeyMeta, UnicodeModeKeyMeta)
def key_seq_sleep_validator(ms):
return KeySeqSleepMeta(ms)
def layer_key_validator(layer, kc=None):
'''
Validates the syntax (but not semantics) of a layer key call. We won't
have access to the keymap here, so we can't verify much of anything useful
here (like whether the target layer actually exists). The spirit of this
existing is mostly that Python will catch extraneous args/kwargs and error
out.
'''
return LayerKeyMeta(layer=layer, kc=kc)
def mod_tap_validator(kc, mods=None):
'''
Validates that mod tap keys are correctly used
'''
return ModTapKeyMeta(kc=kc, mods=mods)
def tap_dance_key_validator(*codes):
return TapDanceKeyMeta(codes)
def unicode_mode_key_validator(mode):
return UnicodeModeKeyMeta(mode)

View File

@ -1,11 +1,11 @@
import gc
import kmk.handlers.layers as layers import kmk.handlers.layers as layers
import kmk.handlers.modtap as modtap import kmk.handlers.modtap as modtap
import kmk.handlers.stock as handlers import kmk.handlers.stock as handlers
from kmk.consts import UnicodeMode from kmk.consts import UnicodeMode
from kmk.types import (AttrDict, KeySeqSleepMeta, LayerKeyMeta, ModTapKeyMeta, from kmk.key_validators import (key_seq_sleep_validator, layer_key_validator,
TapDanceKeyMeta, UnicodeModeKeyMeta) mod_tap_validator, tap_dance_key_validator,
unicode_mode_key_validator)
from kmk.types import AttrDict, UnicodeModeKeyMeta
FIRST_KMK_INTERNAL_KEY = 1000 FIRST_KMK_INTERNAL_KEY = 1000
NEXT_AVAILABLE_KEY = 1000 NEXT_AVAILABLE_KEY = 1000
@ -367,8 +367,6 @@ def make_argumented_key(
return _argumented_key return _argumented_key
gc.collect()
# Modifiers # Modifiers
make_mod_key(code=0x01, names=('LEFT_CONTROL', 'LCTRL', 'LCTL')) make_mod_key(code=0x01, names=('LEFT_CONTROL', 'LCTRL', 'LCTL'))
make_mod_key(code=0x02, names=('LEFT_SHIFT', 'LSHIFT', 'LSFT')) make_mod_key(code=0x02, names=('LEFT_SHIFT', 'LSHIFT', 'LSFT'))
@ -383,8 +381,6 @@ make_mod_key(code=0x07, names=('MEH',))
# HYPR = LCTL | LALT | LSFT | LGUI # HYPR = LCTL | LALT | LSFT | LGUI
make_mod_key(code=0x0F, names=('HYPER', 'HYPR')) make_mod_key(code=0x0F, names=('HYPER', 'HYPR'))
gc.collect()
# Basic ASCII letters # Basic ASCII letters
make_key(code=4, names=('A',)) make_key(code=4, names=('A',))
make_key(code=5, names=('B',)) make_key(code=5, names=('B',))
@ -413,8 +409,6 @@ make_key(code=27, names=('X',))
make_key(code=28, names=('Y',)) make_key(code=28, names=('Y',))
make_key(code=29, names=('Z',)) make_key(code=29, names=('Z',))
gc.collect()
# Numbers # Numbers
# Aliases to play nicely with AttrDict, since KC.1 isn't a valid # Aliases to play nicely with AttrDict, since KC.1 isn't a valid
# attribute key in Python, but KC.N1 is # attribute key in Python, but KC.N1 is
@ -429,8 +423,6 @@ make_key(code=37, names=('8', 'N8'))
make_key(code=38, names=('9', 'N9')) make_key(code=38, names=('9', 'N9'))
make_key(code=39, names=('0', 'N0')) make_key(code=39, names=('0', 'N0'))
gc.collect()
# More ASCII standard keys # More ASCII standard keys
make_key(code=40, names=('ENTER', 'ENT', "\n")) make_key(code=40, names=('ENTER', 'ENT', "\n"))
make_key(code=41, names=('ESCAPE', 'ESC')) make_key(code=41, names=('ESCAPE', 'ESC'))
@ -449,8 +441,6 @@ make_key(code=54, names=('COMMA', 'COMM', ','))
make_key(code=55, names=('DOT', '.')) make_key(code=55, names=('DOT', '.'))
make_key(code=56, names=('SLASH', 'SLSH')) make_key(code=56, names=('SLASH', 'SLSH'))
gc.collect()
# Function Keys # Function Keys
make_key(code=58, names=('F1',)) make_key(code=58, names=('F1',))
make_key(code=59, names=('F2',)) make_key(code=59, names=('F2',))
@ -477,8 +467,6 @@ make_key(code=113, names=('F22',))
make_key(code=114, names=('F23',)) make_key(code=114, names=('F23',))
make_key(code=115, names=('F24',)) make_key(code=115, names=('F24',))
gc.collect()
# Lock Keys, Navigation, etc. # Lock Keys, Navigation, etc.
make_key(code=57, names=('CAPS_LOCK', 'CAPSLOCK', 'CLCK', 'CAPS')) make_key(code=57, names=('CAPS_LOCK', 'CAPSLOCK', 'CLCK', 'CAPS'))
# FIXME: Investigate whether this key actually works, and # FIXME: Investigate whether this key actually works, and
@ -501,8 +489,6 @@ make_key(code=80, names=('LEFT',))
make_key(code=81, names=('DOWN',)) make_key(code=81, names=('DOWN',))
make_key(code=82, names=('UP',)) make_key(code=82, names=('UP',))
gc.collect()
# Numpad # Numpad
make_key(code=83, names=('NUM_LOCK', 'NUMLOCK', 'NLCK')) make_key(code=83, names=('NUM_LOCK', 'NUMLOCK', 'NLCK'))
# FIXME: Investigate whether this key actually works, and # FIXME: Investigate whether this key actually works, and
@ -528,8 +514,6 @@ make_key(code=103, names=('KP_EQUAL', 'PEQL', 'NUMPAD_EQUAL'))
make_key(code=133, names=('KP_COMMA', 'PCMM', 'NUMPAD_COMMA')) make_key(code=133, names=('KP_COMMA', 'PCMM', 'NUMPAD_COMMA'))
make_key(code=134, names=('KP_EQUAL_AS400', 'NUMPAD_EQUAL_AS400')) make_key(code=134, names=('KP_EQUAL_AS400', 'NUMPAD_EQUAL_AS400'))
gc.collect()
# Making life better for folks on tiny keyboards especially: exposes # Making life better for folks on tiny keyboards especially: exposes
# the "shifted" keys as raw keys. Under the hood we're still # the "shifted" keys as raw keys. Under the hood we're still
# sending Shift+(whatever key is normally pressed) to get these, so # sending Shift+(whatever key is normally pressed) to get these, so
@ -556,8 +540,6 @@ make_shifted_key('COMMA', names=('LEFT_ANGLE_BRACKET', 'LABK', '<'))
make_shifted_key('DOT', names=('RIGHT_ANGLE_BRACKET', 'RABK', '>')) make_shifted_key('DOT', names=('RIGHT_ANGLE_BRACKET', 'RABK', '>'))
make_shifted_key('SLSH', names=('QUESTION', 'QUES', '?')) make_shifted_key('SLSH', names=('QUESTION', 'QUES', '?'))
gc.collect()
# International # International
make_key(code=50, names=('NONUS_HASH', 'NUHS')) make_key(code=50, names=('NONUS_HASH', 'NUHS'))
make_key(code=100, names=('NONUS_BSLASH', 'NUBS')) make_key(code=100, names=('NONUS_BSLASH', 'NUBS'))
@ -582,8 +564,6 @@ make_key(code=150, names=('LANG7',))
make_key(code=151, names=('LANG8',)) make_key(code=151, names=('LANG8',))
make_key(code=152, names=('LANG9',)) make_key(code=152, names=('LANG9',))
gc.collect()
# Consumer ("media") keys. Most known keys aren't supported here. A much # Consumer ("media") keys. Most known keys aren't supported here. A much
# longer list used to exist in this file, but the codes were almost certainly # longer list used to exist in this file, but the codes were almost certainly
# incorrect, conflicting with each other, or otherwise "weird". We'll add them # incorrect, conflicting with each other, or otherwise "weird". We'll add them
@ -605,8 +585,6 @@ make_consumer_key(code=184, names=('MEDIA_EJECT', 'EJCT')) # 0xB8
make_consumer_key(code=179, names=('MEDIA_FAST_FORWARD', 'MFFD')) # 0xB3 make_consumer_key(code=179, names=('MEDIA_FAST_FORWARD', 'MFFD')) # 0xB3
make_consumer_key(code=180, names=('MEDIA_REWIND', 'MRWD')) # 0xB4 make_consumer_key(code=180, names=('MEDIA_REWIND', 'MRWD')) # 0xB4
gc.collect()
# Internal, diagnostic, or auxiliary/enhanced keys # Internal, diagnostic, or auxiliary/enhanced keys
# NO and TRNS are functionally identical in how they (don't) mutate # NO and TRNS are functionally identical in how they (don't) mutate
@ -631,18 +609,6 @@ make_key(
on_release=handlers.passthrough, on_release=handlers.passthrough,
) )
def layer_key_validator(layer, kc=None):
'''
Validates the syntax (but not semantics) of a layer key call. We won't
have access to the keymap here, so we can't verify much of anything useful
here (like whether the target layer actually exists). The spirit of this
existing is mostly that Python will catch extraneous args/kwargs and error
out.
'''
return LayerKeyMeta(layer=layer, kc=kc)
# Layers # Layers
make_argumented_key( make_argumented_key(
validator=layer_key_validator, validator=layer_key_validator,
@ -684,15 +650,6 @@ make_argumented_key(
on_release=layers.tt_released, on_release=layers.tt_released,
) )
def mod_tap_validator(kc, mods=None):
'''
Validates that mod tap keys are correctly used
'''
return ModTapKeyMeta(kc=kc, mods=mods)
# ModTap
make_argumented_key( make_argumented_key(
validator=mod_tap_validator, validator=mod_tap_validator,
names=('MT',), names=('MT',),
@ -700,14 +657,6 @@ make_argumented_key(
on_release=modtap.mt_released, on_release=modtap.mt_released,
) )
gc.collect()
def key_seq_sleep_validator(ms):
return KeySeqSleepMeta(ms)
# A dummy key to trigger a sleep_ms call in a sequence of other keys in a # A dummy key to trigger a sleep_ms call in a sequence of other keys in a
# simple sequence macro. # simple sequence macro.
make_argumented_key( make_argumented_key(
@ -716,8 +665,6 @@ make_argumented_key(
on_press=handlers.sleep_pressed, on_press=handlers.sleep_pressed,
) )
# Switch unicode modes at runtime
make_key( make_key(
names=('UC_MODE_NOOP', 'UC_DISABLE'), names=('UC_MODE_NOOP', 'UC_DISABLE'),
meta=UnicodeModeKeyMeta(UnicodeMode.NOOP), meta=UnicodeModeKeyMeta(UnicodeMode.NOOP),
@ -738,22 +685,14 @@ make_key(
meta=UnicodeModeKeyMeta(UnicodeMode.WINC), meta=UnicodeModeKeyMeta(UnicodeMode.WINC),
on_press=handlers.uc_mode_pressed, on_press=handlers.uc_mode_pressed,
) )
def unicode_mode_key_validator(mode):
return UnicodeModeKeyMeta(mode)
make_argumented_key( make_argumented_key(
validator=unicode_mode_key_validator, validator=unicode_mode_key_validator,
names=('UC_MODE',), names=('UC_MODE',),
on_press=handlers.uc_mode_pressed, on_press=handlers.uc_mode_pressed,
) )
# Tap Dance
make_argumented_key( make_argumented_key(
validator=lambda *codes: TapDanceKeyMeta(codes), validator=tap_dance_key_validator,
names=('TAP_DANCE', 'TD'), names=('TAP_DANCE', 'TD'),
on_press=handlers.td_pressed, on_press=handlers.td_pressed,
on_release=handlers.td_released, on_release=handlers.td_released,