Subversion Repositories Projects

Compare Revisions

Ignore whitespace Rev 1701 → Rev 1702

/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;
}