/* MAX3421E USB Host controller LCD/keyboard demonstration */ #include #include #include #include /* keyboard data taken from configuration descriptor */ #define KBD_ADDR 1 #define KBD_EP 1 #define KBD_IF 0 #define EP_MAXPKTSIZE 8 #define EP_POLL 0x0a /**/ //****************************************************************************** // macros to identify special charaters(other than Digits and Alphabets) //****************************************************************************** #define BANG (0x1E) #define AT (0x1F) #define POUND (0x20) #define DOLLAR (0x21) #define PERCENT (0x22) #define CAP (0x23) #define AND (0x24) #define STAR (0x25) #define OPENBKT (0x26) #define CLOSEBKT (0x27) #define RETURN (0x28) #define ESCAPE (0x29) #define BACKSPACE (0x2A) #define TAB (0x2B) #define SPACE (0x2C) #define HYPHEN (0x2D) #define EQUAL (0x2E) #define SQBKTOPEN (0x2F) #define SQBKTCLOSE (0x30) #define BACKSLASH (0x31) #define SEMICOLON (0x33) #define INVCOMMA (0x34) #define TILDE (0x35) #define COMMA (0x36) #define PERIOD (0x37) #define FRONTSLASH (0x38) #define DELETE (0x4c) /**/ /* Modifier masks. One for both modifiers */ #define SHIFT 0x22 #define CTRL 0x11 #define ALT 0x44 #define GUI 0x88 /**/ /* "Sticky keys */ #define CAPSLOCK (0x39) #define NUMLOCK (0x53) #define SCROLLLOCK (0x47) /* Sticky keys output report bitmasks */ #define bmNUMLOCK 0x01 #define bmCAPSLOCK 0x02 #define bmSCROLLLOCK 0x04 /**/ EP_RECORD ep_record[ 2 ]; //endpoint record structure for the keyboard char buf[ 8 ] = { 0 }; //keyboard buffer char old_buf[ 8 ] = { 0 }; //last poll /* Sticky key state */ bool numLock = false; bool capsLock = false; bool scrollLock = false; bool line = false; void setup(); void loop(); MAX3421E Max; USB Usb; Max_LCD LCD; void setup() { // set up the LCD's number of rows and columns: LCD.begin(16, 2); LCD.home(); Serial.begin( 9600 ); Serial.println("Start"); Max.powerOn(); delay( 200 ); } void loop() { Max.Task(); Usb.Task(); if( Usb.getUsbTaskState() == USB_STATE_CONFIGURING ) { //wait for addressing state kbd_init(); Usb.setUsbTaskState( USB_STATE_RUNNING ); } if( Usb.getUsbTaskState() == USB_STATE_RUNNING ) { //poll the keyboard kbd_poll(); } } /* Initialize keyboard */ void kbd_init( void ) { byte rcode = 0; //return code /**/ /* Initialize data structures */ ep_record[ 0 ] = *( Usb.getDevTableEntry( 0,0 )); //copy endpoint 0 parameters ep_record[ 1 ].MaxPktSize = EP_MAXPKTSIZE; ep_record[ 1 ].Interval = EP_POLL; ep_record[ 1 ].sndToggle = bmSNDTOG0; ep_record[ 1 ].rcvToggle = bmRCVTOG0; Usb.setDevTableEntry( 1, ep_record ); //plug kbd.endpoint parameters to devtable /* Configure device */ rcode = Usb.setConf( KBD_ADDR, 0, 1 ); if( rcode ) { Serial.print("Error attempting to configure keyboard. Return code :"); Serial.println( rcode, HEX ); while(1); //stop } /* Set boot protocol */ rcode = Usb.setProto( KBD_ADDR, 0, 0, 0 ); if( rcode ) { Serial.print("Error attempting to configure boot protocol. Return code :"); Serial.println( rcode, HEX ); while( 1 ); //stop } LCD.print("Keyboard initialized"); delay(2000); LCD.clear(); LCD.home(); Serial.println("Keyboard initialized"); } /* Poll keyboard and print result */ /* buffer starts at position 2, 0 is modifier key state and 1 is irrelevant */ void kbd_poll( void ) { char i; static char leds = 0; byte rcode = 0; //return code /* poll keyboard */ rcode = Usb.inTransfer( KBD_ADDR, KBD_EP, 8, buf ); if( rcode != 0 ) { return; }//if ( rcode.. for( i = 2; i < 8; i++ ) { if( buf[ i ] == 0 ) { //end of non-empty space break; } if( buf_compare( buf[ i ] ) == false ) { //if new key switch( buf[ i ] ) { case CAPSLOCK: capsLock =! capsLock; leds = ( capsLock ) ? leds |= bmCAPSLOCK : leds &= ~bmCAPSLOCK; // set or clear bit 1 of LED report byte break; case NUMLOCK: numLock =! numLock; leds = ( numLock ) ? leds |= bmNUMLOCK : leds &= ~bmNUMLOCK; // set or clear bit 0 of LED report byte break; case SCROLLLOCK: scrollLock =! scrollLock; leds = ( scrollLock ) ? leds |= bmSCROLLLOCK : leds &= ~bmSCROLLLOCK; // set or clear bit 2 of LED report byte break; case DELETE: LCD.clear(); LCD.home(); line = false; break; case RETURN: line =! line; LCD.setCursor( 0, line ); break; default: //LCD.print("A"); //output LCD.print( HIDtoA( buf[ i ], buf[ 0 ] )); Serial.print(HIDtoA( buf[ i ], buf[ 0 ] )); break; }//switch( buf[ i ... rcode = Usb.setReport( KBD_ADDR, 0, 1, KBD_IF, 0x02, 0, &leds ); if( rcode ) { Serial.print("Set report error: "); Serial.println( rcode, HEX ); }//if( rcode ... }//if( buf_compare( buf[ i ] ) == false ... }//for( i = 2... for( i = 2; i < 8; i++ ) { //copy new buffer to old old_buf[ i ] = buf[ i ]; } } /* compare byte against bytes in old buffer */ bool buf_compare( byte data ) { char i; for( i = 2; i < 8; i++ ) { if( old_buf[ i ] == data ) { return( true ); } } return( false ); } /* HID to ASCII converter. Takes HID keyboard scancode, returns ASCII code */ byte HIDtoA( byte HIDbyte, byte mod ) { /* upper row of the keyboard, numbers and special symbols */ if( HIDbyte >= 0x1e && HIDbyte <= 0x27 ) { if(( mod & SHIFT ) || numLock ) { //shift key pressed switch( HIDbyte ) { case BANG: return( 0x21 ); case AT: return( 0x40 ); case POUND: return( 0x23 ); case DOLLAR: return( 0x24 ); case PERCENT: return( 0x25 ); case CAP: return( 0x5e ); case AND: return( 0x26 ); case STAR: return( 0x2a ); case OPENBKT: return( 0x28 ); case CLOSEBKT: return( 0x29 ); }//switch( HIDbyte... } else { //numbers if( HIDbyte == 0x27 ) { //zero return( 0x30 ); } else { return( HIDbyte + 0x13 ); } }//numbers }//if( HIDbyte >= 0x1e && HIDbyte <= 0x27 /**/ /* number pad. Arrows are not supported */ if(( HIDbyte >= 0x59 && HIDbyte <= 0x61 ) && ( numLock == true )) { // numbers 1-9 return( HIDbyte - 0x28 ); } if(( HIDbyte == 0x62 ) && ( numLock == true )) { //zero return( 0x30 ); } /* Letters a-z */ if( HIDbyte >= 0x04 && HIDbyte <= 0x1d ) { if((( capsLock == true ) && ( mod & SHIFT ) == 0 ) || (( capsLock == false ) && ( mod & SHIFT ))) { //upper case return( HIDbyte + 0x3d ); } else { //lower case return( HIDbyte + 0x5d ); } }//if( HIDbyte >= 0x04 && HIDbyte <= 0x1d... /* Other special symbols */ if( HIDbyte >= 0x2c && HIDbyte <= 0x38 ) { switch( HIDbyte ) { case SPACE: return( 0x20 ); case HYPHEN: if(( mod & SHIFT ) == false ) { return( 0x2d ); } else { return( 0x5f ); } case EQUAL: if(( mod & SHIFT ) == false ) { return( 0x3d ); } else { return( 0x2b ); } case SQBKTOPEN: if(( mod & SHIFT ) == false ) { return( 0x5b ); } else { return( 0x7b ); } case SQBKTCLOSE: if(( mod & SHIFT ) == false ) { return( 0x5d ); } else { return( 0x7d ); } case BACKSLASH: if(( mod & SHIFT ) == false ) { return( 0x5c ); } else { return( 0x7c ); } case SEMICOLON: if(( mod & SHIFT ) == false ) { return( 0x3b ); } else { return( 0x3a ); } case INVCOMMA: if(( mod & SHIFT ) == false ) { return( 0x27 ); } else { return( 0x22 ); } case TILDE: if(( mod & SHIFT ) == false ) { return( 0x60 ); } else { return( 0x7e ); } case COMMA: if(( mod & SHIFT ) == false ) { return( 0x2c ); } else { return( 0x3c ); } case PERIOD: if(( mod & SHIFT ) == false ) { return( 0x2e ); } else { return( 0x3e ); } case FRONTSLASH: if(( mod & SHIFT ) == false ) { return( 0x2f ); } else { return( 0x3f ); } default: break; }//switch( HIDbyte.. }//if( HIDbye >= 0x2d && HIDbyte <= 0x38.. return( 0 ); }