Ian Harvey / Mbed 2 deprecated electron_kbd

Dependencies:   USBDevice mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /*
00002  * This is a simple mbed program for driving 
00003  * an Acorn Electron keyboard from a KL25Z mbed
00004  * board.
00005  *
00006  * It is placed in the public domain by its author,
00007  * Ian Harvey. Note that there is NO WARRANTY.
00008  */
00009  
00010 /* About the Electron keyboard -----------------
00011 
00012 The keyboard itself has 14 'columns' and 4 'rows'.
00013 The column being scanned is driven low and four row
00014 bits are read out. The keyboard has diodes on the columns
00015 and pull-ups on the rows, so there's no need to tri-state
00016 un-driven columns or activate pullups. The break key
00017 is wired separately and connects directly to ground
00018 when preseed. Connections are as follows:
00019 
00020 1.  Break key       PTE5
00021 2.  Caps lock LED   PTE4
00022 3.  Ground
00023 4.  V+ for LED 
00024 5.  Row 3           PTE3
00025 6.  Row 2           PTE2
00026 7.  Row 1           PTB11
00027 8.  Row 0           PTB10
00028 9.  Col 13          PTA1
00029 10. Col 12          PTC7
00030 11. Col 11          PTA2
00031 12. Col 10          PTC0
00032 13. Col 9           PTD4
00033 14. Col 8           PTC3
00034 15. Col 7           PTA12
00035 16. Col 6           PTC4
00036 17. Col 5           PTA4
00037 18. Col 4           PTC5
00038 19. Col 3           PTA5
00039 20. Col 2           PTC6
00040 21. Col 1           PTC8
00041 22. Col 0           PTC10
00042 
00043 Pin "1" (my numbering) is closest to the corner
00044 of the board, and pin "22" is next to the space
00045 bar. The connections of the keys follow the 
00046 layout in 'hid_keys' below, so KEY_PERIOD is 
00047 col 0 row 0, KEY_L is col 0 row 1, and so on.
00048 We're using the following modifications:
00049 
00050 "CAPS LK"  -> KEY_TAB
00051 "[ ] COPY" -> KEY_OPEN_SQUARE
00052 "DELETE" -> KEY_LEFT_ALT
00053 ": *" -> KEY_SINGLE_QUOTE
00054 
00055 The firmware also treats the 'break' key as
00056 'row 4' all on its own (mapped to KEY_BACKSPACE).
00057 
00058 When 'DELETE' (the LEFT_ALT key) is pressed,
00059 the keyboard map in 'alt_keys' is used, so
00060 e.g. KEY_MINUS becomes KEY_EQUALS.
00061 
00062 Keyboard layout
00063 ---------------
00064 
00065 Note that the keycaps on the Electron keyboard
00066 are considerably different to those on a regular
00067 PC-style one: shift-6 is labelled '&' not '^',
00068 shift-';' is labelled '+' not ':', and so on.
00069 The code here *doesn't* change which key code
00070 is sent when shift is pressed, so the characters
00071 you get are those you'd get on a PC keyboard -
00072 after some experimentation I personally preferred
00073 this. If this isn't to your taste, creating a
00074 custom keyboard layout on the PC/Pi may be the best
00075 way to fix this.
00076 
00077 I tend to use a 'US' keyboard layout with this
00078 keyboard, so shift-3 generates a '#', not a
00079 UK pound sign, and the single/double quotes are
00080 next to the ';' key (labelled ': *' on the Electron).
00081 
00082 ---------------------------------------------- */
00083 
00084 #include "mbed.h"
00085 #include "USBKeyboard.h"
00086 #include "hid_keys.h"
00087 
00088 #define MAX_ROWS 5
00089 #define MAX_COLS 14
00090 #define REPORT_LEN 9
00091 #define REPORT_ID_KEYBOARD 1
00092 
00093 const uint8_t hid_keys[MAX_ROWS * MAX_COLS] = 
00094 {
00095     KEY_PERIOD,     KEY_L,          KEY_O,      KEY_9,      KEY_BACKSPACE,
00096     KEY_SLASH,      KEY_SEMICOLON,  KEY_P,      KEY_0,      KEY_NONE,
00097     KEY_NONE,       KEY_SINGLE_QUOTE,KEY_UP_ARROW,   KEY_MINUS, KEY_NONE,
00098     KEY_LEFT_ALT,   KEY_ENTER,      KEY_DOWN_ARROW, KEY_LEFT_ARROW, KEY_NONE,
00099 
00100     KEY_SPACE,      KEY_NONE,       KEY_OPEN_SQUARE, KEY_RIGHT_ARROW, KEY_NONE,
00101     KEY_COMMA,      KEY_K,          KEY_I,      KEY_8,      KEY_NONE,
00102     KEY_M,          KEY_J,          KEY_U,      KEY_7,      KEY_NONE,
00103     KEY_N,          KEY_H,          KEY_Y,      KEY_6,      KEY_NONE,
00104 
00105     KEY_B,          KEY_G,          KEY_T,      KEY_5,      KEY_NONE,
00106     KEY_V,          KEY_F,          KEY_R,      KEY_4,      KEY_NONE,
00107     KEY_C,          KEY_D,          KEY_E,      KEY_3,      KEY_NONE,
00108     KEY_X,          KEY_S,          KEY_W,      KEY_2,      KEY_NONE,
00109 
00110     KEY_Z,          KEY_A,          KEY_Q,      KEY_1,      KEY_NONE,
00111     KEY_LEFT_SHIFT, KEY_LEFT_CTRL,  KEY_TAB,    KEY_ESC,    KEY_NONE,
00112 };
00113 
00114 const uint8_t alt_keys[MAX_ROWS * MAX_COLS] = 
00115 {
00116     KEY_NONE,       KEY_NONE,       KEY_NONE,   KEY_NONE,   KEY_NONE,
00117     KEY_NONE,       KEY_NONE,       KEY_NONE,   KEY_NONE,   KEY_NONE,
00118     KEY_NONE,       KEY_NONE,       KEY_HASH_TILDE, KEY_EQUALS, KEY_NONE,
00119     KEY_NONE,       KEY_NONE,       KEY_NONE,   KEY_BACKTICK_TILDE,   KEY_NONE,
00120 
00121     KEY_NONE,       KEY_NONE,       KEY_CLOSE_SQUARE, KEY_BACKSLASH,   KEY_NONE,
00122     KEY_NONE,       KEY_NONE,       KEY_NONE,   KEY_NONE,   KEY_NONE,
00123     KEY_NONE,       KEY_NONE,       KEY_NONE,   KEY_NONE,   KEY_NONE,
00124     KEY_NONE,       KEY_NONE,       KEY_NONE,   KEY_NONE,   KEY_NONE,
00125 
00126     KEY_NONE,       KEY_NONE,       KEY_NONE,   KEY_NONE,   KEY_NONE,
00127     KEY_NONE,       KEY_NONE,       KEY_NONE,   KEY_NONE,   KEY_NONE,
00128     KEY_NONE,       KEY_NONE,       KEY_NONE,   KEY_NONE,   KEY_NONE,
00129     KEY_NONE,       KEY_NONE,       KEY_NONE,   KEY_NONE,   KEY_NONE,
00130 
00131     KEY_NONE,       KEY_NONE,       KEY_NONE,   KEY_NONE,   KEY_NONE,
00132     KEY_NONE,       KEY_NONE,       KEY_NONE,   KEY_NONE,   KEY_NONE,
00133 
00134 };
00135 
00136 
00137 BusOut leds(LED1, LED2, LED3);
00138 
00139 BusOut scanCols(
00140     PTC10,PTC8, 
00141     PTC6, PTA5,   
00142     PTC5, PTA4,  
00143     PTC4, PTA12,
00144     PTC3, PTD4,   
00145     PTC0, PTA2,  
00146     PTC7, PTA1  
00147     );
00148 
00149 BusIn inRows(
00150     PTB10,
00151     PTB11,
00152     PTE2,
00153     PTE3,
00154     PTE5 );
00155 
00156 DigitalOut extLed(PTE4);
00157 
00158 USBKeyboard kbd;
00159 
00160 static int scanColumn(int col)
00161 {
00162     int rowBits;
00163     // Drive output low to scan
00164     scanCols.write(0x3FFF ^ (1 << col));
00165     leds.write(col >> 1);
00166     wait(0.001);
00167     rowBits = inRows.read();
00168     scanCols.write(0x3FFF);
00169     // Inputs also active-low
00170     return rowBits ^ 0x1F;
00171 }
00172 
00173 static const uint8_t altKeys =
00174   MODIFIER_BIT(KEY_LEFT_ALT) | MODIFIER_BIT(KEY_RIGHT_ALT);
00175   
00176       
00177 int main()
00178 {
00179     // Setup
00180     inRows.mode(PullUp);
00181     extLed = 1;
00182 
00183     // Run loop
00184     while(1)
00185     {
00186         int col, ocount;
00187         HID_REPORT report;
00188         uint8_t keyIfAlt = KEY_NONE;
00189         
00190         report.data[0] = REPORT_ID_KEYBOARD;
00191         report.data[1] = 0; // modifiers
00192         report.data[2] = 0;
00193         ocount = 3;
00194         
00195         for (col=0; col < MAX_COLS; col++)
00196         {
00197             int row;
00198             int rowBits = scanColumn(col);
00199             if ( !rowBits )
00200               continue;
00201             
00202             for (row=0; row < MAX_ROWS; row++)
00203             {
00204               if ( rowBits & (1 << row) )
00205               {
00206                 uint8_t key = hid_keys[col * MAX_ROWS + row];
00207                 if ( IS_MODIFIER(key) )
00208                   report.data[1] |= MODIFIER_BIT(key);
00209                 else if ( key != KEY_NONE )
00210                 {
00211                   if ( ocount < REPORT_LEN )
00212                     report.data[ocount++] = key;
00213                 }
00214                 
00215                 key = alt_keys[col * MAX_ROWS + row];
00216                 if ( key != KEY_NONE )
00217                   keyIfAlt = key;
00218                 //kbd.printf("c%dr%d ", col, row);
00219               }
00220             }
00221         }
00222 
00223         if ( (report.data[1] & altKeys) != 0 &&
00224              keyIfAlt != KEY_NONE
00225            )
00226         {
00227             report.data[3] = keyIfAlt;
00228             ocount = 4; // Zero out the rest
00229             report.data[1] &= ~altKeys; // And put alt key up
00230         }
00231         
00232         while( ocount < REPORT_LEN )
00233           report.data[ocount++] = KEY_NONE;
00234             
00235         report.length = REPORT_LEN;  
00236         kbd.send(&report);
00237     }
00238 }