more example

This commit is contained in:
Jeff Epler 2022-09-08 15:56:08 -05:00
parent 3d42798227
commit 8a6d35c0c3
No known key found for this signature in database
GPG key ID: D5BF15AB975AB4DE
3 changed files with 205 additions and 5 deletions

View file

@ -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

View 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)

View 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()