diff --git a/kmk/extensions/ble_split.py b/kmk/extensions/ble_split.py index ffbba89..94a6408 100644 --- a/kmk/extensions/ble_split.py +++ b/kmk/extensions/ble_split.py @@ -39,13 +39,8 @@ class BLE_Split(Extension): if self.split_flip and not self._is_target: keyboard.col_pins = list(reversed(keyboard.col_pins)) - if self.split_side == 'Left': - self._is_target = True - self.target_advertise() - elif self.split_side == 'Right': - self._is_target = False - self.initiator_scan() + self.connect() # Attempt to sanely guess a coord_mapping if one is not provided. if not keyboard.coord_mapping: keyboard.coord_mapping = [] @@ -77,6 +72,15 @@ class BLE_Split(Extension): elif not self._is_target and self._connection_count < 1: self.initiator_scan() + def connect(self): + if not self.check_all_connections() and self.ble_rescan_timer: + if self.split_side == 'Left': + self._is_target = True + self.target_advertise() + elif self.split_side == 'Right': + self._is_target = False + self.initiator_scan() + def initiator_scan(self): self._uart = None # See if any existing connections are providing UARTService. @@ -88,9 +92,9 @@ class BLE_Split(Extension): break if not self._uart: - print('Scanning...') + print('Scanning') for adv in self._ble.start_scan(ProvideServicesAdvertisement, timeout=20): - print('Scanning...') + print('Scanning') if UARTService in adv.services: self._uart = self._ble.connect(adv) self._ble.stop_scan() @@ -156,3 +160,10 @@ class BLE_Split(Extension): return update return None + + def ble_rescan_timer(self): + return bool(ticks_diff(ticks_ms(), self.ble_last_scan) > 5000) + + def ble_time_reset(self): + self.ble_last_scan = ticks_ms() + return self diff --git a/kmk/extensions/power.py b/kmk/extensions/power.py new file mode 100644 index 0000000..f08e583 --- /dev/null +++ b/kmk/extensions/power.py @@ -0,0 +1,102 @@ +from kmk.extensions import Extension +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 + self.powersave_pin = powersave_pin + self.is_target = is_target + self._powersave_start = ticks_ms() + self._usb_last_scan = ticks_ms() - 5000 + self._psp = None + + def __repr__(self): + return f'Power({self._to_dict()})' + + def _to_dict(self): + return ( + 'Power( ' + f'enable={self.enable} ' + f'powersave_pin={self.powersave_pin} ' + f'is_target={self.is_target} ' + f'_powersave_start={self._powersave_start} ' + f'_usb_last_scan={self._usb_last_scan} ' + f'_psp={self._psp} ' + ')' + ) + + def during_bootup(self, keyboard): + self.enable = not bool(self.usb_scan) + + def before_matrix_scan(self, keyboard_state): + if self.usb_rescan_timer(): + self.enable = not bool(self.usb_scan) + + def after_matrix_scan(self, keyboard_state, matrix_update): + if matrix_update: + self.psave_time_reset() + else: + self.psleep() + + def enable_powersave(self): + print('Psave True') + if self.powersave_pin: + import digitalio + + # Allows power save to prevent RGB drain. + # Example here https://docs.nicekeyboards.com/#/nice!nano/pinout_schematic + if not self._psp: + self._psp = digitalio.DigitalInOut(self.powersave_pin) + self._psp.direction = digitalio.Direction.OUTPUT + self._psp.value = True + # TODO Allow a hook to stop RGB/OLED to deinit or this causes a lockup + + self.enable = True + + return self + + def disable_powersave(self): + print('Psave False') + if self.powersave_pin: + import digitalio + + # Allows power save to prevent RGB drain. + # Example here https://docs.nicekeyboards.com/#/nice!nano/pinout_schematic + if not self._psp: + self._psp = digitalio.DigitalInOut(self.powersave_pin) + self._psp.direction = digitalio.Direction.OUTPUT + self._psp.value = False + # TODO Allow a hook to stop RGB/OLED to reinit + + self.enable = False + + return self + + def psleep(self): + ''' + 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: + sleep_ms(8) + elif ticks_diff(ticks_ms(), self.powersave_start) >= 240000: + sleep_ms(250) + + def psave_time_reset(self): + self.powersave_start = ticks_ms() + return self + + def usb_rescan_timer(self): + return bool(ticks_diff(ticks_ms(), self.usb_last_scan) > 5000) + + def usb_time_reset(self): + self.usb_last_scan = ticks_ms() + return self + + def usb_scan(self): + # TODO Add USB detection here. Currently lies that it's connected + return True