Skip to content

Commit f1c0dc2

Browse files
authored
Merge pull request #2282 from jepler/tandy1000-keyboard
Tandy1000 keyboard
2 parents dc0a0ca + c4d232c commit f1c0dc2

File tree

1 file changed

+158
-0
lines changed
  • CircuitPython_Tandy1000Keyboard_QTPy_RP2040

1 file changed

+158
-0
lines changed
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
# SPDX-FileCopyrightText: 2022 Jeff Epler for Adafruit Industries
2+
# SPDX-License-Identifier: MIT
3+
import time
4+
import array
5+
6+
import board
7+
import digitalio
8+
import rp2pio
9+
import usb_hid
10+
11+
import adafruit_pioasm
12+
from adafruit_hid.keyboard import Keyboard
13+
from adafruit_hid.keycode import Keycode as K
14+
15+
KBD_NRESET = board.MISO
16+
KBD_DATA = board.RX
17+
KBD_CLOCK = board.SCK # Note that KBD_CLOCK must be 1 GPIO# above KBD_DATA
18+
KBD_NBUSY = board.MOSI
19+
20+
tandy1000_keycodes = [
21+
None, K.ESCAPE, K.ONE, K.TWO, K.THREE, K.FOUR, K.FIVE, K.SIX, K.SEVEN,
22+
K.EIGHT, K.NINE, K.ZERO, K.MINUS, K.EQUALS, K.BACKSPACE, K.TAB, K.Q, K.W,
23+
K.E, K.R, K.T, K.Y, K.U, K.I, K.O, K.P, K.LEFT_BRACKET, K.RIGHT_BRACKET,
24+
K.ENTER, K.LEFT_CONTROL, K.A, K.S, K.D, K.F, K.G, K.H, K.J, K.K, K.L,
25+
K.SEMICOLON, K.QUOTE, K.UP_ARROW, K.LEFT_SHIFT, K.LEFT_ARROW, K.Z, K.X,
26+
K.C, K.V, K.B, K.N, K.M, K.COMMA, K.PERIOD, K.FORWARD_SLASH, K.RIGHT_SHIFT,
27+
K.PRINT_SCREEN, K.LEFT_ALT, K.SPACE, K.CAPS_LOCK, K.F1, K.F2, K.F3, K.F4,
28+
K.F5, K.F6, K.F7, K.F8, K.F9, K.F10, K.KEYPAD_NUMLOCK, K.PAUSE,
29+
K.KEYPAD_SEVEN, K.KEYPAD_EIGHT, K.KEYPAD_NINE, K.DOWN_ARROW, K.KEYPAD_FOUR,
30+
K.KEYPAD_FIVE, K.KEYPAD_SIX, K.RIGHT_ARROW, K.KEYPAD_ONE, K.KEYPAD_TWO,
31+
K.KEYPAD_THREE, K.KEYPAD_ZERO, K.KEYPAD_MINUS, (K.LEFT_CONTROL, K.PAUSE),
32+
K.KEYPAD_PLUS, K.KEYPAD_PERIOD, K.KEYPAD_ENTER, K.HOME, K.F11, K.F12
33+
]
34+
35+
LOCK_KEYS = (K.CAPS_LOCK, K.KEYPAD_NUMLOCK)
36+
LOCK_STATE = {
37+
K.CAPS_LOCK: False,
38+
K.KEYPAD_NUMLOCK: False,
39+
}
40+
KEYPAD_NUMLOCK_LOOKUP = [
41+
{
42+
K.KEYPAD_PLUS: K.INSERT,
43+
K.KEYPAD_MINUS: K.DELETE,
44+
45+
K.KEYPAD_SEVEN: K.BACKSLASH,
46+
K.KEYPAD_EIGHT: (K.LEFT_SHIFT, K.GRAVE_ACCENT),
47+
K.KEYPAD_NINE: K.PAGE_UP,
48+
49+
K.KEYPAD_FOUR: (K.LEFT_SHIFT, K.BACKSLASH),
50+
#K.KEYPAD_FIVE:
51+
#K.KEYPAD_SIX:
52+
53+
K.KEYPAD_ONE: K.END,
54+
K.KEYPAD_TWO: K.GRAVE_ACCENT,
55+
K.KEYPAD_THREE: K.PAGE_DOWN,
56+
57+
K.KEYPAD_ZERO: K.ZERO,
58+
K.KEYPAD_PERIOD: K.PERIOD,
59+
},
60+
{
61+
K.KEYPAD_PLUS: (K.LEFT_SHIFT, K.EQUALS),
62+
K.KEYPAD_MINUS: K.MINUS,
63+
64+
K.KEYPAD_SEVEN: K.SEVEN,
65+
K.KEYPAD_EIGHT: K.EIGHT,
66+
K.KEYPAD_NINE: K.NINE,
67+
68+
K.KEYPAD_FOUR: K.FOUR,
69+
K.KEYPAD_FIVE: K.FIVE,
70+
K.KEYPAD_SIX: K.SIX,
71+
72+
K.KEYPAD_ONE: K.ONE,
73+
K.KEYPAD_TWO: K.TWO,
74+
K.KEYPAD_THREE: K.THREE,
75+
76+
K.KEYPAD_ZERO: K.ZERO,
77+
K.KEYPAD_PERIOD: K.PERIOD,
78+
}
79+
]
80+
81+
# Assert busy
82+
busy_out = digitalio.DigitalInOut(KBD_NBUSY)
83+
busy_out.switch_to_output(False, digitalio.DriveMode.OPEN_DRAIN)
84+
85+
# Reset the keyboard
86+
reset_out = digitalio.DigitalInOut(KBD_NRESET)
87+
reset_out.switch_to_output(False, digitalio.DriveMode.OPEN_DRAIN)
88+
time.sleep(.1)
89+
reset_out.value = True
90+
91+
program = adafruit_pioasm.Program("""
92+
wait 1 pin 1
93+
in pins, 1
94+
wait 0 pin 1
95+
""")
96+
97+
sm = rp2pio.StateMachine(program.assembled,
98+
first_in_pin = KBD_DATA,
99+
in_pin_count = 2,
100+
pull_in_pin_up = 0b11,
101+
auto_push=True,
102+
push_threshold=8,
103+
in_shift_right=True,
104+
frequency=8_000_000,
105+
**program.pio_kwargs)
106+
107+
buf = array.array('B', [0])
108+
109+
MASK_LEFT_SHIFT = K.modifier_bit(K.LEFT_SHIFT)
110+
MASK_RIGHT_SHIFT = K.modifier_bit(K.RIGHT_SHIFT)
111+
MASK_ANY_SHIFT = (MASK_LEFT_SHIFT | MASK_RIGHT_SHIFT)
112+
113+
# Now ready to get keystrokes
114+
kbd = Keyboard(usb_hid.devices)
115+
busy_out.value = True
116+
while True:
117+
sm.readinto(buf, swap=False)
118+
val = buf[0]
119+
pressed = (val & 0x80) == 0
120+
key_number = val & 0x7f
121+
122+
if key_number > len(tandy1000_keycodes):
123+
# invalid keycode -- reset the keyboard
124+
reset_out.switch_to_output(False, digitalio.DriveMode.OPEN_DRAIN)
125+
time.sleep(.1)
126+
reset_out.value = True
127+
continue
128+
129+
keycode = tandy1000_keycodes[key_number]
130+
if keycode is None:
131+
continue
132+
keycode = KEYPAD_NUMLOCK_LOOKUP[LOCK_STATE[K.KEYPAD_NUMLOCK]].get(keycode, keycode)
133+
if pressed:
134+
if keycode in LOCK_KEYS:
135+
LOCK_STATE[keycode] = True
136+
elif LOCK_STATE[K.CAPS_LOCK] and K.A <= keycode <= K.Z:
137+
old_report_modifier = kbd.report_modifier[0]
138+
kbd.report_modifier[0] = (old_report_modifier & ~MASK_RIGHT_SHIFT) ^ MASK_LEFT_SHIFT
139+
kbd.press(keycode)
140+
kbd.release_all()
141+
kbd.report_modifier[0] = old_report_modifier
142+
continue
143+
elif isinstance(keycode, tuple):
144+
old_report_modifier = kbd.report_modifier[0]
145+
kbd.report_modifier[0] = 0
146+
kbd.press(*keycode)
147+
kbd.release_all()
148+
kbd.report_modifier[0] = old_report_modifier
149+
else:
150+
kbd.press(keycode)
151+
152+
else:
153+
if keycode in LOCK_KEYS:
154+
LOCK_STATE[keycode] = False
155+
elif isinstance(keycode, tuple):
156+
pass
157+
else:
158+
kbd.release(keycode)

0 commit comments

Comments
 (0)