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)