Pārlūkot izejas kodu

added all files

Robert Walker 6 gadi atpakaļ
vecāks
revīzija
40bf5366a7
9 mainītis faili ar 965 papildinājumiem un 2 dzēšanām
  1. 47 2
      README.md
  2. 126 0
      src/abc806serialdriver.h
  3. 165 0
      src/abckeys.h
  4. 86 0
      src/kdbparser.cpp
  5. 46 0
      src/kdbparser.h
  6. 41 0
      src/main.ino
  7. 28 0
      src/scancodeconversion.h
  8. 177 0
      src/swedishlayouttoabclayout.h
  9. 249 0
      src/usbhidkeys.h

+ 47 - 2
README.md

@@ -1,2 +1,47 @@
-# abc806keyboardadapter
-Use a USB keyboard with your Luxor ABC806 computer
+# ABC 806 Keyboard adapter
+
+This project is released under the GNU General Public License v2.
+
+## Summary
+
+This project contains the software needed to build a USB keyboard adapter for the Luxor ABC 806 computer.
+
+## Required hardware
+
+    - [Arudino USB Host shield Uno](https://store.arduino.cc/arduino-uno-rev3) (or compatible)
+    - [Arudino USB Host shield USB Host shield](https://store.arduino.cc/arduino-usb-host-shield)
+
+## Required Software
+
+    - [Arudino IDE](https://www.arduino.cc/en/main/software)
+    
+While the Arduino IDE is serviceable, VS Code together with the new [Arduino plugin](https://marketplace.visualstudio.com/items?itemName=vsciot-vscode.vscode-arduino) gives a far better development experience.
+
+## Library dependencies
+
+    - [USB Host Shield Library 2.0](https://github.com/felis/USB_Host_Shield_2.0)
+    
+## Pin mappings
+
+This is how the pins should be mapped between the Arduino Uno board and the ABC 806 keyboard connector.
+
+    DIN pin     Signal      Arduino Pin
+    ----------------------------------------------------------------
+    1           TxD         1
+    2           GnD         GND
+    3           RxD         0
+    4           TRxC        3
+    5           Keydown     2
+    6           +12v        Vin
+    7           Reset       Not connected
+
+## Information about the serial connection
+
+The keyboard is connected to the B channel of the Z80 dart using an asynchronous serial connection. In addition to the serial connection the keyboard side generates a 10 khz signal as well as a `keydown` event, triggering an processor interrupt.
+
+These are the setting of the serial connection:
+
+    - 650 baud
+    - 8 bits
+    - no parity
+    - 2 stop bits

+ 126 - 0
src/abc806serialdriver.h

@@ -0,0 +1,126 @@
+/*    
+    USB Keyboard driver for Luxor ABC 806 computers
+    Copyright (C) 2019  Robert Walker
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <https://www.gnu.org/licenses/>. 
+*/
+
+#ifndef ABC806SERIALDRIVER 
+#define ABC806SERIALDRIVER
+
+#include <avr/io.h>  
+#include <util/delay.h>
+#include <assert.h>
+
+// Class with used to communicate with the ABC80x, its hard coded to
+// use the first usart 
+class abc806serialdriver {
+  #define KEYDOWN_PIN 2
+  #define RESET_PIN   9
+  #define CLOCK_PIN   3    // PD3 = OC2B.
+  #define BAUD        650
+  #define UBRR        (F_CPU / (16 * BAUD))  - 1
+
+public:
+  static void Setup(){
+    SetupSerialport();
+    SetupClock();
+
+    // Setup additional pins
+    pinMode(KEYDOWN_PIN, OUTPUT); 
+    pinMode(RESET_PIN, OUTPUT);
+  }
+
+  static void Send(unsigned char data) {
+    digitalWrite(KEYDOWN_PIN, HIGH);    
+    while(!(UCSR0A && (1<<UDRE0)));
+    UCSR0A |= _BV(TXC0);
+    UDR0 = data;
+    digitalWrite(KEYDOWN_PIN, LOW);    
+  }
+
+  static void Receive() {
+    while(!(UCSR0A & (1<<RXC0)));
+    return UDR0;
+  }
+
+private:
+  static void SetupSerialport() 
+  {
+    UBRR0H  = (uint8_t)(UBRR>>8); // USART Baud Rate Register High
+    UBRR0L  = (uint8_t)(UBRR);    // USART Baud Rate Register Low
+    UCSR0B  = _BV(RXEN0)
+              |_BV(TXEN0);        // Enable TX/ Enable RX
+    /*
+    USBSn Stop Bit(s)
+    0     1-bit
+    1     2-bit    
+    UCSZn2  UCSZn1  UCSZn0  Character Size
+    0       0       0       5-bit
+    0       0       1       6-bit
+    0       1       0       7-bit
+    0       1       1       8-bit
+    1       0       0       Reserved
+    1       0       1       Reserved
+    1       1       0       Reserved
+    1       1       1       9-bit    
+
+    UCPOLn  UCPHAn  SPI Mode  Leading Edge      Trailing Edge
+    0       0       0         Sample (Rising)   Setup (Falling)
+    0       1       1         Setup (Rising)    Sample (Falling)
+    1       0       2         Sample (Falling)  Setup (Rising)
+    1       1       3         Setup (Falling)   Sample (Rising) */
+
+    UCSR0C = _BV(USBS0)
+             |_BV(UCSZ00)
+             |_BV(UCSZ01);
+    /*
+    UPMn1 UPMn0 Parity Mode
+    ----------------------------
+    0     0     Disabled
+    0     1     Reserved
+    1     0     Enabled, Even Parity
+    1     1     Enabled, Odd Parity */
+    UCSR0C |= (0<<UPM01)|(0<<UPM01);        // No parity
+
+    /*
+    UMSELn1 UMSELn0   Mode
+    0       0         Asynchronous USART
+    0       1         Synchronous USART
+    1       0         (Reserved)
+    1       1         Master SPI (MSPIM) */
+    UCSR0C |= (0<<UMSEL00)|(0<<UMSEL01);    // Set sync flag off 
+
+    // Clear existing transmit 
+    UCSR0A |= _BV(TXC0);
+
+    // Turn off double speed
+    UCSR0A &= ~(1<<U2X0);
+
+  }
+  static void SetupClock() 
+  {
+    pinMode(CLOCK_PIN, OUTPUT);
+    // Configure timer 2 for PWM @ 10 kHz on OC2B.
+    TCCR2A = _BV(COM2B1)  // non-inverting PWM on OC2B 
+           | _BV(WGM20)   // mode 7: fast PWM, TOP = OCR2A
+           | _BV(WGM21);  // ditto
+    TCCR2B = _BV(WGM22)   // ditto
+           | _BV(CS21);   // Here we prescale the CPU clock by dividing it by 8, there are options also to divide it with 32 and 64
+    OCR2A  = 199;         // The output compare register A, Here we decided on the top value count, when the 199 + 1 cycles (times 8 as of the prescaler) 
+    OCR2B  = 99;          // The output compare register B, Here we decided how long we will remain HIGH (99 + 1) * 8 CPU cycles 
+  }
+};
+
+#endif

+ 165 - 0
src/abckeys.h

@@ -0,0 +1,165 @@
+/*     
+    USB Keyboard driver for Luxor ABC 806 computers
+    Copyright (C) 2019  Robert Walker
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <https://www.gnu.org/licenses/>. 
+*/
+
+#ifndef ABCKEYS
+#define ABCKEYS
+
+#define ABC_KEY_BREAK           3   // Ctrl-c
+#define ABC_KEY_BS              8   // Backspace
+#define ABC_KEY_BELL            7   // Ctrl-g
+#define ABC_KEY_HT              9   // "Forward"
+#define ABC_KEY_LF              10  // Ctrl-m
+#define ABC_KEY_CS              12  // Ctrl-m
+#define ABC_KEY_ENTER           13  // Enter
+#define ABC_KEY_STEP            19  // Ctrl-s
+#define ABC_KEY_KILL            24  // Ctrl-x
+
+#define ABC_KEY_SPACE           32
+#define ABC_KEY_EXCLMATION      33
+#define ABC_KEY_QUOTE           34
+#define ABC_KEY_HASH            35
+#define ABC_KEY_SOL             36
+#define ABC_KEY_PERCENT         37
+#define ABC_KEY_AMPERSAND       38
+#define ABC_KEY_APOSTROPHE      39
+#define ABC_KEY_LEFT_PAR        40
+#define ABC_KEY_RIGHT_PAR       41
+#define ABC_KEY_STAR            42
+#define ABC_KEY_PLUS            43
+#define ABC_KEY_COMMA           44
+#define ABC_KEY_UNDERSCORE      45
+#define ABC_KEY_DOT             46
+#define ABC_KEY_FSLASH          47
+#define ABC_KEY_ZERO            48
+#define ABC_KEY_ONE             49
+#define ABC_KEY_TWO             50
+#define ABC_KEY_THREE           51
+#define ABC_KEY_FOUR            52
+#define ABC_KEY_FIVE            53
+#define ABC_KEY_SIX             54
+#define ABC_KEY_SEVEN           55
+#define ABC_KEY_EIGHT           56
+#define ABC_KEY_NINE            57
+#define ABC_KEY_COLON           58
+#define ABC_KEY_SEMICOLON       59
+#define ABC_KEY_LESS            60
+#define ABC_KEY_EQUAL           61
+#define ABC_KEY_GREATER         62
+#define ABC_KEY_QM              63
+#define ABC_KEY_64              64 // Captial é
+#define ABC_KEY_A               65
+#define ABC_KEY_B               66
+#define ABC_KEY_C               67
+#define ABC_KEY_D               68
+#define ABC_KEY_E               69
+#define ABC_KEY_F               70
+#define ABC_KEY_G               71
+#define ABC_KEY_H               72
+#define ABC_KEY_I               73
+#define ABC_KEY_J               74
+#define ABC_KEY_K               75
+#define ABC_KEY_L               76
+#define ABC_KEY_M               77
+#define ABC_KEY_N               78
+#define ABC_KEY_O               79
+#define ABC_KEY_P               80
+#define ABC_KEY_Q               81
+#define ABC_KEY_R               82
+#define ABC_KEY_S               83
+#define ABC_KEY_T               84
+#define ABC_KEY_U               85
+#define ABC_KEY_V               86
+#define ABC_KEY_W               87
+#define ABC_KEY_X               88
+#define ABC_KEY_Y               89
+#define ABC_KEY_Z               90
+#define ABC_KEY_91              91  // Ä
+#define ABC_KEY_92              92  // Ö
+#define ABC_KEY_93              93  // Å
+#define ABC_KEY_94              94  // Ü
+#define ABC_KEY_MINUS           95
+#define ABC_KEY_96              96  // é
+#define ABC_KEY_AL              97
+#define ABC_KEY_BL              98
+#define ABC_KEY_CL              99
+#define ABC_KEY_DL              100
+#define ABC_KEY_EL              101
+#define ABC_KEY_FL              102
+#define ABC_KEY_GL              103
+#define ABC_KEY_HL              104
+#define ABC_KEY_IL              105
+#define ABC_KEY_KL              106
+#define ABC_KEY_JL              107
+#define ABC_KEY_LL              108
+#define ABC_KEY_ML              109
+#define ABC_KEY_NL              110
+#define ABC_KEY_OL              111
+#define ABC_KEY_PL              112
+#define ABC_KEY_QL              113
+#define ABC_KEY_RL              114
+#define ABC_KEY_SL              115
+#define ABC_KEY_TL              116
+#define ABC_KEY_UL              117
+#define ABC_KEY_VL              118
+#define ABC_KEY_WL              119
+#define ABC_KEY_XL              120
+#define ABC_KEY_YL              121
+#define ABC_KEY_ZL              122
+#define ABC_KEY_123             123 // ä
+#define ABC_KEY_125             125 // å 
+#define ABC_KEY_124             124 // ö
+#define ABC_KEY_126             126 // ü
+#define ABC_KEY_127             127 // BLOCK
+
+#define ABC_KEY_PF1             192
+#define ABC_KEY_PF2             193
+#define ABC_KEY_PF3             194
+#define ABC_KEY_PF4             195
+#define ABC_KEY_PF5             196
+#define ABC_KEY_PF6             197
+#define ABC_KEY_PF7             198
+#define ABC_KEY_PF8             199
+
+#define ABC_KEY_PF1_SHIFT       208
+#define ABC_KEY_PF2_SHIFT       209
+#define ABC_KEY_PF3_SHIFT       210
+#define ABC_KEY_PF4_SHIFT       211
+#define ABC_KEY_PF5_SHIFT       212
+#define ABC_KEY_PF6_SHIFT       213
+#define ABC_KEY_PF7_SHIFT       214
+#define ABC_KEY_PF8_SHIFT       215
+
+#define ABC_KEY_PF1_CTRL        224
+#define ABC_KEY_PF2_CTRL        225
+#define ABC_KEY_PF3_CTRL        226
+#define ABC_KEY_PF4_CTRL        227
+#define ABC_KEY_PF5_CTRL        228
+#define ABC_KEY_PF6_CTRL        229
+#define ABC_KEY_PF7_CTRL        230
+#define ABC_KEY_PF8_CTRL        231
+
+#define ABC_KEY_PF1_SHIFT_CTRL  240
+#define ABC_KEY_PF2_SHIFT_CTRL  241
+#define ABC_KEY_PF3_SHIFT_CTRL  242
+#define ABC_KEY_PF4_SHIFT_CTRL  243
+#define ABC_KEY_PF5_SHIFT_CTRL  244
+#define ABC_KEY_PF6_SHIFT_CTRL  245
+#define ABC_KEY_PF7_SHIFT_CTRL  246
+#define ABC_KEY_PF8_SHIFT_CTRL  247
+
+#endif // ABCKEYS

+ 86 - 0
src/kdbparser.cpp

@@ -0,0 +1,86 @@
+/*     
+    USB Keyboard driver for Luxor ABC 806 computers
+    Copyright (C) 2019  Robert Walker
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <https://www.gnu.org/licenses/>. 
+*/
+
+#include <usbhub.h>
+
+#include "kdbparser.h"
+#include "abc806serialdriver.h"
+#include "swedishlayouttoabclayout.h"
+#include "abckeys.h"
+#include "usbhidkeys.h"
+
+KdbParser::KdbParser() {
+    repeatIntervalMs    = 100; // 100 ms
+    initalRepeatDelay   = 200; // 200 ms
+    Reset();
+}
+void KdbParser::SendKey(uint8_t key) {
+    abc806serialdriver::Send(key);
+}
+void KdbParser::Reset(void) {
+    currentKey          = 0;  
+    initalRepeatMark    = 0;
+    lastRepeatOfKey     = millis();
+}
+void KdbParser::RepeatKey(void) {
+
+    if(currentKey != 0) {
+        unsigned long currentTime = millis();
+        // Stop it from repeat on every keystroke
+        if(initalRepeatMark == 0) 
+            initalRepeatMark = currentTime;
+
+        if(currentTime - initalRepeatMark > initalRepeatDelay) {
+            if(currentTime - lastRepeatOfKey > repeatIntervalMs) {
+                SendKey(currentKey);
+                lastRepeatOfKey = currentTime;
+            }
+        }
+    }
+}
+
+uint8_t KdbParser::OemToABC(uint8_t mod, uint8_t key) {
+    uint8_t shift = (mod & 0x22);
+    size_t count = sizeof(swedishLayoutToABCLayout) / sizeof(swedishLayoutToABCLayout[0]);
+    for(int i=0;i<count;i++) {
+        ScancodeConversion conv = swedishLayoutToABCLayout[i];
+        if(mod) {
+            if(conv.scanCode == key && (mod & conv.modifierMask))
+                return conv.abcKeyCode;
+        } else {
+            if(conv.scanCode == key && !conv.modifierMask) 
+                return conv.abcKeyCode;
+        }
+    }
+    return 0;
+}
+
+void KdbParser::OnKeyDown(uint8_t mod, uint8_t key)
+{
+    uint8_t abcKeyCode = OemToABC(mod,key);
+    if(abcKeyCode) {
+        currentKey = abcKeyCode;    
+        SendKey(currentKey);
+    } else
+        currentKey = 0;
+}
+
+void KdbParser::OnKeyUp(uint8_t mod, uint8_t key)
+{
+    Reset();
+}

+ 46 - 0
src/kdbparser.h

@@ -0,0 +1,46 @@
+/*     
+    USB Keyboard driver for Luxor ABC 806 computers
+    Copyright (C) 2019  Robert Walker
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <https://www.gnu.org/licenses/>. 
+*/
+
+#ifndef KDBPARSER
+#define KDBPARSER
+
+#include <hidboot.h>
+
+class KdbParser : public KeyboardReportParser
+{
+  public:
+    KdbParser();
+    void RepeatKey(void);
+
+  protected:
+    uint8_t OemToABC(uint8_t mod, uint8_t key);
+
+    void SendKey(uint8_t key);
+    void Reset(void);
+
+    void OnKeyDown	(uint8_t mod, uint8_t key);
+    void OnKeyUp	(uint8_t mod, uint8_t key);
+
+    unsigned long initalRepeatDelay;
+    unsigned long initalRepeatMark; 
+    unsigned long lastRepeatOfKey;
+    unsigned long repeatIntervalMs;
+    uint8_t       currentKey;
+};
+
+#endif

+ 41 - 0
src/main.ino

@@ -0,0 +1,41 @@
+/*     
+    USB Keyboard driver for Luxor ABC 806 computers
+    Copyright (C) 2019  Robert Walker
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <https://www.gnu.org/licenses/>. 
+*/
+
+#include <avr/io.h>  
+#include <util/delay.h>
+#include <assert.h>
+
+#include "kdbparser.h"
+#include "abc806serialdriver.h"
+
+
+USB                                 usb;
+HIDBoot<USB_HID_PROTOCOL_KEYBOARD>  HidKeyboard(&usb);
+KdbParser                           kbdparser;
+
+void setup() {
+  abc806serialdriver::Setup();
+  usb.Init();
+  delay( 200 );
+  HidKeyboard.SetReportParser(0, &kbdparser);
+}
+
+void loop() {
+  usb.Task();
+  kbdparser.RepeatKey();  
+}

+ 28 - 0
src/scancodeconversion.h

@@ -0,0 +1,28 @@
+/*     
+    USB Keyboard driver for Luxor ABC 806 computers
+    Copyright (C) 2019  Robert Walker
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <https://www.gnu.org/licenses/>. 
+*/
+
+#ifndef SCANCODECONVERSION
+#define SCANCODECONVERSION
+
+struct ScancodeConversion {
+  uint8_t   scanCode;
+  uint8_t   abcKeyCode;
+  uint8_t   modifierMask;
+};
+
+#endif

+ 177 - 0
src/swedishlayouttoabclayout.h

@@ -0,0 +1,177 @@
+/*     
+    USB Keyboard driver for Luxor ABC 806 computers
+    Copyright (C) 2019  Robert Walker
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <https://www.gnu.org/licenses/>. 
+*/
+
+#ifndef SWEDISH_LAYOUT
+#define SWEDISH_LAYOUT
+
+#include "scancodeconversion.h"
+#include "abckeys.h"
+#include "usbhidkeys.h"
+
+// This is a table for converting USB Hid scan codes applied to a Swedish layout to the ABC layout
+ScancodeConversion swedishLayoutToABCLayout[] = {
+
+// Control keys
+  {KEY_BACKSPACE,ABC_KEY_BS,0},                 // Backspace
+  {KEY_ENTER,ABC_KEY_ENTER,0},                  // Enter
+  {KEY_SPACE,ABC_KEY_SPACE,0},                  // Space
+  {KEY_C,ABC_KEY_BREAK,0x30},                   // Break / Ctrl-c
+  {KEY_G,ABC_KEY_BELL,0x30},                    // Bell / Ctrl-g
+  {KEY_X,ABC_KEY_KILL,0x30},                    // Kill line / Ctrl-x
+  {KEY_M,ABC_KEY_LF,0x30},                      // Line feed / Ctrl-m
+  {KEY_L,ABC_KEY_CS,0x30},                      // Clear screen / Ctrl-l
+
+// Top row
+  {KEY_1,ABC_KEY_EXCLMATION,0x22},              // !
+  {KEY_2,ABC_KEY_QUOTE,0x22},                   // "
+  {KEY_3,ABC_KEY_HASH,0x22},                    // #
+  {KEY_4,ABC_KEY_SOL,0x22},                     // Sol
+  {KEY_5,ABC_KEY_PERCENT,0x22},                 // %
+  {KEY_6,ABC_KEY_AMPERSAND,0x22},               // &
+  {KEY_7,ABC_KEY_FSLASH,0x22},                  // /
+  {KEY_8,ABC_KEY_LEFT_PAR,0x22},                // (
+  {KEY_9,ABC_KEY_RIGHT_PAR,0x22},               // )
+  {KEY_0,ABC_KEY_EQUAL,0x22},                   // =  
+  {KEY_MINUS,ABC_KEY_PLUS,0},                   // +  
+  {KEY_MINUS,ABC_KEY_QM,0x22},                  // ?  
+  {KEY_EQUAL,ABC_KEY_64,0x22},                  // Captial é
+  {KEY_EQUAL,ABC_KEY_96,0},                     // é
+
+// Misc
+  {KEY_SLASH,ABC_KEY_MINUS,0x0},                // -
+  {KEY_SLASH,ABC_KEY_UNDERSCORE,0x22},          // _
+  {KEY_SEMICOLON,ABC_KEY_92,0x22},              // Ö
+  {KEY_SEMICOLON,ABC_KEY_124,0},                // ö
+  {KEY_APOSTROPHE,ABC_KEY_91,0x22},             // Ä
+  {KEY_APOSTROPHE,ABC_KEY_123,0},               // Ä
+  {KEY_LEFTBRACE,ABC_KEY_93,0x22},              // Å
+  {KEY_LEFTBRACE,ABC_KEY_125,0},                // å
+  {KEY_RIGHTBRACE,ABC_KEY_94,0x22},             // Ü
+  {KEY_RIGHTBRACE,ABC_KEY_126,0},               // ü
+  {KEY_COMMA,ABC_KEY_COMMA,0},                  // ,
+  {KEY_DOT,ABC_KEY_DOT,0},                      // .
+  {KEY_COMMA,ABC_KEY_SEMICOLON,0x22},           // ;
+  {KEY_DOT,ABC_KEY_COLON,0x22},                 // :
+  {KEY_HASHTILDE,ABC_KEY_STAR,0x22},           // *
+  {KEY_HASHTILDE,ABC_KEY_APOSTROPHE,0},        // '
+  {KEY_102ND,ABC_KEY_LESS,0},                  // >
+  {KEY_102ND,ABC_KEY_GREATER,0x22},            // <
+
+// Alpha and numeric  
+  {KEY_0,ABC_KEY_ZERO,0},       
+  {KEY_1,ABC_KEY_ONE,0},
+  {KEY_2,ABC_KEY_TWO,0},
+  {KEY_3,ABC_KEY_THREE,0},
+  {KEY_4,ABC_KEY_FOUR,0},
+  {KEY_5,ABC_KEY_FIVE,0},
+  {KEY_6,ABC_KEY_SIX,0},
+  {KEY_7,ABC_KEY_SEVEN,0},
+  {KEY_8,ABC_KEY_EIGHT,0},
+  {KEY_9,ABC_KEY_NINE,0},
+  {KEY_A,ABC_KEY_AL,0},
+  {KEY_B,ABC_KEY_BL,0},
+  {KEY_C,ABC_KEY_CL,0},
+  {KEY_D,ABC_KEY_DL,0},
+  {KEY_E,ABC_KEY_EL,0},
+  {KEY_F,ABC_KEY_FL,0},
+  {KEY_G,ABC_KEY_GL,0},
+  {KEY_H,ABC_KEY_HL,0},
+  {KEY_I,ABC_KEY_IL,0},
+  {KEY_J,ABC_KEY_JL,0},
+  {KEY_K,ABC_KEY_KL,0},
+  {KEY_L,ABC_KEY_LL,0},
+  {KEY_M,ABC_KEY_ML,0},
+  {KEY_N,ABC_KEY_NL,0},
+  {KEY_O,ABC_KEY_OL,0},
+  {KEY_P,ABC_KEY_PL,0},
+  {KEY_Q,ABC_KEY_QL,0},
+  {KEY_R,ABC_KEY_RL,0},
+  {KEY_S,ABC_KEY_SL,0},
+  {KEY_T,ABC_KEY_TL,0},
+  {KEY_U,ABC_KEY_UL,0},
+  {KEY_V,ABC_KEY_VL,0},
+  {KEY_W,ABC_KEY_WL,0},
+  {KEY_X,ABC_KEY_XL,0},
+  {KEY_Y,ABC_KEY_YL,0},
+  {KEY_Z,ABC_KEY_ZL,0},
+  {KEY_A,ABC_KEY_A,0x22},
+  {KEY_B,ABC_KEY_B,0x22},
+  {KEY_C,ABC_KEY_C,0x22},
+  {KEY_D,ABC_KEY_D,0x22},
+  {KEY_E,ABC_KEY_E,0x22},
+  {KEY_F,ABC_KEY_F,0x22},
+  {KEY_G,ABC_KEY_G,0x22},
+  {KEY_H,ABC_KEY_H,0x22},
+  {KEY_I,ABC_KEY_I,0x22},
+  {KEY_J,ABC_KEY_J,0x22},
+  {KEY_K,ABC_KEY_K,0x22},
+  {KEY_L,ABC_KEY_L,0x22},
+  {KEY_M,ABC_KEY_M,0x22},
+  {KEY_N,ABC_KEY_N,0x22},
+  {KEY_O,ABC_KEY_O,0x22},
+  {KEY_P,ABC_KEY_P,0x22},
+  {KEY_Q,ABC_KEY_Q,0x22},
+  {KEY_R,ABC_KEY_R,0x22},
+  {KEY_S,ABC_KEY_S,0x22},
+  {KEY_T,ABC_KEY_T,0x22},
+  {KEY_U,ABC_KEY_U,0x22},
+  {KEY_V,ABC_KEY_V,0x22},
+  {KEY_W,ABC_KEY_W,0x22},
+  {KEY_X,ABC_KEY_X,0x22},
+  {KEY_Y,ABC_KEY_Y,0x22},
+  {KEY_Z,ABC_KEY_Z,0x22},
+
+// Function keys
+  {KEY_F1,ABC_KEY_PF1,0},
+  {KEY_F2,ABC_KEY_PF2,0},
+  {KEY_F3,ABC_KEY_PF3,0},
+  {KEY_F4,ABC_KEY_PF4,0},
+  {KEY_F5,ABC_KEY_PF5,0},
+  {KEY_F6,ABC_KEY_PF6,0},
+  {KEY_F7,ABC_KEY_PF7,0},
+  {KEY_F8,ABC_KEY_PF8,0},
+
+  {KEY_F1,ABC_KEY_PF1_SHIFT,0x22},
+  {KEY_F2,ABC_KEY_PF2_SHIFT,0x22},
+  {KEY_F3,ABC_KEY_PF3_SHIFT,0x22},
+  {KEY_F4,ABC_KEY_PF4_SHIFT,0x22},
+  {KEY_F5,ABC_KEY_PF5_SHIFT,0x22},
+  {KEY_F6,ABC_KEY_PF6_SHIFT,0x22},
+  {KEY_F7,ABC_KEY_PF7_SHIFT,0x22},
+  {KEY_F8,ABC_KEY_PF8_SHIFT,0x22},
+
+  {KEY_F1,ABC_KEY_PF1_SHIFT_CTRL,0x52},
+  {KEY_F2,ABC_KEY_PF2_SHIFT_CTRL,0x52},
+  {KEY_F3,ABC_KEY_PF3_SHIFT_CTRL,0x52},
+  {KEY_F4,ABC_KEY_PF4_SHIFT_CTRL,0x52},
+  {KEY_F5,ABC_KEY_PF5_SHIFT_CTRL,0x52},
+  {KEY_F6,ABC_KEY_PF6_SHIFT_CTRL,0x52},
+  {KEY_F7,ABC_KEY_PF7_SHIFT_CTRL,0x52},
+  {KEY_F8,ABC_KEY_PF8_SHIFT_CTRL,0x52},
+
+  {KEY_F1,ABC_KEY_PF1_CTRL,0x30},
+  {KEY_F2,ABC_KEY_PF2_CTRL,0x30},
+  {KEY_F3,ABC_KEY_PF3_CTRL,0x30},
+  {KEY_F4,ABC_KEY_PF4_CTRL,0x30},
+  {KEY_F5,ABC_KEY_PF5_CTRL,0x30},
+  {KEY_F6,ABC_KEY_PF6_CTRL,0x30},
+  {KEY_F7,ABC_KEY_PF7_CTRL,0x30},
+  {KEY_F8,ABC_KEY_PF8_CTRL,0x30},
+};
+
+#endif 

+ 249 - 0
src/usbhidkeys.h

@@ -0,0 +1,249 @@
+/*     
+    USB Keyboard driver for Luxor ABC 806 computers
+    Copyright (C) 2019  Robert Walker
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <https://www.gnu.org/licenses/>. 
+*/
+
+#ifndef USB_HID_KEYS
+#define USB_HID_KEYS
+
+/**
+ * Modifier masks - used for the first byte in the HID report.
+ * NOTE: The second byte in the report is reserved, 0x00
+ */
+#define KEY_MOD_LCTRL  0x01
+#define KEY_MOD_LSHIFT 0x02
+#define KEY_MOD_LALT   0x04
+#define KEY_MOD_LMETA  0x08
+#define KEY_MOD_RCTRL  0x10
+#define KEY_MOD_RSHIFT 0x20
+#define KEY_MOD_RALT   0x40
+#define KEY_MOD_RMETA  0x80
+
+#define KEY_NONE 0x00 // No key pressed
+#define KEY_ERR_OVF 0x01 //  Keyboard Error Roll Over - used for all slots if too many keys are pressed ("Phantom key")
+// 0x02 //  Keyboard POST Fail
+// 0x03 //  Keyboard Error Undefined
+#define KEY_A 0x04 // Keyboard a and A
+#define KEY_B 0x05 // Keyboard b and B
+#define KEY_C 0x06 // Keyboard c and C
+#define KEY_D 0x07 // Keyboard d and D
+#define KEY_E 0x08 // Keyboard e and E
+#define KEY_F 0x09 // Keyboard f and F
+#define KEY_G 0x0a // Keyboard g and G
+#define KEY_H 0x0b // Keyboard h and H
+#define KEY_I 0x0c // Keyboard i and I
+#define KEY_J 0x0d // Keyboard j and J
+#define KEY_K 0x0e // Keyboard k and K
+#define KEY_L 0x0f // Keyboard l and L
+#define KEY_M 0x10 // Keyboard m and M
+#define KEY_N 0x11 // Keyboard n and N
+#define KEY_O 0x12 // Keyboard o and O
+#define KEY_P 0x13 // Keyboard p and P
+#define KEY_Q 0x14 // Keyboard q and Q
+#define KEY_R 0x15 // Keyboard r and R
+#define KEY_S 0x16 // Keyboard s and S
+#define KEY_T 0x17 // Keyboard t and T
+#define KEY_U 0x18 // Keyboard u and U
+#define KEY_V 0x19 // Keyboard v and V
+#define KEY_W 0x1a // Keyboard w and W
+#define KEY_X 0x1b // Keyboard x and X
+#define KEY_Y 0x1c // Keyboard y and Y
+#define KEY_Z 0x1d // Keyboard z and Z
+
+#define KEY_1 0x1e // Keyboard 1 and !
+#define KEY_2 0x1f // Keyboard 2 and @
+#define KEY_3 0x20 // Keyboard 3 and #
+#define KEY_4 0x21 // Keyboard 4 and $
+#define KEY_5 0x22 // Keyboard 5 and %
+#define KEY_6 0x23 // Keyboard 6 and ^
+#define KEY_7 0x24 // Keyboard 7 and &
+#define KEY_8 0x25 // Keyboard 8 and *
+#define KEY_9 0x26 // Keyboard 9 and (
+#define KEY_0 0x27 // Keyboard 0 and )
+
+#define KEY_ENTER 0x28 // Keyboard Return (ENTER)
+#define KEY_ESC 0x29 // Keyboard ESCAPE
+#define KEY_BACKSPACE 0x2a // Keyboard DELETE (Backspace)
+#define KEY_TAB 0x2b // Keyboard Tab
+#define KEY_SPACE 0x2c // Keyboard Spacebar
+#define KEY_MINUS 0x2d // Keyboard - and _
+#define KEY_EQUAL 0x2e // Keyboard = and +
+#define KEY_LEFTBRACE 0x2f // Keyboard [ and {
+#define KEY_RIGHTBRACE 0x30 // Keyboard ] and }
+#define KEY_BACKSLASH 0x31 // Keyboard \ and |
+#define KEY_HASHTILDE 0x32 // Keyboard Non-US # and ~
+#define KEY_SEMICOLON 0x33 // Keyboard ; and :
+#define KEY_APOSTROPHE 0x34 // Keyboard ' and "
+#define KEY_GRAVE 0x35 // Keyboard ` and ~
+#define KEY_COMMA 0x36 // Keyboard , and <
+#define KEY_DOT 0x37 // Keyboard . and >
+#define KEY_SLASH 0x38 // Keyboard / and ?
+#define KEY_CAPSLOCK 0x39 // Keyboard Caps Lock
+
+#define KEY_F1 0x3a // Keyboard F1
+#define KEY_F2 0x3b // Keyboard F2
+#define KEY_F3 0x3c // Keyboard F3
+#define KEY_F4 0x3d // Keyboard F4
+#define KEY_F5 0x3e // Keyboard F5
+#define KEY_F6 0x3f // Keyboard F6
+#define KEY_F7 0x40 // Keyboard F7
+#define KEY_F8 0x41 // Keyboard F8
+#define KEY_F9 0x42 // Keyboard F9
+#define KEY_F10 0x43 // Keyboard F10
+#define KEY_F11 0x44 // Keyboard F11
+#define KEY_F12 0x45 // Keyboard F12
+
+#define KEY_SYSRQ 0x46 // Keyboard Print Screen
+#define KEY_SCROLLLOCK 0x47 // Keyboard Scroll Lock
+#define KEY_PAUSE 0x48 // Keyboard Pause
+#define KEY_INSERT 0x49 // Keyboard Insert
+#define KEY_HOME 0x4a // Keyboard Home
+#define KEY_PAGEUP 0x4b // Keyboard Page Up
+#define KEY_DELETE 0x4c // Keyboard Delete Forward
+#define KEY_END 0x4d // Keyboard End
+#define KEY_PAGEDOWN 0x4e // Keyboard Page Down
+#define KEY_RIGHT 0x4f // Keyboard Right Arrow
+#define KEY_LEFT 0x50 // Keyboard Left Arrow
+#define KEY_DOWN 0x51 // Keyboard Down Arrow
+#define KEY_UP 0x52 // Keyboard Up Arrow
+
+#define KEY_NUMLOCK 0x53 // Keyboard Num Lock and Clear
+#define KEY_KPSLASH 0x54 // Keypad /
+#define KEY_KPASTERISK 0x55 // Keypad *
+#define KEY_KPMINUS 0x56 // Keypad -
+#define KEY_KPPLUS 0x57 // Keypad +
+#define KEY_KPENTER 0x58 // Keypad ENTER
+#define KEY_KP1 0x59 // Keypad 1 and End
+#define KEY_KP2 0x5a // Keypad 2 and Down Arrow
+#define KEY_KP3 0x5b // Keypad 3 and PageDn
+#define KEY_KP4 0x5c // Keypad 4 and Left Arrow
+#define KEY_KP5 0x5d // Keypad 5
+#define KEY_KP6 0x5e // Keypad 6 and Right Arrow
+#define KEY_KP7 0x5f // Keypad 7 and Home
+#define KEY_KP8 0x60 // Keypad 8 and Up Arrow
+#define KEY_KP9 0x61 // Keypad 9 and Page Up
+#define KEY_KP0 0x62 // Keypad 0 and Insert
+#define KEY_KPDOT 0x63 // Keypad . and Delete
+
+#define KEY_102ND 0x64 // Keyboard Non-US \ and |
+#define KEY_COMPOSE 0x65 // Keyboard Application
+#define KEY_POWER 0x66 // Keyboard Power
+#define KEY_KPEQUAL 0x67 // Keypad =
+
+#define KEY_F13 0x68 // Keyboard F13
+#define KEY_F14 0x69 // Keyboard F14
+#define KEY_F15 0x6a // Keyboard F15
+#define KEY_F16 0x6b // Keyboard F16
+#define KEY_F17 0x6c // Keyboard F17
+#define KEY_F18 0x6d // Keyboard F18
+#define KEY_F19 0x6e // Keyboard F19
+#define KEY_F20 0x6f // Keyboard F20
+#define KEY_F21 0x70 // Keyboard F21
+#define KEY_F22 0x71 // Keyboard F22
+#define KEY_F23 0x72 // Keyboard F23
+#define KEY_F24 0x73 // Keyboard F24
+
+#define KEY_OPEN 0x74 // Keyboard Execute
+#define KEY_HELP 0x75 // Keyboard Help
+#define KEY_PROPS 0x76 // Keyboard Menu
+#define KEY_FRONT 0x77 // Keyboard Select
+#define KEY_STOP 0x78 // Keyboard Stop
+#define KEY_AGAIN 0x79 // Keyboard Again
+#define KEY_UNDO 0x7a // Keyboard Undo
+#define KEY_CUT 0x7b // Keyboard Cut
+#define KEY_COPY 0x7c // Keyboard Copy
+#define KEY_PASTE 0x7d // Keyboard Paste
+#define KEY_FIND 0x7e // Keyboard Find
+#define KEY_MUTE 0x7f // Keyboard Mute
+#define KEY_VOLUMEUP 0x80 // Keyboard Volume Up
+#define KEY_VOLUMEDOWN 0x81 // Keyboard Volume Down
+// 0x82  Keyboard Locking Caps Lock
+// 0x83  Keyboard Locking Num Lock
+// 0x84  Keyboard Locking Scroll Lock
+#define KEY_KPCOMMA 0x85 // Keypad Comma
+
+#define KEY_KPLEFTPAREN 0xb6 // Keypad (
+#define KEY_KPRIGHTPAREN 0xb7 // Keypad )
+// 0xb8  Keypad {
+// 0xb9  Keypad }
+// 0xba  Keypad Tab
+// 0xbb  Keypad Backspace
+// 0xbc  Keypad A
+// 0xbd  Keypad B
+// 0xbe  Keypad C
+// 0xbf  Keypad D
+// 0xc0  Keypad E
+// 0xc1  Keypad F
+// 0xc2  Keypad XOR
+// 0xc3  Keypad ^
+// 0xc4  Keypad %
+// 0xc5  Keypad <
+// 0xc6  Keypad >
+// 0xc7  Keypad &
+// 0xc8  Keypad &&
+// 0xc9  Keypad |
+// 0xca  Keypad ||
+// 0xcb  Keypad :
+// 0xcc  Keypad #
+// 0xcd  Keypad Space
+// 0xce  Keypad @
+// 0xcf  Keypad !
+// 0xd0  Keypad Memory Store
+// 0xd1  Keypad Memory Recall
+// 0xd2  Keypad Memory Clear
+// 0xd3  Keypad Memory Add
+// 0xd4  Keypad Memory Subtract
+// 0xd5  Keypad Memory Multiply
+// 0xd6  Keypad Memory Divide
+// 0xd7  Keypad +/-
+// 0xd8  Keypad Clear
+// 0xd9  Keypad Clear Entry
+// 0xda  Keypad Binary
+// 0xdb  Keypad Octal
+// 0xdc  Keypad Decimal
+// 0xdd  Keypad Hexadecimal
+
+#define KEY_LEFTCTRL 0xe0 // Keyboard Left Control
+#define KEY_LEFTSHIFT 0xe1 // Keyboard Left Shift
+#define KEY_LEFTALT 0xe2 // Keyboard Left Alt
+#define KEY_LEFTMETA 0xe3 // Keyboard Left GUI
+#define KEY_RIGHTCTRL 0xe4 // Keyboard Right Control
+#define KEY_RIGHTSHIFT 0xe5 // Keyboard Right Shift
+#define KEY_RIGHTALT 0xe6 // Keyboard Right Alt
+#define KEY_RIGHTMETA 0xe7 // Keyboard Right GUI
+
+#define KEY_MEDIA_PLAYPAUSE 0xe8
+#define KEY_MEDIA_STOPCD 0xe9
+#define KEY_MEDIA_PREVIOUSSONG 0xea
+#define KEY_MEDIA_NEXTSONG 0xeb
+#define KEY_MEDIA_EJECTCD 0xec
+#define KEY_MEDIA_VOLUMEUP 0xed
+#define KEY_MEDIA_VOLUMEDOWN 0xee
+#define KEY_MEDIA_MUTE 0xef
+#define KEY_MEDIA_WWW 0xf0
+#define KEY_MEDIA_BACK 0xf1
+#define KEY_MEDIA_FORWARD 0xf2
+#define KEY_MEDIA_STOP 0xf3
+#define KEY_MEDIA_FIND 0xf4
+#define KEY_MEDIA_SCROLLUP 0xf5
+#define KEY_MEDIA_SCROLLDOWN 0xf6
+#define KEY_MEDIA_EDIT 0xf7
+#define KEY_MEDIA_SLEEP 0xf8
+#define KEY_MEDIA_COFFEE 0xf9
+#define KEY_MEDIA_REFRESH 0xfa
+#define KEY_MEDIA_CALC 0xfb
+
+#endif // USB_HID_KEYS