summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErik Gilling <konkers@android.com>2011-02-17 20:39:36 -0800
committerErik Gilling <konkers@android.com>2011-03-08 14:36:07 -0800
commit51f17515b983385dd8db453e8d36732818b2232e (patch)
tree7081dc714125de0e97f2d17fb1d8f7fac4e8bf80
parenta35b98c9e393a15a136f6163655661ee1372d8bb (diff)
downloadarduino-51f17515b983385dd8db453e8d36732818b2232e.tar.gz
import of stable branch of USB_Host_Shield
from SHA https://github.com/felis/USB_Host_Shield/commit/a59ba5b6fcc96ac79c4dbbffb6c8559d4c944a43 Change-Id: I8244f70db34c734dd8dd454b4957ecdbffd85087
-rw-r--r--USB_Host_Shield/Max3421e.cpp270
-rw-r--r--USB_Host_Shield/Max3421e.h54
-rw-r--r--USB_Host_Shield/Max3421e_constants.h236
-rw-r--r--USB_Host_Shield/Max_LCD.cpp250
-rw-r--r--USB_Host_Shield/Max_LCD.h87
-rw-r--r--USB_Host_Shield/README4
-rw-r--r--USB_Host_Shield/Usb.cpp378
-rw-r--r--USB_Host_Shield/Usb.h175
-rw-r--r--USB_Host_Shield/ch9.h168
-rw-r--r--USB_Host_Shield/examples/LCDkbd.pde335
-rw-r--r--USB_Host_Shield/examples/PS3LCD.pde566
-rw-r--r--USB_Host_Shield/examples/arm_mouse.pde284
-rw-r--r--USB_Host_Shield/examples/board_test/board_test.h21
-rw-r--r--USB_Host_Shield/examples/board_test/board_test.pde296
-rw-r--r--USB_Host_Shield/examples/conf_descr_dump.pde181
-rw-r--r--USB_Host_Shield/examples/descriptor_parser/descriptor_parser.h284
-rw-r--r--USB_Host_Shield/examples/descriptor_parser/descriptor_parser.pde720
-rw-r--r--USB_Host_Shield/main.cpp96
18 files changed, 4405 insertions, 0 deletions
diff --git a/USB_Host_Shield/Max3421e.cpp b/USB_Host_Shield/Max3421e.cpp
new file mode 100644
index 0000000..9531fe7
--- /dev/null
+++ b/USB_Host_Shield/Max3421e.cpp
@@ -0,0 +1,270 @@
+/* Copyright 2009-2011 Oleg Mazurov, Circuits At Home, http://www.circuitsathome.com */
+/* MAX3421E USB host controller support */
+
+#include "Max3421e.h"
+// #include "Max3421e_constants.h"
+
+static byte vbusState;
+
+/* Functions */
+
+/* Constructor */
+MAX3421E::MAX3421E()
+{
+ spi_init();
+ pinMode( MAX_INT, INPUT);
+ pinMode( MAX_GPX, INPUT );
+ pinMode( MAX_SS, OUTPUT );
+ digitalWrite(MAX_SS,HIGH);
+ pinMode( MAX_RESET, OUTPUT );
+ digitalWrite( MAX_RESET, HIGH ); //release MAX3421E from reset
+}
+
+byte MAX3421E::getVbusState( void )
+{
+ return( vbusState );
+}
+/* initialization */
+//void MAX3421E::init()
+//{
+// /* setup pins */
+// pinMode( MAX_INT, INPUT);
+// pinMode( MAX_GPX, INPUT );
+// pinMode( MAX_SS, OUTPUT );
+// //pinMode( BPNT_0, OUTPUT );
+// //pinMode( BPNT_1, OUTPUT );
+// //digitalWrite( BPNT_0, LOW );
+// //digitalWrite( BPNT_1, LOW );
+// Deselect_MAX3421E;
+// pinMode( MAX_RESET, OUTPUT );
+// digitalWrite( MAX_RESET, HIGH ); //release MAX3421E from reset
+//}
+//byte MAX3421E::getVbusState( void )
+//{
+// return( vbusState );
+//}
+//void MAX3421E::toggle( byte pin )
+//{
+// digitalWrite( pin, HIGH );
+// digitalWrite( pin, LOW );
+//}
+/* Single host register write */
+void MAX3421E::regWr( byte reg, byte val)
+{
+ digitalWrite(MAX_SS,LOW);
+ SPDR = ( reg | 0x02 );
+ while(!( SPSR & ( 1 << SPIF )));
+ SPDR = val;
+ while(!( SPSR & ( 1 << SPIF )));
+ digitalWrite(MAX_SS,HIGH);
+ return;
+}
+/* multiple-byte write */
+/* returns a pointer to a memory position after last written */
+char * MAX3421E::bytesWr( byte reg, byte nbytes, char * data )
+{
+ digitalWrite(MAX_SS,LOW);
+ SPDR = ( reg | 0x02 );
+ while( nbytes-- ) {
+ while(!( SPSR & ( 1 << SPIF ))); //check if previous byte was sent
+ SPDR = ( *data ); // send next data byte
+ data++; // advance data pointer
+ }
+ while(!( SPSR & ( 1 << SPIF )));
+ digitalWrite(MAX_SS,HIGH);
+ return( data );
+}
+/* GPIO write. GPIO byte is split between 2 registers, so two writes are needed to write one byte */
+/* GPOUT bits are in the low nibble. 0-3 in IOPINS1, 4-7 in IOPINS2 */
+/* upper 4 bits of IOPINS1, IOPINS2 are read-only, so no masking is necessary */
+void MAX3421E::gpioWr( byte val )
+{
+ regWr( rIOPINS1, val );
+ val = val >>4;
+ regWr( rIOPINS2, val );
+
+ return;
+}
+/* Single host register read */
+byte MAX3421E::regRd( byte reg )
+{
+ byte tmp;
+ digitalWrite(MAX_SS,LOW);
+ SPDR = reg;
+ while(!( SPSR & ( 1 << SPIF )));
+ SPDR = 0; //send empty byte
+ while(!( SPSR & ( 1 << SPIF )));
+ digitalWrite(MAX_SS,HIGH);
+ return( SPDR );
+}
+/* multiple-bytes register read */
+/* returns a pointer to a memory position after last read */
+char * MAX3421E::bytesRd ( byte reg, byte nbytes, char * data )
+{
+ digitalWrite(MAX_SS,LOW);
+ SPDR = reg;
+ while(!( SPSR & ( 1 << SPIF ))); //wait
+ while( nbytes ) {
+ SPDR = 0; //send empty byte
+ nbytes--;
+ while(!( SPSR & ( 1 << SPIF )));
+ *data = SPDR;
+ data++;
+ }
+ digitalWrite(MAX_SS,HIGH);
+ return( data );
+}
+/* GPIO read. See gpioWr for explanation */
+/* GPIN pins are in high nibbles of IOPINS1, IOPINS2 */
+byte MAX3421E::gpioRd( void )
+{
+ byte tmpbyte = 0;
+ tmpbyte = regRd( rIOPINS2 ); //pins 4-7
+ tmpbyte &= 0xf0; //clean lower nibble
+ tmpbyte |= ( regRd( rIOPINS1 ) >>4 ) ; //shift low bits and OR with upper from previous operation. Upper nibble zeroes during shift, at least with this compiler
+ return( tmpbyte );
+}
+/* reset MAX3421E using chip reset bit. SPI configuration is not affected */
+boolean MAX3421E::reset()
+{
+ byte tmp = 0;
+ regWr( rUSBCTL, bmCHIPRES ); //Chip reset. This stops the oscillator
+ regWr( rUSBCTL, 0x00 ); //Remove the reset
+ while(!(regRd( rUSBIRQ ) & bmOSCOKIRQ )) { //wait until the PLL is stable
+ tmp++; //timeout after 256 attempts
+ if( tmp == 0 ) {
+ return( false );
+ }
+ }
+ return( true );
+}
+/* turn USB power on/off */
+/* does nothing, returns TRUE. Left for compatibility with old sketches */
+/* will be deleted eventually */
+///* ON pin of VBUS switch (MAX4793 or similar) is connected to GPOUT7 */
+///* OVERLOAD pin of Vbus switch is connected to GPIN7 */
+///* OVERLOAD state low. NO OVERLOAD or VBUS OFF state high. */
+boolean MAX3421E::vbusPwr ( boolean action )
+{
+// byte tmp;
+// tmp = regRd( rIOPINS2 ); //copy of IOPINS2
+// if( action ) { //turn on by setting GPOUT7
+// tmp |= bmGPOUT7;
+// }
+// else { //turn off by clearing GPOUT7
+// tmp &= ~bmGPOUT7;
+// }
+// regWr( rIOPINS2, tmp ); //send GPOUT7
+// if( action ) {
+// delay( 60 );
+// }
+// if (( regRd( rIOPINS2 ) & bmGPIN7 ) == 0 ) { // check if overload is present. MAX4793 /FLAG ( pin 4 ) goes low if overload
+// return( false );
+// }
+ return( true ); // power on/off successful
+}
+/* probe bus to determine device presense and speed and switch host to this speed */
+void MAX3421E::busprobe( void )
+{
+ byte bus_sample;
+ bus_sample = regRd( rHRSL ); //Get J,K status
+ bus_sample &= ( bmJSTATUS|bmKSTATUS ); //zero the rest of the byte
+ switch( bus_sample ) { //start full-speed or low-speed host
+ case( bmJSTATUS ):
+ if(( regRd( rMODE ) & bmLOWSPEED ) == 0 ) {
+ regWr( rMODE, MODE_FS_HOST ); //start full-speed host
+ vbusState = FSHOST;
+ }
+ else {
+ regWr( rMODE, MODE_LS_HOST); //start low-speed host
+ vbusState = LSHOST;
+ }
+ break;
+ case( bmKSTATUS ):
+ if(( regRd( rMODE ) & bmLOWSPEED ) == 0 ) {
+ regWr( rMODE, MODE_LS_HOST ); //start low-speed host
+ vbusState = LSHOST;
+ }
+ else {
+ regWr( rMODE, MODE_FS_HOST ); //start full-speed host
+ vbusState = FSHOST;
+ }
+ break;
+ case( bmSE1 ): //illegal state
+ vbusState = SE1;
+ break;
+ case( bmSE0 ): //disconnected state
+ vbusState = SE0;
+ break;
+ }//end switch( bus_sample )
+}
+/* MAX3421E initialization after power-on */
+void MAX3421E::powerOn()
+{
+ /* Configure full-duplex SPI, interrupt pulse */
+ regWr( rPINCTL,( bmFDUPSPI + bmINTLEVEL + bmGPXB )); //Full-duplex SPI, level interrupt, GPX
+ if( reset() == false ) { //stop/start the oscillator
+ Serial.println("Error: OSCOKIRQ failed to assert");
+ }
+
+ /* configure host operation */
+ regWr( rMODE, bmDPPULLDN|bmDMPULLDN|bmHOST|bmSEPIRQ ); // set pull-downs, Host, Separate GPIN IRQ on GPX
+ regWr( rHIEN, bmCONDETIE|bmFRAMEIE ); //connection detection
+ /* check if device is connected */
+ regWr( rHCTL,bmSAMPLEBUS ); // sample USB bus
+ while(!(regRd( rHCTL ) & bmSAMPLEBUS )); //wait for sample operation to finish
+ busprobe(); //check if anything is connected
+ regWr( rHIRQ, bmCONDETIRQ ); //clear connection detect interrupt
+ regWr( rCPUCTL, 0x01 ); //enable interrupt pin
+}
+/* MAX3421 state change task and interrupt handler */
+byte MAX3421E::Task( void )
+{
+ byte rcode = 0;
+ byte pinvalue;
+ //Serial.print("Vbus state: ");
+ //Serial.println( vbusState, HEX );
+ pinvalue = digitalRead( MAX_INT );
+ if( pinvalue == LOW ) {
+ rcode = IntHandler();
+ }
+ pinvalue = digitalRead( MAX_GPX );
+ if( pinvalue == LOW ) {
+ GpxHandler();
+ }
+// usbSM(); //USB state machine
+ return( rcode );
+}
+byte MAX3421E::IntHandler()
+{
+ byte HIRQ;
+ byte HIRQ_sendback = 0x00;
+ HIRQ = regRd( rHIRQ ); //determine interrupt source
+ //if( HIRQ & bmFRAMEIRQ ) { //->1ms SOF interrupt handler
+ // HIRQ_sendback |= bmFRAMEIRQ;
+ //}//end FRAMEIRQ handling
+ if( HIRQ & bmCONDETIRQ ) {
+ busprobe();
+ HIRQ_sendback |= bmCONDETIRQ;
+ }
+ /* End HIRQ interrupts handling, clear serviced IRQs */
+ regWr( rHIRQ, HIRQ_sendback );
+ return( HIRQ_sendback );
+}
+byte MAX3421E::GpxHandler()
+{
+ byte GPINIRQ = regRd( rGPINIRQ ); //read GPIN IRQ register
+// if( GPINIRQ & bmGPINIRQ7 ) { //vbus overload
+// vbusPwr( OFF ); //attempt powercycle
+// delay( 1000 );
+// vbusPwr( ON );
+// regWr( rGPINIRQ, bmGPINIRQ7 );
+// }
+ return( GPINIRQ );
+}
+
+//void MAX3421E::usbSM( void ) //USB state machine
+//{
+//
+//
+//} \ No newline at end of file
diff --git a/USB_Host_Shield/Max3421e.h b/USB_Host_Shield/Max3421e.h
new file mode 100644
index 0000000..cf40c5d
--- /dev/null
+++ b/USB_Host_Shield/Max3421e.h
@@ -0,0 +1,54 @@
+/* Copyright 2009-2011 Oleg Mazurov, Circuits At Home, http://www.circuitsathome.com */
+/* MAX3421E functions */
+#ifndef _MAX3421E_H_
+#define _MAX3421E_H_
+
+
+//#include <Spi.h>
+//#include <WProgram.h>
+#include "WProgram.h"
+#include "Max3421e_constants.h"
+
+class MAX3421E /* : public SPI */ {
+ // byte vbusState;
+ public:
+ MAX3421E( void );
+ byte getVbusState( void );
+// void toggle( byte pin );
+ static void regWr( byte, byte );
+ char * bytesWr( byte, byte, char * );
+ static void gpioWr( byte );
+ byte regRd( byte );
+ char * bytesRd( byte, byte, char * );
+ byte gpioRd( void );
+ boolean reset();
+ boolean vbusPwr ( boolean );
+ void busprobe( void );
+ void powerOn();
+ byte IntHandler();
+ byte GpxHandler();
+ byte Task();
+ private:
+ static void spi_init() {
+ uint8_t tmp;
+ // initialize SPI pins
+ pinMode(SCK_PIN, OUTPUT);
+ pinMode(MOSI_PIN, OUTPUT);
+ pinMode(MISO_PIN, INPUT);
+ pinMode(SS_PIN, OUTPUT);
+ digitalWrite( SS_PIN, HIGH );
+ /* mode 00 (CPOL=0, CPHA=0) master, fclk/2. Mode 11 (CPOL=11, CPHA=11) is also supported by MAX3421E */
+ SPCR = 0x50;
+ SPSR = 0x01;
+ /**/
+ tmp = SPSR;
+ tmp = SPDR;
+ }
+// void init();
+ friend class Max_LCD;
+};
+
+
+
+
+#endif //_MAX3421E_H_
diff --git a/USB_Host_Shield/Max3421e_constants.h b/USB_Host_Shield/Max3421e_constants.h
new file mode 100644
index 0000000..ed59a6b
--- /dev/null
+++ b/USB_Host_Shield/Max3421e_constants.h
@@ -0,0 +1,236 @@
+/* Copyright 2009-2011 Oleg Mazurov, Circuits At Home, http://www.circuitsathome.com */
+/* MAX3421E register/bit names and bitmasks */
+
+#ifndef _MAX3421Econstants_h_
+#define _MAX3421Econstants_h_
+
+/* SPI pins for diffrent Arduinos */
+
+#if defined(__AVR_ATmega1280__) || (__AVR_ATmega2560__)
+ #define SCK_PIN 52
+ #define MISO_PIN 50
+ #define MOSI_PIN 51
+ #define SS_PIN 53
+#endif
+#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__)
+ #define SCK_PIN 13
+ #define MISO_PIN 12
+ #define MOSI_PIN 11
+ #define SS_PIN 10
+#endif
+
+#define MAX_SS 10
+#define MAX_INT 9
+#define MAX_GPX 8
+#define MAX_RESET 7
+
+/* "Breakpoint" pins for debugging */
+//#define BPNT_0 3
+//#define BPNT_1 2
+
+//#define Select_MAX3421E digitalWrite(MAX_SS,LOW)
+//#define Deselect_MAX3421E digitalWrite(MAX_SS,HIGH)
+
+/* */
+
+#define ON true
+#define OFF false
+
+/* VBUS states */
+#define SE0 0
+#define SE1 1
+#define FSHOST 2
+#define LSHOST 3
+
+/* MAX3421E command byte format: rrrrr0wa where 'r' is register number */
+//
+// MAX3421E Registers in HOST mode.
+//
+#define rRCVFIFO 0x08 //1<<3
+#define rSNDFIFO 0x10 //2<<3
+#define rSUDFIFO 0x20 //4<<3
+#define rRCVBC 0x30 //6<<3
+#define rSNDBC 0x38 //7<<3
+
+#define rUSBIRQ 0x68 //13<<3
+/* USBIRQ Bits */
+#define bmVBUSIRQ 0x40 //b6
+#define bmNOVBUSIRQ 0x20 //b5
+#define bmOSCOKIRQ 0x01 //b0
+
+#define rUSBIEN 0x70 //14<<3
+/* USBIEN Bits */
+#define bmVBUSIE 0x40 //b6
+#define bmNOVBUSIE 0x20 //b5
+#define bmOSCOKIE 0x01 //b0
+
+#define rUSBCTL 0x78 //15<<3
+/* USBCTL Bits */
+#define bmCHIPRES 0x20 //b5
+#define bmPWRDOWN 0x10 //b4
+
+#define rCPUCTL 0x80 //16<<3
+/* CPUCTL Bits */
+#define bmPUSLEWID1 0x80 //b7
+#define bmPULSEWID0 0x40 //b6
+#define bmIE 0x01 //b0
+
+#define rPINCTL 0x88 //17<<3
+/* PINCTL Bits */
+#define bmFDUPSPI 0x10 //b4
+#define bmINTLEVEL 0x08 //b3
+#define bmPOSINT 0x04 //b2
+#define bmGPXB 0x02 //b1
+#define bmGPXA 0x01 //b0
+// GPX pin selections
+#define GPX_OPERATE 0x00
+#define GPX_VBDET 0x01
+#define GPX_BUSACT 0x02
+#define GPX_SOF 0x03
+
+#define rREVISION 0x90 //18<<3
+
+#define rIOPINS1 0xa0 //20<<3
+
+/* IOPINS1 Bits */
+#define bmGPOUT0 0x01
+#define bmGPOUT1 0x02
+#define bmGPOUT2 0x04
+#define bmGPOUT3 0x08
+#define bmGPIN0 0x10
+#define bmGPIN1 0x20
+#define bmGPIN2 0x40
+#define bmGPIN3 0x80
+
+#define rIOPINS2 0xa8 //21<<3
+/* IOPINS2 Bits */
+#define bmGPOUT4 0x01
+#define bmGPOUT5 0x02
+#define bmGPOUT6 0x04
+#define bmGPOUT7 0x08
+#define bmGPIN4 0x10
+#define bmGPIN5 0x20
+#define bmGPIN6 0x40
+#define bmGPIN7 0x80
+
+#define rGPINIRQ 0xb0 //22<<3
+/* GPINIRQ Bits */
+#define bmGPINIRQ0 0x01
+#define bmGPINIRQ1 0x02
+#define bmGPINIRQ2 0x04
+#define bmGPINIRQ3 0x08
+#define bmGPINIRQ4 0x10
+#define bmGPINIRQ5 0x20
+#define bmGPINIRQ6 0x40
+#define bmGPINIRQ7 0x80
+
+#define rGPINIEN 0xb8 //23<<3
+/* GPINIEN Bits */
+#define bmGPINIEN0 0x01
+#define bmGPINIEN1 0x02
+#define bmGPINIEN2 0x04
+#define bmGPINIEN3 0x08
+#define bmGPINIEN4 0x10
+#define bmGPINIEN5 0x20
+#define bmGPINIEN6 0x40
+#define bmGPINIEN7 0x80
+
+#define rGPINPOL 0xc0 //24<<3
+/* GPINPOL Bits */
+#define bmGPINPOL0 0x01
+#define bmGPINPOL1 0x02
+#define bmGPINPOL2 0x04
+#define bmGPINPOL3 0x08
+#define bmGPINPOL4 0x10
+#define bmGPINPOL5 0x20
+#define bmGPINPOL6 0x40
+#define bmGPINPOL7 0x80
+
+#define rHIRQ 0xc8 //25<<3
+/* HIRQ Bits */
+#define bmBUSEVENTIRQ 0x01 // indicates BUS Reset Done or BUS Resume
+#define bmRWUIRQ 0x02
+#define bmRCVDAVIRQ 0x04
+#define bmSNDBAVIRQ 0x08
+#define bmSUSDNIRQ 0x10
+#define bmCONDETIRQ 0x20
+#define bmFRAMEIRQ 0x40
+#define bmHXFRDNIRQ 0x80
+
+#define rHIEN 0xd0 //26<<3
+/* HIEN Bits */
+#define bmBUSEVENTIE 0x01
+#define bmRWUIE 0x02
+#define bmRCVDAVIE 0x04
+#define bmSNDBAVIE 0x08
+#define bmSUSDNIE 0x10
+#define bmCONDETIE 0x20
+#define bmFRAMEIE 0x40
+#define bmHXFRDNIE 0x80
+
+#define rMODE 0xd8 //27<<3
+/* MODE Bits */
+#define bmHOST 0x01
+#define bmLOWSPEED 0x02
+#define bmHUBPRE 0x04
+#define bmSOFKAENAB 0x08
+#define bmSEPIRQ 0x10
+#define bmDELAYISO 0x20
+#define bmDMPULLDN 0x40
+#define bmDPPULLDN 0x80
+
+#define rPERADDR 0xe0 //28<<3
+
+#define rHCTL 0xe8 //29<<3
+/* HCTL Bits */
+#define bmBUSRST 0x01
+#define bmFRMRST 0x02
+#define bmSAMPLEBUS 0x04
+#define bmSIGRSM 0x08
+#define bmRCVTOG0 0x10
+#define bmRCVTOG1 0x20
+#define bmSNDTOG0 0x40
+#define bmSNDTOG1 0x80
+
+#define rHXFR 0xf0 //30<<3
+/* Host transfer token values for writing the HXFR register (R30) */
+/* OR this bit field with the endpoint number in bits 3:0 */
+#define tokSETUP 0x10 // HS=0, ISO=0, OUTNIN=0, SETUP=1
+#define tokIN 0x00 // HS=0, ISO=0, OUTNIN=0, SETUP=0
+#define tokOUT 0x20 // HS=0, ISO=0, OUTNIN=1, SETUP=0
+#define tokINHS 0x80 // HS=1, ISO=0, OUTNIN=0, SETUP=0
+#define tokOUTHS 0xA0 // HS=1, ISO=0, OUTNIN=1, SETUP=0
+#define tokISOIN 0x40 // HS=0, ISO=1, OUTNIN=0, SETUP=0
+#define tokISOOUT 0x60 // HS=0, ISO=1, OUTNIN=1, SETUP=0
+
+#define rHRSL 0xf8 //31<<3
+/* HRSL Bits */
+#define bmRCVTOGRD 0x10
+#define bmSNDTOGRD 0x20
+#define bmKSTATUS 0x40
+#define bmJSTATUS 0x80
+#define bmSE0 0x00 //SE0 - disconnect state
+#define bmSE1 0xc0 //SE1 - illegal state
+/* Host error result codes, the 4 LSB's in the HRSL register */
+#define hrSUCCESS 0x00
+#define hrBUSY 0x01
+#define hrBADREQ 0x02
+#define hrUNDEF 0x03
+#define hrNAK 0x04
+#define hrSTALL 0x05
+#define hrTOGERR 0x06
+#define hrWRONGPID 0x07
+#define hrBADBC 0x08
+#define hrPIDERR 0x09
+#define hrPKTERR 0x0A
+#define hrCRCERR 0x0B
+#define hrKERR 0x0C
+#define hrJERR 0x0D
+#define hrTIMEOUT 0x0E
+#define hrBABBLE 0x0F
+
+#define MODE_FS_HOST (bmDPPULLDN|bmDMPULLDN|bmHOST|bmSOFKAENAB)
+#define MODE_LS_HOST (bmDPPULLDN|bmDMPULLDN|bmHOST|bmLOWSPEED|bmSOFKAENAB)
+
+
+#endif //_MAX3421Econstants_h_
diff --git a/USB_Host_Shield/Max_LCD.cpp b/USB_Host_Shield/Max_LCD.cpp
new file mode 100644
index 0000000..c09977d
--- /dev/null
+++ b/USB_Host_Shield/Max_LCD.cpp
@@ -0,0 +1,250 @@
+/* Copyright 2009-2011 Oleg Mazurov, Circuits At Home, http://www.circuitsathome.com */
+//this code is heavily borrowed from official Arduino source v.0017
+// link to original http://code.google.com/p/arduino/source/browse/trunk/hardware/libraries/LiquidCrystal/LiquidCrystal.cpp
+#include "Max_LCD.h"
+#include "Max3421e.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+#include "WProgram.h"
+
+// When the display powers up, it is configured as follows:
+//
+// 1. Display clear
+// 2. Function set:
+// DL = 1; 8-bit interface data
+// N = 0; 1-line display
+// F = 0; 5x8 dot character font
+// 3. Display on/off control:
+// D = 0; Display off
+// C = 0; Cursor off
+// B = 0; Blinking off
+// 4. Entry mode set:
+// I/D = 1; Increment by 1
+// S = 0; No shift
+//
+// Note, however, that resetting the Arduino doesn't reset the LCD, so we
+// can't assume that it's in that state when a sketch starts
+
+// pin definition and set/clear
+
+#define RS 0x04 // RS pin
+#define E 0x08 // E pin
+
+#define SET_RS lcdPins |= RS
+#define CLR_RS lcdPins &= ~RS
+#define SET_E lcdPins |= E
+#define CLR_E lcdPins &= ~E
+
+#define SENDlcdPins() MAX3421E::gpioWr( lcdPins )
+
+#define LCD_sendcmd(a) { CLR_RS; \
+ sendbyte(a); \
+ }
+
+#define LCD_sendchar(a) { SET_RS; \
+ sendbyte(a); \
+ }
+
+static byte lcdPins; //copy of LCD pins
+
+Max_LCD::Max_LCD()
+{
+ lcdPins = 0;
+}
+
+
+void Max_LCD::init()
+{
+ _displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
+
+ // MAX3421E::gpioWr(0x55);
+
+ begin(16, 1);
+}
+
+void Max_LCD::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) {
+ if (lines > 1) {
+ _displayfunction |= LCD_2LINE;
+ }
+ _numlines = lines;
+ _currline = 0;
+
+ // for some 1 line displays you can select a 10 pixel high font
+ if ((dotsize != 0) && (lines == 1)) {
+ _displayfunction |= LCD_5x10DOTS;
+ }
+
+ // SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION!
+ // according to datasheet, we need at least 40ms after power rises above 2.7V
+ // before sending commands. Arduino can turn on way befer 4.5V so we'll wait 50
+ delayMicroseconds(50000);
+ lcdPins = 0x30;
+ SET_E;
+ SENDlcdPins();
+ CLR_E;
+ SENDlcdPins();
+ delayMicroseconds(10000); // wait min 4.1ms
+ //second try
+ SET_E;
+ SENDlcdPins();
+ CLR_E;
+ SENDlcdPins();
+ delayMicroseconds(10000); // wait min 4.1ms
+ // third go!
+ SET_E;
+ SENDlcdPins();
+ CLR_E;
+ SENDlcdPins();
+ delayMicroseconds(10000);
+ // finally, set to 4-bit interface
+ lcdPins = 0x20;
+ //SET_RS;
+ SET_E;
+ SENDlcdPins();
+ //CLR_RS;
+ CLR_E;
+ SENDlcdPins();
+ delayMicroseconds(10000);
+ // finally, set # lines, font size, etc.
+ command(LCD_FUNCTIONSET | _displayfunction);
+
+ // turn the display on with no cursor or blinking default
+ _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
+ display();
+
+ // clear it off
+ clear();
+
+ // Initialize to default text direction (for romance languages)
+ _displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
+ // set the entry mode
+ command(LCD_ENTRYMODESET | _displaymode);
+}
+
+/********** high level commands, for the user! */
+void Max_LCD::clear()
+{
+ command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero
+ delayMicroseconds(2000); // this command takes a long time!
+}
+
+void Max_LCD::home()
+{
+ command(LCD_RETURNHOME); // set cursor position to zero
+ delayMicroseconds(2000); // this command takes a long time!
+}
+
+void Max_LCD::setCursor(uint8_t col, uint8_t row)
+{
+ int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 };
+ if ( row > _numlines ) {
+ row = _numlines-1; // we count rows starting w/0
+ }
+
+ command(LCD_SETDDRAMADDR | (col + row_offsets[row]));
+}
+
+// Turn the display on/off (quickly)
+void Max_LCD::noDisplay() {
+ _displaycontrol &= ~LCD_DISPLAYON;
+ command(LCD_DISPLAYCONTROL | _displaycontrol);
+}
+void Max_LCD::display() {
+ _displaycontrol |= LCD_DISPLAYON;
+ command(LCD_DISPLAYCONTROL | _displaycontrol);
+}
+
+// Turns the underline cursor on/off
+void Max_LCD::noCursor() {
+ _displaycontrol &= ~LCD_CURSORON;
+ command(LCD_DISPLAYCONTROL | _displaycontrol);
+}
+void Max_LCD::cursor() {
+ _displaycontrol |= LCD_CURSORON;
+ command(LCD_DISPLAYCONTROL | _displaycontrol);
+}
+
+
+// Turn on and off the blinking cursor
+void Max_LCD::noBlink() {
+ _displaycontrol &= ~LCD_BLINKON;
+ command(LCD_DISPLAYCONTROL | _displaycontrol);
+}
+void Max_LCD::blink() {
+ _displaycontrol |= LCD_BLINKON;
+ command(LCD_DISPLAYCONTROL | _displaycontrol);
+}
+
+// These commands scroll the display without changing the RAM
+void Max_LCD::scrollDisplayLeft(void) {
+ command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);
+}
+void Max_LCD::scrollDisplayRight(void) {
+ command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);
+}
+
+// This is for text that flows Left to Right
+void Max_LCD::leftToRight(void) {
+ _displaymode |= LCD_ENTRYLEFT;
+ command(LCD_ENTRYMODESET | _displaymode);
+}
+
+// This is for text that flows Right to Left
+void Max_LCD::rightToLeft(void) {
+ _displaymode &= ~LCD_ENTRYLEFT;
+ command(LCD_ENTRYMODESET | _displaymode);
+}
+
+// This will 'right justify' text from the cursor
+void Max_LCD::autoscroll(void) {
+ _displaymode |= LCD_ENTRYSHIFTINCREMENT;
+ command(LCD_ENTRYMODESET | _displaymode);
+}
+
+// This will 'left justify' text from the cursor
+void Max_LCD::noAutoscroll(void) {
+ _displaymode &= ~LCD_ENTRYSHIFTINCREMENT;
+ command(LCD_ENTRYMODESET | _displaymode);
+}
+
+// Allows us to fill the first 8 CGRAM locations
+// with custom characters
+void Max_LCD::createChar(uint8_t location, uint8_t charmap[]) {
+ location &= 0x7; // we only have 8 locations 0-7
+ command(LCD_SETCGRAMADDR | (location << 3));
+ for (int i=0; i<8; i++) {
+ write(charmap[i]);
+ }
+}
+
+/*********** mid level commands, for sending data/cmds */
+
+inline void Max_LCD::command(uint8_t value) {
+ LCD_sendcmd(value);
+ delayMicroseconds(100);
+}
+
+inline void Max_LCD::write(uint8_t value) {
+ LCD_sendchar(value);
+}
+
+void Max_LCD::sendbyte( uint8_t val )
+{
+ lcdPins &= 0x0f; //prepare place for the upper nibble
+ lcdPins |= ( val & 0xf0 ); //copy upper nibble to LCD variable
+ SET_E; //send
+ SENDlcdPins();
+ delayMicroseconds(2);
+ CLR_E;
+ delayMicroseconds(2);
+ SENDlcdPins();
+ lcdPins &= 0x0f; //prepare place for the lower nibble
+ lcdPins |= ( val << 4 ) & 0xf0; //copy lower nibble to LCD variable
+ SET_E; //send
+ SENDlcdPins();
+ CLR_E;
+ SENDlcdPins();
+ delayMicroseconds(100);
+}
diff --git a/USB_Host_Shield/Max_LCD.h b/USB_Host_Shield/Max_LCD.h
new file mode 100644
index 0000000..c1ad45f
--- /dev/null
+++ b/USB_Host_Shield/Max_LCD.h
@@ -0,0 +1,87 @@
+/* Copyright 2009-2011 Oleg Mazurov, Circuits At Home, http://www.circuitsathome.com */
+//HD44780 compatible LCD display via MAX3421E GPOUT support header
+//pinout: D[4-7] -> GPOUT[4-7], RS-> GPOUT[2], E ->GPOUT[3]
+//
+//this code is heavily borrowed from official Arduino source v.0017
+// link to original http://code.google.com/p/arduino/source/browse/trunk/hardware/libraries/LiquidCrystal/LiquidCrystal.h
+//
+#ifndef _Max_LCD_h_
+#define _Max_LCD_h_
+
+#include <inttypes.h>
+#include "Print.h"
+
+// commands
+#define LCD_CLEARDISPLAY 0x01
+#define LCD_RETURNHOME 0x02
+#define LCD_ENTRYMODESET 0x04
+#define LCD_DISPLAYCONTROL 0x08
+#define LCD_CURSORSHIFT 0x10
+#define LCD_FUNCTIONSET 0x20
+#define LCD_SETCGRAMADDR 0x40
+#define LCD_SETDDRAMADDR 0x80
+
+// flags for display entry mode
+#define LCD_ENTRYRIGHT 0x00
+#define LCD_ENTRYLEFT 0x02
+#define LCD_ENTRYSHIFTINCREMENT 0x01
+#define LCD_ENTRYSHIFTDECREMENT 0x00
+
+// flags for display on/off control
+#define LCD_DISPLAYON 0x04
+#define LCD_DISPLAYOFF 0x00
+#define LCD_CURSORON 0x02
+#define LCD_CURSOROFF 0x00
+#define LCD_BLINKON 0x01
+#define LCD_BLINKOFF 0x00
+
+// flags for display/cursor shift
+#define LCD_DISPLAYMOVE 0x08
+#define LCD_CURSORMOVE 0x00
+#define LCD_MOVERIGHT 0x04
+#define LCD_MOVELEFT 0x00
+
+// flags for function set
+#define LCD_8BITMODE 0x10
+#define LCD_4BITMODE 0x00
+#define LCD_2LINE 0x08
+#define LCD_1LINE 0x00
+#define LCD_5x10DOTS 0x04
+#define LCD_5x8DOTS 0x00
+
+class Max_LCD : public Print {
+public:
+ Max_LCD();
+ void init();
+ void begin(uint8_t cols, uint8_t rows, uint8_t charsize = LCD_5x8DOTS);
+ void clear();
+ void home();
+ void noDisplay();
+ void display();
+ void noBlink();
+ void blink();
+ void noCursor();
+ void cursor();
+ void scrollDisplayLeft();
+ void scrollDisplayRight();
+ void leftToRight();
+ void rightToLeft();
+ void autoscroll();
+ void noAutoscroll();
+ void createChar(uint8_t, uint8_t[]);
+ void setCursor(uint8_t, uint8_t);
+ virtual void write(uint8_t);
+ void command(uint8_t);
+private:
+ void sendbyte( uint8_t val );
+ uint8_t _displayfunction; //tokill
+ uint8_t _displaycontrol;
+ uint8_t _displaymode;
+ uint8_t _initialized;
+ uint8_t _numlines,_currline;
+};
+
+
+
+
+#endif \ No newline at end of file
diff --git a/USB_Host_Shield/README b/USB_Host_Shield/README
new file mode 100644
index 0000000..401034c
--- /dev/null
+++ b/USB_Host_Shield/README
@@ -0,0 +1,4 @@
+This is a library for MAX3421E-based USB Host Shield for Arduino -> http://www.circuitsathome.com/arduino_usb_host_shield_projects
+
+More information can be found at http://www.circuitsathome.com
+
diff --git a/USB_Host_Shield/Usb.cpp b/USB_Host_Shield/Usb.cpp
new file mode 100644
index 0000000..197f8cd
--- /dev/null
+++ b/USB_Host_Shield/Usb.cpp
@@ -0,0 +1,378 @@
+/* Copyright 2009-2011 Oleg Mazurov, Circuits At Home, http://www.circuitsathome.com */
+/* USB functions */
+
+#include "Usb.h"
+
+static byte usb_error = 0;
+static byte usb_task_state;
+DEV_RECORD devtable[ USB_NUMDEVICES + 1 ];
+EP_RECORD dev0ep; //Endpoint data structure used during enumeration for uninitialized device
+
+
+/* constructor */
+
+USB::USB () {
+ usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE; //set up state machine
+ init();
+}
+/* Initialize data structures */
+void USB::init()
+{
+ byte i;
+ for( i = 0; i < ( USB_NUMDEVICES + 1 ); i++ ) {
+ devtable[ i ].epinfo = NULL; //clear device table
+ devtable[ i ].devclass = 0;
+ }
+ devtable[ 0 ].epinfo = &dev0ep; //set single ep for uninitialized device
+ // not necessary dev0ep.MaxPktSize = 8; //minimum possible
+ dev0ep.sndToggle = bmSNDTOG0; //set DATA0/1 toggles to 0
+ dev0ep.rcvToggle = bmRCVTOG0;
+}
+byte USB::getUsbTaskState( void )
+{
+ return( usb_task_state );
+}
+void USB::setUsbTaskState( byte state )
+{
+ usb_task_state = state;
+}
+EP_RECORD* USB::getDevTableEntry( byte addr, byte ep )
+{
+ EP_RECORD* ptr;
+ ptr = devtable[ addr ].epinfo;
+ ptr += ep;
+ return( ptr );
+}
+/* set device table entry */
+/* each device is different and has different number of endpoints. This function plugs endpoint record structure, defined in application, to devtable */
+void USB::setDevTableEntry( byte addr, EP_RECORD* eprecord_ptr )
+{
+ devtable[ addr ].epinfo = eprecord_ptr;
+ //return();
+}
+/* Control transfer. Sets address, endpoint, fills control packet with necessary data, dispatches control packet, and initiates bulk IN transfer, */
+/* depending on request. Actual requests are defined as inlines */
+/* return codes: */
+/* 00 = success */
+/* 01-0f = non-zero HRSLT */
+byte USB::ctrlReq( byte addr, byte ep, byte bmReqType, byte bRequest, byte wValLo, byte wValHi, unsigned int wInd, unsigned int nbytes, char* dataptr, unsigned int nak_limit )
+{
+ boolean direction = false; //request direction, IN or OUT
+ byte rcode;
+ SETUP_PKT setup_pkt;
+
+ regWr( rPERADDR, addr ); //set peripheral address
+ if( bmReqType & 0x80 ) {
+ direction = true; //determine request direction
+ }
+ /* fill in setup packet */
+ setup_pkt.ReqType_u.bmRequestType = bmReqType;
+ setup_pkt.bRequest = bRequest;
+ setup_pkt.wVal_u.wValueLo = wValLo;
+ setup_pkt.wVal_u.wValueHi = wValHi;
+ setup_pkt.wIndex = wInd;
+ setup_pkt.wLength = nbytes;
+ bytesWr( rSUDFIFO, 8, ( char *)&setup_pkt ); //transfer to setup packet FIFO
+ rcode = dispatchPkt( tokSETUP, ep, nak_limit ); //dispatch packet
+ //Serial.println("Setup packet"); //DEBUG
+ if( rcode ) { //return HRSLT if not zero
+ Serial.print("Setup packet error: ");
+ Serial.print( rcode, HEX );
+ return( rcode );
+ }
+ //Serial.println( direction, HEX );
+ if( dataptr != NULL ) { //data stage, if present
+ rcode = ctrlData( addr, ep, nbytes, dataptr, direction );
+ }
+ if( rcode ) { //return error
+ Serial.print("Data packet error: ");
+ Serial.print( rcode, HEX );
+ return( rcode );
+ }
+ rcode = ctrlStatus( ep, direction ); //status stage
+ return( rcode );
+}
+/* Control transfer with status stage and no data stage */
+/* Assumed peripheral address is already set */
+byte USB::ctrlStatus( byte ep, boolean direction, unsigned int nak_limit )
+{
+ byte rcode;
+ if( direction ) { //GET
+ rcode = dispatchPkt( tokOUTHS, ep, nak_limit );
+ }
+ else {
+ rcode = dispatchPkt( tokINHS, ep, nak_limit );
+ }
+ return( rcode );
+}
+/* Control transfer with data stage. Stages 2 and 3 of control transfer. Assumes preipheral address is set and setup packet has been sent */
+byte USB::ctrlData( byte addr, byte ep, unsigned int nbytes, char* dataptr, boolean direction, unsigned int nak_limit )
+{
+ byte rcode;
+ if( direction ) { //IN transfer
+ devtable[ addr ].epinfo[ ep ].rcvToggle = bmRCVTOG1;
+ rcode = inTransfer( addr, ep, nbytes, dataptr, nak_limit );
+ return( rcode );
+ }
+ else { //OUT transfer
+ devtable[ addr ].epinfo[ ep ].sndToggle = bmSNDTOG1;
+ rcode = outTransfer( addr, ep, nbytes, dataptr, nak_limit );
+ return( rcode );
+ }
+}
+/* IN transfer to arbitrary endpoint. Assumes PERADDR is set. Handles multiple packets if necessary. Transfers 'nbytes' bytes. */
+/* Keep sending INs and writes data to memory area pointed by 'data' */
+/* rcode 0 if no errors. rcode 01-0f is relayed from dispatchPkt(). Rcode f0 means RCVDAVIRQ error,
+ fe USB xfer timeout */
+byte USB::inTransfer( byte addr, byte ep, unsigned int nbytes, char* data, unsigned int nak_limit )
+{
+ byte rcode;
+ byte pktsize;
+ byte maxpktsize = devtable[ addr ].epinfo[ ep ].MaxPktSize;
+ unsigned int xfrlen = 0;
+ regWr( rHCTL, devtable[ addr ].epinfo[ ep ].rcvToggle ); //set toggle value
+ while( 1 ) { // use a 'return' to exit this loop
+ rcode = dispatchPkt( tokIN, ep, nak_limit ); //IN packet to EP-'endpoint'. Function takes care of NAKS.
+ if( rcode ) {
+ return( rcode ); //should be 0, indicating ACK. Else return error code.
+ }
+ /* check for RCVDAVIRQ and generate error if not present */
+ /* the only case when absense of RCVDAVIRQ makes sense is when toggle error occured. Need to add handling for that */
+ if(( regRd( rHIRQ ) & bmRCVDAVIRQ ) == 0 ) {
+ return ( 0xf0 ); //receive error
+ }
+ pktsize = regRd( rRCVBC ); //number of received bytes
+ data = bytesRd( rRCVFIFO, pktsize, data );
+ regWr( rHIRQ, bmRCVDAVIRQ ); // Clear the IRQ & free the buffer
+ xfrlen += pktsize; // add this packet's byte count to total transfer length
+ /* The transfer is complete under two conditions: */
+ /* 1. The device sent a short packet (L.T. maxPacketSize) */
+ /* 2. 'nbytes' have been transferred. */
+ if (( pktsize < maxpktsize ) || (xfrlen >= nbytes )) { // have we transferred 'nbytes' bytes?
+ if( regRd( rHRSL ) & bmRCVTOGRD ) { //save toggle value
+ devtable[ addr ].epinfo[ ep ].rcvToggle = bmRCVTOG1;
+ }
+ else {
+ devtable[ addr ].epinfo[ ep ].rcvToggle = bmRCVTOG0;
+ }
+ return( 0 );
+ }
+ }//while( 1 )
+}
+/* OUT transfer to arbitrary endpoint. Assumes PERADDR is set. Handles multiple packets if necessary. Transfers 'nbytes' bytes. */
+/* Handles NAK bug per Maxim Application Note 4000 for single buffer transfer */
+/* rcode 0 if no errors. rcode 01-0f is relayed from HRSL */
+/* major part of this function borrowed from code shared by Richard Ibbotson */
+byte USB::outTransfer( byte addr, byte ep, unsigned int nbytes, char* data, unsigned int nak_limit )
+{
+ byte rcode, retry_count;
+ char* data_p = data; //local copy of the data pointer
+ unsigned int bytes_tosend, nak_count;
+ unsigned int bytes_left = nbytes;
+ byte maxpktsize = devtable[ addr ].epinfo[ ep ].MaxPktSize;
+ unsigned long timeout = millis() + USB_XFER_TIMEOUT;
+
+ if (!maxpktsize) { //todo: move this check close to epinfo init. Make it 1< pktsize <64
+ return 0xFE;
+ }
+
+ regWr( rHCTL, devtable[ addr ].epinfo[ ep ].sndToggle ); //set toggle value
+ while( bytes_left ) {
+ retry_count = 0;
+ nak_count = 0;
+ bytes_tosend = ( bytes_left >= maxpktsize ) ? maxpktsize : bytes_left;
+ bytesWr( rSNDFIFO, bytes_tosend, data_p ); //filling output FIFO
+ regWr( rSNDBC, bytes_tosend ); //set number of bytes
+ regWr( rHXFR, ( tokOUT | ep )); //dispatch packet
+ while(!(regRd( rHIRQ ) & bmHXFRDNIRQ )); //wait for the completion IRQ
+ regWr( rHIRQ, bmHXFRDNIRQ ); //clear IRQ
+ rcode = ( regRd( rHRSL ) & 0x0f );
+ while( rcode && ( timeout > millis())) {
+ switch( rcode ) {
+ case hrNAK:
+ nak_count++;
+ if( nak_limit && ( nak_count == USB_NAK_LIMIT )) {
+ return( rcode); //return NAK
+ }
+ break;
+ case hrTIMEOUT:
+ retry_count++;
+ if( retry_count == USB_RETRY_LIMIT ) {
+ return( rcode ); //return TIMEOUT
+ }
+ break;
+ default:
+ return( rcode );
+ }//switch( rcode...
+ /* process NAK according to Host out NAK bug */
+ regWr( rSNDBC, 0 );
+ regWr( rSNDFIFO, *data_p );
+ regWr( rSNDBC, bytes_tosend );
+ regWr( rHXFR, ( tokOUT | ep )); //dispatch packet
+ while(!(regRd( rHIRQ ) & bmHXFRDNIRQ )); //wait for the completion IRQ
+ regWr( rHIRQ, bmHXFRDNIRQ ); //clear IRQ
+ rcode = ( regRd( rHRSL ) & 0x0f );
+ }//while( rcode && ....
+ bytes_left -= bytes_tosend;
+ data_p += bytes_tosend;
+ }//while( bytes_left...
+ devtable[ addr ].epinfo[ ep ].sndToggle = ( regRd( rHRSL ) & bmSNDTOGRD ) ? bmSNDTOG1 : bmSNDTOG0; //update toggle
+ return( rcode ); //should be 0 in all cases
+}
+/* dispatch usb packet. Assumes peripheral address is set and relevant buffer is loaded/empty */
+/* If NAK, tries to re-send up to nak_limit times */
+/* If nak_limit == 0, do not count NAKs, exit after timeout */
+/* If bus timeout, re-sends up to USB_RETRY_LIMIT times */
+/* return codes 0x00-0x0f are HRSLT( 0x00 being success ), 0xff means timeout */
+byte USB::dispatchPkt( byte token, byte ep, unsigned int nak_limit )
+{
+ unsigned long timeout = millis() + USB_XFER_TIMEOUT;
+ byte tmpdata;
+ byte rcode;
+ unsigned int nak_count = 0;
+ char retry_count = 0;
+
+ while( timeout > millis() ) {
+ regWr( rHXFR, ( token|ep )); //launch the transfer
+ rcode = 0xff;
+ while( millis() < timeout ) { //wait for transfer completion
+ tmpdata = regRd( rHIRQ );
+ if( tmpdata & bmHXFRDNIRQ ) {
+ regWr( rHIRQ, bmHXFRDNIRQ ); //clear the interrupt
+ rcode = 0x00;
+ break;
+ }//if( tmpdata & bmHXFRDNIRQ
+ }//while ( millis() < timeout
+ if( rcode != 0x00 ) { //exit if timeout
+ return( rcode );
+ }
+ rcode = ( regRd( rHRSL ) & 0x0f ); //analyze transfer result
+ switch( rcode ) {
+ case hrNAK:
+ nak_count ++;
+ if( nak_limit && ( nak_count == nak_limit )) {
+ return( rcode );
+ }
+ break;
+ case hrTIMEOUT:
+ retry_count ++;
+ if( retry_count == USB_RETRY_LIMIT ) {
+ return( rcode );
+ }
+ break;
+ default:
+ return( rcode );
+ }//switch( rcode
+ }//while( timeout > millis()
+ return( rcode );
+}
+/* USB main task. Performs enumeration/cleanup */
+void USB::Task( void ) //USB state machine
+{
+ byte i;
+ byte rcode;
+ static byte tmpaddr;
+ byte tmpdata;
+ static unsigned long delay = 0;
+ USB_DEVICE_DESCRIPTOR buf;
+ tmpdata = getVbusState();
+ /* modify USB task state if Vbus changed */
+
+ switch( tmpdata ) {
+ case SE1: //illegal state
+ usb_task_state = USB_DETACHED_SUBSTATE_ILLEGAL;
+ break;
+ case SE0: //disconnected
+ if(( usb_task_state & USB_STATE_MASK ) != USB_STATE_DETACHED ) {
+ usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE;
+ }
+ break;
+ case FSHOST: //attached
+ case LSHOST:
+ if(( usb_task_state & USB_STATE_MASK ) == USB_STATE_DETACHED ) {
+ delay = millis() + USB_SETTLE_DELAY;
+ usb_task_state = USB_ATTACHED_SUBSTATE_SETTLE;
+ }
+ break;
+ }// switch( tmpdata
+ //Serial.print("USB task state: ");
+ //Serial.println( usb_task_state, HEX );
+ switch( usb_task_state ) {
+ case USB_DETACHED_SUBSTATE_INITIALIZE:
+ init();
+ usb_task_state = USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE;
+ break;
+ case USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE: //just sit here
+ break;
+ case USB_DETACHED_SUBSTATE_ILLEGAL: //just sit here
+ break;
+ case USB_ATTACHED_SUBSTATE_SETTLE: //setlle time for just attached device
+ if( delay < millis() ) {
+ usb_task_state = USB_ATTACHED_SUBSTATE_RESET_DEVICE;
+ }
+ break;
+ case USB_ATTACHED_SUBSTATE_RESET_DEVICE:
+ regWr( rHCTL, bmBUSRST ); //issue bus reset
+ usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE;
+ break;
+ case USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE:
+ if(( regRd( rHCTL ) & bmBUSRST ) == 0 ) {
+ tmpdata = regRd( rMODE ) | bmSOFKAENAB; //start SOF generation
+ regWr( rMODE, tmpdata );
+// regWr( rMODE, bmSOFKAENAB );
+ usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_SOF;
+ delay = millis() + 20; //20ms wait after reset per USB spec
+ }
+ break;
+ case USB_ATTACHED_SUBSTATE_WAIT_SOF: //todo: change check order
+ if( regRd( rHIRQ ) & bmFRAMEIRQ ) { //when first SOF received we can continue
+ if( delay < millis() ) { //20ms passed
+ usb_task_state = USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE;
+ }
+ }
+ break;
+ case USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE:
+ // toggle( BPNT_0 );
+ devtable[ 0 ].epinfo->MaxPktSize = 8; //set max.packet size to min.allowed
+ rcode = getDevDescr( 0, 0, 8, ( char* )&buf );
+ if( rcode == 0 ) {
+ devtable[ 0 ].epinfo->MaxPktSize = buf.bMaxPacketSize0;
+ usb_task_state = USB_STATE_ADDRESSING;
+ }
+ else {
+ usb_error = USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE;
+ usb_task_state = USB_STATE_ERROR;
+ }
+ break;
+ case USB_STATE_ADDRESSING:
+ for( i = 1; i < USB_NUMDEVICES; i++ ) {
+ if( devtable[ i ].epinfo == NULL ) {
+ devtable[ i ].epinfo = devtable[ 0 ].epinfo; //set correct MaxPktSize
+ //temporary record
+ //until plugged with real device endpoint structure
+ rcode = setAddr( 0, 0, i );
+ if( rcode == 0 ) {
+ tmpaddr = i;
+ usb_task_state = USB_STATE_CONFIGURING;
+ }
+ else {
+ usb_error = USB_STATE_ADDRESSING; //set address error
+ usb_task_state = USB_STATE_ERROR;
+ }
+ break; //break if address assigned or error occured during address assignment attempt
+ }
+ }//for( i = 1; i < USB_NUMDEVICES; i++
+ if( usb_task_state == USB_STATE_ADDRESSING ) { //no vacant place in devtable
+ usb_error = 0xfe;
+ usb_task_state = USB_STATE_ERROR;
+ }
+ break;
+ case USB_STATE_CONFIGURING:
+ break;
+ case USB_STATE_RUNNING:
+ break;
+ case USB_STATE_ERROR:
+ break;
+ }// switch( usb_task_state
+}
+ \ No newline at end of file
diff --git a/USB_Host_Shield/Usb.h b/USB_Host_Shield/Usb.h
new file mode 100644
index 0000000..2d912b8
--- /dev/null
+++ b/USB_Host_Shield/Usb.h
@@ -0,0 +1,175 @@
+/* Copyright 2009-2011 Oleg Mazurov, Circuits At Home, http://www.circuitsathome.com */
+/* USB functions */
+#ifndef _usb_h_
+#define _usb_h_
+
+#include <Max3421e.h>
+#include "ch9.h"
+
+/* Common setup data constant combinations */
+#define bmREQ_GET_DESCR USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_DEVICE //get descriptor request type
+#define bmREQ_SET USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_DEVICE //set request type for all but 'set feature' and 'set interface'
+#define bmREQ_CL_GET_INTF USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE //get interface request type
+/* HID requests */
+#define bmREQ_HIDOUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
+#define bmREQ_HIDIN USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
+#define bmREQ_HIDREPORT USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_INTERFACE
+
+#define USB_XFER_TIMEOUT 5000 //USB transfer timeout in milliseconds, per section 9.2.6.1 of USB 2.0 spec
+#define USB_NAK_LIMIT 32000 //NAK limit for a transfer. o meand NAKs are not counted
+#define USB_RETRY_LIMIT 3 //retry limit for a transfer
+#define USB_SETTLE_DELAY 200 //settle delay in milliseconds
+#define USB_NAK_NOWAIT 1 //used in Richard's PS2/Wiimote code
+
+#define USB_NUMDEVICES 2 //number of USB devices
+
+/* USB state machine states */
+
+#define USB_STATE_MASK 0xf0
+
+#define USB_STATE_DETACHED 0x10
+#define USB_DETACHED_SUBSTATE_INITIALIZE 0x11
+#define USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE 0x12
+#define USB_DETACHED_SUBSTATE_ILLEGAL 0x13
+#define USB_ATTACHED_SUBSTATE_SETTLE 0x20
+#define USB_ATTACHED_SUBSTATE_RESET_DEVICE 0x30
+#define USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE 0x40
+#define USB_ATTACHED_SUBSTATE_WAIT_SOF 0x50
+#define USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE 0x60
+#define USB_STATE_ADDRESSING 0x70
+#define USB_STATE_CONFIGURING 0x80
+#define USB_STATE_RUNNING 0x90
+#define USB_STATE_ERROR 0xa0
+
+// byte usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE
+
+/* USB Setup Packet Structure */
+typedef struct {
+ union { // offset description
+ byte bmRequestType; // 0 Bit-map of request type
+ struct {
+ byte recipient: 5; // Recipient of the request
+ byte type: 2; // Type of request
+ byte direction: 1; // Direction of data X-fer
+ };
+ }ReqType_u;
+ byte bRequest; // 1 Request
+ union {
+ unsigned int wValue; // 2 Depends on bRequest
+ struct {
+ byte wValueLo;
+ byte wValueHi;
+ };
+ }wVal_u;
+ unsigned int wIndex; // 4 Depends on bRequest
+ unsigned int wLength; // 6 Depends on bRequest
+} SETUP_PKT, *PSETUP_PKT;
+
+/* Endpoint information structure */
+/* bToggle of endpoint 0 initialized to 0xff */
+/* during enumeration bToggle is set to 00 */
+typedef struct {
+ byte epAddr; //copy from endpoint descriptor. Bit 7 indicates direction ( ignored for control endpoints )
+ byte Attr; // Endpoint transfer type.
+ unsigned int MaxPktSize; // Maximum packet size.
+ byte Interval; // Polling interval in frames.
+ byte sndToggle; //last toggle value, bitmask for HCTL toggle bits
+ byte rcvToggle; //last toggle value, bitmask for HCTL toggle bits
+ /* not sure if both are necessary */
+} EP_RECORD;
+/* device record structure */
+typedef struct {
+ EP_RECORD* epinfo; //device endpoint information
+ byte devclass; //device class
+} DEV_RECORD;
+
+
+
+class USB : public MAX3421E {
+//data structures
+/* device table. Filled during enumeration */
+/* index corresponds to device address */
+/* each entry contains pointer to endpoint structure */
+/* and device class to use in various places */
+//DEV_RECORD devtable[ USB_NUMDEVICES + 1 ];
+//EP_RECORD dev0ep; //Endpoint data structure used during enumeration for uninitialized device
+
+//byte usb_task_state;
+
+ public:
+ USB( void );
+ byte getUsbTaskState( void );
+ void setUsbTaskState( byte state );
+ EP_RECORD* getDevTableEntry( byte addr, byte ep );
+ void setDevTableEntry( byte addr, EP_RECORD* eprecord_ptr );
+ byte ctrlReq( byte addr, byte ep, byte bmReqType, byte bRequest, byte wValLo, byte wValHi, unsigned int wInd, unsigned int nbytes, char* dataptr, unsigned int nak_limit = USB_NAK_LIMIT );
+ /* Control requests */
+ byte getDevDescr( byte addr, byte ep, unsigned int nbytes, char* dataptr, unsigned int nak_limit = USB_NAK_LIMIT );
+ byte getConfDescr( byte addr, byte ep, unsigned int nbytes, byte conf, char* dataptr, unsigned int nak_limit = USB_NAK_LIMIT );
+ byte getStrDescr( byte addr, byte ep, unsigned int nbytes, byte index, unsigned int langid, char* dataptr, unsigned int nak_limit = USB_NAK_LIMIT );
+ byte setAddr( byte oldaddr, byte ep, byte newaddr, unsigned int nak_limit = USB_NAK_LIMIT );
+ byte setConf( byte addr, byte ep, byte conf_value, unsigned int nak_limit = USB_NAK_LIMIT );
+ /**/
+ byte setProto( byte addr, byte ep, byte interface, byte protocol, unsigned int nak_limit = USB_NAK_LIMIT );
+ byte getProto( byte addr, byte ep, byte interface, char* dataptr, unsigned int nak_limit = USB_NAK_LIMIT );
+ byte getReportDescr( byte addr, byte ep, unsigned int nbytes, char* dataptr, unsigned int nak_limit = USB_NAK_LIMIT );
+ byte setReport( byte addr, byte ep, unsigned int nbytes, byte interface, byte report_type, byte report_id, char* dataptr, unsigned int nak_limit = USB_NAK_LIMIT );
+ byte getReport( byte addr, byte ep, unsigned int nbytes, byte interface, byte report_type, byte report_id, char* dataptr, unsigned int nak_limit = USB_NAK_LIMIT );
+ byte getIdle( byte addr, byte ep, byte interface, byte reportID, char* dataptr, unsigned int nak_limit = USB_NAK_LIMIT );
+ byte setIdle( byte addr, byte ep, byte interface, byte reportID, byte duration, unsigned int nak_limit = USB_NAK_LIMIT );
+ /**/
+ byte ctrlData( byte addr, byte ep, unsigned int nbytes, char* dataptr, boolean direction, unsigned int nak_limit = USB_NAK_LIMIT );
+ byte ctrlStatus( byte ep, boolean direction, unsigned int nak_limit = USB_NAK_LIMIT );
+ byte inTransfer( byte addr, byte ep, unsigned int nbytes, char* data, unsigned int nak_limit = USB_NAK_LIMIT );
+ byte outTransfer( byte addr, byte ep, unsigned int nbytes, char* data, unsigned int nak_limit = USB_NAK_LIMIT );
+ byte dispatchPkt( byte token, byte ep, unsigned int nak_limit = USB_NAK_LIMIT );
+ void Task( void );
+ private:
+ void init();
+};
+
+//get device descriptor
+inline byte USB::getDevDescr( byte addr, byte ep, unsigned int nbytes, char* dataptr, unsigned int nak_limit ) {
+ return( ctrlReq( addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, 0x00, USB_DESCRIPTOR_DEVICE, 0x0000, nbytes, dataptr, nak_limit ));
+}
+//get configuration descriptor
+inline byte USB::getConfDescr( byte addr, byte ep, unsigned int nbytes, byte conf, char* dataptr, unsigned int nak_limit ) {
+ return( ctrlReq( addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, nbytes, dataptr, nak_limit ));
+}
+//get string descriptor
+inline byte USB::getStrDescr( byte addr, byte ep, unsigned int nbytes, byte index, unsigned int langid, char* dataptr, unsigned int nak_limit ) {
+ return( ctrlReq( addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, index, USB_DESCRIPTOR_STRING, langid, nbytes, dataptr, nak_limit ));
+}
+//set address
+inline byte USB::setAddr( byte oldaddr, byte ep, byte newaddr, unsigned int nak_limit ) {
+ return( ctrlReq( oldaddr, ep, bmREQ_SET, USB_REQUEST_SET_ADDRESS, newaddr, 0x00, 0x0000, 0x0000, NULL, nak_limit ));
+}
+//set configuration
+inline byte USB::setConf( byte addr, byte ep, byte conf_value, unsigned int nak_limit ) {
+ return( ctrlReq( addr, ep, bmREQ_SET, USB_REQUEST_SET_CONFIGURATION, conf_value, 0x00, 0x0000, 0x0000, NULL, nak_limit ));
+}
+//class requests
+inline byte USB::setProto( byte addr, byte ep, byte interface, byte protocol, unsigned int nak_limit ) {
+ return( ctrlReq( addr, ep, bmREQ_HIDOUT, HID_REQUEST_SET_PROTOCOL, protocol, 0x00, interface, 0x0000, NULL, nak_limit ));
+}
+inline byte USB::getProto( byte addr, byte ep, byte interface, char* dataptr, unsigned int nak_limit ) {
+ return( ctrlReq( addr, ep, bmREQ_HIDIN, HID_REQUEST_GET_PROTOCOL, 0x00, 0x00, interface, 0x0001, dataptr, nak_limit ));
+}
+//get HID report descriptor
+inline byte USB::getReportDescr( byte addr, byte ep, unsigned int nbytes, char* dataptr, unsigned int nak_limit ) {
+ return( ctrlReq( addr, ep, bmREQ_HIDREPORT, USB_REQUEST_GET_DESCRIPTOR, 0x00, HID_DESCRIPTOR_REPORT, 0x0000, nbytes, dataptr, nak_limit ));
+}
+inline byte USB::setReport( byte addr, byte ep, unsigned int nbytes, byte interface, byte report_type, byte report_id, char* dataptr, unsigned int nak_limit ) {
+ return( ctrlReq( addr, ep, bmREQ_HIDOUT, HID_REQUEST_SET_REPORT, report_id, report_type, interface, nbytes, dataptr, nak_limit ));
+}
+inline byte USB::getReport( byte addr, byte ep, unsigned int nbytes, byte interface, byte report_type, byte report_id, char* dataptr, unsigned int nak_limit ) { // ** RI 04/11/09
+ return( ctrlReq( addr, ep, bmREQ_HIDIN, HID_REQUEST_GET_REPORT, report_id, report_type, interface, nbytes, dataptr, nak_limit ));
+}
+/* returns one byte of data in dataptr */
+inline byte USB::getIdle( byte addr, byte ep, byte interface, byte reportID, char* dataptr, unsigned int nak_limit ) {
+ return( ctrlReq( addr, ep, bmREQ_HIDIN, HID_REQUEST_GET_IDLE, reportID, 0, interface, 0x0001, dataptr, nak_limit ));
+}
+inline byte USB::setIdle( byte addr, byte ep, byte interface, byte reportID, byte duration, unsigned int nak_limit ) {
+ return( ctrlReq( addr, ep, bmREQ_HIDOUT, HID_REQUEST_SET_IDLE, reportID, duration, interface, 0x0000, NULL, nak_limit ));
+ }
+#endif //_usb_h_
diff --git a/USB_Host_Shield/ch9.h b/USB_Host_Shield/ch9.h
new file mode 100644
index 0000000..4766346
--- /dev/null
+++ b/USB_Host_Shield/ch9.h
@@ -0,0 +1,168 @@
+/* Copyright 2009-2011 Oleg Mazurov, Circuits At Home, http://www.circuitsathome.com */
+/* USB chapter 9 structures */
+#ifndef _ch9_h_
+#define _ch9_h_
+
+/* Misc.USB constants */
+#define DEV_DESCR_LEN 18 //device descriptor length
+#define CONF_DESCR_LEN 9 //configuration descriptor length
+#define INTR_DESCR_LEN 9 //interface descriptor length
+#define EP_DESCR_LEN 7 //endpoint descriptor length
+
+/* Standard Device Requests */
+
+#define USB_REQUEST_GET_STATUS 0 // Standard Device Request - GET STATUS
+#define USB_REQUEST_CLEAR_FEATURE 1 // Standard Device Request - CLEAR FEATURE
+#define USB_REQUEST_SET_FEATURE 3 // Standard Device Request - SET FEATURE
+#define USB_REQUEST_SET_ADDRESS 5 // Standard Device Request - SET ADDRESS
+#define USB_REQUEST_GET_DESCRIPTOR 6 // Standard Device Request - GET DESCRIPTOR
+#define USB_REQUEST_SET_DESCRIPTOR 7 // Standard Device Request - SET DESCRIPTOR
+#define USB_REQUEST_GET_CONFIGURATION 8 // Standard Device Request - GET CONFIGURATION
+#define USB_REQUEST_SET_CONFIGURATION 9 // Standard Device Request - SET CONFIGURATION
+#define USB_REQUEST_GET_INTERFACE 10 // Standard Device Request - GET INTERFACE
+#define USB_REQUEST_SET_INTERFACE 11 // Standard Device Request - SET INTERFACE
+#define USB_REQUEST_SYNCH_FRAME 12 // Standard Device Request - SYNCH FRAME
+
+#define USB_FEATURE_ENDPOINT_HALT 0 // CLEAR/SET FEATURE - Endpoint Halt
+#define USB_FEATURE_DEVICE_REMOTE_WAKEUP 1 // CLEAR/SET FEATURE - Device remote wake-up
+#define USB_FEATURE_TEST_MODE 2 // CLEAR/SET FEATURE - Test mode
+
+/* Setup Data Constants */
+
+#define USB_SETUP_HOST_TO_DEVICE 0x00 // Device Request bmRequestType transfer direction - host to device transfer
+#define USB_SETUP_DEVICE_TO_HOST 0x80 // Device Request bmRequestType transfer direction - device to host transfer
+#define USB_SETUP_TYPE_STANDARD 0x00 // Device Request bmRequestType type - standard
+#define USB_SETUP_TYPE_CLASS 0x20 // Device Request bmRequestType type - class
+#define USB_SETUP_TYPE_VENDOR 0x40 // Device Request bmRequestType type - vendor
+#define USB_SETUP_RECIPIENT_DEVICE 0x00 // Device Request bmRequestType recipient - device
+#define USB_SETUP_RECIPIENT_INTERFACE 0x01 // Device Request bmRequestType recipient - interface
+#define USB_SETUP_RECIPIENT_ENDPOINT 0x02 // Device Request bmRequestType recipient - endpoint
+#define USB_SETUP_RECIPIENT_OTHER 0x03 // Device Request bmRequestType recipient - other
+
+/* USB descriptors */
+
+#define USB_DESCRIPTOR_DEVICE 0x01 // bDescriptorType for a Device Descriptor.
+#define USB_DESCRIPTOR_CONFIGURATION 0x02 // bDescriptorType for a Configuration Descriptor.
+#define USB_DESCRIPTOR_STRING 0x03 // bDescriptorType for a String Descriptor.
+#define USB_DESCRIPTOR_INTERFACE 0x04 // bDescriptorType for an Interface Descriptor.
+#define USB_DESCRIPTOR_ENDPOINT 0x05 // bDescriptorType for an Endpoint Descriptor.
+#define USB_DESCRIPTOR_DEVICE_QUALIFIER 0x06 // bDescriptorType for a Device Qualifier.
+#define USB_DESCRIPTOR_OTHER_SPEED 0x07 // bDescriptorType for a Other Speed Configuration.
+#define USB_DESCRIPTOR_INTERFACE_POWER 0x08 // bDescriptorType for Interface Power.
+#define USB_DESCRIPTOR_OTG 0x09 // bDescriptorType for an OTG Descriptor.
+
+/* OTG SET FEATURE Constants */
+#define OTG_FEATURE_B_HNP_ENABLE 3 // SET FEATURE OTG - Enable B device to perform HNP
+#define OTG_FEATURE_A_HNP_SUPPORT 4 // SET FEATURE OTG - A device supports HNP
+#define OTG_FEATURE_A_ALT_HNP_SUPPORT 5 // SET FEATURE OTG - Another port on the A device supports HNP
+
+/* USB Endpoint Transfer Types */
+#define USB_TRANSFER_TYPE_CONTROL 0x00 // Endpoint is a control endpoint.
+#define USB_TRANSFER_TYPE_ISOCHRONOUS 0x01 // Endpoint is an isochronous endpoint.
+#define USB_TRANSFER_TYPE_BULK 0x02 // Endpoint is a bulk endpoint.
+#define USB_TRANSFER_TYPE_INTERRUPT 0x03 // Endpoint is an interrupt endpoint.
+#define bmUSB_TRANSFER_TYPE 0x03 // bit mask to separate transfer type from ISO attributes
+
+
+/* Standard Feature Selectors for CLEAR_FEATURE Requests */
+#define USB_FEATURE_ENDPOINT_STALL 0 // Endpoint recipient
+#define USB_FEATURE_DEVICE_REMOTE_WAKEUP 1 // Device recipient
+#define USB_FEATURE_TEST_MODE 2 // Device recipient
+
+/* HID constants. Not part of chapter 9 */
+/* Class-Specific Requests */
+#define HID_REQUEST_GET_REPORT 0x01
+#define HID_REQUEST_GET_IDLE 0x02
+#define HID_REQUEST_GET_PROTOCOL 0x03
+#define HID_REQUEST_SET_REPORT 0x09
+#define HID_REQUEST_SET_IDLE 0x0A
+#define HID_REQUEST_SET_PROTOCOL 0x0B
+
+/* Class Descriptor Types */
+#define HID_DESCRIPTOR_HID 0x21
+#define HID_DESCRIPTOR_REPORT 0x22
+#define HID_DESRIPTOR_PHY 0x23
+
+/* Protocol Selection */
+#define BOOT_PROTOCOL 0x00
+#define RPT_PROTOCOL 0x01
+/* HID Interface Class Code */
+#define HID_INTF 0x03
+/* HID Interface Class SubClass Codes */
+#define BOOT_INTF_SUBCLASS 0x01
+/* HID Interface Class Protocol Codes */
+#define HID_PROTOCOL_NONE 0x00
+#define HID_PROTOCOL_KEYBOARD 0x01
+#define HID_PROTOCOL_MOUSE 0x02
+
+
+/* descriptor data structures */
+
+/* Device descriptor structure */
+typedef struct {
+ byte bLength; // Length of this descriptor.
+ byte bDescriptorType; // DEVICE descriptor type (USB_DESCRIPTOR_DEVICE).
+ unsigned int bcdUSB; // USB Spec Release Number (BCD).
+ byte bDeviceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific.
+ byte bDeviceSubClass; // Subclass code (assigned by the USB-IF).
+ byte bDeviceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific.
+ byte bMaxPacketSize0; // Maximum packet size for endpoint 0.
+ unsigned int idVendor; // Vendor ID (assigned by the USB-IF).
+ unsigned int idProduct; // Product ID (assigned by the manufacturer).
+ unsigned int bcdDevice; // Device release number (BCD).
+ byte iManufacturer; // Index of String Descriptor describing the manufacturer.
+ byte iProduct; // Index of String Descriptor describing the product.
+ byte iSerialNumber; // Index of String Descriptor with the device's serial number.
+ byte bNumConfigurations; // Number of possible configurations.
+} USB_DEVICE_DESCRIPTOR;
+
+/* Configuration descriptor structure */
+typedef struct
+{
+ byte bLength; // Length of this descriptor.
+ byte bDescriptorType; // CONFIGURATION descriptor type (USB_DESCRIPTOR_CONFIGURATION).
+ unsigned int wTotalLength; // Total length of all descriptors for this configuration.
+ byte bNumInterfaces; // Number of interfaces in this configuration.
+ byte bConfigurationValue; // Value of this configuration (1 based).
+ byte iConfiguration; // Index of String Descriptor describing the configuration.
+ byte bmAttributes; // Configuration characteristics.
+ byte bMaxPower; // Maximum power consumed by this configuration.
+} USB_CONFIGURATION_DESCRIPTOR;
+
+/* Interface descriptor structure */
+typedef struct
+{
+ byte bLength; // Length of this descriptor.
+ byte bDescriptorType; // INTERFACE descriptor type (USB_DESCRIPTOR_INTERFACE).
+ byte bInterfaceNumber; // Number of this interface (0 based).
+ byte bAlternateSetting; // Value of this alternate interface setting.
+ byte bNumEndpoints; // Number of endpoints in this interface.
+ byte bInterfaceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific.
+ byte bInterfaceSubClass; // Subclass code (assigned by the USB-IF).
+ byte bInterfaceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific.
+ byte iInterface; // Index of String Descriptor describing the interface.
+} USB_INTERFACE_DESCRIPTOR;
+
+/* Endpoint descriptor structure */
+typedef struct
+{
+ byte bLength; // Length of this descriptor.
+ byte bDescriptorType; // ENDPOINT descriptor type (USB_DESCRIPTOR_ENDPOINT).
+ byte bEndpointAddress; // Endpoint address. Bit 7 indicates direction (0=OUT, 1=IN).
+ byte bmAttributes; // Endpoint transfer type.
+ unsigned int wMaxPacketSize; // Maximum packet size.
+ byte bInterval; // Polling interval in frames.
+} USB_ENDPOINT_DESCRIPTOR;
+
+/* HID descriptor */
+typedef struct {
+ byte bLength;
+ byte bDescriptorType;
+ unsigned int bcdHID;
+ byte bCountryCode;
+ byte bNumDescriptors;
+ byte bDescrType;
+ unsigned int wDescriptorLength;
+} USB_HID_DESCRIPTOR;
+
+#endif // _ch9_h_
diff --git a/USB_Host_Shield/examples/LCDkbd.pde b/USB_Host_Shield/examples/LCDkbd.pde
new file mode 100644
index 0000000..0f4dba1
--- /dev/null
+++ b/USB_Host_Shield/examples/LCDkbd.pde
@@ -0,0 +1,335 @@
+/* MAX3421E USB Host controller LCD/keyboard demonstration */
+#include <Spi.h>
+#include <Max3421e.h>
+#include <Usb.h>
+#include <Max_LCD.h>
+
+/* 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 );
+}
+
+
+
+
diff --git a/USB_Host_Shield/examples/PS3LCD.pde b/USB_Host_Shield/examples/PS3LCD.pde
new file mode 100644
index 0000000..ae103e0
--- /dev/null
+++ b/USB_Host_Shield/examples/PS3LCD.pde
@@ -0,0 +1,566 @@
+
+
+/* MAX3421E USB Host controller LCD/PS3 demonstration */
+#include <Spi.h>
+#include <Max3421e.h>
+#include <Usb.h>
+#include <Max_LCD.h>
+#include <MemoryFree.h>
+#include <avr/pgmspace.h>
+
+/*The application will work in reduced host mode, so we can save program and data
+memory space. After verifying the PID and VID we will use known values for the
+configuration values for device, interface, endpoints and HID */
+
+/* PS3 data taken from descriptors */
+#define PS3_ADDR 1
+#define PS3_VID_LO 0x4c // Sony VID
+#define PS3_VID_HI 0x05
+#define PS3_PID_LO 0x68 // Batch Device
+#define PS3_PID_HI 0x02
+#define PS3_CONFIGURATION 1
+#define PS3_IF 0
+#define PS3_NUM_EP 3
+#define EP_MAXPKTSIZE 64
+#define EP_INTERRUPT 0x03
+#define EP_POLL 0x01
+#define CONTROL_EP 0
+#define OUTPUT_EP 1
+#define REPORT_EP 2
+
+
+#define PS3_F4_REPORT_LEN 4
+#define PS3_F5_REPORT_LEN 8
+#define PS3_01_REPORT_LEN 48
+#define HID_REPORT_FEATURE 3
+#define HID_REPORT_OUTPUT 2
+#define PS3_F4_REPORT_ID 0xF4
+#define PS3_01_REPORT_ID 0x01
+#define PS3_F5_REPORT_ID 0xF5
+
+/* Defines for the PS3 Data in the HID Report
+*/
+#define LAnalogX buf[6]
+#define LAnalogY buf[7]
+#define RAnalogX buf[8]
+#define RAnalogY buf[9]
+#define buttons1 buf[2]
+#define buttons2 buf[3]
+#define buttons3 buf[4]
+#define buttonchange ((buttons1 != oldbuttons1) | (buttons2 != oldbuttons2))
+#define buSelect (buttons1 & 0x01)
+#define buLAnalog (buttons1 & 0x02)
+#define buRAnalog (buttons1 & 0x04)
+#define buStart (buttons1 & 0x08)
+#define buUp (buttons1 & 0x10)
+#define buRight (buttons1 & 0x20)
+#define buDown (buttons1 & 0x40)
+#define buLeft (buttons1 & 0x80)
+#define buL2 (buttons2 & 0x01)
+#define buR2 (buttons2 & 0x02)
+#define buL1 (buttons2 & 0x04)
+#define buR1 (buttons2 & 0x08)
+#define buTriangle (buttons2 & 0x10)
+#define buCircle (buttons2 & 0x20)
+#define buCross (buttons2 & 0x40)
+#define buSquare (buttons2 & 0x80)
+#define buPS (buttons3 & 0x01)
+#define AnalogUp buf[14]
+#define AnalogRight buf[15]
+#define AnalogDown buf[16]
+#define AnalogLeft buf[17]
+#define AnalogL2 buf[18]
+#define AnalogR2 buf[19]
+#define AnalogL1 buf[20]
+#define AnalogR1 buf[21]
+#define AnalogTriangle buf[22]
+#define AnalogCircle buf[23]
+#define AnalogCross buf[24]
+#define AnalogSquare buf[25]
+#define AccelX (((unsigned char)buf[42] | (unsigned char)buf[41] << 8)-512)
+#define AccelY (((unsigned char)buf[44] | (unsigned char)buf[43] << 8)-512)
+#define AccelZ (((unsigned char)buf[46] | (unsigned char)buf[45] << 8)-512)
+#define GyroX (((unsigned char)buf[48] | (unsigned char)buf[47] << 8)-512)
+
+
+
+/*Menu screens
+
+*/
+#define Root 0
+#define Basic 1
+#define Buttons 2
+#define Joystick 3
+#define Pressure 4
+#define Accelerometer 5
+#define LED 6
+#define Bdaddr 7
+#define Freememory 8
+
+
+/* Menu Text
+*/
+
+prog_char menutext_0[] PROGMEM = "Select Test";
+prog_char menutext_1[] PROGMEM = "Basic Tests";
+prog_char menutext_2[] PROGMEM = "Buttons Test";
+prog_char menutext_3[] PROGMEM = "Joystick Test";
+prog_char menutext_4[] PROGMEM = "Pressure Test";
+prog_char menutext_5[] PROGMEM = "Motion Test";
+prog_char menutext_6[] PROGMEM = "LED/Rumble Test";
+prog_char menutext_7[] PROGMEM = "Bluetooth Addr";
+prog_char menutext_8[] PROGMEM = "Free Memory";
+
+
+PROGMEM const char *menu_table[] =
+{
+ menutext_0,
+ menutext_1,
+ menutext_2,
+ menutext_3,
+ menutext_4,
+ menutext_5,
+ menutext_6,
+ menutext_7,
+ menutext_8 };
+
+prog_char output_01_report[] PROGMEM = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x02, 0xff, 0x27, 0x10, 0x00, 0x32, 0xff,
+ 0x27, 0x10, 0x00, 0x32, 0xff, 0x27, 0x10, 0x00,
+ 0x32, 0xff, 0x27, 0x10, 0x00, 0x32, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+prog_char feature_F4_report[] PROGMEM = {0x42, 0x0c, 0x00, 0x00};
+
+EP_RECORD ep_record[ PS3_NUM_EP ]; //endpoint record structure for the PS3 controller
+
+char buf[ 64 ] = { 0 }; //General purpose buffer for usb data
+char oldbuttons1, oldbuttons2;
+char screen, selscreen;
+char lcdbuffer[17];
+unsigned char bdaddr[6];
+char bdcursor;
+char ledrum;
+char lrcursor;
+
+
+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();
+ LCD.print("PS3 Controller");
+ LCD.setCursor(0,1);
+ LCD.print("Wait for connect");
+ Serial.begin( 9600 );
+ Serial.println("PS3 Controller Start");
+ Serial.print("freeMemory() reports ");
+ Serial.println( freeMemory() );
+ Max.powerOn();
+ delay(200);
+}
+
+void loop() {
+
+
+ Max.Task();
+ Usb.Task();
+ if( Usb.getUsbTaskState() == USB_STATE_CONFIGURING ) { //wait for addressing state
+ PS3_init();
+ process_report();
+ Usb.setUsbTaskState( USB_STATE_RUNNING );
+ }
+ if( Usb.getUsbTaskState() == USB_STATE_RUNNING ) { //poll the PS3 Controller
+ PS3_poll();
+ }
+}
+/* Initialize PS3 Controller */
+void PS3_init( void )
+{
+ byte rcode = 0; //return code
+ byte i;
+/**/
+
+ /* Initialize data structures for endpoints of device 1*/
+ ep_record[ CONTROL_EP ] = *( Usb.getDevTableEntry( 0,0 )); //copy endpoint 0 parameters
+ ep_record[ OUTPUT_EP ].epAddr = 0x02; // PS3 output endpoint
+ ep_record[ OUTPUT_EP ].Attr = EP_INTERRUPT;
+ ep_record[ OUTPUT_EP ].MaxPktSize = EP_MAXPKTSIZE;
+ ep_record[ OUTPUT_EP ].Interval = EP_POLL;
+ ep_record[ OUTPUT_EP ].sndToggle = bmSNDTOG0;
+ ep_record[ OUTPUT_EP ].rcvToggle = bmRCVTOG0;
+ ep_record[ REPORT_EP ].epAddr = 0x01; // PS3 report endpoint
+ ep_record[ REPORT_EP ].Attr = EP_INTERRUPT;
+ ep_record[ REPORT_EP ].MaxPktSize = EP_MAXPKTSIZE;
+ ep_record[ REPORT_EP ].Interval = EP_POLL;
+ ep_record[ REPORT_EP ].sndToggle = bmSNDTOG0;
+ ep_record[ REPORT_EP ].rcvToggle = bmRCVTOG0;
+
+ Usb.setDevTableEntry( PS3_ADDR, ep_record ); //plug kbd.endpoint parameters to devtable
+
+ /* read the device descriptor and check VID and PID*/
+ rcode = Usb.getDevDescr( PS3_ADDR, ep_record[ CONTROL_EP ].epAddr, DEV_DESCR_LEN , buf );
+ if( rcode ) {
+ Serial.print("Error attempting read device descriptor. Return code :");
+ Serial.println( rcode, HEX );
+ while(1); //stop
+ }
+ if((buf[ 8 ] != PS3_VID_LO) || (buf[ 9 ] != PS3_VID_HI) || (buf[ 10 ] != PS3_PID_LO) || (buf[ 11 ] != PS3_PID_HI) ) {
+ Serial.print("Unsupported USB Device");
+ while(1); //stop
+ }
+
+ /* Configure device */
+ rcode = Usb.setConf( PS3_ADDR, ep_record[ CONTROL_EP ].epAddr, PS3_CONFIGURATION );
+ if( rcode ) {
+ Serial.print("Error attempting to configure PS3 controller. Return code :");
+ Serial.println( rcode, HEX );
+ while(1); //stop
+ }
+
+
+ /* Set the PS3 controller to send reports */
+ for (i=0; i < PS3_F4_REPORT_LEN; i++) buf[i] = pgm_read_byte_near( feature_F4_report + i);
+ rcode = Usb.setReport( PS3_ADDR, ep_record[ CONTROL_EP ].epAddr, PS3_F4_REPORT_LEN, PS3_IF, HID_REPORT_FEATURE, PS3_F4_REPORT_ID , buf );
+ if( rcode ) {
+ Serial.print("Set report error: ");
+ Serial.println( rcode, HEX );
+ while(1); //stop
+
+ }
+
+ /* Set the PS3 controller LED 1 On */
+ for (i=0; i < PS3_01_REPORT_LEN; i++) buf[i] = pgm_read_byte_near( output_01_report + i);
+ rcode = Usb.setReport( PS3_ADDR, ep_record[ CONTROL_EP ].epAddr, PS3_01_REPORT_LEN, PS3_IF, HID_REPORT_OUTPUT, PS3_01_REPORT_ID , buf );
+ if( rcode ) {
+ Serial.print("Set report error: ");
+ Serial.println( rcode, HEX );
+ while(1); //stop
+
+ }
+
+ LCD.print("PS3 initialized");
+ Serial.println("PS3 initialized");
+ delay(200);
+ screen = Root;
+ selscreen = Basic;
+ LCD.clear();
+ LCD.home();
+ LCD.print("Main Menu");
+ LCD.setCursor(0,1);
+ strcpy_P(lcdbuffer, (char*)pgm_read_word(&(menu_table[selscreen])));
+ LCD.print(lcdbuffer);
+
+
+}
+
+/* Poll PS3 and print result */
+
+void PS3_poll( void )
+{
+
+ byte rcode = 0; //return code
+ /* poll PS3 */
+ rcode = Usb.inTransfer(PS3_ADDR, ep_record[ REPORT_EP ].epAddr, PS3_01_REPORT_LEN, buf );
+ if( rcode != 0 ) {
+ return;
+ }
+ process_report();
+ return;
+}
+
+void process_report(void)
+{
+ byte i, j, mask;
+ if(buPS){
+ screen = Root;
+ selscreen = Basic;
+ LCD.clear();
+ LCD.home();
+ LCD.print("Main Menu");
+ LCD.setCursor(0,1);
+ strcpy_P(lcdbuffer, (char*)pgm_read_word(&(menu_table[selscreen])));
+ LCD.print(lcdbuffer);
+ oldbuttons1 = buttons1;
+ oldbuttons2 = buttons2;
+
+ }
+
+ switch (screen){
+
+ case Root:
+ if(buttonchange){
+ if(buDown) selscreen--;
+ else if(buUp | buSelect) selscreen++;
+ else if(buStart) {
+ screen = selscreen;
+ LCD.clear();
+ oldbuttons1 = buttons1;
+ oldbuttons2 = buttons2;
+ break;
+ }
+ else {
+ oldbuttons1 = buttons1;
+ oldbuttons2 = buttons2;
+ break;
+
+ }
+ if (selscreen == 0) selscreen = 1;
+ if (selscreen > 8) selscreen = 1;
+ LCD.clear();
+ LCD.home();
+ LCD.print("Main Menu:");
+ LCD.setCursor(0,1);
+ strcpy_P(lcdbuffer, (char*)pgm_read_word(&(menu_table[selscreen])));
+ LCD.print(lcdbuffer);
+ oldbuttons1 = buttons1;
+ oldbuttons2 = buttons2;
+ }
+ break;
+
+ case Basic:
+ if(buttonchange){
+ LCD.home();
+ if (buL1) LCD.print('X');
+ else LCD.print(' ');
+ LCD.print(" Test L/R");
+ LCD.setCursor(0,1);
+ if (buL2) LCD.print('X');
+ else LCD.print(' ');
+ LCD.print(" Buttons");
+ LCD.setCursor(15,0);
+ if (buR1) LCD.print('X');
+ else LCD.print(' ');
+
+ LCD.setCursor(15,1);
+ if (buR2) LCD.print('X');
+ else LCD.print(' ');
+ }
+
+ break;
+
+ case Buttons:
+ if(buttonchange){
+ LCD.home();
+ LCD.print("0123456789ABCDEF");
+ LCD.setCursor(0,1);
+ mask = 1;
+ for( i = 0; i < 8; i++){
+ if (buttons1 & mask) lcdbuffer[i] = '^';
+ else lcdbuffer[i] = ' ';
+ mask <<= 1;
+ }
+ mask = 1;
+ for( i = 0; i < 8; i++){
+ if (buttons2 & mask) lcdbuffer[i+8] = '^';
+ else lcdbuffer[i+8] = ' ';
+ mask <<= 1;
+ }
+ LCD.print(lcdbuffer);
+ oldbuttons1 = buttons1;
+ oldbuttons2 = buttons2;
+
+ }
+
+ break;
+
+ case Joystick:
+ LCD.home();
+ LCD.print('^');
+ LCD.print((unsigned char)LAnalogY, DEC);
+ LCD.print(" ");
+ LCD.setCursor(8,0);
+ LCD.print('^');
+ LCD.print((unsigned char)RAnalogY, DEC);
+ LCD.print(" ");
+ LCD.setCursor(0,1);
+ LCD.print('>');
+ LCD.print((unsigned char)LAnalogX, DEC);
+ LCD.print(" ");
+ LCD.setCursor(8,1);
+ LCD.print('>');
+ LCD.print((unsigned char)RAnalogX, DEC);
+ LCD.print(" ");
+ break;
+
+ case Pressure:
+ LCD.home();
+ LCD.print((unsigned char)AnalogUp, DEC);
+ LCD.print(" ");
+ LCD.print((unsigned char)AnalogDown, DEC);
+ LCD.print(" ");
+ LCD.print((unsigned char)AnalogLeft, DEC);
+ LCD.print(" ");
+ LCD.print((unsigned char)AnalogRight, DEC);
+ LCD.print(" ");
+ LCD.print((unsigned char)AnalogL1, DEC);
+ LCD.print(" ");
+ LCD.print((unsigned char)AnalogR1, DEC);
+ LCD.print(" ");
+
+ LCD.setCursor(0,1);
+ LCD.print((unsigned char)AnalogCircle, DEC);
+ LCD.print(" ");
+ LCD.print((unsigned char)AnalogTriangle, DEC);
+ LCD.print(" ");
+ LCD.print((unsigned char)AnalogSquare, DEC);
+ LCD.print(" ");
+ LCD.print((unsigned char)AnalogCross, DEC);
+ LCD.print(" ");
+ LCD.print((unsigned char)AnalogL2, DEC);
+ LCD.print(" ");
+ LCD.print((unsigned char)AnalogR2, DEC);
+ LCD.print(" ");
+
+ break;
+
+ case Accelerometer:
+ LCD.home();
+ LCD.print('X');
+ LCD.print(AccelX, DEC);
+ LCD.print(" ");
+ LCD.setCursor(8,0);
+ LCD.print('Y');
+ LCD.print(AccelY, DEC);
+ LCD.print(" ");
+ LCD.setCursor(0,1);
+ LCD.print('Z');
+ LCD.print(AccelZ, DEC);
+ LCD.print(" ");
+ LCD.setCursor(8,1);
+ LCD.print('G');
+ LCD.print(GyroX, DEC);
+ LCD.print(" ");
+ break;
+
+ case LED:
+ if(buttonchange){
+ oldbuttons1 = buttons1;
+ oldbuttons2 = buttons2;
+ if (buRight) lrcursor++;
+ else if (buLeft) lrcursor--;
+ else if (buUp) ledrum |= 1 << lrcursor;
+ else if (buDown) ledrum &= ~(1 << lrcursor);
+ if (lrcursor > 7) lrcursor = 0;
+ if (lrcursor < 0) lrcursor = 7;
+ }
+ LCD.home();
+ LCD.print("1 2 3 4 S W ");
+ LCD.setCursor(0,1);
+ j = 0;
+ for (i=0; i < 6; i++){
+ if(ledrum & 1 << i) lcdbuffer[j] = 'X';
+ else lcdbuffer[j] = ' ';
+ j++; ;
+ lcdbuffer[j] = ' ';
+ j++;
+ }
+ lcdbuffer[j] = 0;
+ LCD.print(lcdbuffer);
+ LCD.setCursor((lrcursor * 2),1);
+ LCD.cursor();
+ /* default buffer values */
+ for (i=0; i < PS3_01_REPORT_LEN; i++) buf[i] = pgm_read_byte_near( output_01_report + i);
+ /* LED setings */
+ buf[9] = (ledrum & 0x0f) << 1;
+ /* rumble settings */
+ if (ledrum & 0x30){
+ buf[1] = buf[3] = 0xfe;
+ if (ledrum & 0x10) buf[4] = 0xff;
+ else buf[2] = 0xff;
+ }
+
+ Usb.setReport( PS3_ADDR, ep_record[ CONTROL_EP ].epAddr, PS3_01_REPORT_LEN, PS3_IF, HID_REPORT_OUTPUT, PS3_01_REPORT_ID , buf );
+
+ delay(100);
+ LCD.noCursor();
+ break;
+
+ case Bdaddr:
+ if(buttonchange){
+ oldbuttons1 = buttons1;
+ oldbuttons2 = buttons2;
+
+ if (buRight) bdcursor++;
+ else if (buLeft) bdcursor--;
+ if (bdcursor > 11) bdcursor = 0;
+ if (bdcursor < 0) bdcursor = 11;
+ if(buUp){
+ if(bdcursor % 2){
+ if ((bdaddr[bdcursor /2] & 0x0f) == 0x0f) bdaddr[bdcursor /2] &= 0xf0;
+ bdaddr[bdcursor / 2] += 0x1;
+ }
+ else{
+ if ((bdaddr[bdcursor /2] & 0xf0) == 0xf0) bdaddr[bdcursor /2] &= 0x0f;
+ bdaddr[bdcursor / 2] += 0x10;
+ }
+
+ }
+ else if (buDown){
+ if(bdcursor % 2){
+ if ((bdaddr[bdcursor /2] & 0x0f) == 0x0) bdaddr[bdcursor /2] |= 0x0f;
+ bdaddr[bdcursor / 2] -= 0x1;
+ }
+ else{
+ if ((bdaddr[bdcursor /2] & 0xf0) == 0x0) bdaddr[bdcursor /2] |= 0xf0;
+ bdaddr[bdcursor / 2] -= 0x10;
+ }
+
+ }
+ if( buCross){
+ buf[0] = 0x01;
+ buf[1] = 0x00;
+ for (i=0; i < 6; i++){
+ buf[i+2] = bdaddr[i];
+ }
+ Serial.println( "bdaddr");
+ Usb.setReport( PS3_ADDR, ep_record[ CONTROL_EP ].epAddr, PS3_F5_REPORT_LEN, PS3_IF, HID_REPORT_FEATURE, PS3_F5_REPORT_ID , buf );
+ }
+ }
+ LCD.home();
+ LCD.print("R: ");
+ Usb.getReport( PS3_ADDR, ep_record[ CONTROL_EP ].epAddr, PS3_F5_REPORT_LEN, PS3_IF, HID_REPORT_FEATURE, PS3_F5_REPORT_ID , buf );
+ for( i=0; i < 6; i++){
+ if ((unsigned char)buf[i+2] < 16) LCD.print ('0');
+ LCD.print((unsigned char)buf[i + 2], HEX);
+ }
+
+ LCD.setCursor(0,1);
+ LCD.print("W: ");
+ for( i=0; i < 6; i++){
+ if (bdaddr[i] < 16) LCD.print ('0');
+ LCD.print(bdaddr[i], HEX);
+ }
+ LCD.setCursor(3 + bdcursor ,1);
+ LCD.cursor();
+
+ delay(100);
+ LCD.noCursor();
+ break;
+
+ case Freememory:
+ LCD.home();
+ LCD.print("Free Memory ");
+ LCD.print( freeMemory(), DEC );
+ LCD.setCursor(0,1);
+ break;
+
+ default:
+ break;
+
+ }
+
+ return;
+}
+
+
+
+
diff --git a/USB_Host_Shield/examples/arm_mouse.pde b/USB_Host_Shield/examples/arm_mouse.pde
new file mode 100644
index 0000000..e934354
--- /dev/null
+++ b/USB_Host_Shield/examples/arm_mouse.pde
@@ -0,0 +1,284 @@
+/* AL5D robotic arm manual control using USB mouse. Servo controller by Renbotics with some pins swapped, USB Host Shield by Circuits At Home */
+#include <ServoShield.h>
+#include <Spi.h>
+#include <Max3421e.h>
+#include <Usb.h>
+
+#define DEVADDR 1
+#define CONFVALUE 1
+
+
+
+
+/* Arm dimensions( mm ) */
+#define BASE_HGT 67.31 //base hight 2.65"
+#define HUMERUS 146.05 //shoulder-to-elbow "bone" 5.75"
+#define ULNA 187.325 //elbow-to-wrist "bone" 7.375"
+#define GRIPPER 100.00 //gripper (incl.heavy duty wrist rotate mechanism) length 3.94"
+
+#define ftl(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5)) //float to long conversion
+
+/* Servo names/numbers */
+/* Base servo HS-485HB */
+#define BAS_SERVO 0
+/* Shoulder Servo HS-5745-MG */
+#define SHL_SERVO 1
+/* Elbow Servo HS-5745-MG */
+#define ELB_SERVO 2
+/* Wrist servo HS-645MG */
+#define WRI_SERVO 3
+/* Wrist rotate servo HS-485HB */
+#define WRO_SERVO 4
+/* Gripper servo HS-422 */
+#define GRI_SERVO 5
+
+//#define ARM_PARK set_arm( -50, 140, 100, 0 ) //arm parking position
+
+/* pre-calculations */
+float hum_sq = HUMERUS*HUMERUS;
+float uln_sq = ULNA*ULNA;
+
+void setup();
+void loop();
+
+ServoShield servos; //ServoShield object
+MAX3421E Max;
+USB Usb;
+//ServoShield servos; //ServoShield object
+
+/* Arm data structure */
+struct {
+ float x_coord; // X coordinate of the gripper tip
+ float y_coord; // Y coordinate of the gripper tip
+ float z_coord; //Z coordinate of the gripper tip
+ float gripper_angle; //gripper angle
+ int16_t gripper_servo; //gripper servo pulse duration
+ int16_t wrist_rotate; //wrist rotate servo pulse duration
+} armdata;
+
+void setup()
+{
+ /* set servo end points */
+ servos.setbounds( BAS_SERVO, 900, 2100 );
+ servos.setbounds( SHL_SERVO, 1000, 2100 );
+ servos.setbounds( ELB_SERVO, 900, 2100 );
+ servos.setbounds( WRI_SERVO, 600, 2400 );
+ servos.setbounds( WRO_SERVO, 600, 2400 );
+ servos.setbounds( GRI_SERVO, 890, 2100 );
+ /**/
+// servo_park();
+ arm_park();
+
+ servos.start(); //Start the servo shield
+ Max.powerOn();
+ Serial.begin( 115200 );
+ Serial.println("Start");
+ delay( 500 );
+ //ARM_PARK;
+}
+
+void loop()
+{
+byte rcode;
+ //delay( 10 );
+ set_arm( armdata.x_coord, armdata.y_coord, armdata.z_coord, armdata.gripper_angle );
+ servos.setposition( WRO_SERVO, armdata.wrist_rotate );
+ servos.setposition( GRI_SERVO, armdata.gripper_servo );
+ //ARM_PARK;
+ // circle();
+ Max.Task();
+ Usb.Task();
+ if( Usb.getUsbTaskState() == USB_STATE_CONFIGURING ) {
+ mouse_init();
+ }//if( Usb.getUsbTaskState() == USB_STATE_CONFIGURING...
+ if( Usb.getUsbTaskState() == USB_STATE_RUNNING ) { //poll the keyboard
+ rcode = mouse_poll();
+ if( rcode ) {
+ Serial.print("Mouse Poll Error: ");
+ Serial.println( rcode, HEX );
+ }//if( rcode...
+ }//if( Usb.getUsbTaskState() == USB_STATE_RUNNING...
+ //Serial.println( armdata.gripper_servo, DEC );
+}
+
+/* Initialize mouse */
+void mouse_init( void )
+{
+ byte rcode = 0; //return code
+ /**/
+ Usb.setDevTableEntry( 1, Usb.getDevTableEntry( 0,0 ) ); //copy device 0 endpoint information to device 1
+ /* Configure device */
+ rcode = Usb.setConf( DEVADDR, 0, CONFVALUE );
+ if( rcode ) {
+ Serial.print("Error configuring mouse. Return code : ");
+ Serial.println( rcode, HEX );
+ while(1); //stop
+ }//if( rcode...
+ Usb.setUsbTaskState( USB_STATE_RUNNING );
+ return;
+}
+
+/* Poll mouse using Get Report and fill arm data structure */
+byte mouse_poll( void )
+{
+ byte rcode;
+ char buf[ 4 ]; //mouse buffer
+ static uint16_t delay = 500; //delay before park
+
+ /* poll mouse */
+ rcode = Usb.getReport( DEVADDR, 0, 4, 0, 1, 0, buf );
+ if( rcode ) { //error
+ return( rcode );
+ }
+ // todo: add arm limit check
+ armdata.x_coord += ( buf[ 1 ] * -0.1 );
+ armdata.y_coord += ( buf[ 2 ] * -0.1 );
+ switch( buf[ 0 ] ) { //read buttons
+ case 0x00: //no buttons pressed
+ armdata.z_coord += ( buf[ 3 ] * -2 ) ;
+ break;
+ case 0x01: //button 1 pressed. Wheel sets gripper angle
+ armdata.gripper_servo += ( buf[ 3 ] * -20 );
+ /* check gripper boundaries */
+ if( armdata.gripper_servo < 1000 ) {
+ armdata.gripper_servo = 1000;
+ }
+ if( armdata.gripper_servo > 2100 ) {
+ armdata.gripper_servo = 2100;
+ }
+ break;
+ case 0x02: //button 2 pressed. Wheel sets wrist rotate
+ armdata.wrist_rotate += ( buf[ 3 ] * -10 );
+ /* check wrist rotate boundaries */
+ if( armdata.wrist_rotate < 600 ) {
+ armdata.wrist_rotate = 600;
+ }
+ if( armdata.wrist_rotate > 2400 ) {
+ armdata.wrist_rotate = 2400;
+ }
+ break;
+ case 0x04: //wheel button pressed. Wheel controls gripper
+ armdata.gripper_angle += ( buf[ 3 ] * -1 );
+ /* check gripper angle boundaries */
+ if( armdata.gripper_angle < -90 ) {
+ armdata.gripper_angle = -90;
+ }
+ if( armdata.gripper_angle > 90 ) {
+ armdata.gripper_angle = 90;
+ }
+ break;
+ case 0x07: //all 3 buttons pressed. Park the arm
+ arm_park();
+ break;
+ }//switch( buf[ 0 ...
+ Serial.println( armdata.wrist_rotate, DEC );
+}
+
+
+/* arm positioning routine utilizing inverse kinematics */
+/* z is height, y is distance from base center out, x is side to side. y,z can only be positive */
+//void set_arm( uint16_t x, uint16_t y, uint16_t z, uint16_t grip_angle )
+void set_arm( float x, float y, float z, float grip_angle_d )
+{
+ float grip_angle_r = radians( grip_angle_d ); //grip angle in radians for use in calculations
+ /* Base angle and radial distance from x,y coordinates */
+ float bas_angle_r = atan2( x, y );
+ float rdist = sqrt(( x * x ) + ( y * y ));
+ /* rdist is y coordinate for the arm */
+ y = rdist;
+ /* Grip offsets calculated based on grip angle */
+ float grip_off_z = ( sin( grip_angle_r )) * GRIPPER;
+ float grip_off_y = ( cos( grip_angle_r )) * GRIPPER;
+ /* Wrist position */
+ float wrist_z = ( z - grip_off_z ) - BASE_HGT;
+ float wrist_y = y - grip_off_y;
+ /* Shoulder to wrist distance ( AKA sw ) */
+ float s_w = ( wrist_z * wrist_z ) + ( wrist_y * wrist_y );
+ float s_w_sqrt = sqrt( s_w );
+ /* s_w angle to ground */
+ //float a1 = atan2( wrist_y, wrist_z );
+ float a1 = atan2( wrist_z, wrist_y );
+ /* s_w angle to humerus */
+ float a2 = acos((( hum_sq - uln_sq ) + s_w ) / ( 2 * HUMERUS * s_w_sqrt ));
+ /* shoulder angle */
+ float shl_angle_r = a1 + a2;
+ float shl_angle_d = degrees( shl_angle_r );
+ /* elbow angle */
+ float elb_angle_r = acos(( hum_sq + uln_sq - s_w ) / ( 2 * HUMERUS * ULNA ));
+ float elb_angle_d = degrees( elb_angle_r );
+ float elb_angle_dn = -( 180.0 - elb_angle_d );
+ /* wrist angle */
+ float wri_angle_d = ( grip_angle_d - elb_angle_dn ) - shl_angle_d;
+
+ /* Servo pulses */
+ float bas_servopulse = 1500.0 - (( degrees( bas_angle_r )) * 11.11 );
+ float shl_servopulse = 1500.0 + (( shl_angle_d - 90.0 ) * 6.6 );
+ float elb_servopulse = 1500.0 - (( elb_angle_d - 90.0 ) * 6.6 );
+ float wri_servopulse = 1500 + ( wri_angle_d * 11.1 );
+
+ /* Set servos */
+ servos.setposition( BAS_SERVO, ftl( bas_servopulse ));
+ servos.setposition( WRI_SERVO, ftl( wri_servopulse ));
+ servos.setposition( SHL_SERVO, ftl( shl_servopulse ));
+ servos.setposition( ELB_SERVO, ftl( elb_servopulse ));
+
+}
+
+/* moves the arm to parking position */
+void arm_park()
+{
+ set_arm( armdata.x_coord = -50, armdata.y_coord = 140, armdata.z_coord = 100, armdata.gripper_angle = 0 );
+ servos.setposition( WRO_SERVO, armdata.wrist_rotate = 600 );
+ servos.setposition( GRI_SERVO, armdata.gripper_servo = 900 );
+}
+
+/* move servos to parking position */
+void servo_park()
+{
+ servos.setposition( BAS_SERVO, 1715 );
+ servos.setposition( SHL_SERVO, 2100 );
+ servos.setposition( ELB_SERVO, 2100 );
+ servos.setposition( WRI_SERVO, 1800 );
+ servos.setposition( WRO_SERVO, 600 );
+ servos.setposition( GRI_SERVO, 900 );
+ return;
+}
+
+void zero_x()
+{
+ for( double yaxis = 150.0; yaxis < 356.0; yaxis += 1 ) {
+ set_arm( 0, yaxis, 127.0, 0 );
+ delay( 10 );
+ }
+ for( double yaxis = 356.0; yaxis > 150.0; yaxis -= 1 ) {
+ set_arm( 0, yaxis, 127.0, 0 );
+ delay( 10 );
+ }
+}
+
+/* moves arm in a straight line */
+void line()
+{
+ for( double xaxis = -100.0; xaxis < 100.0; xaxis += 0.5 ) {
+ set_arm( xaxis, 250, 100, 0 );
+ delay( 10 );
+ }
+ for( float xaxis = 100.0; xaxis > -100.0; xaxis -= 0.5 ) {
+ set_arm( xaxis, 250, 100, 0 );
+ delay( 10 );
+ }
+}
+
+void circle()
+{
+ #define RADIUS 80.0
+ //float angle = 0;
+ float zaxis,yaxis;
+ for( float angle = 0.0; angle < 360.0; angle += 1.0 ) {
+ yaxis = RADIUS * sin( radians( angle )) + 200;
+ zaxis = RADIUS * cos( radians( angle )) + 200;
+ set_arm( 0, yaxis, zaxis, 0 );
+ delay( 1 );
+ }
+}
+
diff --git a/USB_Host_Shield/examples/board_test/board_test.h b/USB_Host_Shield/examples/board_test/board_test.h
new file mode 100644
index 0000000..7435d7d
--- /dev/null
+++ b/USB_Host_Shield/examples/board_test/board_test.h
@@ -0,0 +1,21 @@
+/* USB Host Shield board test sketch header */
+#ifndef _BOARD_TEST_H_
+#define _BOARD_TEST_H_
+
+/* PGMSPACE */
+#include <inttypes.h>
+#include <avr/pgmspace.h>
+
+/* Messages */
+const char startBanner [] PROGMEM = "\r\nCircuits At Home 2010"
+ "\r\nUSB Host Shield QC test routine\r\n";
+const char anykey_msg [] PROGMEM = "\r\nPress any key to continue...";
+const char testpassed_msg [] PROGMEM = "\r\nTest PASSED";
+const char testfailed_msg [] PROGMEM = "\r\nTest FAILED*!*";
+const char osctest_oscstate_msg [] PROGMEM = " Oscillator state is ";
+const char test_halted_msg [] PROGMEM = "\r\nTest Halted."
+ "\r\n0x55 pattern is being transmitted via SPI to aid in troubleshooting";
+const char spitest_fail_msg [] PROGMEM = "\r\nSPI transmit/receive mismatch"
+ "\r\nValue written: ";
+
+#endif
diff --git a/USB_Host_Shield/examples/board_test/board_test.pde b/USB_Host_Shield/examples/board_test/board_test.pde
new file mode 100644
index 0000000..1188fbf
--- /dev/null
+++ b/USB_Host_Shield/examples/board_test/board_test.pde
@@ -0,0 +1,296 @@
+/* USB Host Shield Board test routine. Runs after assembly to check board functionality */
+
+/* USB related */
+//#include <Spi.h>
+#include <Max3421e.h>
+#include <Max3421e_constants.h>
+#include <Usb.h>
+
+#include "board_test.h" /* Board test messages */
+
+//#define MAX_SS 10
+
+void setup();
+void loop();
+
+MAX3421E Max;
+USB Usb;
+
+void setup()
+{
+ Serial.begin( 115200 );
+ //Serial.println("Start");
+ //Serial.println( SCK_PIN, DEC );
+ Max.powerOn();
+ printProgStr( startBanner );
+ printProgStr( anykey_msg );
+ //Serial.print( Max.getvar(), DEC);
+}
+
+void loop()
+{
+ while( Serial.available() == 0 ); //wait for input
+ Serial.read(); //empty input buffer
+ /* start tests */
+ /* SPI short test */
+ if (!revregcheck()) test_halted();
+ /* GPIO test */
+ if (!gpiocheck()) printProgStr(PSTR("\r\nGPIO check failed. Make sure GPIO loopback adapter is installed"));
+ /* SPI long test */
+ if (!spitest()) test_halted(); //test SPI for transmission errors
+ if (!osctest()) printProgStr(PSTR("OSCOK test failed. Check the oscillator"));
+ if (!usbtest()) printProgStr(PSTR("USB connection test failed. Check traces from USB connector to MAX3421E, as well as VBUS")); //never gets here
+ /* All tests passed */
+ printProgStr( anykey_msg );
+}
+
+/* SPI short test. Checks connectivity to MAX3421E by reading REVISION register. */
+/* Die rev.1 returns 0x01, rev.2 0x12, rev.3 0x13. Any other value is considered communication error */
+bool revregcheck()
+{
+ byte tmpbyte;
+ printProgStr(PSTR("\r\nReading REVISION register...Die revision "));
+ tmpbyte = Max.regRd( rREVISION );
+ switch( tmpbyte ) {
+ case( 0x01 ): //rev.01
+ printProgStr(PSTR("01"));
+ break;
+ case( 0x12 ): //rev.02
+ printProgStr(PSTR("02"));
+ break;
+ case( 0x13 ): //rev.03
+ printProgStr(PSTR("03"));
+ break;
+ default:
+ printProgStr(PSTR("invalid. Value returned: "));
+ print_hex( tmpbyte, 8 );
+ printProgStr( testfailed_msg );
+ return( false );
+ break;
+ }//switch( tmpbyte )...
+ printProgStr( testpassed_msg );
+ return( true );
+}
+/* SPI long test */
+bool spitest()
+{
+ byte l = 0;
+ byte k = 0;
+ byte gpinpol_copy = Max.regRd( rGPINPOL );
+ printProgStr(PSTR("\r\nSPI test. Each '.' indicates 64K transferred. Stops after transferring 1MB (16 dots)\r\n"));
+ /**/
+ for( byte j = 0; j < 16; j++ ) {
+ for( word i = 0; i < 65535; i++ ) {
+ Max.regWr( rGPINPOL, k );
+ l = Max.regRd( rGPINPOL);
+ if( l != k ) {
+ printProgStr( spitest_fail_msg );
+ print_hex( k, 8);
+ printProgStr(PSTR("Value read: "));
+ print_hex( l, 8 );
+ return( false ); //test failed
+ }
+ k++;
+ }//for( i = 0; i < 65535; i++
+ Serial.print(".");
+ }//for j = 0; j < 16...
+ Max.regWr( rGPINPOL, gpinpol_copy );
+ printProgStr(testpassed_msg);
+ return( true );
+}
+/* Oscillator test */
+bool osctest()
+{
+ printProgStr(PSTR("\r\nOscillator start/stop test."));
+ printProgStr( osctest_oscstate_msg );
+ check_OSCOKIRQ(); //print OSCOK state
+ printProgStr(PSTR("\r\nSetting CHIP RESET."));
+ Max.regWr( rUSBCTL, bmCHIPRES ); //Chip reset. This stops the oscillator
+ printProgStr( osctest_oscstate_msg );
+ check_OSCOKIRQ(); //print OSCOK state
+ printProgStr(PSTR("\r\nClearing CHIP RESET. "));
+ Max.regWr( rUSBCTL, 0x00 ); //Chip reset release
+ for( word i = 0; i < 65535; i++) {
+ if( Max.regRd( rUSBIRQ ) & bmOSCOKIRQ ) {
+ printProgStr(PSTR("PLL is stable. Time to stabilize - "));
+ Serial.print( i, DEC );
+ printProgStr(PSTR(" cycles"));
+ printProgStr( testpassed_msg );
+ return( true );
+ }
+ }//for i =
+ return(false);
+}
+/* Stop/start oscillator */
+void check_OSCOKIRQ()
+{
+ if( Max.regRd( rUSBIRQ ) & bmOSCOKIRQ ) { //checking oscillator state
+ printProgStr(PSTR("ON"));
+ }
+ else {
+ printProgStr(PSTR("OFF"));
+ }
+}
+/* Test USB connectivity */
+bool usbtest()
+{
+ byte rcode;
+ byte usbstate;
+ Max.powerOn();
+ delay( 200 );
+ printProgStr(PSTR("\r\nUSB Connectivity test. Waiting for device connection... "));
+ while( 1 ) {
+ delay( 200 );
+ Max.Task();
+ Usb.Task();
+ usbstate = Usb.getUsbTaskState();
+ switch( usbstate ) {
+ case( USB_ATTACHED_SUBSTATE_RESET_DEVICE ):
+ printProgStr(PSTR("\r\nDevice connected. Resetting"));
+ break;
+ case( USB_ATTACHED_SUBSTATE_WAIT_SOF ):
+ printProgStr(PSTR("\r\nReset complete. Waiting for the first SOF..."));
+ //delay( 1000 );
+ break;
+ case( USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE ):
+ printProgStr(PSTR("\r\nSOF generation started. Enumerating device."));
+ break;
+ case( USB_STATE_ADDRESSING ):
+ printProgStr(PSTR("\r\nSetting device address"));
+ //delay( 100 );
+ break;
+ case( USB_STATE_CONFIGURING ):
+ //delay( 1000 );
+ printProgStr(PSTR("\r\nGetting device descriptor"));
+ rcode = getdevdescr( 1 );
+ if( rcode ) {
+ printProgStr(PSTR("\r\nError reading device descriptor. Error code "));
+ print_hex( rcode, 8 );
+ }
+ else {
+ printProgStr(PSTR("\r\n\nAll tests passed. Press RESET to restart test"));
+ while(1);
+ }
+ break;
+ case( USB_STATE_ERROR ):
+ printProgStr(PSTR("\r\nUSB state machine reached error state"));
+ break;
+ default:
+ break;
+ }//switch
+ }//while(1)
+}
+/* Get device descriptor */
+byte getdevdescr( byte addr )
+{
+ USB_DEVICE_DESCRIPTOR buf;
+ byte rcode;
+ rcode = Usb.getDevDescr( addr, 0, 0x12, ( char *)&buf );
+ if( rcode ) {
+ return( rcode );
+ }
+ printProgStr(PSTR("\r\nDevice descriptor: "));
+ printProgStr(PSTR("\r\nDescriptor Length:\t"));
+ print_hex( buf.bLength, 8 );
+ printProgStr(PSTR("\r\nDescriptor type:\t"));
+ print_hex( buf.bDescriptorType, 8 );
+ printProgStr(PSTR("\r\nUSB version:\t"));
+ print_hex( buf.bcdUSB, 16 );
+ printProgStr(PSTR("\r\nDevice class:\t"));
+ print_hex( buf.bDeviceClass, 8 );
+ printProgStr(PSTR("\r\nDevice Subclass:\t"));
+ print_hex( buf.bDeviceSubClass, 8 );
+ printProgStr(PSTR("\r\nDevice Protocol:\t"));
+ print_hex( buf.bDeviceProtocol, 8 );
+ printProgStr(PSTR("\r\nMax.packet size:\t"));
+ print_hex( buf.bMaxPacketSize0, 8 );
+ printProgStr(PSTR("\r\nVendor ID:\t"));
+ print_hex( buf.idVendor, 16 );
+ printProgStr(PSTR("\r\nProduct ID:\t"));
+ print_hex( buf.idProduct, 16 );
+ printProgStr(PSTR("\r\nRevision ID:\t"));
+ print_hex( buf.bcdDevice, 16 );
+ printProgStr(PSTR("\r\nMfg.string index:\t"));
+ print_hex( buf.iManufacturer, 8 );
+ printProgStr(PSTR("\r\nProd.string index:\t"));
+ print_hex( buf.iProduct, 8 );
+ printProgStr(PSTR("\r\nSerial number index:\t"));
+ print_hex( buf.iSerialNumber, 8 );
+ printProgStr(PSTR("\r\nNumber of conf.:\t"));
+ print_hex( buf.bNumConfigurations, 8 );
+ return( 0 );
+}
+
+/* GPIO lines check. A loopback adapter connecting GPIN to GPOUT is assumed */
+bool gpiocheck()
+{
+ byte tmpbyte = 0;
+ printProgStr(PSTR("\r\nChecking GPIO lines. Install GPIO loopback adapter and press any key to continue..."));
+ while( Serial.available() == 0 ); //wait for input
+ Serial.read(); //empty input buffer
+ for( byte i = 0; i < 255; i++ ) {
+ Max.gpioWr( i );
+ tmpbyte = Max.gpioRd();
+ if( tmpbyte != i ) {
+ printProgStr(PSTR("GPIO read/write mismatch. Write: "));
+ Serial.print(i, HEX);
+ printProgStr(PSTR(" Read: "));
+ Serial.println( tmpbyte, HEX );
+ return( false );
+ }//if( tmpbyte != i )
+ }//for( i= 0...
+ printProgStr( testpassed_msg );
+ return( true );
+}
+/* Test halted state. Generates 0x55 to aid in SPI troubleshooting */
+void test_halted()
+{
+ printProgStr( test_halted_msg );
+ printProgStr(PSTR("\r\nPress RESET to restart test"));
+ while( 1 ) { //System Stop. Generating pattern to keep SCLK, MISO, MOSI, SS busy
+ digitalWrite(MAX_SS,LOW);
+ Max.regWr( 0x55, 0x55 );
+// Spi.transfer( 0x55 );
+ digitalWrite(MAX_SS,HIGH);
+ }
+}
+/* given a PROGMEM string, use Serial.print() to send it out */
+/* Some non-intuitive casting necessary: */
+/* printProgStr(PSTR("Func.Mode:\t0x")); */
+/* printProgStr((char*)pgm_read_word(&mtpopNames[(op & 0xFF)])); */
+void printProgStr(const char* str )
+{
+ if(!str) {
+ return;
+ }
+ char c;
+ while((c = pgm_read_byte(str++))) {
+ Serial.print(c,BYTE);
+ }
+}
+/* prints hex numbers with leading zeroes */
+// copyright, Peter H Anderson, Baltimore, MD, Nov, '07
+// source: http://www.phanderson.com/arduino/arduino_display.html
+void print_hex(int v, int num_places)
+{
+ int mask=0, n, num_nibbles, digit;
+
+ for (n=1; n<=num_places; n++)
+ {
+ mask = (mask << 1) | 0x0001;
+ }
+ v = v & mask; // truncate v to specified number of places
+
+ num_nibbles = num_places / 4;
+ if ((num_places % 4) != 0)
+ {
+ ++num_nibbles;
+ }
+
+ do
+ {
+ digit = ((v >> (num_nibbles-1) * 4)) & 0x0f;
+ Serial.print(digit, HEX);
+ }
+ while(--num_nibbles);
+}
diff --git a/USB_Host_Shield/examples/conf_descr_dump.pde b/USB_Host_Shield/examples/conf_descr_dump.pde
new file mode 100644
index 0000000..56d7a58
--- /dev/null
+++ b/USB_Host_Shield/examples/conf_descr_dump.pde
@@ -0,0 +1,181 @@
+/* MAX3421E USB Host controller get configuration descriptor */
+#include <Spi.h>
+#include <Max3421e.h>
+#include <Usb.h>
+
+#define LOBYTE(x) ((char*)(&(x)))[0]
+#define HIBYTE(x) ((char*)(&(x)))[1]
+#define BUFSIZE 256 //buffer size
+
+void setup();
+void loop();
+
+MAX3421E Max;
+USB Usb;
+
+void setup()
+{
+ byte tmpdata = 0;
+ Serial.begin( 9600 );
+ Serial.println("Start");
+ Max.powerOn();
+ delay( 200 );
+}
+
+void loop()
+{
+ byte rcode;
+ byte tmpbyte;
+ Max.Task();
+ Usb.Task();
+ if( Usb.getUsbTaskState() >= USB_STATE_CONFIGURING ) { //state configuring or higher
+ /* entering configuration number to decode. Restricted to first 10 configurations */
+ Serial.print("Enter configuration number: ");
+ while( Serial.available() == 0 ); //wait for input
+ tmpbyte = Serial.read();
+ Serial.println( tmpbyte );
+ tmpbyte -= 0x30; //convert to number
+ if( tmpbyte > 9 ) {
+ Serial.println("Not a number. Assuming configuration 0");
+ tmpbyte = 0;
+ }
+ rcode = getconfdescr( 1, tmpbyte ); //get configuration descriptor
+ if( rcode ) {
+ Serial.println( rcode, HEX );
+ }
+// while( 1 ); //stop
+ }
+}
+
+byte getconfdescr( byte addr, byte conf )
+{
+ char buf[ BUFSIZE ];
+ char* buf_ptr = buf;
+ byte rcode;
+ byte descr_length;
+ byte descr_type;
+ unsigned int total_length;
+ rcode = Usb.getConfDescr( addr, 0, 4, conf, buf ); //get total length
+ LOBYTE( total_length ) = buf[ 2 ];
+ HIBYTE( total_length ) = buf[ 3 ];
+ if( total_length > BUFSIZE ) { //check if total length is larger than buffer
+ Serial.println("Total length truncated to 256 bytes");
+ total_length = BUFSIZE;
+ }
+ rcode = Usb.getConfDescr( addr, 0, total_length, conf, buf ); //get the whole descriptor
+ while( buf_ptr < buf + total_length ) { //parsing descriptors
+ descr_length = *( buf_ptr );
+ descr_type = *( buf_ptr + 1 );
+ switch( descr_type ) {
+ case( USB_DESCRIPTOR_CONFIGURATION ):
+ printconfdescr( buf_ptr );
+ break;
+ case( USB_DESCRIPTOR_INTERFACE ):
+ printintfdescr( buf_ptr );
+ break;
+ case( USB_DESCRIPTOR_ENDPOINT ):
+ printepdescr( buf_ptr );
+ break;
+ default:
+ printunkdescr( buf_ptr );
+ break;
+ }//switch( descr_type
+ Serial.println("");
+ buf_ptr = ( buf_ptr + descr_length ); //advance buffer pointer
+ }//while( buf_ptr <=...
+ return( 0 );
+}
+/* prints hex numbers with leading zeroes */
+// copyright, Peter H Anderson, Baltimore, MD, Nov, '07
+// source: http://www.phanderson.com/arduino/arduino_display.html
+void print_hex(int v, int num_places)
+{
+ int mask=0, n, num_nibbles, digit;
+
+ for (n=1; n<=num_places; n++) {
+ mask = (mask << 1) | 0x0001;
+ }
+ v = v & mask; // truncate v to specified number of places
+
+ num_nibbles = num_places / 4;
+ if ((num_places % 4) != 0) {
+ ++num_nibbles;
+ }
+ do {
+ digit = ((v >> (num_nibbles-1) * 4)) & 0x0f;
+ Serial.print(digit, HEX);
+ }
+ while(--num_nibbles);
+}
+/* function to print configuration descriptor */
+void printconfdescr( char* descr_ptr )
+{
+ USB_CONFIGURATION_DESCRIPTOR* conf_ptr = ( USB_CONFIGURATION_DESCRIPTOR* )descr_ptr;
+ Serial.println("Configuration descriptor:");
+ Serial.print("Total length:\t");
+ print_hex( conf_ptr->wTotalLength, 16 );
+ Serial.print("\r\nNum.intf:\t\t");
+ print_hex( conf_ptr->bNumInterfaces, 8 );
+ Serial.print("\r\nConf.value:\t");
+ print_hex( conf_ptr->bConfigurationValue, 8 );
+ Serial.print("\r\nConf.string:\t");
+ print_hex( conf_ptr->iConfiguration, 8 );
+ Serial.print("\r\nAttr.:\t\t");
+ print_hex( conf_ptr->bmAttributes, 8 );
+ Serial.print("\r\nMax.pwr:\t\t");
+ print_hex( conf_ptr->bMaxPower, 8 );
+ return;
+}
+/* function to print interface descriptor */
+void printintfdescr( char* descr_ptr )
+{
+ USB_INTERFACE_DESCRIPTOR* intf_ptr = ( USB_INTERFACE_DESCRIPTOR* )descr_ptr;
+ Serial.println("\r\nInterface descriptor:");
+ Serial.print("Intf.number:\t");
+ print_hex( intf_ptr->bInterfaceNumber, 8 );
+ Serial.print("\r\nAlt.:\t\t");
+ print_hex( intf_ptr->bAlternateSetting, 8 );
+ Serial.print("\r\nEndpoints:\t\t");
+ print_hex( intf_ptr->bNumEndpoints, 8 );
+ Serial.print("\r\nClass:\t\t");
+ print_hex( intf_ptr->bInterfaceClass, 8 );
+ Serial.print("\r\nSubclass:\t\t");
+ print_hex( intf_ptr->bInterfaceSubClass, 8 );
+ Serial.print("\r\nProtocol:\t\t");
+ print_hex( intf_ptr->bInterfaceProtocol, 8 );
+ Serial.print("\r\nIntf.string:\t");
+ print_hex( intf_ptr->iInterface, 8 );
+ return;
+}
+/* function to print endpoint descriptor */
+void printepdescr( char* descr_ptr )
+{
+ USB_ENDPOINT_DESCRIPTOR* ep_ptr = ( USB_ENDPOINT_DESCRIPTOR* )descr_ptr;
+ Serial.println("\r\nEndpoint descriptor:");
+ Serial.print("Endpoint address:\t");
+ print_hex( ep_ptr->bEndpointAddress, 8 );
+ Serial.print("\r\nAttr.:\t\t");
+ print_hex( ep_ptr->bmAttributes, 8 );
+ Serial.print("\r\nMax.pkt size:\t");
+ print_hex( ep_ptr->wMaxPacketSize, 16 );
+ Serial.print("\r\nPolling interval:\t");
+ print_hex( ep_ptr->bInterval, 8 );
+ return;
+}
+/*function to print unknown descriptor */
+void printunkdescr( char* descr_ptr )
+{
+ byte length = *descr_ptr;
+ byte i;
+ Serial.println("\r\nUnknown descriptor:");
+ Serial. print("Length:\t\t");
+ print_hex( *descr_ptr, 8 );
+ Serial.print("\r\nType:\t\t");
+ print_hex( *(descr_ptr + 1 ), 8 );
+ Serial.print("\r\nContents:\t");
+ descr_ptr += 2;
+ for( i = 0; i < length; i++ ) {
+ print_hex( *descr_ptr, 8 );
+ descr_ptr++;
+ }
+}
diff --git a/USB_Host_Shield/examples/descriptor_parser/descriptor_parser.h b/USB_Host_Shield/examples/descriptor_parser/descriptor_parser.h
new file mode 100644
index 0000000..7570841
--- /dev/null
+++ b/USB_Host_Shield/examples/descriptor_parser/descriptor_parser.h
@@ -0,0 +1,284 @@
+#ifndef _DESCRIPTOR_PARSER_
+#define _DESCRIPTOR_PARSER_
+
+/* PGMSPACE */
+#include <inttypes.h>
+#include <avr/pgmspace.h>
+
+typedef void (*PARSE)( uint8_t bytes );
+
+/* Common Messages */
+
+const char descr_len [] PROGMEM = "\r\nDescriptor Length:\t";
+const char descr_type [] PROGMEM = "\r\nDescriptor type:\t";
+const char class_str [] PROGMEM = "\r\nClass:\t\t\t";
+const char subclass_str [] PROGMEM = "\r\nSubclass:\t\t";
+const char protocol_str [] PROGMEM = "\r\nProtocol:\t\t";
+const char maxpktsize_str [] PROGMEM = "\r\nMax.packet size:\t";
+const char unk_msg [] PROGMEM = " Unknown";
+const char reserved_msg [] PROGMEM = "Reserved";
+const char rcode_error_msg [] PROGMEM = "\r\nRequest error. Reurn code: ";
+
+/* Endpoint attributes */
+
+const char control_tr [] PROGMEM = "Control";
+const char iso_tr [] PROGMEM = "Isochronous";
+const char bulk_tr [] PROGMEM = "Bulk";
+const char int_tr [] PROGMEM = "Interrupt";
+
+const char* transfer_types [] PROGMEM =
+{
+ control_tr,
+ iso_tr,
+ bulk_tr,
+ int_tr
+};
+
+const char nosync_type [] PROGMEM = "No Synchronization";
+const char async_type [] PROGMEM = "Asynchronous";
+const char adaptive_type [] PROGMEM = "Adaptive";
+const char sync_type [] PROGMEM = "Synchronous";
+
+const char* sync_types [] PROGMEM =
+{
+ nosync_type,
+ async_type,
+ adaptive_type,
+ sync_type
+};
+
+const char data_usage [] PROGMEM = "Data";
+const char feedback_usage [] PROGMEM = "Feedback";
+const char implicit_usage [] PROGMEM = "Implicit Feedback Data";
+const char reserved_usage [] PROGMEM = "Reserved";
+
+const char* usage_types [] PROGMEM =
+{
+ data_usage,
+ feedback_usage,
+ implicit_usage,
+ reserved_usage
+};
+
+/* HID Country Codes */
+
+const char notsupported_cc [] PROGMEM = "Not Supported";
+const char arabic_cc [] PROGMEM = "Arabic";
+const char belgian_cc [] PROGMEM = "Belgian";
+const char canadianbi_cc [] PROGMEM = "Canadian-Bilingual";
+const char canadianfr_cc [] PROGMEM = "Canadian-French";
+const char czech_cc [] PROGMEM = "Czech Republic";
+const char danish_cc [] PROGMEM = "Danish";
+const char finnish_cc [] PROGMEM = "Finnish";
+const char french_cc [] PROGMEM = "French";
+const char german_cc [] PROGMEM = "German";
+const char greek_cc [] PROGMEM = "Greek";
+const char hebrew_cc [] PROGMEM = "Hebrew";
+const char hungary_cc [] PROGMEM = "Hungary";
+const char intl_cc [] PROGMEM = "International (ISO)";
+const char italian_cc [] PROGMEM = "Italian";
+const char japan_cc [] PROGMEM = "Japan (Katakana)";
+const char korean_cc [] PROGMEM = "Korean";
+const char latam_cc [] PROGMEM = "Latin American";
+const char dutch_cc [] PROGMEM = "Netherlands/Dutch";
+const char norwegian_cc [] PROGMEM = "Norwegian";
+const char persian_cc [] PROGMEM = "Persian (Farsi)";
+const char poland_cc [] PROGMEM = "Poland";
+const char portuguese_cc [] PROGMEM = "Portuguese";
+const char russia_cc [] PROGMEM = "Russia";
+const char slovakia_cc [] PROGMEM = "Slovakia";
+const char spanish_cc [] PROGMEM = "Spanish";
+const char swedish_cc [] PROGMEM = "Swedish";
+const char swiss_fr_cc [] PROGMEM = "Swiss/French";
+const char swiss_ger_cc [] PROGMEM = "Swiss/German";
+const char swiss_cc [] PROGMEM = "Switzerland";
+const char taiwan_cc [] PROGMEM = "Taiwan";
+const char turkish_q_cc [] PROGMEM = "Turkish-Q";
+const char uk_cc [] PROGMEM = "UK";
+const char us_cc [] PROGMEM = "US";
+const char yugo_cc [] PROGMEM = "Yugoslavia";
+const char turkish_f_cc [] PROGMEM = "Turkish-F";
+
+const char* HID_Country_Codes [] PROGMEM =
+{
+notsupported_cc,
+arabic_cc,
+belgian_cc,
+canadianbi_cc,
+canadianfr_cc,
+czech_cc,
+danish_cc,
+finnish_cc,
+french_cc,
+german_cc,
+greek_cc,
+hebrew_cc,
+hungary_cc,
+intl_cc,
+italian_cc,
+japan_cc,
+korean_cc,
+latam_cc,
+dutch_cc,
+norwegian_cc,
+persian_cc,
+poland_cc,
+portuguese_cc,
+russia_cc,
+slovakia_cc,
+spanish_cc,
+swedish_cc,
+swiss_fr_cc,
+swiss_ger_cc,
+swiss_cc,
+taiwan_cc,
+turkish_q_cc,
+uk_cc,
+us_cc,
+yugo_cc,
+turkish_f_cc
+};
+
+/* HID report descriptor parser string definitions */
+/* Item type strings */
+const char btype_main [] PROGMEM = "Main";
+const char btype_global [] PROGMEM = "Global";
+const char btype_local [] PROGMEM = "Local";
+const char btype_reserved [] PROGMEM = "Reserved";
+/* Item types strings array. Array index corresponds to bType */
+const char* btypes [] PROGMEM =
+{
+ btype_main,
+ btype_global,
+ btype_local,
+ btype_reserved
+};
+/* Main Item Tag Strings */
+const char main_tag_input [] PROGMEM = "Input\t\t";
+const char main_tag_output [] PROGMEM = "Output\t\t";
+const char main_tag_collection [] PROGMEM = "Collection\t\t";
+const char main_tag_feature [] PROGMEM = "Feature\t\t";
+const char main_tag_endcoll [] PROGMEM = "End Collection\t";
+/* Main Item Tags Strings Array */
+const char* maintags [] PROGMEM =
+{
+ main_tag_input,
+ main_tag_output,
+ main_tag_collection,
+ main_tag_feature,
+ main_tag_endcoll
+};
+/* Global Item Tag Strings */
+const char global_tag_usagepage [] PROGMEM = "Usage Page\t\t";
+const char global_tag_logmin [] PROGMEM = "Logical Minimum\t";
+const char global_tag_logmax [] PROGMEM = "Logical Maximum\t";
+const char global_tag_physmin [] PROGMEM = "Physical Minimum\t";
+const char global_tag_physmax [] PROGMEM = "Physical Maximum\t";
+const char global_tag_unitexp [] PROGMEM = "Unit Exponent\t";
+const char global_tag_unit [] PROGMEM = "Unit\t\t";
+const char global_tag_repsize [] PROGMEM = "Report Size\t";
+const char global_tag_repid [] PROGMEM = "Report ID\t\t";
+const char global_tag_repcount [] PROGMEM = "Report Count\t";
+const char global_tag_push [] PROGMEM = "Push\t\t";
+const char global_tag_pop [] PROGMEM = "Pop\t\t";
+/* Global Item Tag Strings Array */
+const char* globaltags [] PROGMEM =
+{
+ global_tag_usagepage,
+ global_tag_logmin,
+ global_tag_logmax,
+ global_tag_physmin,
+ global_tag_physmax,
+ global_tag_unitexp,
+ global_tag_unit,
+ global_tag_repsize,
+ global_tag_repid,
+ global_tag_repcount,
+ global_tag_push,
+ global_tag_pop
+};
+/* Local Item Tag Strings */
+const char local_tag_usage [] PROGMEM = "Usage\t\t";
+const char local_tag_usagemin [] PROGMEM = "Usage Minimum\t";
+const char local_tag_usagemax [] PROGMEM = "Usage Maximum\t";
+const char local_tag_desidx [] PROGMEM = "Designator Index\t";
+const char local_tag_desmin [] PROGMEM = "Designator Minimum\t";
+const char local_tag_desmax [] PROGMEM = "Designator Maximum\t";
+const char local_tag_stridx [] PROGMEM = "String Index\t";
+const char local_tag_strmin [] PROGMEM = "String Minimum\t";
+const char local_tag_strmax [] PROGMEM = "String Maximum\t";
+const char local_tag_delimiter [] PROGMEM = "Delimiter\t";
+/* Local Item Tag Strings Array */
+const char* localtags [] PROGMEM =
+{
+ local_tag_usage,
+ local_tag_usagemin,
+ local_tag_usagemax,
+ local_tag_desidx,
+ local_tag_desmin,
+ local_tag_desmax,
+ local_tag_stridx,
+ local_tag_strmin,
+ local_tag_strmax,
+ local_tag_delimiter
+};
+/* Collection Types Strings */
+const char coll_phy [] PROGMEM = "Physical (group of axes)";
+const char coll_app [] PROGMEM = "Application (mouse, keyboard)";
+const char coll_log [] PROGMEM = "Logical (interrelated data)";
+const char coll_rep [] PROGMEM = "Report";
+const char coll_arr [] PROGMEM = "Named Array";
+const char coll_usw [] PROGMEM = "Usage Switch";
+const char coll_umod [] PROGMEM = "Usage Modifier";
+/* Collection Types Strings Array */
+const char* collections [] PROGMEM =
+{
+ coll_phy,
+ coll_app,
+ coll_log,
+ coll_rep,
+ coll_arr,
+ coll_usw,
+ coll_umod
+};
+/* Usage Pages Strings */
+const char up_undef [] PROGMEM = "Undefined";
+const char up_gendesk [] PROGMEM = "Generic Desktop Controls";
+const char up_sim [] PROGMEM = "Simulation Controls";
+const char up_vr [] PROGMEM = "VR Controls";
+const char up_sport [] PROGMEM = "Sport Controls";
+const char up_game [] PROGMEM = "Game Controls";
+const char up_gendev [] PROGMEM = "Generic Device Controls";
+const char up_kbd [] PROGMEM = "Keyboard/Keypad";
+const char up_led [] PROGMEM = "LEDs";
+const char up_button [] PROGMEM = "Button";
+const char up_ord [] PROGMEM = "Ordinal";
+const char up_tele [] PROGMEM = "Telephony";
+const char up_cons [] PROGMEM = "Consumer";
+const char up_dig [] PROGMEM = "Digitizer";
+//const char up_res [] PROGMEM = "Reserved";
+const char up_pid [] PROGMEM = "PID Page";
+const char up_uni [] PROGMEM = "Unicode";
+/* Usage Pages Strings Array */
+const char * usage_pages [] PROGMEM =
+{
+ up_undef,
+ up_gendesk,
+ up_sim,
+ up_vr,
+ up_sport,
+ up_game,
+ up_gendev,
+ up_kbd,
+ up_led,
+ up_button,
+ up_ord,
+ up_tele,
+ up_cons,
+ up_dig,
+ reserved_msg,
+ up_pid,
+ up_uni
+};
+
+#endif //_DESCRIPTOR_PARSER_
diff --git a/USB_Host_Shield/examples/descriptor_parser/descriptor_parser.pde b/USB_Host_Shield/examples/descriptor_parser/descriptor_parser.pde
new file mode 100644
index 0000000..d417e76
--- /dev/null
+++ b/USB_Host_Shield/examples/descriptor_parser/descriptor_parser.pde
@@ -0,0 +1,720 @@
+/* MAX3421E USB Host controller configuration descriptor parser */
+#include <Spi.h>
+#include <Max3421e.h>
+#include <Usb.h>
+#include "descriptor_parser.h"
+
+#define LOBYTE(x) ((char*)(&(x)))[0]
+#define HIBYTE(x) ((char*)(&(x)))[1]
+#define BUFSIZE 256 //buffer size
+#define DEVADDR 1
+
+#define getReportDescr( addr, ep, nbytes, parse_func, nak_limit ) ctrlXfer( addr, ep, bmREQ_HIDREPORT, USB_REQUEST_GET_DESCRIPTOR, 0x00, HID_DESCRIPTOR_REPORT, 0x0000, nbytes, parse_func, nak_limit )
+#define getReport( addr, ep, nbytes, interface, report_type, report_id, parse_func, nak_limit ) ctrlXfer( addr, ep, bmREQ_HIDIN, HID_REQUEST_GET_REPORT, report_id, report_type, interface, nbytes, parse_func, nak_limit )
+
+/* Foeward declarations */
+void setup();
+void loop();
+byte ctrlXfer( byte addr, byte ep, byte bmReqType, byte bRequest, byte wValLo, byte wValHi, unsigned int wInd, uint16_t nbytes, PARSE parse_func, uint16_t nak_limit );
+void HIDreport_parse( uint8_t* buf, uint8_t* head, uint8_t* tail);
+
+typedef struct {
+ uint8_t bDescriptorType;
+ uint16_t wDescriptorLength;
+} HID_CLASS_DESCRIPTOR;
+
+
+//typedef void (*PARSE)( int8_t*, int8_t*, int8_t );
+
+MAX3421E Max;
+USB Usb;
+
+void setup()
+{
+ Serial.begin( 115200 );
+ printProgStr(PSTR("\r\nStart"));
+ Max.powerOn();
+ delay( 200 );
+}
+
+void loop()
+{
+ uint8_t rcode;
+ uint8_t tmpbyte = 0;
+ //PARSE pf = &HIDreport_parse;
+ /**/
+ Max.Task();
+ Usb.Task();
+ if( Usb.getUsbTaskState() >= USB_STATE_CONFIGURING ) { //state configuring or higher
+ /* printing device descriptor */
+ printProgStr(PSTR("\r\nDevice addressed... "));
+ printProgStr(PSTR("Requesting device descriptor."));
+ tmpbyte = getdevdescr( DEVADDR ); //number of configurations, 0 if error
+ if( tmpbyte == 0 ) {
+ printProgStr(PSTR("\r\nDevice descriptor cannot be retrieved. Program Halted\r\n"));
+ while( 1 ); //stop
+ }//if( tmpbyte
+ /* print configuration descriptors for all configurations */
+ for( uint8_t i = 0; i < tmpbyte; i++ ) {
+ getconfdescr( DEVADDR, i );
+ }
+ /* Stop */
+ while( 1 ); //stop
+ }
+}
+
+/* Prints device descriptor. Returns number of configurations or zero if request error occured */
+byte getdevdescr( byte addr )
+{
+ USB_DEVICE_DESCRIPTOR buf;
+ byte rcode;
+ //Max.toggle( BPNT_0 );
+ rcode = Usb.getDevDescr( addr, 0, 0x12, ( char *)&buf );
+ if( rcode ) {
+ printProgStr( rcode_error_msg );
+ print_hex( rcode, 8 );
+ return( 0 );
+ }
+ printProgStr(PSTR("\r\nDevice descriptor: \r\n"));
+ //Descriptor length
+ printProgStr( descr_len );
+ print_hex( buf.bLength, 8 );
+ //Descriptor type
+// printProgStr( descr_type );
+// print_hex( buf.bDescriptorType, 8 );
+// printProgStr( descrtype_parse( buf.bDescriptorType ));
+ //USB Version
+ printProgStr(PSTR("\r\nUSB version:\t\t"));
+ Serial.print(( HIBYTE( buf.bcdUSB )), HEX );
+ Serial.print(".");
+ Serial.print(( LOBYTE( buf.bcdUSB )), HEX );
+ //Device class
+ printProgStr( class_str );
+ print_hex( buf.bDeviceClass, 8 );
+ printProgStr( classname_parse( buf.bDeviceClass ));
+ //Device Subclass
+ printProgStr( subclass_str );
+ print_hex( buf.bDeviceSubClass, 8 );
+ //Device Protocol
+ printProgStr( protocol_str );
+ print_hex( buf.bDeviceProtocol, 8 );
+ //Max.packet size
+ printProgStr( maxpktsize_str );
+ print_hex( buf.bMaxPacketSize0, 8 );
+ //VID
+ printProgStr(PSTR("\r\nVendor ID:\t\t"));
+ print_hex( buf.idVendor, 16 );
+ //PID
+ printProgStr(PSTR("\r\nProduct ID:\t\t"));
+ print_hex( buf.idProduct, 16 );
+ //Revision
+ printProgStr(PSTR("\r\nRevision ID:\t\t"));
+ print_hex( buf.bcdDevice, 16 );
+ //Mfg.string
+ printProgStr (PSTR("\r\nMfg.string index:\t"));
+ print_hex( buf.iManufacturer, 8 );
+ getstrdescr( addr, buf.iManufacturer );
+ //Prod.string
+ printProgStr(PSTR("\r\nProd.string index:\t"));
+ print_hex( buf.iProduct, 8 );
+ //printProgStr( str_cont );
+ getstrdescr( addr, buf.iProduct );
+ //Serial number string
+ printProgStr(PSTR("\r\nSerial number index:\t"));
+ print_hex( buf.iSerialNumber, 8 );
+ //printProgStr( str_cont );
+ getstrdescr( addr, buf.iSerialNumber );
+ //Number of configurations
+ printProgStr(PSTR("\r\nNumber of conf.:\t"));
+ print_hex( buf.bNumConfigurations, 8 );
+ return( buf.bNumConfigurations );
+}
+/* Get string descriptor. Takes device address and string index */
+byte getstrdescr( byte addr, byte idx )
+{
+ char buf[ BUFSIZE ];
+ byte rcode;
+ byte length;
+ byte i;
+ unsigned int langid;
+ if( idx == 0 ) { //don't try to get index zero
+ return( 0 );
+ }
+ rcode = Usb.getStrDescr( addr, 0, 1, 0, 0, buf ); //get language table length
+ if( rcode ) {
+ printProgStr(PSTR("\r\nError retrieving LangID table length"));
+ return( rcode );
+ }
+ length = buf[ 0 ]; //length is the first byte
+ rcode = Usb.getStrDescr( addr, 0, length, 0, 0, buf ); //get language table
+ if( rcode ) {
+ printProgStr(PSTR("\r\nError retrieving LangID table"));
+ return( rcode );
+ }
+ HIBYTE( langid ) = buf[ 3 ]; //get first langid
+ LOBYTE( langid ) = buf[ 2 ]; //bytes are swapped to account for endiannes
+ //printProgStr(PSTR("\r\nLanguage ID: "));
+ //print_hex( langid, 16 );
+ rcode = Usb.getStrDescr( addr, 0, 1, idx, langid, buf );
+ if( rcode ) {
+ printProgStr(PSTR("\r\nError retrieving string length"));
+ return( rcode );
+ }
+ length = ( buf[ 0 ] < 254 ? buf[ 0 ] : 254 );
+ printProgStr(PSTR(" Length: "));
+ Serial.print( length, DEC );
+ rcode = Usb.getStrDescr( addr, 0, length, idx, langid, buf );
+ if( rcode ) {
+ printProgStr(PSTR("\r\nError retrieveing string"));
+ return( rcode );
+ }
+ printProgStr(PSTR(" Contents: "));
+ for( i = 2; i < length; i+=2 ) {
+ Serial.print( buf[ i ] );
+ }
+ return( idx );
+}
+/* Returns string to class name */
+const char* classname_parse( byte class_number )
+{
+ switch( class_number ) {
+ case 0x00:
+ return PSTR(" Use class information in the Interface Descriptor");
+ case 0x01:
+ return PSTR(" Audio");
+ case 0x02:
+ return PSTR(" Communications and CDC Control");
+ case 0x03:
+ return PSTR(" HID (Human Interface Device)");
+ case 0x05:
+ return PSTR(" Physical");
+ case 0x06:
+ return PSTR(" Image");
+ case 0x07:
+ return PSTR(" Printer");
+ case 0x08:
+ return PSTR(" Mass Storage");
+ case 0x09:
+ return PSTR(" Hub");
+ case 0x0a:
+ return PSTR(" CDC-Data");
+ case 0x0b:
+ return PSTR(" Smart Card");
+ case 0x0d:
+ return PSTR(" Content Security");
+ case 0x0e:
+ return PSTR(" Video");
+ case 0x0f:
+ return PSTR(" Personal Healthcare");
+ case 0xdc:
+ return PSTR("Diagnostic Device");
+ case 0xe0:
+ return PSTR(" Wireless Controller");
+ case 0xef:
+ return PSTR(" Miscellaneous");
+ case 0xfe:
+ return PSTR(" Application Specific");
+ case 0xff:
+ return PSTR(" Vendor Specific");
+ default:
+ return unk_msg;
+ }//switch( class_number
+}
+/* Getting configuration descriptor */
+byte getconfdescr( byte addr, byte conf )
+{
+ char buf[ BUFSIZE ];
+ char* buf_ptr = buf;
+ byte rcode;
+ byte descr_length;
+ byte descr_type;
+ unsigned int total_length;
+ printProgStr(PSTR("\r\n\nConfiguration number "));
+ Serial.print( conf, HEX );
+ rcode = Usb.getConfDescr( addr, 0, 4, conf, buf ); //get total length
+ if( rcode ) {
+ printProgStr(PSTR("Error retrieving configuration length. Error code "));
+ Serial.println( rcode, HEX );
+ return( 0 );
+ }//if( rcode
+ LOBYTE( total_length ) = buf[ 2 ];
+ HIBYTE( total_length ) = buf[ 3 ];
+ printProgStr(PSTR("\r\nTotal configuration length: "));
+ Serial.print( total_length, DEC );
+ printProgStr(PSTR(" bytes"));
+ if( total_length > BUFSIZE ) { //check if total length is larger than buffer
+ printProgStr(PSTR("Total length truncated to "));
+ Serial.print( BUFSIZE, DEC);
+ printProgStr(PSTR("bytes"));
+ total_length = BUFSIZE;
+ }
+ rcode = Usb.getConfDescr( addr, 0, total_length, conf, buf ); //get the whole descriptor
+ while( buf_ptr < buf + total_length ) { //parsing descriptors
+ descr_length = *( buf_ptr );
+ descr_type = *( buf_ptr + 1 );
+ switch( descr_type ) {
+ case( USB_DESCRIPTOR_CONFIGURATION ):
+ printconfdescr( buf_ptr );
+ break;
+ case( USB_DESCRIPTOR_INTERFACE ):
+ printintfdescr( buf_ptr );
+ break;
+ case( USB_DESCRIPTOR_ENDPOINT ):
+ printepdescr( buf_ptr );
+ break;
+ case( HID_DESCRIPTOR_HID ):
+ printhid_descr( buf_ptr );
+ break;
+ default:
+ printunkdescr( buf_ptr );
+ break;
+ }//switch( descr_type
+ Serial.println("");
+ buf_ptr = ( buf_ptr + descr_length ); //advance buffer pointer
+ }//while( buf_ptr <=...
+ return( 0 );
+}
+/* function to print configuration descriptor */
+void printconfdescr( char* descr_ptr )
+{
+ USB_CONFIGURATION_DESCRIPTOR* conf_ptr = ( USB_CONFIGURATION_DESCRIPTOR* )descr_ptr;
+ uint8_t tmpbyte;
+ printProgStr(PSTR("\r\n\nConfiguration descriptor:"));
+ printProgStr(PSTR("\r\nTotal length:\t\t"));
+ print_hex( conf_ptr->wTotalLength, 16 );
+ printProgStr(PSTR("\r\nNumber of interfaces:\t"));
+ print_hex( conf_ptr->bNumInterfaces, 8 );
+ printProgStr(PSTR("\r\nConfiguration value:\t"));
+ print_hex( conf_ptr->bConfigurationValue, 8 );
+ printProgStr(PSTR("\r\nConfiguration string:\t"));
+ tmpbyte = conf_ptr->iConfiguration;
+ print_hex( tmpbyte, 8 );
+ getstrdescr( DEVADDR, tmpbyte );
+ printProgStr(PSTR("\r\nAttributes:\t\t"));
+ tmpbyte = conf_ptr->bmAttributes;
+ print_hex( tmpbyte, 8 );
+ if( tmpbyte & 0x40 ) { //D6
+ printProgStr(PSTR(" Self-powered"));
+ }
+ if( tmpbyte & 0x20 ) { //D5
+ printProgStr(PSTR(" Remote Wakeup"));
+ }
+ printProgStr(PSTR("\r\nMax.power:\t\t"));
+ tmpbyte = conf_ptr->bMaxPower;
+ print_hex( tmpbyte, 8 );
+ printProgStr(PSTR(" "));
+ Serial.print(( tmpbyte * 2 ), DEC);
+ printProgStr(PSTR("ma"));
+ return;
+}
+/* function to print interface descriptor */
+void printintfdescr( char* descr_ptr )
+{
+ USB_INTERFACE_DESCRIPTOR* intf_ptr = ( USB_INTERFACE_DESCRIPTOR* )descr_ptr;
+ uint8_t tmpbyte;
+ printProgStr(PSTR("\r\nInterface descriptor:"));
+ printProgStr(PSTR("\r\nInterface number:\t"));
+ print_hex( intf_ptr->bInterfaceNumber, 8 );
+ printProgStr(PSTR("\r\nAlternate setting:\t"));
+ print_hex( intf_ptr->bAlternateSetting, 8 );
+ printProgStr(PSTR("\r\nEndpoints:\t\t"));
+ print_hex( intf_ptr->bNumEndpoints, 8 );
+ printProgStr( class_str );
+ tmpbyte = intf_ptr->bInterfaceClass;
+ print_hex( tmpbyte, 8 );
+ printProgStr(classname_parse( tmpbyte ));
+ printProgStr( subclass_str );
+ print_hex( intf_ptr->bInterfaceSubClass, 8 );
+ printProgStr( protocol_str );
+ print_hex( intf_ptr->bInterfaceProtocol, 8 );
+ printProgStr(PSTR("\r\nInterface string:\t"));
+ tmpbyte = intf_ptr->iInterface;
+ print_hex( tmpbyte, 8 );
+ getstrdescr( DEVADDR, tmpbyte );
+ return;
+}
+/* function to print endpoint descriptor */
+void printepdescr( char* descr_ptr )
+{
+ USB_ENDPOINT_DESCRIPTOR* ep_ptr = ( USB_ENDPOINT_DESCRIPTOR* )descr_ptr;
+ uint8_t tmpbyte;
+ printProgStr(PSTR("\r\nEndpoint descriptor:"));
+ printProgStr(PSTR("\r\nEndpoint address:\t"));
+ tmpbyte = ep_ptr->bEndpointAddress;
+ print_hex( tmpbyte & 0x0f, 8 );
+ printProgStr(PSTR(" Direction: "));
+ ( tmpbyte & 0x80 ) ? printProgStr(PSTR("IN")) : printProgStr(PSTR("OUT"));
+ printProgStr(PSTR("\r\nAttributes:\t\t"));
+ tmpbyte = ep_ptr->bmAttributes;
+ print_hex( tmpbyte, 8 );
+ printProgStr(PSTR(" Transfer type: "));
+ printProgStr((char*)pgm_read_word(&transfer_types[(tmpbyte & 0x03)]));
+ if(( tmpbyte & 0x03 ) == 1 ) { //Isochronous Transfer
+ printProgStr(PSTR(", Sync Type: "));
+ printProgStr((char*)pgm_read_word(&sync_types[(tmpbyte & 0x0c)]));
+ printProgStr(PSTR(", Usage Type: "));
+ printProgStr((char*)pgm_read_word(&usage_types[(tmpbyte & 0x30)]));
+ }//if( tmpbyte & 0x01
+ printProgStr( maxpktsize_str );
+ print_hex( ep_ptr->wMaxPacketSize, 16 );
+ printProgStr(PSTR("\r\nPolling interval:\t"));
+ tmpbyte = ep_ptr->bInterval;
+ print_hex( tmpbyte, 8 );
+ printProgStr(PSTR(" "));
+ Serial.print( tmpbyte, DEC );
+ printProgStr(PSTR(" ms"));
+ return;
+}
+/* function to print HID descriptor */
+void printhid_descr( char* descr_ptr )
+{
+ PARSE pf = &HIDreport_parse;
+ USB_HID_DESCRIPTOR* hid_ptr = ( USB_HID_DESCRIPTOR* )descr_ptr;
+ uint8_t tmpbyte;
+ /**/
+ printProgStr(PSTR("\r\nHID descriptor:"));
+ printProgStr(PSTR("\r\nDescriptor length:\t"));
+ tmpbyte = hid_ptr->bLength;
+ print_hex( tmpbyte, 8 );
+ printProgStr(PSTR(" "));
+ Serial.print( tmpbyte, DEC );
+ printProgStr(PSTR(" bytes"));
+ printProgStr(PSTR("\r\nHID version:\t\t"));
+ Serial.print(( HIBYTE( hid_ptr->bcdHID )), HEX );
+ Serial.print(".");
+ Serial.print(( LOBYTE( hid_ptr->bcdHID )), HEX );
+ tmpbyte = hid_ptr->bCountryCode;
+ printProgStr(PSTR("\r\nCountry Code:\t\t"));
+ Serial.print( tmpbyte, DEC );
+ printProgStr(PSTR(" "));
+ ( tmpbyte > 35 ) ? printProgStr(PSTR("Reserved")) : printProgStr((char*)pgm_read_word(&HID_Country_Codes[ tmpbyte ]));
+ tmpbyte = hid_ptr->bNumDescriptors;
+ printProgStr(PSTR("\r\nClass Descriptors:\t"));
+ Serial.print( tmpbyte, DEC );
+ //Printing class descriptors
+ descr_ptr += 6; //advance buffer pointer
+ for( uint8_t i = 0; i < tmpbyte; i++ ) {
+ uint8_t tmpdata;
+ HID_CLASS_DESCRIPTOR* hidclass_ptr = ( HID_CLASS_DESCRIPTOR* )descr_ptr;
+ tmpdata = hidclass_ptr->bDescriptorType;
+ printProgStr(PSTR("\r\nClass Descriptor Type:\t"));
+ Serial.print( tmpdata, HEX );
+ if(( tmpdata < 0x21 ) || ( tmpdata > 0x2f )) {
+ printProgStr(PSTR(" Invalid"));
+ }
+ switch( tmpdata ) {
+ case 0x21:
+ printProgStr(PSTR(" HID"));
+ break;
+ case 0x22:
+ printProgStr(PSTR(" Report"));
+ break;
+ case 0x23:
+ printProgStr(PSTR(" Physical"));
+ break;
+ default:
+ printProgStr(PSTR(" Reserved"));
+ break;
+ }//switch( tmpdata
+ printProgStr(PSTR("\r\nClass Descriptor Length:"));
+ Serial.print( hidclass_ptr->wDescriptorLength );
+ printProgStr(PSTR(" bytes"));
+ printProgStr(PSTR("\r\n\nHID report descriptor:\r\n"));
+ getReportDescr( DEVADDR, 0 , hidclass_ptr->wDescriptorLength, pf, USB_NAK_LIMIT );
+ descr_ptr += 3; //advance to the next record
+ }//for( uint8_t i=...
+ return;
+}
+/*function to print unknown descriptor */
+void printunkdescr( char* descr_ptr )
+{
+ byte length = *descr_ptr;
+ byte i;
+ printProgStr(PSTR("\r\nUnknown descriptor:"));
+ printProgStr(PSTR("Length:\t\t"));
+ print_hex( *descr_ptr, 8 );
+ printProgStr(PSTR("\r\nType:\t\t"));
+ print_hex( *(descr_ptr + 1 ), 8 );
+ printProgStr(PSTR("\r\nContents:\t"));
+ descr_ptr += 2;
+ for( i = 0; i < length; i++ ) {
+ print_hex( *descr_ptr, 8 );
+ descr_ptr++;
+ }
+}
+/* Control-IN transfer with callback. Sets address, endpoint, fills control packet with necessary data, dispatches control packet, and initiates bulk IN transfer */
+/* Control, data, and setup stages combined from standard USB library to be able to read large data blocks. Restricted to control-IN transfers with data stage */
+/* data read and MAX3421E RECV FIFO buffer release shall be performed by parse_func callback */
+/* return codes: */
+/* 00 = success */
+/* 01-0f = non-zero HRSLT */
+byte ctrlXfer( byte addr, byte ep, byte bmReqType, byte bRequest, byte wValLo, byte wValHi, unsigned int wInd, uint16_t nbytes, PARSE parse_func, uint16_t nak_limit = USB_NAK_LIMIT )
+{
+ byte rcode;
+ SETUP_PKT sp;
+ EP_RECORD* ep_rec = Usb.getDevTableEntry( addr, ep );
+ byte pktsize;
+ byte maxpktsize = ep_rec->MaxPktSize;
+ unsigned int xfrlen = 0;
+ /**/
+ Max.regWr( rPERADDR, addr ); //set peripheral address
+ /* fill in setup packet */
+ sp.ReqType_u.bmRequestType = bmReqType;
+ sp.bRequest = bRequest;
+ sp.wVal_u.wValueLo = wValLo;
+ sp.wVal_u.wValueHi = wValHi;
+ sp.wIndex = wInd;
+ sp.wLength = nbytes;
+ Max.bytesWr( rSUDFIFO, 8, ( char *)&sp ); //transfer to setup packet FIFO
+ rcode = Usb.dispatchPkt( tokSETUP, ep, nak_limit ); //dispatch packet
+ //Serial.println("Setup packet"); //DEBUG
+ if( rcode ) { //return HRSLT if not zero
+ printProgStr(PSTR("\r\nSetup packet error: "));
+ Serial.print( rcode, HEX );
+ return( rcode );
+ }
+ /* Data stage */
+ //ep_rec->rcvToggle = bmRCVTOG1;
+ Max.regWr( rHCTL, bmRCVTOG1 ); //set toggle
+ while( 1 ) { //exited by break
+ /* request data */
+ rcode = Usb.dispatchPkt( tokIN, ep, nak_limit );
+ if( rcode ) {
+ printProgStr(PSTR("\r\nData Stage Error: "));
+ Serial.print( rcode, HEX );
+ return( rcode );
+ }
+ /* check for RCVDAVIRQ and generate error if not present */
+ /* the only case when absense of RCVDAVIRQ makes sense is when toggle error occured. Need to add handling for that */
+ if(( Max.regRd( rHIRQ ) & bmRCVDAVIRQ ) == 0 ) {
+ printProgStr(PSTR("\r\nData Toggle error."));
+ return ( 0xf0 );
+ }
+ pktsize = Max.regRd( rRCVBC ); //get received bytes count
+ parse_func( pktsize ); //call parse function. Parse is expected to read the FIFO completely
+ Max.regWr( rHIRQ, bmRCVDAVIRQ ); // Clear the IRQ & free the buffer
+ xfrlen += pktsize; // add this packet's byte count to total transfer length
+ /* The transfer is complete under two conditions: */
+ /* 1. The device sent a short packet (L.T. maxPacketSize) */
+ /* 2. 'nbytes' have been transferred. */
+ if (( pktsize < maxpktsize ) || (xfrlen >= nbytes )) { // have we transferred 'nbytes' bytes?
+ break;
+ }
+ }//while( 1 )
+ rcode = Usb.dispatchPkt( tokOUTHS, ep, nak_limit );
+ if( rcode ) { //return error
+ printProgStr(PSTR("Status packet error: "));
+ Serial.print( rcode, HEX );
+ }
+ return( rcode );
+}
+/* Parses bitfields in main items */
+void print_mainbitfield( uint8_t byte_toparse )
+{
+ ( byte_toparse & 0x01 ) ? printProgStr(PSTR("Constant,")) : printProgStr(PSTR("Data,")); //bit 0
+ ( byte_toparse & 0x02 ) ? printProgStr(PSTR("Variable,")) : printProgStr(PSTR("Array,")); //bit 1
+ ( byte_toparse & 0x04 ) ? printProgStr(PSTR("Relative,")) : printProgStr(PSTR("Absolute,")); //...
+ ( byte_toparse & 0x08 ) ? printProgStr(PSTR("Wrap,")) : printProgStr(PSTR("No Wrap,"));
+ ( byte_toparse & 0x10 ) ? printProgStr(PSTR("Non Linear,")) : printProgStr(PSTR("Linear,"));
+ ( byte_toparse & 0x20 ) ? printProgStr(PSTR("No preferred,")) : printProgStr(PSTR("Preferred State,"));
+ ( byte_toparse & 0x40 ) ? printProgStr(PSTR("Null State,")) : printProgStr(PSTR("No Null Position,")); //bit 6
+ ( byte_toparse & 0x40 ) ? printProgStr(PSTR("Volatile( ignore for Input),")) : printProgStr(PSTR("Non-volatile(Ignore for Input),")); //bit 7
+}
+/* HID Report Desriptor Parser Callback */
+/* called repeatedly from Control transfer function */
+void HIDreport_parse( uint8_t pkt_size )
+{
+#define B_SIZE 0x03 //bSize bitmask
+#define B_TYPE 0x0c //bType bitmask
+#define B_TAG 0xf0 //bTag bitmask
+ /* parser states */
+ enum STATE { ITEM_START, DATA_PARSE };
+ static STATE state = ITEM_START;
+ static uint8_t databytes_left = 0;
+ static uint8_t prefix; //item prefix - type and tag
+ uint8_t byte_toparse;
+ uint8_t bType;
+ uint8_t tmpbyte;
+ /**/
+ while( 1 ) {
+ if( pkt_size ) {
+ byte_toparse = Max.regRd( rRCVFIFO ); //read a byte from FIFO
+ pkt_size--;
+ }
+ else {
+ return; //all bytes read
+ }
+ switch( state ) {
+ case ITEM_START: //start of the record
+ prefix = byte_toparse >>2; //store prefix for databyte parsing
+ tmpbyte = byte_toparse & B_SIZE;
+ /* get item length */
+ ( tmpbyte == 0x03 ) ? databytes_left = 4 : databytes_left = tmpbyte;
+ if( databytes_left ) {
+ state = DATA_PARSE; //read bytes after prefix
+ }
+ printProgStr(PSTR("\r\nLength: "));
+ Serial.print( databytes_left, DEC );
+ /* get item type */
+ bType = ( byte_toparse & B_TYPE ) >>2;
+ printProgStr(PSTR(" Type: "));
+ printProgStr((char*)pgm_read_word(&btypes[ bType ]));
+ /* get item tag */
+ printProgStr(PSTR("\t\tTag: "));
+ tmpbyte = ( byte_toparse & B_TAG ) >>4 ;
+ switch( bType ) {
+ case 0: //Main
+ if( tmpbyte < 0x08 ) {
+ printProgStr(PSTR("Invalid Tag"));
+ }
+ else if( tmpbyte > 0x0c ) {
+ printProgStr( reserved_msg );
+ }
+ else {
+ printProgStr((char*)pgm_read_word(&maintags[ tmpbyte - 8 /* & 0x03 */]));
+ //Serial.print("Byte: ");
+ //Serial.println( tmpbyte, HEX );
+ }
+ break;//case 0 Main
+ case 1: //Global
+ ( tmpbyte > 0x0b ) ? printProgStr( reserved_msg ) : printProgStr((char*)pgm_read_word(&globaltags[ tmpbyte ]));
+ break;//case 1 Global
+ case 2: //Local
+ ( tmpbyte > 0x0a ) ? printProgStr( reserved_msg ) : printProgStr((char*)pgm_read_word(&localtags[ tmpbyte ]));
+ break;//case 2 Local
+ default:
+ break;
+ }//switch( bType...
+ break;//case ITEM_START
+ case DATA_PARSE:
+ switch( prefix ) {
+ case 0x20: //Main Input
+ case 0x24: //Main Output
+ case 0x2c: //Main Feature
+ /* todo: add parsing 8th bit */
+ print_mainbitfield( byte_toparse );
+ break;
+ case 0x28: //Main Collection
+ if(( byte_toparse > 0x06 ) && ( byte_toparse < 0x80 )) {
+ printProgStr( reserved_msg );
+ }
+ else if(( byte_toparse > 0x7f ) && ( byte_toparse <= 0xff )) {
+ printProgStr(PSTR("Vendor-defined"));
+ }
+ else {
+ printProgStr((char*)pgm_read_word(&collections[ byte_toparse ]));
+ }
+ break;//case 0x28 Main Collection
+ //case 0x30: //Main End Collection
+ case 0x01: //Global Usage Page
+ switch( byte_toparse ) { //see HID Usage Tables doc v.1.12 page 14
+ case 0x00:
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x04:
+ case 0x05:
+ case 0x06:
+ case 0x07:
+ case 0x08:
+ case 0x09:
+ case 0x0a:
+ case 0x0b:
+ case 0x0c:
+ case 0x0d:
+ case 0x0e:
+ case 0x0f:
+ case 0x10:
+ printProgStr((char*)pgm_read_word(&usage_pages[ byte_toparse ]));
+ break;
+ case 0x14:
+ printProgStr(PSTR("Alphanumeric Display"));
+ break;
+ case 0x40:
+ printProgStr(PSTR("Medical Instruments"));
+ break;
+ case 0x80:
+ case 0x81:
+ case 0x82:
+ case 0x83:
+ printProgStr(PSTR("Monitor page"));
+ break;
+ case 0x84:
+ case 0x85:
+ case 0x86:
+ case 0x87:
+ printProgStr(PSTR("Power page"));
+ break;
+ case 0x8c:
+ printProgStr(PSTR("Bar Code Scanner page"));
+ break;
+ case 0x8d:
+ printProgStr(PSTR("Scale page"));
+ break;
+ case 0x8e:
+ printProgStr(PSTR("Magnetic Stripe Reading (MSR) Devices"));
+ break;
+ case 0x8f:
+ printProgStr(PSTR("Reserved Point of Sale pages"));
+ break;
+ case 0x90:
+ printProgStr(PSTR("Camera Control Page"));
+ break;
+ case 0x91:
+ printProgStr(PSTR("Arcade Page"));
+ break;
+ default:
+// printProgStr(PSTR("Data: "));
+// print_hex( byte_toparse, 8 );
+ //databytes_left--;
+ break;
+ }//switch case 0x01: //Global Usage Page
+ }//switch( prefix ...
+ printProgStr(PSTR(" Data: "));
+ print_hex( byte_toparse, 8 );
+ databytes_left--;
+ if( !databytes_left ) {
+ state = ITEM_START;
+ }
+ break;
+ }//switch( state...
+ }//while( 1 ...
+}
+/* prints hex numbers with leading zeroes */
+// copyright, Peter H Anderson, Baltimore, MD, Nov, '07
+// source: http://www.phanderson.com/arduino/arduino_display.html
+void print_hex(int v, int num_places)
+{
+ int mask=0, n, num_nibbles, digit;
+
+ for (n=1; n<=num_places; n++) {
+ mask = (mask << 1) | 0x0001;
+ }
+ v = v & mask; // truncate v to specified number of places
+
+ num_nibbles = num_places / 4;
+ if ((num_places % 4) != 0) {
+ ++num_nibbles;
+ }
+ do {
+ digit = ((v >> (num_nibbles-1) * 4)) & 0x0f;
+ Serial.print(digit, HEX);
+ }
+ while(--num_nibbles);
+}
+
+/* given a PROGMEM string, use Serial.print() to send it out */
+/* Some non-intuitive casting necessary: */
+/* printProgStr(PSTR("Func.Mode:\t0x")); */
+/* printProgStr((char*)pgm_read_word(&mtpopNames[(op & 0xFF)])); */
+void printProgStr(const char* str)
+{
+ if(!str) {
+ return;
+ }
+ char c;
+ while((c = pgm_read_byte(str++))) {
+ Serial.print(c,BYTE);
+ }
+ return;
+}
diff --git a/USB_Host_Shield/main.cpp b/USB_Host_Shield/main.cpp
new file mode 100644
index 0000000..bd04984
--- /dev/null
+++ b/USB_Host_Shield/main.cpp
@@ -0,0 +1,96 @@
+/* Mouse communication via control endpoint */
+#include <spi.h>
+#include <max3421e.h>
+#include <usb.h>
+
+#define DEVADDR 1
+#define CONFVALUE 1
+
+void setup();
+void loop();
+
+MAX3421E Max;
+USB Usb;
+
+void setup()
+{
+ Serial.begin( 115200 );
+ Serial.println("Start");
+ Max.powerOn();
+ delay( 200 );
+}
+
+void loop()
+{
+ byte rcode;
+ Max.Task();
+ Usb.Task();
+ if( Usb.getUsbTaskState() == USB_STATE_CONFIGURING ) {
+ mouse0_init();
+ }//if( Usb.getUsbTaskState() == USB_STATE_CONFIGURING...
+ if( Usb.getUsbTaskState() == USB_STATE_RUNNING ) { //poll the keyboard
+ rcode = mouse0_poll();
+ if( rcode ) {
+ Serial.print("Mouse Poll Error: ");
+ Serial.println( rcode, HEX );
+ }//if( rcode...
+ }//if( Usb.getUsbTaskState() == USB_STATE_RUNNING...
+}
+/* Initialize mouse */
+void mouse0_init( void )
+{
+ byte rcode = 0; //return code
+ /**/
+ Usb.setDevTableEntry( 1, Usb.getDevTableEntry( 0,0 ) ); //copy device 0 endpoint information to device 1
+ /* Configure device */
+ rcode = Usb.setConf( DEVADDR, 0, CONFVALUE );
+ if( rcode ) {
+ Serial.print("Error configuring mouse. Return code : ");
+ Serial.println( rcode, HEX );
+ while(1); //stop
+ }//if( rcode...
+ Usb.setUsbTaskState( USB_STATE_RUNNING );
+ return;
+}
+/* Poll mouse using Get Report and print result */
+byte mouse0_poll( void )
+{
+ byte rcode,i;
+ char buf[ 4 ] = { 0 }; //mouse buffer
+ static char old_buf[ 4 ] = { 0 }; //last poll
+ /* poll mouse */
+ rcode = Usb.getReport( DEVADDR, 0, 4, 0, 1, 0, buf );
+ if( rcode ) { //error
+ return( rcode );
+ }
+ for( i = 0; i < 4; i++) { //check for new information
+ if( buf[ i ] != old_buf[ i ] ) { //new info in buffer
+ break;
+ }
+ }
+ if( i == 4 ) {
+ return( 0 ); //all bytes are the same
+ }
+ /* print buffer */
+ if( buf[ 0 ] & 0x01 ) {
+ Serial.print("Button1 pressed ");
+ }
+ if( buf[ 0 ] & 0x02 ) {
+ Serial.print("Button2 pressed ");
+ }
+ if( buf[ 0 ] & 0x04 ) {
+ Serial.print("Button3 pressed ");
+ }
+ Serial.println("");
+ Serial.print("X-axis: ");
+ Serial.println( buf[ 1 ], DEC);
+ Serial.print("Y-axis: ");
+ Serial.println( buf[ 2 ], DEC);
+ Serial.print("Wheel: ");
+ Serial.println( buf[ 3 ], DEC);
+ for( i = 0; i < 4; i++ ) {
+ old_buf[ i ] = buf[ i ]; //copy buffer
+ }
+ Serial.println("");
+ return( rcode );
+}