more example
This commit is contained in:
parent
3d42798227
commit
8a6d35c0c3
3 changed files with 205 additions and 5 deletions
|
|
@ -8,7 +8,7 @@
|
|||
# * There are no diodes, not even on modifiers, so there's only 2-key rollover.
|
||||
|
||||
import asyncio.core
|
||||
from board import * # pylint: disable=wildcard-import,unused-wildcard-import
|
||||
import board
|
||||
import keypad
|
||||
from adafruit_hid.keycode import Keycode as K
|
||||
from adafruit_hid.keyboard import Keyboard
|
||||
|
|
@ -22,10 +22,9 @@ POSITIONAL = True
|
|||
# 1 3 6 7 8 9 10 11 12 13 14 15 16 17 18 19 # connector pins
|
||||
# R5 C7 R7 C4 R1 C5 C6 R3 R2 R4 C2 C1 R6 C3 C0 R0 # row/column in schematic
|
||||
# D2 D3 D4 D5 D6 D7 D8 D9 D10 MOSI MISO SCK A0 A1 A2 A3 # conencted to kb2040 at
|
||||
# pylint: disable=undefined-variable
|
||||
rows = [A3, D6, D10, D9, MOSI, D2, A0, D4] # give the following ...
|
||||
cols = [A2, SCK, MISO, A1, D5, D7, D8, D3]
|
||||
# pylint: enable=undefined-variable
|
||||
# results in the the following assignment of rows and columns:
|
||||
rows = [board.A3, board.D6, board.D10, board.D9, board.MOSI, board.D2, board.A0, board.D4]
|
||||
cols = [board.A2, board.SCK, board.MISO, board.A1, board.D5, board.D7, board.D8, board.D3]
|
||||
|
||||
# ROM listing of key values from ed7.src in
|
||||
# http://www.zimmers.net/anonftp/pub/cbm/src/plus4/ted_kernal_basic_src.tar.gz
|
||||
43
CircuitPython_Commodore_16_KB2040/basic/code.py
Normal file
43
CircuitPython_Commodore_16_KB2040/basic/code.py
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
# SPDX-FileCopyrightText: 2022 Jeff Epler for Adafruit Industries
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
# Commodore 16 to USB HID adapter with Adafruit KB2040
|
||||
#
|
||||
# Note that:
|
||||
# * This matrix is different than the (more common) Commodore 64 matrix
|
||||
# * There are no diodes, not even on modifiers, so there's only 2-key rollover.
|
||||
# * This is a "physical" keymap, so that the functions of the keys are similar to the
|
||||
# function of a standard PC keyboard key in the same location.
|
||||
#
|
||||
# See the guide or the advanced code for more information about the key matrix
|
||||
|
||||
import board
|
||||
import keypad
|
||||
from adafruit_hid.keycode import Keycode as K
|
||||
from adafruit_hid.keyboard import Keyboard
|
||||
import usb_hid
|
||||
|
||||
rows = [board.A3, board.D6, board.D10, board.D9, board.MOSI, board.D2, board.A0, board.D4]
|
||||
cols = [board.A2, board.SCK, board.MISO, board.A1, board.D5, board.D7, board.D8, board.D3]
|
||||
|
||||
keycodes = [
|
||||
K.BACKSPACE, K.ENTER, K.LEFT_ARROW, K.F8, K.F1, K.F2, K.F3, K.LEFT_BRACKET,
|
||||
K.THREE, K.W, K.A, K.FOUR, K.Z, K.S, K.E, K.LEFT_SHIFT,
|
||||
K.FIVE, K.R, K.D, K.SIX, K.C, K.F, K.T, K.X,
|
||||
K.SEVEN, K.Y, K.G, K.EIGHT, K.B, K.H, K.U, K.V,
|
||||
K.NINE, K.I, K.J, K.ZERO, K.M, K.K, K.O, K.N,
|
||||
K.DOWN_ARROW, K.P, K.L, K.UP_ARROW, K.PERIOD, K.SEMICOLON, K.BACKSLASH, K.COMMA,
|
||||
K.MINUS, K.KEYPAD_ASTERISK, K.QUOTE, K.EQUALS, K.ESCAPE, K.RIGHT_ARROW, K.RIGHT_BRACKET,
|
||||
K.FORWARD_SLASH, K.ONE, K.HOME, K.LEFT_CONTROL, K.TWO, K.SPACE, K.ALT, K.Q, K.GRAVE_ACCENT,
|
||||
]
|
||||
|
||||
kbd = Keyboard(usb_hid.devices)
|
||||
|
||||
with keypad.KeyMatrix(rows, cols) as keys:
|
||||
while True:
|
||||
if ev := keys.events.get():
|
||||
keycode = keycodes[ev.key_number]
|
||||
if ev.pressed:
|
||||
kbd.press(keycode)
|
||||
else:
|
||||
kbd.release(keycode)
|
||||
158
CircuitPython_Commodore_16_KB2040/matrixwhisperer/code.py
Normal file
158
CircuitPython_Commodore_16_KB2040/matrixwhisperer/code.py
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
# SPDX-FileCopyrightText: 2022 Jeff Epler for Adafruit Industries
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
# KeyMatrix Whisperer
|
||||
#
|
||||
# Interactively determine a matrix keypad's row and column pins
|
||||
#
|
||||
# Wait until the program prints "press keys now". Then, press and hold a key
|
||||
# until it registers. Repeat until all rows and columns are identified. If your
|
||||
# keyboard matrix does NOT have dioes, you MUST take care to only press a
|
||||
# single key at a time.
|
||||
#
|
||||
# How identification is performed: When a key is pressed _some_ pair of I/Os
|
||||
# will be connected. This code repeatedly scans all possible pairs, recording
|
||||
# them. The very first pass when no key is pressed is recorded as "junk" so it
|
||||
# can be ignored.
|
||||
#
|
||||
# Then, the first I/O involved in the first non-junk press is arbitrarily
|
||||
# recorded as a "row pin". If the matrix does not have diodes, this can
|
||||
# actually vary from run to run or depending on the first key you pressed. The
|
||||
# only net effect of this is that the row & column lists are exchanged.
|
||||
#
|
||||
# After enough key presses, you'll get a full list of "row" and "column" pins.
|
||||
# For instance, on the Commodore 16 keyboard you'd get 8 row pins and 8 column pins.
|
||||
#
|
||||
# This doesn't help determine the LOGICAL ORDER of rows and columns or the
|
||||
# physical layout of the keyboard. You still have to do that for yourself.
|
||||
|
||||
import board
|
||||
import microcontroller
|
||||
from digitalio import DigitalInOut, Pull
|
||||
|
||||
# List of pins to test, or None to test all pins
|
||||
IO_PINS = None # [board.D0, board.D1]
|
||||
# Which value(s) to set the driving pin to
|
||||
values = [True] # [True, False]
|
||||
|
||||
def discover_io():
|
||||
return [pin_maybe for name in dir(microcontroller.pin) if isinstance(pin_maybe := getattr(microcontroller.pin, name), microcontroller.Pin)]
|
||||
|
||||
def pin_lookup(pin):
|
||||
for i in dir(board):
|
||||
if getattr(board, i) is pin: return i
|
||||
for i in dir(microcontroller.pin):
|
||||
if getattr(microcontroller.pin, i) is pin: return i
|
||||
|
||||
# Find all I/O pins, if IO_PINS is not explicitly set above
|
||||
if IO_PINS is None:
|
||||
IO_PINS = discover_io()
|
||||
|
||||
# Initialize all pins as inputs, make a lookup table to get the name from the pin
|
||||
ios_lookup = dict([(pin_lookup(pin), DigitalInOut(pin)) for pin in IO_PINS])
|
||||
ios = ios_lookup.values()
|
||||
ios_items = ios_lookup.items()
|
||||
for io in ios:
|
||||
io.switch_to_input(pull=Pull.UP)
|
||||
|
||||
# Partial implementation of 'defaultdict' class from standard Python
|
||||
# from https://github.com/micropython/micropython-lib/blob/master/python-stdlib/collections.defaultdict/collections/defaultdict.py
|
||||
class defaultdict:
|
||||
@staticmethod
|
||||
def __new__(cls, default_factory=None, **kwargs):
|
||||
# Some code (e.g. urllib.urlparse) expects that basic defaultdict
|
||||
# functionality will be available to subclasses without them
|
||||
# calling __init__().
|
||||
self = super(defaultdict, cls).__new__(cls)
|
||||
self.d = {}
|
||||
return self
|
||||
|
||||
def __init__(self, default_factory=None, **kwargs):
|
||||
self.d = kwargs
|
||||
self.default_factory = default_factory
|
||||
|
||||
def __getitem__(self, key):
|
||||
try:
|
||||
return self.d[key]
|
||||
except KeyError:
|
||||
v = self.__missing__(key)
|
||||
self.d[key] = v
|
||||
return v
|
||||
|
||||
def __setitem__(self, key, v):
|
||||
self.d[key] = v
|
||||
|
||||
def __delitem__(self, key):
|
||||
del self.d[key]
|
||||
|
||||
def __contains__(self, key):
|
||||
return key in self.d
|
||||
|
||||
def __missing__(self, key):
|
||||
if self.default_factory is None:
|
||||
raise KeyError(key)
|
||||
return self.default_factory()
|
||||
|
||||
# Track combinations that were pressed, including ones during the "junk" scan
|
||||
pressed_or_junk = defaultdict(set)
|
||||
# Track combinations that were pressed, excluding the "junk" scan
|
||||
pressed = defaultdict(set)
|
||||
# During the first run, anything scanned is "junk". Could occur for unused pins.
|
||||
first_run = True
|
||||
# List of pins identified as rows and columns
|
||||
rows = []
|
||||
cols = []
|
||||
# The first pin identified is arbitrarily called a 'row' pin.
|
||||
row_arbitrarily = None
|
||||
|
||||
while True:
|
||||
changed = False
|
||||
last_pressed = None
|
||||
for value in values:
|
||||
pull = [Pull.UP, Pull.DOWN][value]
|
||||
for io in ios:
|
||||
io.switch_to_input(pull=pull)
|
||||
for name1, io1 in ios_items:
|
||||
io1.switch_to_output(value)
|
||||
for name2, io2 in ios_items:
|
||||
if io2 is io1: continue
|
||||
if io2.value == value:
|
||||
if first_run:
|
||||
pressed_or_junk[name1].add(name2)
|
||||
pressed_or_junk[name2].add(name1)
|
||||
elif name2 not in pressed_or_junk[name1]:
|
||||
if row_arbitrarily is None: row_arbitrarily = name1
|
||||
pressed_or_junk[name1].add(name2)
|
||||
pressed_or_junk[name2].add(name1)
|
||||
if name2 not in pressed[name1]:
|
||||
pressed[name1].add(name2)
|
||||
pressed[name2].add(name1)
|
||||
changed = True
|
||||
if name2 in pressed[name1]:
|
||||
last_pressed = (name1, name2)
|
||||
print("Key registered. Release to continue")
|
||||
while io2.value == value: pass
|
||||
io1.switch_to_input(pull=pull)
|
||||
if first_run:
|
||||
print("Press keys now")
|
||||
first_run = False
|
||||
elif changed:
|
||||
rows = set([row_arbitrarily])
|
||||
cols = set()
|
||||
to_check = [row_arbitrarily]
|
||||
for check in to_check:
|
||||
for other in pressed[check]:
|
||||
if other in rows or other in cols: continue
|
||||
if check in rows:
|
||||
cols.add(other)
|
||||
else:
|
||||
rows.add(other)
|
||||
to_check.append(other)
|
||||
|
||||
rows = sorted(rows)
|
||||
cols = sorted(cols)
|
||||
if changed or last_pressed:
|
||||
print("Rows", len(rows), *rows)
|
||||
print("Cols", len(cols), *cols)
|
||||
print("Last pressed", *last_pressed)
|
||||
print()
|
||||
Loading…
Reference in a new issue