/C-OSD/arducam-osd/libraries/USBHOST/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 |
//{ |
// |
// |
//} |
/C-OSD/arducam-osd/libraries/USBHOST/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_ |
/C-OSD/arducam-osd/libraries/USBHOST/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_ |
/C-OSD/arducam-osd/libraries/USBHOST/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); |
} |
/C-OSD/arducam-osd/libraries/USBHOST/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 |
/C-OSD/arducam-osd/libraries/USBHOST/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 |
/C-OSD/arducam-osd/libraries/USBHOST/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 |
} |
/C-OSD/arducam-osd/libraries/USBHOST/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_ |
/C-OSD/arducam-osd/libraries/USBHOST/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_ |
/C-OSD/arducam-osd/libraries/USBHOST/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 ); |
} |
/C-OSD/arducam-osd/libraries/USBHOST/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; |
} |
/C-OSD/arducam-osd/libraries/USBHOST/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 ); |
} |
} |
/C-OSD/arducam-osd/libraries/USBHOST/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 |
/C-OSD/arducam-osd/libraries/USBHOST/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); |
} |
/C-OSD/arducam-osd/libraries/USBHOST/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++; |
} |
} |
/C-OSD/arducam-osd/libraries/USBHOST/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_ |
/C-OSD/arducam-osd/libraries/USBHOST/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; |
} |