diff --git a/leonardo_a500_keyboard/a500_keyboard_leonardo.ino b/leonardo_a500_keyboard/a500_keyboard_leonardo.ino index 1480d46..d7ed3b3 100644 --- a/leonardo_a500_keyboard/a500_keyboard_leonardo.ino +++ b/leonardo_a500_keyboard/a500_keyboard_leonardo.ino @@ -9,211 +9,265 @@ * keyboard using an Arduino Leonardo. It includes support for joystick inputs * and special function keys. * - * The code has been optimized for performance and readability, with direct - * calls to HID().SendReport for efficient USB communication. + * The code has been refactored for better maintainability and readability, while + * preserving or improving performance. * * TODO: Macro recording and replay (planned next version) */ - + #include #include +// Define bit masks for keyboard and joystick inputs #define BITMASK_A500CLK 0b00010000 // IO 8 #define BITMASK_A500SP 0b00100000 // IO 9 #define BITMASK_A500RES 0b01000000 // IO 10 #define BITMASK_JOY1 0b10011111 // IO 0..4,6 #define BITMASK_JOY2 0b11110011 // IO A0..A5 -#define SYNCH_HI 0 -#define SYNCH_LO 1 -#define HANDSHAKE 2 -#define READ 3 -#define WAIT_LO 4 -#define WAIT_RES 5 - -KeyReport _keyReport; -uint32_t counter = 0; -uint8_t Joy, MemoJoy1, MemoJoy2, state, bitn, key, fn,keydown, ktab[0x68]={ + +// Enumerate keyboard states for better readability +enum KeyboardState { + SYNCH_HI = 0, + SYNCH_LO, + HANDSHAKE, + READ, + WAIT_LO, + WAIT_RES +}; + +// Global variables +KeyReport keyReport; +uint32_t handshakeTimer = 0; + +// Joystick states +uint8_t currentJoy1State = 0; +uint8_t currentJoy2State = 0; +uint8_t previousJoy1State = 0xFF; // Initialize to 0xFF so that initial state triggers update +uint8_t previousJoy2State = 0xFF; + +// Keyboard state machine variables +KeyboardState keyboardState = SYNCH_HI; +uint8_t bitIndex = 0; +uint8_t currentKeyCode = 0; +bool functionMode = false; // Indicates if 'Help' key is active +bool isKeyDown = false; + +// Key mapping table: Amiga keycodes to USB HID keycodes +const uint8_t keyTable[0x68] = { // Tilde, 1-9, 0, sz, Accent, backslash, Num 0 (00 - 0F) - 0x35, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x2D, 0x2E, 0x31, 0, 0x62, - // Q bis +, -, Num 1, Num 2, Num3 (10 - 1F) - 0x14, 0x1A, 0x08, 0x15, 0x17, 0x1C, 0x18, 0x0C, 0x12, 0x13, 0x2F, 0x30, 0 , 0x59, 0x5A, 0x5B, - // A-#, -, Num 4, Num 5, Num 6 (20 - 2F) - 0x04, 0x16, 0x07, 0x09, 0x0A, 0x0B, 0x0D, 0x0E, 0x0F, 0x33, 0x34, 0x32, 0, 0x5C, 0x5D, 0x5E, - // <>,Y- -, -, Num . , Num 7, Num 8, Num 9 (30 - 3F) - 0x64, 0x1D, 0x1B, 0x06, 0x19, 0x05, 0x11, 0x10, 0x36, 0x37, 0x38, 0, 0x63, 0x5F, 0x60, 0x61, - // Space, BS, Tab, Enter, Return, ESC, Del, -, -, -, Num -, -, up, down, right, left (40 - 4F) - 0x2C, 0x2A, 0x2B, 0x58, 0x28, 0x29, 0x4C, 0, 0, 0, 0x56, 0, 0x52, 0x51, 0x4F, 0x50, - // F1-F10, -, -, Num /, Num *, Num +, - (50 - 5F) - 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0, 0, 0x54, 0x55, 0x57, 0, - // modifiers: Shift left, Shift right, -, Crtl left, Alt left, Alt right, Win (amiga) left, Ctrl (amiga)right + 0x35, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, + 0x25, 0x26, 0x27, 0x2D, 0x2E, 0x31, 0, 0x62, + // Q to '+', '-', Num 1, Num 2, Num3 (10 - 1F) + 0x14, 0x1A, 0x08, 0x15, 0x17, 0x1C, 0x18, 0x0C, + 0x12, 0x13, 0x2F, 0x30, 0, 0x59, 0x5A, 0x5B, + // A to '#', '-', Num 4, Num 5, Num 6 (20 - 2F) + 0x04, 0x16, 0x07, 0x09, 0x0A, 0x0B, 0x0D, 0x0E, + 0x0F, 0x33, 0x34, 0x32, 0, 0x5C, 0x5D, 0x5E, + // '<>', Y to '-', '-', Num '.', Num 7, Num 8, Num 9 (30 - 3F) + 0x64, 0x1D, 0x1B, 0x06, 0x19, 0x05, 0x11, 0x10, + 0x36, 0x37, 0x38, 0, 0x63, 0x5F, 0x60, 0x61, + // Space, Backspace, Tab, Enter, Return, ESC, Delete, '-', '-', '-', Num '-', '-', Up, Down, Right, Left (40 - 4F) + 0x2C, 0x2A, 0x2B, 0x58, 0x28, 0x29, 0x4C, 0, + 0, 0, 0x56, 0, 0x52, 0x51, 0x4F, 0x50, + // F1-F10, '-', '-', Num '/', Num '*', Num '+', '-' (50 - 5F) + 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, + 0x42, 0x43, 0, 0, 0x54, 0x55, 0x57, 0, + // Modifiers: Shift left, Shift right, '-', Ctrl left, Alt left, Alt right, Win (Amiga) left, Ctrl (Amiga) right 0x02, 0x20, 0x00, 0x01, 0x04, 0x40, 0x08, 0x10 }; void setup() { - // Joystick 1 (Port D) - DDRD = (uint8_t)(~BITMASK_JOY1); // direction INPUT - PORTD = BITMASK_JOY1; // activate PULLUP + // Initialize Joystick 1 (Port D) + DDRD = (uint8_t)(~BITMASK_JOY1); // Set pins as INPUT + PORTD = BITMASK_JOY1; // Enable internal PULL-UP resistors - // Joystick 2 (Port F) - DDRF = (uint8_t)(~BITMASK_JOY2); // direction INPUT - PORTF = BITMASK_JOY2; // activate PULLUP + // Initialize Joystick 2 (Port F) + DDRF = (uint8_t)(~BITMASK_JOY2); // Set pins as INPUT + PORTF = BITMASK_JOY2; // Enable internal PULL-UP resistors - // Keyboard (Port B) - DDRB = ~(BITMASK_A500CLK | BITMASK_A500SP | BITMASK_A500RES); // direction INPUT + // Initialize Keyboard (Port B) + DDRB &= ~(BITMASK_A500CLK | BITMASK_A500SP | BITMASK_A500RES); // Set pins as INPUT } - void loop() { - // Joystick 1 - Joy = ~PIND & BITMASK_JOY1; - if (Joy != MemoJoy1) { - HID().SendReport(3, &Joy, 1); - MemoJoy1 = Joy; - } - -// Joystick 2 - Joy = ~PINF & BITMASK_JOY2; - if (Joy != MemoJoy2) { - HID().SendReport(4, &Joy, 1); - MemoJoy2 = Joy; - } - - // Keyboard - if (((PINB & BITMASK_A500RES)==0) && state!=WAIT_RES) { // Reset - interrupts(); - keystroke(0x4C,05); // CTRL+ALT+DEL - fn=0; - state=WAIT_RES; - } - - else if (state==WAIT_RES) { // Waiting for reset end - if ((PINB & BITMASK_A500RES)!=0) state=SYNCH_HI; - } - - else if (state==SYNCH_HI) { // Sync-Pulse HI - if ((PINB & BITMASK_A500CLK)==0) state=SYNCH_LO; + handleJoystick1(); + handleJoystick2(); + handleKeyboard(); +} + +void handleJoystick1() { + uint8_t currentJoyState = ~PIND & BITMASK_JOY1; + if (currentJoyState != previousJoy1State) { + HID().SendReport(3, ¤tJoyState, 1); + previousJoy1State = currentJoyState; } +} - else if (state==SYNCH_LO) { // Sync-Pulse LOW - if ((PINB & BITMASK_A500CLK)!=0) state=HANDSHAKE; +void handleJoystick2() { + uint8_t currentJoyState = ~PINF & BITMASK_JOY2; + if (currentJoyState != previousJoy2State) { + HID().SendReport(4, ¤tJoyState, 1); + previousJoy2State = currentJoyState; } +} + +void handleKeyboard() { + uint8_t pinB = PINB; - else if (state==HANDSHAKE) { // Handshake - if (counter==0) { - DDRB |= BITMASK_A500SP; // set IO direction to OUTPUT - PORTB &= ~BITMASK_A500SP; // set OUTPUT to LOW - counter=millis(); + if (((pinB & BITMASK_A500RES) == 0) && keyboardState != WAIT_RES) { + // Reset detected + interrupts(); + keystroke(0x4C, 0x05); // Send CTRL+ALT+DEL + functionMode = false; + keyboardState = WAIT_RES; + } else if (keyboardState == WAIT_RES) { + // Waiting for reset end + if ((pinB & BITMASK_A500RES) != 0) { + keyboardState = SYNCH_HI; } - else if (millis()-counter>10) { - counter=0; - DDRB &= ~BITMASK_A500SP; // set IO direction to INPUT - state=WAIT_LO; - key=0; - bitn=7; + } else if (keyboardState == SYNCH_HI) { + // Sync Pulse High + if ((pinB & BITMASK_A500CLK) == 0) { + keyboardState = SYNCH_LO; } - } - - else if (state==READ) { // read key message (8 bits) - if ((PINB & BITMASK_A500CLK)!=0) { - if (bitn--){ - key+=((PINB & BITMASK_A500SP)==0)<<(bitn); // key code (add bits 0...6) - - state=WAIT_LO; - } - else { // read last bit (key down) - keydown=((PINB & BITMASK_A500SP)!=0); // true if key down + } else if (keyboardState == SYNCH_LO) { + // Sync Pulse Low + if ((pinB & BITMASK_A500CLK) != 0) { + keyboardState = HANDSHAKE; + } + } else if (keyboardState == HANDSHAKE) { + // Handshake + if (handshakeTimer == 0) { + DDRB |= BITMASK_A500SP; // Set SP pin as OUTPUT + PORTB &= ~BITMASK_A500SP; // Set SP pin LOW + handshakeTimer = millis(); + } else if (millis() - handshakeTimer > 10) { + handshakeTimer = 0; + DDRB &= ~BITMASK_A500SP; // Set SP pin as INPUT + keyboardState = WAIT_LO; + currentKeyCode = 0; + bitIndex = 7; + } + } else if (keyboardState == READ) { + // Read key message (8 bits) + if ((pinB & BITMASK_A500CLK) != 0) { + if (bitIndex--) { + currentKeyCode |= ((pinB & BITMASK_A500SP) == 0) << bitIndex; // Accumulate bits + keyboardState = WAIT_LO; + } else { + // Read last bit (key down/up) + isKeyDown = ((pinB & BITMASK_A500SP) != 0); // true if key down interrupts(); - state=HANDSHAKE; - if (key==0x5F) fn=keydown; // "Help" key: special function on/off - else if (key==0x62) keystroke(0x39,0x00); // CapsLock - else { - if (keydown){ - // keydown message received------ - if (fn) { - // special function with "Help" key - if (key == 0x50) keystroke(0x44, 0); // F11 - else if (key == 0x51) keystroke(0x45, 0); // F12 - else if (key == 0x5A) keystroke(0x53, 0); // NumLock - else if (key == 0x5B) keystroke(0x47, 0); // ScrollLock - else if (key == 0x5D) keystroke(0x46, 0); // PrtSc - else if (key == 0x0F) keystroke(0x49, 0); // Insert - else if (key == 0x3C) keystroke(0x4C, 0); // Delete - else if (key == 0x1F) keystroke(0x4E, 0); // Page Down - else if (key == 0x3F) keystroke(0x4B, 0); // Page Up - else if (key == 0x3D) keystroke(0x4A, 0); // Home - else if (key == 0x1D) keystroke(0x4D, 0); // End - else if (key == 0x52) keystroke(0x7F, 0); // Help + F3 = Mute - else if (key == 0x53) keystroke(0x81, 0); // Help + F4 = Volume Down - else if (key == 0x54) keystroke(0x80, 0); // Help + F5 = Volume Up - else if (key == 0x55) keystroke(0x82, 0); // Help + F6 = Play/Pause - else if (key == 0x56) keystroke(0x85, 0); // Help + F7 = Stop - else if (key == 0x57) keystroke(0x86, 0); // Help + F8 = Previous Track - else if (key == 0x58) keystroke(0x87, 0); // Help + F9 = Next Track - else if (key == 0x59) keystroke(0x65, 0); // Help + F10 = Application/Special Key - } - else { - if (key==0x5A) keystroke(0x26,0x20); // ( - else if (key==0x5B) keystroke(0x27,0x20); // ) - else if (key < 0x68) keypress(key); // Code table - } - } - else { - // keyrelease message received - if (key < 0x68) keyrelease(key); // Code table - } - } + keyboardState = HANDSHAKE; + processKeyCode(); } } - } - - else if (state==WAIT_LO) { // waiting for the next bit - if ((PINB & BITMASK_A500CLK)==0) { + } else if (keyboardState == WAIT_LO) { + // Waiting for the next bit + if ((pinB & BITMASK_A500CLK) == 0) { noInterrupts(); - state=READ; + keyboardState = READ; } } } - -void keypress(uint8_t k) { - - if (k > 0x5f) _keyReport.modifiers |= ktab[key]; // modifier - else { - for (uint8_t i=0; i<6; i++) { - if (_keyReport.keys[i] == 0) { - _keyReport.keys[i] = ktab[key]; - break; +void processKeyCode() { + if (currentKeyCode == 0x5F) { + // 'Help' key toggles function mode + functionMode = isKeyDown; + } else if (currentKeyCode == 0x62) { + // CapsLock key + keystroke(0x39, 0x00); + } else { + if (isKeyDown) { + // Key down message received + if (functionMode) { + // Special function with 'Help' key + handleFunctionModeKey(); + } else { + if (currentKeyCode == 0x5A) { + keystroke(0x26, 0x20); // '(' + } else if (currentKeyCode == 0x5B) { + keystroke(0x27, 0x20); // ')' + } else if (currentKeyCode < 0x68) { + keyPress(currentKeyCode); + } + } + } else { + // Key release message received + if (currentKeyCode < 0x68) { + keyRelease(currentKeyCode); } } } - HID().SendReport(2,&_keyReport,8); } +void handleFunctionModeKey() { + switch (currentKeyCode) { + case 0x50: keystroke(0x44, 0); break; // F11 + case 0x51: keystroke(0x45, 0); break; // F12 + case 0x5A: keystroke(0x53, 0); break; // NumLock + case 0x5B: keystroke(0x47, 0); break; // ScrollLock + case 0x5D: keystroke(0x46, 0); break; // PrtSc + case 0x0F: keystroke(0x49, 0); break; // Insert + case 0x3C: keystroke(0x4C, 0); break; // Delete + case 0x1F: keystroke(0x4E, 0); break; // Page Down + case 0x3F: keystroke(0x4B, 0); break; // Page Up + case 0x3D: keystroke(0x4A, 0); break; // Home + case 0x1D: keystroke(0x4D, 0); break; // End + case 0x52: keystroke(0x7F, 0); break; // Mute + case 0x53: keystroke(0x81, 0); break; // Volume Down + case 0x54: keystroke(0x80, 0); break; // Volume Up + case 0x55: keystroke(0x82, 0); break; // Play/Pause + case 0x56: keystroke(0x85, 0); break; // Stop + case 0x57: keystroke(0x86, 0); break; // Previous Track + case 0x58: keystroke(0x87, 0); break; // Next Track + case 0x59: keystroke(0x65, 0); break; // Application/Special Key + default: break; + } +} -void keyrelease(uint8_t k) { - - if (k > 0x5f) _keyReport.modifiers &= ~ktab[key]; // modifier - else { - for (uint8_t i=0; i<6; i++) { - if (_keyReport.keys[i] == ktab[key]) _keyReport.keys[i] = 0; +void keyPress(uint8_t keyCode) { + uint8_t hidCode = keyTable[keyCode]; + if (keyCode > 0x5F) { + keyReport.modifiers |= hidCode; // Modifier key + } else { + for (uint8_t i = 0; i < 6; i++) { + if (keyReport.keys[i] == 0) { + keyReport.keys[i] = hidCode; + break; + } } } - HID().SendReport(2,&_keyReport,8); + HID().SendReport(2, &keyReport, sizeof(keyReport)); } - -void keystroke(uint8_t k, uint8_t m) { - - unsigned short memomodifiers = _keyReport.modifiers; // save last modifier state - for (uint8_t i=0; i<6; i++) { - if (_keyReport.keys[i] == 0) { - _keyReport.keys[i] = k; - _keyReport.modifiers = m; - HID().SendReport(2,&_keyReport,8); - _keyReport.keys[i] = 0; - _keyReport.modifiers = memomodifiers; // recover modifier state - HID().SendReport(2,&_keyReport,8); - break; +void keyRelease(uint8_t keyCode) { + uint8_t hidCode = keyTable[keyCode]; + if (keyCode > 0x5F) { + keyReport.modifiers &= ~hidCode; // Modifier key + } else { + for (uint8_t i = 0; i < 6; i++) { + if (keyReport.keys[i] == hidCode) { + keyReport.keys[i] = 0; } } + } + HID().SendReport(2, &keyReport, sizeof(keyReport)); +} + +void keystroke(uint8_t keyCode, uint8_t modifiers) { + uint8_t originalModifiers = keyReport.modifiers; + for (uint8_t i = 0; i < 6; i++) { + if (keyReport.keys[i] == 0) { + keyReport.keys[i] = keyCode; + keyReport.modifiers = modifiers; + HID().SendReport(2, &keyReport, sizeof(keyReport)); + keyReport.keys[i] = 0; + keyReport.modifiers = originalModifiers; + HID().SendReport(2, &keyReport, sizeof(keyReport)); + break; + } + } } +