/************************************* * USB Keyboard * rev 1.0 shabaz July 2017 * * license: free for all non-commercial use * *************************************/ /************************************* * includes *************************************/ #include "mbed.h" #include "USBKeyboard.h" /************************************* * defines *************************************/ #define COL0 PTC11 #define COL1 PTC10 #define COL2 PTC6 #define COL3 PTC5 #define ROW0 PTC4 #define ROW1 PTC3 #define ROW2 PTC0 #define ROW3 PTC7 // timings/counts to get good keypress behavior #define TICK_TIME 0.005 #define DEBOUNCE_NUM 2 #define FIRST_WAIT_NUM 100 #define NEXT_WAIT_NUM 1 // states to handle the keypress behaviour #define BSTATE_IDLE 0 #define BSTATE_FIRST 1 #define BSTATE_FIRST_WAIT 2 #define BSTATE_NEXT_WAIT 3 /************************************* * constants *************************************/ const char chardefault[4][4]={ {'1', '2', '3', 'a'}, {'4', '5', '6', 'B'}, {'7', '8', '9', 'C'}, {'*', '0', '#', 'D'}}; // valid values for modifier: 0, KEY_CTRL, KEY_SHIFT, KEY_ALT const char modifierdefault[4][4]={ {0, 0, 0, KEY_CTRL}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}; /************************************* * global variables *************************************/ BusOut leds(LED1, LED2, LED3); DigitalOut* row[4]; DigitalIn* col[4]; char charmap[4][4]; char modifiermap[4][4]; char tstring[2]; char isattached; char dosend; char keypad_event; char keyval_store; char modifier_store; char bstate; unsigned int tick_count; DigitalOut row0(ROW0); DigitalOut row1(ROW1); DigitalOut row2(ROW2); DigitalOut row3(ROW3); DigitalIn col0(COL0); DigitalIn col1(COL1); DigitalIn col2(COL2); DigitalIn col3(COL3); USBKeyboard kb; Ticker press_ticker; /************************************* * functions *************************************/ // copy from ROM into RAM the default config void init_map(void) { memcpy(charmap, chardefault, 16); memcpy(modifiermap, modifierdefault, 16); } // scan the entire keypad and then map any pressed button // into the kepyress value and any modifier char kbscan(char* modifier) { char ret=0; char row_idx=0; char col_idx=0; for (row_idx=0; row_idx<4; row_idx++) { row[row_idx]->write(0); for (col_idx=0; col_idx<4; col_idx++) { if (col[col_idx]->read()==0) { // a button is pressed ret=charmap[row_idx][col_idx]; *modifier=modifiermap[row_idx][col_idx]; } } row[row_idx]->write(1); } return(ret); } // send the keypress (with any modifier) to the PC void send_kb(char keyval, char modifier) { switch (modifier) { case 0: tstring[0]=keyval; kb.printf(tstring); break; default: kb.keyCode(keyval, modifier); break; } } // keypress handler engine. This kicks in whenever a button is pressed // and handles debounce and key repeat, and runs periodically (timer tick) // until the key is finally released by the user void press_handler(void) { char tempkey; char modifier; tempkey=kbscan(&modifier); switch (bstate) { case BSTATE_IDLE: // the keypress has been sent // now lets wait a short debounce period tick_count=0; bstate=BSTATE_FIRST; break; case BSTATE_FIRST: if (tempkey!=keyval_store) // key released! { bstate=BSTATE_IDLE; press_ticker.detach(); isattached=0; } else if (tick_count>=DEBOUNCE_NUM) // debounce period expired { tick_count=0; bstate=BSTATE_FIRST_WAIT; } break; case BSTATE_FIRST_WAIT: if (tempkey!=keyval_store) // key released! { bstate=BSTATE_IDLE; press_ticker.detach(); isattached=0; } else if (tick_count>=FIRST_WAIT_NUM) // first key repeat time expired { // we can send a keypress tstring[0]=keyval_store; tick_count=0; bstate=BSTATE_NEXT_WAIT; dosend=1; } break; case BSTATE_NEXT_WAIT: if (tempkey!=keyval_store) // key released! { bstate=BSTATE_IDLE; press_ticker.detach(); isattached=0; } else if (tick_count>=NEXT_WAIT_NUM) // key repeat time expired { // we can send a keypress faster now tstring[0]=keyval_store; tick_count=0; dosend=1; // stay in this current BSTATE } break; default: break; } tick_count++; } /****************************************** * main function ******************************************/ int main(void) { char i; char forever=1; char modifier; isattached=0; keypad_event=0; tstring[1]='\0'; tick_count=0; dosend=0; bstate=BSTATE_IDLE; init_map(); row[0]=&row0; row[1]=&row1; row[2]=&row2; row[3]=&row3; col[0]=&col0; col[1]=&col1; col[2]=&col2; col[3]=&col3; // set matrix output pins all high, and // set matrix input pins to have pullups for (i=0; i<4; i++) { row[i]->write(1); // set all rows high by default col[i]->mode(PullUp); // set all columns to have pullups } // main loop while (forever) { if (dosend) // keypress handler engine has invoked a key repeat { send_kb(keyval_store, modifier_store); dosend=0; } if ((isattached==0) && (bstate==BSTATE_IDLE)) // no current keypress { keypad_event=kbscan(&modifier); if (keypad_event!=0) // new keypress! { isattached=1; keyval_store=keypad_event; modifier_store=modifier; send_kb(keyval_store, modifier_store); press_ticker.attach(&press_handler, TICK_TIME); // activate keypress engine } } } return(0); // warning on this line is ok }