power integrated fully, and guarded against i2c locks

power integrated fully, and guarded against i2c locks

led update

touchup
This commit is contained in:
Kyle Brown
2020-11-04 13:01:42 -08:00
parent 34b808efb7
commit 8a166ac91f
14 changed files with 164 additions and 64 deletions

View File

@@ -23,6 +23,7 @@ class KMKKeyboard(_KMKKeyboard):
uart_pin = board.P0_08
rgb_pixel_pin = board.P0_06
i2c = board.I2C
powersave_pin = board.P0_13
coord_mapping = []
coord_mapping.extend(ic(0, x) for x in range(12))

View File

@@ -43,3 +43,9 @@ class Extension:
def after_hid_send(self, keyboard):
raise NotImplementedError
def on_powersave_enable(self, keyboard):
raise NotImplementedError
def on_powersave_disable(self, keyboard):
raise NotImplementedError

View File

@@ -12,7 +12,9 @@ from storage import getmount
class BLE_Split(Extension):
'''Enables splitting keyboards wirelessly'''
def __init__(self, split_flip=True, split_side=None, hid_type=HIDModes.BLE):
def __init__(
self, split_flip=True, split_side=None, psave_ms=30, hid_type=HIDModes.BLE
):
self._is_target = True
self._uart_buffer = []
self.hid_type = hid_type
@@ -27,6 +29,8 @@ class BLE_Split(Extension):
self._uart_connection = None
self._advertisment = None
self._advertising = False
self._psave_ms = psave_ms
self._psave_enable = False
def __repr__(self):
return f'BLE_SPLIT({self._to_dict()})'
@@ -90,6 +94,16 @@ class BLE_Split(Extension):
def after_hid_send(self, keyboard):
return
def on_powersave_enable(self, keyboard):
if self._uart_connection and not self._psave_enable:
self._uart_connection.connection_interval = self._psave_ms
self._psave_enable = True
def on_powersave_disable(self, keyboard):
if self._uart_connection and self._psave_enable:
self._uart_connection.connection_interval = 11.25
self._psave_enable = False
def _check_all_connections(self):
'''Validates the correct number of BLE connections'''
self._connection_count = len(self._ble.connections)

View File

@@ -51,3 +51,9 @@ class International(Extension):
def after_hid_send(self, keyboard):
return
def on_powersave_enable(self, keyboard):
return
def on_powersave_disable(self, keyboard):
return

View File

@@ -82,7 +82,13 @@ class Layers(Extension):
def before_hid_send(self, keyboard):
return
def _after_hid_send(self, keyboard):
def after_hid_send(self, keyboard):
return
def on_powersave_enable(self, keyboard):
return
def on_powersave_disable(self, keyboard):
return
@staticmethod

View File

@@ -76,6 +76,12 @@ class Leader(Extension):
def after_hid_send(self, keyboard):
return
def on_powersave_enable(self, keyboard):
return
def on_powersave_disable(self, keyboard):
return
@staticmethod
def _compile_sequences(sequences):

View File

@@ -90,6 +90,12 @@ class LED(Extension):
return keyboard
def on_powersave_enable(self, keyboard):
return
def on_powersave_disable(self, keyboard):
return
def _init_effect(self):
self._pos = 0
self._effect_init = False
@@ -154,13 +160,10 @@ class LED(Extension):
self._pos = (self._pos + self.animation_speed) % 256
self.set_brightness(self._brightness)
return self
def effect_static(self):
self.set_brightness(self._brightness)
# Set animation mode to none to prevent cycles from being wasted
self.animation_mode = None
return self
def animate(self):
'''
@@ -184,30 +187,23 @@ class LED(Extension):
self.animation_mode = AnimationModes.STATIC
self._enabled = not self._enabled
return state
def _key_led_inc(self, key, state, *args, **kwargs):
self.increase_brightness()
return state
def _key_led_dec(self, key, state, *args, **kwargs):
self.decrease_brightness()
return state
def _key_led_ani(self, key, state, *args, **kwargs):
self.increase_ani()
return state
def _key_led_and(self, key, state, *args, **kwargs):
self.decrease_ani()
return state
def _key_led_mode_static(self, key, state, *args, **kwargs):
self._effect_init = True
self.animation_mode = AnimationModes.STATIC
return state
def _key_led_mode_breathe(self, key, state, *args, **kwargs):
self._effect_init = True
self.animation_mode = AnimationModes.BREATHING
return state

View File

@@ -47,3 +47,9 @@ class MediaKeys(Extension):
def after_hid_send(self, keyboard):
return
def on_powersave_enable(self, keyboard):
return
def on_powersave_disable(self, keyboard):
return

View File

@@ -35,6 +35,12 @@ class ModTap(Extension):
def after_hid_send(self, keyboard):
return
def on_powersave_enable(self, keyboard):
return
def on_powersave_disable(self, keyboard):
return
def mt_pressed(self, key, state, *args, **kwargs):
'''Sets the timer start and acts like a modifier otherwise'''
state.keys_pressed.add(key.meta.mods)

View File

@@ -8,23 +8,23 @@ from kmk.kmktime import sleep_ms, ticks_diff, ticks_ms
class Power(Extension):
def __init__(self, powersave_pin=None, enable=False, is_target=True):
self.enable = enable
def __init__(self, powersave_pin=None):
self.enable = False
self.powersave_pin = powersave_pin # Powersave pin board object
self.is_target = is_target
self._powersave_start = ticks_ms()
self._usb_last_scan = ticks_ms() - 5000
self._psp = None # Powersave pin object
self._i2c = None
self._loopcounter = 0
make_key(
names=('PS_TOG',), on_press=self._ps_tog, on_release=handler_passthrough
)
make_key(
names=('PS_ENB',), on_press=self._ps_enable, on_release=handler_passthrough
names=('PS_ON',), on_press=self._ps_enable, on_release=handler_passthrough
)
make_key(
names=('PS_DIS',), on_press=self._ps_disable, on_release=handler_passthrough
names=('PS_OFF',), on_press=self._ps_disable, on_release=handler_passthrough
)
def __repr__(self):
@@ -34,7 +34,6 @@ class Power(Extension):
return f'''Power(
enable={self.enable}
powersave_pin={self.powersave_pin}
is_target={self.is_target}
_powersave_start={self._powersave_start}
_usb_last_scan={self._usb_last_scan}
_psp={self._psp} )
@@ -44,32 +43,47 @@ class Power(Extension):
return
def on_runtime_disable(self, keyboard):
self.disable_powersave
self.disable_powersave()
def during_bootup(self, keyboard):
self._detect_i2c()
self.enable = not bool(self.usb_scan)
self._i2c_scan()
return
def before_matrix_scan(self, keyboard):
if self.usb_rescan_timer():
self.enable = not bool(self.usb_scan)
return
def after_matrix_scan(self, keyboard, matrix_update):
if matrix_update:
self.psave_time_reset()
else:
self.psleep()
return
def before_hid_send(self, keyboard):
return
def after_hid_send(self, keyboard):
if self.enable:
self.psleep()
def on_powersave_enable(self, keyboard):
'''Gives 10 cycles to allow other extentions to clean up before powersave'''
if keyboard._trigger_powersave_enable:
if self._loopcounter > 10:
self._loopcounter += 1
return
self._loopcounter = 0
keyboard._trigger_powersave_enable = False
self.enable_powersave(keyboard)
return
def enable_powersave(self):
def on_powersave_disable(self, keyboard):
keyboard._trigger_powersave_disable = False
self.disable_powersave()
return
def enable_powersave(self, keyboard):
'''Enables power saving features'''
print('Psave True')
if self.powersave_pin:
if keyboard.i2c_deinit_count >= self._i2c and self.powersave_pin:
# Allows power save to prevent RGB drain.
# Example here https://docs.nicekeyboards.com/#/nice!nano/pinout_schematic
@@ -98,18 +112,23 @@ class Power(Extension):
'''
Sleeps longer and longer to save power the more time in between updates.
'''
if ticks_diff(ticks_ms(), self._powersave_start) <= 20000 and self.is_target:
sleep_ms(1)
elif ticks_diff(ticks_ms(), self._powersave_start) <= 40000 and self.is_target:
sleep_ms(4)
elif ticks_diff(ticks_ms(), self._powersave_start) <= 60000 and self.is_target:
if ticks_diff(ticks_ms(), self._powersave_start) <= 60000:
sleep_ms(8)
elif ticks_diff(ticks_ms(), self._powersave_start) >= 240000:
sleep_ms(250)
sleep_ms(180)
def psave_time_reset(self):
self._powersave_start = ticks_ms()
def _i2c_scan(self):
i2c = board.I2C()
while not i2c.try_lock():
pass
try:
self._i2c = len(i2c.scan())
finally:
i2c.unlock()
def usb_rescan_timer(self):
return bool(ticks_diff(ticks_ms(), self._usb_last_scan) > 5000)
@@ -121,24 +140,16 @@ class Power(Extension):
# https://github.com/adafruit/circuitpython/pull/3513
return True
def _detect_i2c(self):
'''Detects i2c devices and disables cutting power to them'''
# TODO Figure out how this could deinit/reinit instead.
self._i2c = board.I2C()
devices = self._i2c.scan()
if devices != []:
self.powersave_pin = None
def _ps_tog(self):
def _ps_tog(self, key, keyboard, *args, **kwargs):
if self.enable:
self.enable_powersave()
keyboard._trigger_powersave_disable = True
else:
self.disable_powersave()
keyboard._trigger_powersave_enable = True
def _ps_enable(self):
def _ps_enable(self, key, keyboard, *args, **kwargs):
if not self.enable:
self.enable_powersave()
keyboard._trigger_powersave_enable = True
def _ps_disable(self):
def _ps_disable(self, key, keyboard, *args, **kwargs):
if self.enable:
self.disable_powersave()
keyboard._trigger_powersave_disable = True

View File

@@ -168,6 +168,12 @@ class RGB(Extension):
return keyboard
def on_powersave_enable(self, keyboard):
return
def on_powersave_disable(self, keyboard):
self._do_update()
@staticmethod
def time_ms():
return int(time.monotonic() * 1000)

View File

@@ -96,6 +96,12 @@ class Split(Extension):
def after_hid_send(self, keyboard):
return
def on_powersave_enable(self, keyboard):
return
def on_powersave_disable(self, keyboard):
return
def _send(self, update):
if self.split_target_left:
update[1] += self.split_offset

View File

@@ -1,3 +1,5 @@
import gc
from kmk.consts import KMK_RELEASE, UnicodeMode
from kmk.hid import BLEHID, USBHID, AbstractHID, HIDModes
from kmk.keys import KC
@@ -39,6 +41,9 @@ class KMKKeyboard:
state_changed = False
_old_timeouts_len = None
_new_timeouts_len = None
_trigger_powersave_enable = False
_trigger_powersave_disable = False
i2c_deinit_count = 0
# this should almost always be PREpended to, replaces
# former use of reversed_active_layers which had pointless
@@ -345,6 +350,10 @@ class KMKKeyboard:
return self
# Only one GC to allow for extentions to have room.
# There are random memory allocations without this
gc.collect()
def go(self, hid_type=HIDModes.USB, **kwargs):
self.hid_type = hid_type
@@ -372,7 +381,7 @@ class KMKKeyboard:
try:
self._handle_matrix_report(ext.before_matrix_scan(self))
except Exception as err:
print('Failed to run pre matrix function: ', err)
print('Failed to run pre matrix function: ', err, ext)
self.matrix_update = self.matrix.scan_for_changes()
@@ -384,7 +393,7 @@ class KMKKeyboard:
if self._matrix_modify is not None:
self.matrix_update = self._matrix_modify
except Exception as err:
print('Failed to run post matrix function: ', err)
print('Failed to run post matrix function: ', err, ext)
self._handle_matrix_report(self.matrix_update)
self.matrix_update = None
@@ -393,7 +402,7 @@ class KMKKeyboard:
try:
ext.before_hid_send(self)
except Exception as err:
print('Failed to run pre hid function: ', err)
print('Failed to run pre hid function: ', err, ext)
if self.hid_pending:
self._send_hid()
@@ -411,7 +420,21 @@ class KMKKeyboard:
try:
ext.after_hid_send(self)
except Exception as err:
print('Failed to run post hid function: ', err)
print('Failed to run post hid function: ', err, ext)
if self._trigger_powersave_enable:
for ext in self.extensions:
try:
ext.on_powersave_enable(self)
except Exception as err:
print('Failed to run post hid function: ', err, ext)
if self._trigger_powersave_disable:
for ext in self.extensions:
try:
ext.on_powersave_disable(self)
except Exception as err:
print('Failed to run post hid function: ', err, ext)
if self.state_changed:
self._print_debug_cycle()

View File

@@ -7,6 +7,7 @@ import terminalio
from adafruit_display_text import label
from kb import KMKKeyboard
from kmk.extensions.ble_split import BLE_Split
from kmk.extensions.power import Power
from kmk.extensions.rgb import RGB
from kmk.handlers.sequences import send_string, simple_key_sequence
from kmk.hid import HIDModes
@@ -26,19 +27,25 @@ SUPER_L = KC.LM(4, KC.LGUI)
keyboard.tap_time = 320
keyboard.debug_enabled = False
# TODO Get this out of here
rgb_pixel_pin = board.P0_06
rgb_ext = RGB(pixel_pin=rgb_pixel_pin, num_pixels=27, val_limit=100, hue_default=190, sat_default=100, val_default=5)
rgb_ext = RGB(pixel_pin=keyboard.rgb_pixel_pin, num_pixels=27, val_limit=100, hue_default=190, sat_default=100, val_default=5)
split = BLE_Split(split_side=split_side)
keyboard.extensions = [split, rgb_ext]
power = Power(powersave_pin=keyboard.powersave_pin)
displayio.release_displays()
i2c = board.I2C()
display_bus = displayio.I2CDisplay(i2c, device_address=0x3c)
display = adafruit_displayio_ssd1306.SSD1306(display_bus, width=128, height=32)
splash = displayio.Group(max_size=10)
display.show(splash)
keyboard.extensions = [split, rgb_ext, power]
enable_oled = False
if enable_oled:
displayio.release_displays()
i2c = board.I2C()
display_bus = displayio.I2CDisplay(i2c, device_address=0x3c)
display = adafruit_displayio_ssd1306.SSD1306(display_bus, width=128, height=32)
splash = displayio.Group(max_size=10)
display.show(splash)
else:
displayio.release_displays()
keyboard.i2c_deinit_count += 1
keyboard.keymap = [
# DVORAK
@@ -94,7 +101,7 @@ keyboard.keymap = [
#
[
# RAISE1
_______, _______, _______, _______, _______, _______, XXXXXXX, XXXXXXX, KC.N7, KC.N8, KC.N9, KC.DEL, \
_______, _______, _______, _______, _______, _______, KC.PS_TOG, XXXXXXX, KC.N7, KC.N8, KC.N9, KC.DEL, \
_______, _______, _______, _______, _______, _______, XXXXXXX, XXXXXXX, KC.N4, KC.N5, KC.N6, KC.BSLS, \
_______, _______, _______, _______, _______, _______, XXXXXXX, XXXXXXX, KC.N1, KC.N2, KC.N3, KC.MINS, \
_______, _______, _______, _______, KC.EQL, KC.N0,