/ CircuitPython_Tandy1000Keyboard_QTPy_RP2040 / code.py
code.py
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)