Ian Harvey
/
electron_kbd
Acorn Electron keyboard scanner, turns an old Acorn Electron into a USB keyboard.
main.cpp
- Committer:
- IH
- Date:
- 2014-06-18
- Revision:
- 2:9352b1232e6d
- Parent:
- 1:84cd616cc684
File content as of revision 2:9352b1232e6d:
/* * This is a simple mbed program for driving * an Acorn Electron keyboard from a KL25Z mbed * board. * * It is placed in the public domain by its author, * Ian Harvey. Note that there is NO WARRANTY. */ /* About the Electron keyboard ----------------- The keyboard itself has 14 'columns' and 4 'rows'. The column being scanned is driven low and four row bits are read out. The keyboard has diodes on the columns and pull-ups on the rows, so there's no need to tri-state un-driven columns or activate pullups. The break key is wired separately and connects directly to ground when preseed. Connections are as follows: 1. Break key PTE5 2. Caps lock LED PTE4 3. Ground 4. V+ for LED 5. Row 3 PTE3 6. Row 2 PTE2 7. Row 1 PTB11 8. Row 0 PTB10 9. Col 13 PTA1 10. Col 12 PTC7 11. Col 11 PTA2 12. Col 10 PTC0 13. Col 9 PTD4 14. Col 8 PTC3 15. Col 7 PTA12 16. Col 6 PTC4 17. Col 5 PTA4 18. Col 4 PTC5 19. Col 3 PTA5 20. Col 2 PTC6 21. Col 1 PTC8 22. Col 0 PTC10 Pin "1" (my numbering) is closest to the corner of the board, and pin "22" is next to the space bar. The connections of the keys follow the layout in 'hid_keys' below, so KEY_PERIOD is col 0 row 0, KEY_L is col 0 row 1, and so on. We're using the following modifications: "CAPS LK" -> KEY_TAB "[ ] COPY" -> KEY_OPEN_SQUARE "DELETE" -> KEY_LEFT_ALT ": *" -> KEY_SINGLE_QUOTE The firmware also treats the 'break' key as 'row 4' all on its own (mapped to KEY_BACKSPACE). When 'DELETE' (the LEFT_ALT key) is pressed, the keyboard map in 'alt_keys' is used, so e.g. KEY_MINUS becomes KEY_EQUALS. Keyboard layout --------------- Note that the keycaps on the Electron keyboard are considerably different to those on a regular PC-style one: shift-6 is labelled '&' not '^', shift-';' is labelled '+' not ':', and so on. The code here *doesn't* change which key code is sent when shift is pressed, so the characters you get are those you'd get on a PC keyboard - after some experimentation I personally preferred this. If this isn't to your taste, creating a custom keyboard layout on the PC/Pi may be the best way to fix this. I tend to use a 'US' keyboard layout with this keyboard, so shift-3 generates a '#', not a UK pound sign, and the single/double quotes are next to the ';' key (labelled ': *' on the Electron). ---------------------------------------------- */ #include "mbed.h" #include "USBKeyboard.h" #include "hid_keys.h" #define MAX_ROWS 5 #define MAX_COLS 14 #define REPORT_LEN 9 #define REPORT_ID_KEYBOARD 1 const uint8_t hid_keys[MAX_ROWS * MAX_COLS] = { KEY_PERIOD, KEY_L, KEY_O, KEY_9, KEY_BACKSPACE, KEY_SLASH, KEY_SEMICOLON, KEY_P, KEY_0, KEY_NONE, KEY_NONE, KEY_SINGLE_QUOTE,KEY_UP_ARROW, KEY_MINUS, KEY_NONE, KEY_LEFT_ALT, KEY_ENTER, KEY_DOWN_ARROW, KEY_LEFT_ARROW, KEY_NONE, KEY_SPACE, KEY_NONE, KEY_OPEN_SQUARE, KEY_RIGHT_ARROW, KEY_NONE, KEY_COMMA, KEY_K, KEY_I, KEY_8, KEY_NONE, KEY_M, KEY_J, KEY_U, KEY_7, KEY_NONE, KEY_N, KEY_H, KEY_Y, KEY_6, KEY_NONE, KEY_B, KEY_G, KEY_T, KEY_5, KEY_NONE, KEY_V, KEY_F, KEY_R, KEY_4, KEY_NONE, KEY_C, KEY_D, KEY_E, KEY_3, KEY_NONE, KEY_X, KEY_S, KEY_W, KEY_2, KEY_NONE, KEY_Z, KEY_A, KEY_Q, KEY_1, KEY_NONE, KEY_LEFT_SHIFT, KEY_LEFT_CTRL, KEY_TAB, KEY_ESC, KEY_NONE, }; const uint8_t alt_keys[MAX_ROWS * MAX_COLS] = { KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_HASH_TILDE, KEY_EQUALS, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_BACKTICK_TILDE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_CLOSE_SQUARE, KEY_BACKSLASH, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, }; BusOut leds(LED1, LED2, LED3); BusOut scanCols( PTC10,PTC8, PTC6, PTA5, PTC5, PTA4, PTC4, PTA12, PTC3, PTD4, PTC0, PTA2, PTC7, PTA1 ); BusIn inRows( PTB10, PTB11, PTE2, PTE3, PTE5 ); DigitalOut extLed(PTE4); USBKeyboard kbd; static int scanColumn(int col) { int rowBits; // Drive output low to scan scanCols.write(0x3FFF ^ (1 << col)); leds.write(col >> 1); wait(0.001); rowBits = inRows.read(); scanCols.write(0x3FFF); // Inputs also active-low return rowBits ^ 0x1F; } static const uint8_t altKeys = MODIFIER_BIT(KEY_LEFT_ALT) | MODIFIER_BIT(KEY_RIGHT_ALT); int main() { // Setup inRows.mode(PullUp); extLed = 1; // Run loop while(1) { int col, ocount; HID_REPORT report; uint8_t keyIfAlt = KEY_NONE; report.data[0] = REPORT_ID_KEYBOARD; report.data[1] = 0; // modifiers report.data[2] = 0; ocount = 3; for (col=0; col < MAX_COLS; col++) { int row; int rowBits = scanColumn(col); if ( !rowBits ) continue; for (row=0; row < MAX_ROWS; row++) { if ( rowBits & (1 << row) ) { uint8_t key = hid_keys[col * MAX_ROWS + row]; if ( IS_MODIFIER(key) ) report.data[1] |= MODIFIER_BIT(key); else if ( key != KEY_NONE ) { if ( ocount < REPORT_LEN ) report.data[ocount++] = key; } key = alt_keys[col * MAX_ROWS + row]; if ( key != KEY_NONE ) keyIfAlt = key; //kbd.printf("c%dr%d ", col, row); } } } if ( (report.data[1] & altKeys) != 0 && keyIfAlt != KEY_NONE ) { report.data[3] = keyIfAlt; ocount = 4; // Zero out the rest report.data[1] &= ~altKeys; // And put alt key up } while( ocount < REPORT_LEN ) report.data[ocount++] = KEY_NONE; report.length = REPORT_LEN; kbd.send(&report); } }