diff options
author | Erik Gilling <konkers@android.com> | 2011-02-17 20:39:36 -0800 |
---|---|---|
committer | Erik Gilling <konkers@android.com> | 2011-03-08 14:36:07 -0800 |
commit | 51f17515b983385dd8db453e8d36732818b2232e (patch) | |
tree | 7081dc714125de0e97f2d17fb1d8f7fac4e8bf80 | |
parent | a35b98c9e393a15a136f6163655661ee1372d8bb (diff) | |
download | arduino-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.cpp | 270 | ||||
-rw-r--r-- | USB_Host_Shield/Max3421e.h | 54 | ||||
-rw-r--r-- | USB_Host_Shield/Max3421e_constants.h | 236 | ||||
-rw-r--r-- | USB_Host_Shield/Max_LCD.cpp | 250 | ||||
-rw-r--r-- | USB_Host_Shield/Max_LCD.h | 87 | ||||
-rw-r--r-- | USB_Host_Shield/README | 4 | ||||
-rw-r--r-- | USB_Host_Shield/Usb.cpp | 378 | ||||
-rw-r--r-- | USB_Host_Shield/Usb.h | 175 | ||||
-rw-r--r-- | USB_Host_Shield/ch9.h | 168 | ||||
-rw-r--r-- | USB_Host_Shield/examples/LCDkbd.pde | 335 | ||||
-rw-r--r-- | USB_Host_Shield/examples/PS3LCD.pde | 566 | ||||
-rw-r--r-- | USB_Host_Shield/examples/arm_mouse.pde | 284 | ||||
-rw-r--r-- | USB_Host_Shield/examples/board_test/board_test.h | 21 | ||||
-rw-r--r-- | USB_Host_Shield/examples/board_test/board_test.pde | 296 | ||||
-rw-r--r-- | USB_Host_Shield/examples/conf_descr_dump.pde | 181 | ||||
-rw-r--r-- | USB_Host_Shield/examples/descriptor_parser/descriptor_parser.h | 284 | ||||
-rw-r--r-- | USB_Host_Shield/examples/descriptor_parser/descriptor_parser.pde | 720 | ||||
-rw-r--r-- | USB_Host_Shield/main.cpp | 96 |
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 ); +} |