-
-
Save joric/327fafcf40a8a8ccb93c9b7eb631100b to your computer and use it in GitHub Desktop.
code.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# see https://github.com/joric/nrfmicro/wiki/Circuitpython | |
import time | |
import board | |
import adafruit_ssd1306 | |
import busio | |
import digitalio | |
import json | |
ready_str = "Hello from Python!" | |
try: | |
f = open('config.json') | |
config = json.load(f) | |
ready_str = config['config']['device_info']['name'] | |
f.close() | |
except Exception as e: | |
print(e) | |
# enable power | |
power_pin = digitalio.DigitalInOut(board.P1_09) | |
power_pin.direction = digitalio.Direction.OUTPUT | |
power_pin.value = False | |
try: | |
i2c = busio.I2C(board.SCL, board.SDA) | |
oled = adafruit_ssd1306.SSD1306_I2C(128, 32, i2c) | |
oled.fill(0) | |
oled.text(ready_str, 0, 0, 1) | |
oled.show() | |
except Exception as e: | |
print('No OLED (wrong pins?)', e) | |
from adafruit_hid.keyboard import Keyboard | |
from adafruit_hid.keyboard_layout_us import KeyboardLayoutUS | |
from adafruit_hid.keycode import Keycode | |
import adafruit_ble | |
from adafruit_ble.advertising import Advertisement | |
from adafruit_ble.advertising.standard import ProvideServicesAdvertisement | |
from adafruit_ble.services.standard.hid import HIDService | |
from adafruit_ble.services.standard.device_info import DeviceInfoService | |
class Matrix: | |
ROWS = () | |
COLS = () | |
ROW2COL = False | |
def __init__(self): | |
self.keys = len(self.ROWS) * len(self.COLS) | |
self.queue = bytearray(self.keys) | |
self.head = 0 | |
self.tail = 0 | |
self.length = 0 | |
self.rows = [] # row as output | |
for pin in self.ROWS: | |
io = digitalio.DigitalInOut(pin) | |
io.direction = digitalio.Direction.OUTPUT | |
io.drive_mode = digitalio.DriveMode.PUSH_PULL | |
io.value = 0 | |
self.rows.append(io) | |
self.cols = [] # col as input | |
for pin in self.COLS: | |
io = digitalio.DigitalInOut(pin) | |
io.direction = digitalio.Direction.INPUT | |
io.pull = digitalio.Pull.DOWN if self.ROW2COL else digitalio.Pull.UP | |
self.cols.append(io) | |
# row selected value depends on diodes' direction | |
self.pressed = bool(self.ROW2COL) | |
self.t0 = [0] * self.keys # key pressed time | |
self.t1 = [0] * self.keys # key released time | |
self.mask = 0 | |
self.count = 0 | |
self._debounce_time = 20000000 | |
def scan(self): | |
""" | |
Scan keyboard matrix and save key event into the queue. | |
:return: length of the key event queue. | |
""" | |
t = time.monotonic_ns() | |
# use local variables to speed up | |
pressed = self.pressed | |
last_mask = self.mask | |
cols = self.cols | |
mask = 0 | |
count = 0 | |
key_index = -1 | |
for row in self.rows: | |
row.value = pressed # select row | |
for col in cols: | |
key_index += 1 | |
if col.value == pressed: | |
key_mask = 1 << key_index | |
if not (last_mask & key_mask): | |
if t - self.t1[key_index] < self._debounce_time: | |
continue | |
self.t0[key_index] = t | |
self.put(key_index) | |
mask |= key_mask | |
count += 1 | |
elif last_mask and (last_mask & (1 << key_index)): | |
if t - self.t0[key_index] < self._debounce_time: | |
mask |= 1 << key_index | |
continue | |
self.t1[key_index] = t | |
self.put(0x80 | key_index) | |
row.value = not pressed | |
self.mask = mask | |
self.count = count | |
return self.length | |
def wait(self, timeout=1000): | |
"""Wait for a new key event or timeout""" | |
last = self.length | |
if timeout: | |
end_time = time.monotonic_ns() + timeout * 1000000 | |
while True: | |
n = self.scan() | |
if n > last or time.monotonic_ns() > end_time: | |
return n | |
else: | |
while True: | |
n = self.scan() | |
if n > last: | |
return n | |
def put(self, data): | |
"""Put a key event into the queue""" | |
self.queue[self.head] = data | |
self.head += 1 | |
if self.head >= self.keys: | |
self.head = 0 | |
self.length += 1 | |
def get(self): | |
"""Remove and return the first event from the queue.""" | |
data = self.queue[self.tail] | |
self.tail += 1 | |
if self.tail >= self.keys: | |
self.tail = 0 | |
self.length -= 1 | |
return data | |
def view(self, n): | |
"""Return the specified event""" | |
return self.queue[(self.tail + n) % self.keys] | |
def __getitem__(self, n): | |
"""Return the specified event""" | |
return self.queue[(self.tail + n) % self.keys] | |
def __len__(self): | |
"""Return the number of events in the queue""" | |
return self.length | |
def get_keydown_time(self, key): | |
"""Return the key pressed time""" | |
return self.t0[key] | |
def get_keyup_time(self, key): | |
"""Return the key released time""" | |
return self.t1[key] | |
def time(self): | |
"""Return current time""" | |
return time.monotonic_ns() | |
def ms(self, t): | |
"""Convert time to milliseconds""" | |
return t // 1000000 | |
@property | |
def debounce_time(self): | |
return self._debounce_time // 1000000 | |
@debounce_time.setter | |
def debounce_time(self, t): | |
"""Set debounce time""" | |
self._debounce_time = t * 1000000 | |
def suspend(self): | |
"""Suspend keyboard""" | |
pass | |
hid = HIDService() | |
advertisement = ProvideServicesAdvertisement(hid) | |
advertisement.appearance = 961 | |
scan_response = Advertisement() | |
ble = adafruit_ble.BLERadio() | |
ble.name = 'Jorne BLE' | |
if ble.connected: | |
for c in ble.connections: | |
c.disconnect() | |
print("advertising") | |
ble.start_advertising(advertisement, scan_response) | |
k = Keyboard(hid.devices) | |
kl = KeyboardLayoutUS(k) | |
Matrix.ROWS = (board.P0_20, board.P0_13, board.P0_24, board.P0_09) | |
Matrix.COLS = (board.P0_30, board.P0_31, board.P0_29, board.P0_02, board.P1_13, board.P0_03) | |
Matrix.ROW2COL = False | |
matrix = Matrix() | |
import neopixel | |
leds = 6 | |
pixels = neopixel.NeoPixel(board.P0_06, leds, auto_write=False) | |
def wheel(p): | |
p = 255 - p | |
if p < 85: | |
return 255-p*3, 0, p*3 | |
if p < 170: | |
p -= 85 | |
return 0, p*3, 255-p*3 | |
p -= 170 | |
return p*3, 255-p*3, 0 | |
def rgb_update(pixels): | |
for i in range(leds): | |
pixels[i] = (wheel((int(time.monotonic()*100.0) + i*256//leds) & 255)) | |
pixels.show() | |
usb_k = False | |
import usb_hid | |
try: | |
usb_k = Keyboard(usb_hid.devices) | |
except: | |
pass | |
def send_key(key, pressed): | |
if pressed: | |
row, col = divmod(key, len(matrix.ROWS)) | |
if row==0: | |
if usb_k: usb_k.send(Keycode.LEFT_GUI) | |
else: | |
k.send(Keycode.ALT, Keycode.TAB) | |
while True: | |
rgb_update(pixels) | |
n = matrix.wait(20) | |
if n == 0: | |
continue | |
for i in range(n): | |
event = matrix.get() | |
key = event & 0x7F | |
pressed = event < 0x80 | |
row, col = divmod(key, len(matrix.ROWS)) | |
print(row, col, pressed) | |
send_key(key, pressed) | |
#oled.fill(0) | |
#oled.text("%dx%d %s" %(row, col, "pressed" if pressed else "released"), 0, 0, 1) | |
#oled.show() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment