Merge my debug changes.

Merge my format sanity changes.
Track everything.
This commit is contained in:
Andrew J. Kroll 2013-03-28 03:26:02 -04:00
parent f5856c72bc
commit 629594f957
39 changed files with 11136 additions and 11344 deletions

870
Usb.cpp

File diff suppressed because it is too large Load diff

269
Usb.h
View file

@ -13,7 +13,7 @@ Contact information
Circuits At Home, LTD Circuits At Home, LTD
Web : http://www.circuitsathome.com Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com e-mail : support@circuitsathome.com
*/ */
/* USB functions */ /* USB functions */
#ifndef _usb_h_ #ifndef _usb_h_
#define _usb_h_ #define _usb_h_
@ -44,28 +44,18 @@ e-mail : support@circuitsathome.com
#include "hexdump.h" #include "hexdump.h"
#include "message.h" #include "message.h"
extern int UsbDEBUGlvl;
/* shield pins. First parameter - SS pin, second parameter - INT pin */ /* shield pins. First parameter - SS pin, second parameter - INT pin */
#if defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
#define BOARD_TEENSY_PLUS_PLUS
#endif
#ifdef BOARD_BLACK_WIDDOW #ifdef BOARD_BLACK_WIDDOW
typedef MAX3421e<P6, P3> MAX3421E; // Black Widow typedef MAX3421e<P6, P3> MAX3421E; // Black Widow
#elif defined(BOARD_TEENSY_PLUS_PLUS)
typedef MAX3421e<P9, P8> MAX3421E; // Teensy++ 2.0 & 1.0
#elif defined(BOARD_MEGA_ADK)
typedef MAX3421e<P53, P54> MAX3421E; // Arduino Mega ADK
#elif defined(BOARD_BALANDUINO)
typedef MAX3421e<P20, P19> MAX3421E; // Balanduino
#else #else
typedef MAX3421e<P10, P9> MAX3421E; // Official Arduinos (UNO, Duemilanove, Mega, 2560, Leonardo etc.) typedef MAX3421e<P10, P9> MAX3421E; // Official Arduinos (UNO, Duemilanove, Mega, 2560
#endif #endif
//Debug macros. In 1.0 it is possible to move strings to PROGMEM by defining USBTRACE (Serial.print(F(s))) //Debug macros. In 1.0 it is possible to move strings to PROGMEM by defining USBTRACE (Serial.print(F(s)))
#define USBTRACE(s) (Serial.print((s))) #define USBTRACE(s) (Notify(PSTR(s), 0x80))
#define USBTRACE2(s,r) (Serial.print((s)), Serial.println((r),HEX)) #define USBTRACE2(s,r) (Notify(PSTR(s), 0x80), PrintHex((r), 0x80), Notify(PSTR("\r\n"), 0x80))
@ -80,22 +70,22 @@ typedef MAX3421e<P10, P9> MAX3421E; // Official Arduinos (UNO, Duemilanove, Me
// USB Device Classes // USB Device Classes
#define USB_CLASS_USE_CLASS_INFO 0x00 // Use Class Info in the Interface Descriptors #define USB_CLASS_USE_CLASS_INFO 0x00 // Use Class Info in the Interface Descriptors
#define USB_CLASS_AUDIO 0x01 // Audio #define USB_CLASS_AUDIO 0x01 // Audio
#define USB_CLASS_COM_AND_CDC_CTRL 0x02 // Communications and CDC Control #define USB_CLASS_COM_AND_CDC_CTRL 0x02 // Communications and CDC Control
#define USB_CLASS_HID 0x03 // HID #define USB_CLASS_HID 0x03 // HID
#define USB_CLASS_PHYSICAL 0x05 // Physical #define USB_CLASS_PHYSICAL 0x05 // Physical
#define USB_CLASS_IMAGE 0x06 // Image #define USB_CLASS_IMAGE 0x06 // Image
#define USB_CLASS_PRINTER 0x07 // Printer #define USB_CLASS_PRINTER 0x07 // Printer
#define USB_CLASS_MASS_STORAGE 0x08 // Mass Storage #define USB_CLASS_MASS_STORAGE 0x08 // Mass Storage
#define USB_CLASS_HUB 0x09 // Hub #define USB_CLASS_HUB 0x09 // Hub
#define USB_CLASS_CDC_DATA 0x0a // CDC-Data #define USB_CLASS_CDC_DATA 0x0a // CDC-Data
#define USB_CLASS_SMART_CARD 0x0b // Smart-Card #define USB_CLASS_SMART_CARD 0x0b // Smart-Card
#define USB_CLASS_CONTENT_SECURITY 0x0d // Content Security #define USB_CLASS_CONTENT_SECURITY 0x0d // Content Security
#define USB_CLASS_VIDEO 0x0e // Video #define USB_CLASS_VIDEO 0x0e // Video
#define USB_CLASS_PERSONAL_HEALTH 0x0f // Personal Healthcare #define USB_CLASS_PERSONAL_HEALTH 0x0f // Personal Healthcare
#define USB_CLASS_DIAGNOSTIC_DEVICE 0xdc // Diagnostic Device #define USB_CLASS_DIAGNOSTIC_DEVICE 0xdc // Diagnostic Device
#define USB_CLASS_WIRELESS_CTRL 0xe0 // Wireless Controller #define USB_CLASS_WIRELESS_CTRL 0xe0 // Wireless Controller
#define USB_CLASS_MISC 0xef // Miscellaneous #define USB_CLASS_MISC 0xef // Miscellaneous
#define USB_CLASS_APP_SPECIFIC 0xfe // Application Specific #define USB_CLASS_APP_SPECIFIC 0xfe // Application Specific
#define USB_CLASS_VENDOR_SPECIFIC 0xff // Vendor Specific #define USB_CLASS_VENDOR_SPECIFIC 0xff // Vendor Specific
@ -104,32 +94,31 @@ typedef MAX3421e<P10, P9> MAX3421E; // Official Arduinos (UNO, Duemilanove, Me
#define USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE 0xD2 #define USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE 0xD2
#define USB_ERROR_UNABLE_TO_REGISTER_DEVICE_CLASS 0xD3 #define USB_ERROR_UNABLE_TO_REGISTER_DEVICE_CLASS 0xD3
#define USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL 0xD4 #define USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL 0xD4
#define USB_ERROR_HUB_ADDRESS_OVERFLOW 0xD5 #define USB_ERROR_HUB_ADDRESS_OVERFLOW 0xD5
#define USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL 0xD6 #define USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL 0xD6
#define USB_ERROR_EPINFO_IS_NULL 0xD7 #define USB_ERROR_EPINFO_IS_NULL 0xD7
#define USB_ERROR_INVALID_ARGUMENT 0xD8 #define USB_ERROR_INVALID_ARGUMENT 0xD8
#define USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE 0xD9 #define USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE 0xD9
#define USB_ERROR_INVALID_MAX_PKT_SIZE 0xDA #define USB_ERROR_INVALID_MAX_PKT_SIZE 0xDA
#define USB_ERROR_EP_NOT_FOUND_IN_TBL 0xDB #define USB_ERROR_EP_NOT_FOUND_IN_TBL 0xDB
#define USB_ERROR_TRANSFER_TIMEOUT 0xFF #define USB_ERROR_TRANSFER_TIMEOUT 0xFF
class USBDeviceConfig class USBDeviceConfig {
{
public: public:
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed) = 0; virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed) = 0;
virtual uint8_t Release() = 0; virtual uint8_t Release() = 0;
virtual uint8_t Poll() = 0; virtual uint8_t Poll() = 0;
virtual uint8_t GetAddress() = 0; virtual uint8_t GetAddress() = 0;
}; };
#define USB_XFER_TIMEOUT 5000 //USB transfer timeout in milliseconds, per section 9.2.6.1 of USB 2.0 spec #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. 0 means NAKs are not counted //#define USB_NAK_LIMIT 32000 //NAK limit for a transfer. 0 means NAKs are not counted
#define USB_RETRY_LIMIT 3 //retry limit for a transfer #define USB_RETRY_LIMIT 3 //retry limit for a transfer
#define USB_SETTLE_DELAY 200 //settle delay in milliseconds #define USB_SETTLE_DELAY 200 //settle delay in milliseconds
#define USB_NUMDEVICES 16 //number of USB devices #define USB_NUMDEVICES 16 //number of USB devices
//#define HUB_MAX_HUBS 7 // maximum number of hubs that can be attached to the host controller //#define HUB_MAX_HUBS 7 // maximum number of hubs that can be attached to the host controller
#define HUB_PORT_RESET_DELAY 20 // hub port reset delay 10 ms recomended, can be up to 20 ms #define HUB_PORT_RESET_DELAY 20 // hub port reset delay 10 ms recomended, can be up to 20 ms
/* USB state machine states */ /* USB state machine states */
#define USB_STATE_MASK 0xf0 #define USB_STATE_MASK 0xf0
@ -150,134 +139,138 @@ public:
/* USB Setup Packet Structure */ /* USB Setup Packet Structure */
typedef struct { typedef struct {
union { // offset description
uint8_t bmRequestType; // 0 Bit-map of request type union { // offset description
struct { uint8_t bmRequestType; // 0 Bit-map of request type
uint8_t recipient: 5; // Recipient of the request
uint8_t type: 2; // Type of request struct {
uint8_t direction: 1; // Direction of data X-fer uint8_t recipient : 5; // Recipient of the request
}; uint8_t type : 2; // Type of request
}ReqType_u; uint8_t direction : 1; // Direction of data X-fer
uint8_t bRequest; // 1 Request }__attribute__((packed));
union { } ReqType_u;
uint16_t wValue; // 2 Depends on bRequest uint8_t bRequest; // 1 Request
struct {
uint8_t wValueLo; union {
uint8_t wValueHi; uint16_t wValue; // 2 Depends on bRequest
};
}wVal_u; struct {
uint16_t wIndex; // 4 Depends on bRequest uint8_t wValueLo;
uint16_t wLength; // 6 Depends on bRequest uint8_t wValueHi;
} SETUP_PKT, *PSETUP_PKT; }__attribute__((packed));
} wVal_u;
uint16_t wIndex; // 4 Depends on bRequest
uint16_t wLength; // 6 Depends on bRequest
} SETUP_PKT, *PSETUP_PKT __attribute__((packed));
// Base class for incomming data parser // Base class for incomming data parser
class USBReadParser
{ class USBReadParser {
public: public:
virtual void Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset) = 0; virtual void Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset) = 0;
}; };
class USB : public MAX3421E {
AddressPoolImpl<USB_NUMDEVICES> addrPool;
USBDeviceConfig* devConfig[USB_NUMDEVICES];
uint8_t devConfigIndex;
uint8_t bmHubPre;
class USB : public MAX3421E public:
{ USB(void);
AddressPoolImpl<USB_NUMDEVICES> addrPool;
USBDeviceConfig* devConfig[USB_NUMDEVICES];
uint8_t devConfigIndex;
uint8_t bmHubPre;
public: void SetHubPreMask() {
USB( void ); bmHubPre |= bmHUBPRE;
};
void SetHubPreMask() { bmHubPre |= bmHUBPRE; }; void ResetHubPreMask() {
void ResetHubPreMask() { bmHubPre &= (~bmHUBPRE); }; bmHubPre &= (~bmHUBPRE);
};
AddressPool& GetAddressPool() AddressPool& GetAddressPool() {
{ return (AddressPool&) addrPool;
return (AddressPool&)addrPool; };
};
uint8_t RegisterDeviceClass(USBDeviceConfig *pdev)
{
for (uint8_t i=0; i<USB_NUMDEVICES; i++)
{
if (!devConfig[i])
{
devConfig[i] = pdev;
return 0;
}
}
return USB_ERROR_UNABLE_TO_REGISTER_DEVICE_CLASS;
};
void ForEachUsbDevice(UsbDeviceHandleFunc pfunc)
{
addrPool.ForEachUsbDevice(pfunc);
};
uint8_t getUsbTaskState( void );
void setUsbTaskState( uint8_t state );
EpInfo* getEpInfoEntry( uint8_t addr, uint8_t ep ); uint8_t RegisterDeviceClass(USBDeviceConfig *pdev) {
uint8_t setEpInfoEntry( uint8_t addr, uint8_t epcount, EpInfo* eprecord_ptr ); for (uint8_t i = 0; i < USB_NUMDEVICES; i++) {
if (!devConfig[i]) {
devConfig[i] = pdev;
return 0;
}
}
return USB_ERROR_UNABLE_TO_REGISTER_DEVICE_CLASS;
};
void ForEachUsbDevice(UsbDeviceHandleFunc pfunc) {
addrPool.ForEachUsbDevice(pfunc);
};
uint8_t getUsbTaskState(void);
void setUsbTaskState(uint8_t state);
EpInfo* getEpInfoEntry(uint8_t addr, uint8_t ep);
uint8_t setEpInfoEntry(uint8_t addr, uint8_t epcount, EpInfo* eprecord_ptr);
//uint8_t ctrlReq( uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bRequest, uint8_t wValLo, uint8_t wValHi, uint16_t wInd, uint16_t nbytes, uint8_t* dataptr); //uint8_t ctrlReq( uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bRequest, uint8_t wValLo, uint8_t wValHi, uint16_t wInd, uint16_t nbytes, uint8_t* dataptr);
/* Control requests */ /* Control requests */
uint8_t getDevDescr( uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* dataptr ); uint8_t getDevDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* dataptr);
uint8_t getConfDescr( uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t* dataptr ); uint8_t getConfDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t* dataptr);
uint8_t getConfDescr( uint8_t addr, uint8_t ep, uint8_t conf, USBReadParser *p ); uint8_t getConfDescr(uint8_t addr, uint8_t ep, uint8_t conf, USBReadParser *p);
uint8_t getStrDescr( uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t index, uint16_t langid, uint8_t* dataptr ); uint8_t getStrDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t index, uint16_t langid, uint8_t* dataptr);
uint8_t setAddr( uint8_t oldaddr, uint8_t ep, uint8_t newaddr ); uint8_t setAddr(uint8_t oldaddr, uint8_t ep, uint8_t newaddr);
uint8_t setConf( uint8_t addr, uint8_t ep, uint8_t conf_value ); uint8_t setConf(uint8_t addr, uint8_t ep, uint8_t conf_value);
/**/ /**/
uint8_t ctrlData( uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* dataptr, boolean direction ); uint8_t ctrlData(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* dataptr, boolean direction);
uint8_t ctrlStatus( uint8_t ep, boolean direction, uint16_t nak_limit ); uint8_t ctrlStatus(uint8_t ep, boolean direction, uint16_t nak_limit);
uint8_t inTransfer( uint8_t addr, uint8_t ep, uint16_t *nbytesptr, uint8_t* data ); uint8_t inTransfer(uint8_t addr, uint8_t ep, uint16_t *nbytesptr, uint8_t* data);
uint8_t outTransfer( uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* data ); uint8_t outTransfer(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* data);
uint8_t dispatchPkt( uint8_t token, uint8_t ep, uint16_t nak_limit ); uint8_t dispatchPkt(uint8_t token, uint8_t ep, uint16_t nak_limit);
void Task( void ); void Task(void);
uint8_t DefaultAddressing(uint8_t parent, uint8_t port, bool lowspeed); uint8_t DefaultAddressing(uint8_t parent, uint8_t port, bool lowspeed);
uint8_t Configuring(uint8_t parent, uint8_t port, bool lowspeed); uint8_t Configuring(uint8_t parent, uint8_t port, bool lowspeed);
uint8_t ReleaseDevice(uint8_t addr); uint8_t ReleaseDevice(uint8_t addr);
uint8_t ctrlReq( uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bRequest, uint8_t wValLo, uint8_t wValHi, uint8_t ctrlReq(uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bRequest, uint8_t wValLo, uint8_t wValHi,
uint16_t wInd, uint16_t total, uint16_t nbytes, uint8_t* dataptr, USBReadParser *p); uint16_t wInd, uint16_t total, uint16_t nbytes, uint8_t* dataptr, USBReadParser *p);
private: private:
void init(); void init();
uint8_t SetAddress(uint8_t addr, uint8_t ep, EpInfo **ppep, uint16_t &nak_limit); uint8_t SetAddress(uint8_t addr, uint8_t ep, EpInfo **ppep, uint16_t &nak_limit);
uint8_t OutTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t nbytes, uint8_t *data); uint8_t OutTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t nbytes, uint8_t *data);
uint8_t InTransfer (EpInfo *pep, uint16_t nak_limit, uint16_t *nbytesptr, uint8_t *data); uint8_t InTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t *nbytesptr, uint8_t *data);
}; };
#if 0 //defined(USB_METHODS_INLINE) #if 0 //defined(USB_METHODS_INLINE)
//get device descriptor //get device descriptor
inline uint8_t USB::getDevDescr( uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* dataptr )
{ inline uint8_t USB::getDevDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* dataptr) {
return( ctrlReq( addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, 0x00, USB_DESCRIPTOR_DEVICE, 0x0000, nbytes, dataptr )); return ( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, 0x00, USB_DESCRIPTOR_DEVICE, 0x0000, nbytes, dataptr));
} }
//get configuration descriptor //get configuration descriptor
inline uint8_t USB::getConfDescr( uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t* dataptr )
{ inline uint8_t USB::getConfDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t* dataptr) {
return( ctrlReq( addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, nbytes, dataptr )); return ( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, nbytes, dataptr));
} }
//get string descriptor //get string descriptor
inline uint8_t USB::getStrDescr( uint8_t addr, uint8_t ep, uint16_t nuint8_ts, uint8_t index, uint16_t langid, uint8_t* dataptr )
{ inline uint8_t USB::getStrDescr(uint8_t addr, uint8_t ep, uint16_t nuint8_ts, uint8_t index, uint16_t langid, uint8_t* dataptr) {
return( ctrlReq( addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, index, USB_DESCRIPTOR_STRING, langid, nuint8_ts, dataptr )); return ( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, index, USB_DESCRIPTOR_STRING, langid, nuint8_ts, dataptr));
} }
//set address //set address
inline uint8_t USB::setAddr( uint8_t oldaddr, uint8_t ep, uint8_t newaddr )
{ inline uint8_t USB::setAddr(uint8_t oldaddr, uint8_t ep, uint8_t newaddr) {
return( ctrlReq( oldaddr, ep, bmREQ_SET, USB_REQUEST_SET_ADDRESS, newaddr, 0x00, 0x0000, 0x0000, NULL )); return ( ctrlReq(oldaddr, ep, bmREQ_SET, USB_REQUEST_SET_ADDRESS, newaddr, 0x00, 0x0000, 0x0000, NULL));
} }
//set configuration //set configuration
inline uint8_t USB::setConf( uint8_t addr, uint8_t ep, uint8_t conf_value )
{ inline uint8_t USB::setConf(uint8_t addr, uint8_t ep, uint8_t conf_value) {
return( ctrlReq( addr, ep, bmREQ_SET, USB_REQUEST_SET_CONFIGURATION, conf_value, 0x00, 0x0000, 0x0000, NULL )); return ( ctrlReq(addr, ep, bmREQ_SET, USB_REQUEST_SET_CONFIGURATION, conf_value, 0x00, 0x0000, 0x0000, NULL));
} }
#endif // defined(USB_METHODS_INLINE) #endif // defined(USB_METHODS_INLINE)

394
address.h
View file

@ -13,7 +13,7 @@ Contact information
Circuits At Home, LTD Circuits At Home, LTD
Web : http://www.circuitsathome.com Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com e-mail : support@circuitsathome.com
*/ */
#if !defined(__ADDRESS_H__) #if !defined(__ADDRESS_H__)
#define __ADDRESS_H__ #define __ADDRESS_H__
@ -24,28 +24,25 @@ e-mail : support@circuitsathome.com
/* NAK powers. To save space in endpoint data structure, amount of retries before giving up and returning 0x4 is stored in */ /* NAK powers. To save space in endpoint data structure, amount of retries before giving up and returning 0x4 is stored in */
/* bmNakPower as a power of 2. The actual nak_limit is then calculated as nak_limit = ( 2^bmNakPower - 1) */ /* bmNakPower as a power of 2. The actual nak_limit is then calculated as nak_limit = ( 2^bmNakPower - 1) */
#define USB_NAK_MAX_POWER 16 //NAK binary order maximum value #define USB_NAK_MAX_POWER 15 //NAK binary order maximum value
#define USB_NAK_DEFAULT 14 //default 16K-1 NAKs before giving up #define USB_NAK_DEFAULT 14 //default 32K-1 NAKs before giving up
#define USB_NAK_NOWAIT 1 //Single NAK stops transfer #define USB_NAK_NOWAIT 1 //Single NAK stops transfer
#define USB_NAK_NONAK 0 //Do not count NAKs, stop retrying after USB Timeout #define USB_NAK_NONAK 0 //Do not count NAKs, stop retrying after USB Timeout
struct EpInfo struct EpInfo {
{ uint8_t epAddr; // Endpoint address
uint8_t epAddr; // Endpoint address uint8_t maxPktSize; // Maximum packet size
uint8_t maxPktSize; // Maximum packet size
union union {
{ uint8_t epAttribs;
uint8_t epAttribs;
struct struct {
{ uint8_t bmSndToggle : 1; // Send toggle, when zero bmSNDTOG0, bmSNDTOG1 otherwise
uint8_t bmSndToggle : 1; // Send toggle, when zero bmSNDTOG0, bmSNDTOG1 otherwise uint8_t bmRcvToggle : 1; // Send toggle, when zero bmRCVTOG0, bmRCVTOG1 otherwise
uint8_t bmRcvToggle : 1; // Send toggle, when zero bmRCVTOG0, bmRCVTOG1 otherwise uint8_t bmNakPower : 6; // Binary order for NAK_LIMIT value
uint8_t bmNakPower : 6; // Binary order for NAK_LIMIT value }__attribute__((packed));
}; };
}; }__attribute__((packed));
};
// 7 6 5 4 3 2 1 0 // 7 6 5 4 3 2 1 0
// --------------------------------- // ---------------------------------
@ -56,40 +53,38 @@ struct EpInfo
// P - parent hub address // P - parent hub address
// A - device address / port number in case of hub // A - device address / port number in case of hub
// //
struct UsbDeviceAddress
{ struct UsbDeviceAddress {
union
{ union {
struct
{ struct {
uint8_t bmAddress : 3; // device address/port number uint8_t bmAddress : 3; // device address/port number
uint8_t bmParent : 3; // parent hub address uint8_t bmParent : 3; // parent hub address
uint8_t bmHub : 1; // hub flag uint8_t bmHub : 1; // hub flag
uint8_t bmReserved : 1; // reserved, must be zerro uint8_t bmReserved : 1; // reserved, must be zerro
}; }__attribute__((packed));
uint8_t devAddress; uint8_t devAddress;
}; };
}; }__attribute__((packed));
#define bmUSB_DEV_ADDR_ADDRESS 0x07 #define bmUSB_DEV_ADDR_ADDRESS 0x07
#define bmUSB_DEV_ADDR_PARENT 0x38 #define bmUSB_DEV_ADDR_PARENT 0x38
#define bmUSB_DEV_ADDR_HUB 0x40 #define bmUSB_DEV_ADDR_HUB 0x40
struct UsbDevice struct UsbDevice {
{ EpInfo *epinfo; // endpoint info pointer
EpInfo *epinfo; // endpoint info pointer uint8_t address; // address
uint8_t address; // address uint8_t epcount; // number of endpoints
uint8_t epcount; // number of endpoints bool lowspeed; // indicates if a device is the low speed one
bool lowspeed; // indicates if a device is the low speed one // uint8_t devclass; // device class
// uint8_t devclass; // device class }__attribute__((packed));
};
class AddressPool class AddressPool {
{
public: public:
virtual UsbDevice* GetUsbDevicePtr(uint8_t addr) = 0; virtual UsbDevice* GetUsbDevicePtr(uint8_t addr) = 0;
virtual uint8_t AllocAddress(uint8_t parent, bool is_hub = false, uint8_t port = 0) = 0; virtual uint8_t AllocAddress(uint8_t parent, bool is_hub = false, uint8_t port = 0) = 0;
virtual void FreeAddress(uint8_t addr) = 0; virtual void FreeAddress(uint8_t addr) = 0;
}; };
typedef void (*UsbDeviceHandleFunc)(UsbDevice *pdev); typedef void (*UsbDeviceHandleFunc)(UsbDevice *pdev);
@ -98,191 +93,180 @@ typedef void (*UsbDeviceHandleFunc)(UsbDevice *pdev);
#define ADDR_ERROR_INVALID_ADDRESS 0xFF #define ADDR_ERROR_INVALID_ADDRESS 0xFF
template <const uint8_t MAX_DEVICES_ALLOWED> template <const uint8_t MAX_DEVICES_ALLOWED>
class AddressPoolImpl : public AddressPool class AddressPoolImpl : public AddressPool {
{ EpInfo dev0ep; //Endpoint data structure used during enumeration for uninitialized device
EpInfo dev0ep; //Endpoint data structure used during enumeration for uninitialized device
uint8_t hubCounter; // hub counter is kept uint8_t hubCounter; // hub counter is kept
// in order to avoid hub address duplication // in order to avoid hub address duplication
UsbDevice thePool[MAX_DEVICES_ALLOWED]; UsbDevice thePool[MAX_DEVICES_ALLOWED];
// Initializes address pool entry // Initializes address pool entry
void InitEntry(uint8_t index)
{
thePool[index].address = 0;
thePool[index].epcount = 1;
thePool[index].lowspeed = 0;
thePool[index].epinfo = &dev0ep;
};
// Returns thePool index for a given address
uint8_t FindAddressIndex(uint8_t address = 0)
{
for (uint8_t i=1; i<MAX_DEVICES_ALLOWED; i++)
{
if (thePool[i].address == address)
return i;
}
return 0;
};
// Returns thePool child index for a given parent
uint8_t FindChildIndex(UsbDeviceAddress addr, uint8_t start = 1)
{
for (uint8_t i=(start<1 || start>=MAX_DEVICES_ALLOWED) ? 1 : start; i<MAX_DEVICES_ALLOWED; i++)
{
if (((UsbDeviceAddress*)&thePool[i].address)->bmParent == addr.bmAddress)
return i;
}
return 0;
};
// Frees address entry specified by index parameter
void FreeAddressByIndex(uint8_t index)
{
// Zerro field is reserved and should not be affected
if (index == 0)
return;
// If a hub was switched off all port addresses should be freed void InitEntry(uint8_t index) {
if (((UsbDeviceAddress*)&thePool[index].address)->bmHub == 1) thePool[index].address = 0;
{ thePool[index].epcount = 1;
for (uint8_t i=1; i = FindChildIndex(*((UsbDeviceAddress*)&thePool[index].address), i); ) thePool[index].lowspeed = 0;
FreeAddressByIndex(i); thePool[index].epinfo = &dev0ep;
};
// Returns thePool index for a given address
// If the hub had the last allocated address, hubCounter should be decremented uint8_t FindAddressIndex(uint8_t address = 0) {
if (hubCounter == ((UsbDeviceAddress*)&thePool[index].address)->bmAddress) for (uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++) {
hubCounter --; if (thePool[i].address == address)
} return i;
InitEntry(index); }
} return 0;
// Initializes the whole address pool at once };
void InitAllAddresses() // Returns thePool child index for a given parent
{
for (uint8_t i=1; i<MAX_DEVICES_ALLOWED; i++)
InitEntry(i);
hubCounter = 0; uint8_t FindChildIndex(UsbDeviceAddress addr, uint8_t start = 1) {
}; for (uint8_t i = (start < 1 || start >= MAX_DEVICES_ALLOWED) ? 1 : start; i < MAX_DEVICES_ALLOWED; i++) {
if (((UsbDeviceAddress*) & thePool[i].address)->bmParent == addr.bmAddress)
return i;
}
return 0;
};
// Frees address entry specified by index parameter
void FreeAddressByIndex(uint8_t index) {
// Zerro field is reserved and should not be affected
if (index == 0)
return;
// If a hub was switched off all port addresses should be freed
if (((UsbDeviceAddress*) & thePool[index].address)->bmHub == 1) {
for (uint8_t i = 1; (i = FindChildIndex(*((UsbDeviceAddress*) & thePool[index].address), i));)
FreeAddressByIndex(i);
// If the hub had the last allocated address, hubCounter should be decremented
if (hubCounter == ((UsbDeviceAddress*) & thePool[index].address)->bmAddress)
hubCounter--;
}
InitEntry(index);
}
// Initializes the whole address pool at once
void InitAllAddresses() {
for (uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++)
InitEntry(i);
hubCounter = 0;
};
public: public:
AddressPoolImpl() : hubCounter(0)
{
// Zero address is reserved
InitEntry(0);
thePool[0].address = 0; AddressPoolImpl() : hubCounter(0) {
thePool[0].epinfo = &dev0ep; // Zero address is reserved
dev0ep.epAddr = 0; InitEntry(0);
dev0ep.maxPktSize = 8;
dev0ep.epAttribs = 0; //set DATA0/1 toggles to 0
dev0ep.bmNakPower = USB_NAK_MAX_POWER;
InitAllAddresses(); thePool[0].address = 0;
}; thePool[0].epinfo = &dev0ep;
// Returns a pointer to a specified address entry dev0ep.epAddr = 0;
virtual UsbDevice* GetUsbDevicePtr(uint8_t addr) dev0ep.maxPktSize = 8;
{ dev0ep.epAttribs = 0; //set DATA0/1 toggles to 0
if (!addr) dev0ep.bmNakPower = USB_NAK_MAX_POWER;
return thePool;
uint8_t index = FindAddressIndex(addr); InitAllAddresses();
};
// Returns a pointer to a specified address entry
return (!index) ? NULL : thePool + index; virtual UsbDevice* GetUsbDevicePtr(uint8_t addr) {
}; if (!addr)
return thePool;
// Performs an operation specified by pfunc for each addressed device uint8_t index = FindAddressIndex(addr);
void ForEachUsbDevice(UsbDeviceHandleFunc pfunc)
{
if (!pfunc)
return;
for (uint8_t i=1; i<MAX_DEVICES_ALLOWED; i++) return (!index) ? NULL : thePool + index;
if (thePool[i].address) };
pfunc(thePool + i);
};
// Allocates new address
virtual uint8_t AllocAddress(uint8_t parent, bool is_hub = false, uint8_t port = 0)
{
/* if (parent != 0 && port == 0)
Serial.println("PRT:0"); */
if (parent > 127 || port > 7) // Performs an operation specified by pfunc for each addressed device
return 0;
if (is_hub && hubCounter == 7) void ForEachUsbDevice(UsbDeviceHandleFunc pfunc) {
return 0; if (!pfunc)
return;
// finds first empty address entry starting from one for (uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++)
uint8_t index = FindAddressIndex(0); if (thePool[i].address)
pfunc(thePool + i);
};
// Allocates new address
if (!index) // if empty entry is not found virtual uint8_t AllocAddress(uint8_t parent, bool is_hub = false, uint8_t port = 0) {
return 0; /* if (parent != 0 && port == 0)
Serial.println("PRT:0"); */
if (parent == 0) if (parent > 127 || port > 7)
{ return 0;
if (is_hub)
{
thePool[index].address = 0x41;
hubCounter ++;
}
else
thePool[index].address = 1;
return thePool[index].address; if (is_hub && hubCounter == 7)
} return 0;
UsbDeviceAddress addr; // finds first empty address entry starting from one
uint8_t index = FindAddressIndex(0);
addr.bmParent = ((UsbDeviceAddress*)&parent)->bmAddress; if (!index) // if empty entry is not found
return 0;
if (is_hub) if (parent == 0) {
{ if (is_hub) {
addr.bmHub = 1; thePool[index].address = 0x41;
addr.bmAddress = ++hubCounter; hubCounter++;
} } else
else thePool[index].address = 1;
{
addr.bmHub = 0;
addr.bmAddress = port;
}
thePool[index].address = *((uint8_t*)&addr);
/*
Serial.print("Addr:");
Serial.print(addr.bmHub, HEX);
Serial.print(".");
Serial.print(addr.bmParent, HEX);
Serial.print(".");
Serial.println(addr.bmAddress, HEX);
*/
return thePool[index].address;
};
// Empties pool entry
virtual void FreeAddress(uint8_t addr)
{
// if the root hub is disconnected all the addresses should be initialized
if (addr == 0x41)
{
InitAllAddresses();
return;
}
uint8_t index = FindAddressIndex(addr);
FreeAddressByIndex(index);
};
// Returns number of hubs attached
// It can be rather helpfull to find out if there are hubs attached than getting the exact number of hubs.
//uint8_t GetNumHubs()
//{
// return hubCounter;
//};
//uint8_t GetNumDevices()
//{
// uint8_t counter = 0;
// for (uint8_t i=1; i<MAX_DEVICES_ALLOWED; i++) return thePool[index].address;
// if (thePool[i].address != 0); }
// counter ++;
// return counter; UsbDeviceAddress addr;
//};
addr.bmParent = ((UsbDeviceAddress*) & parent)->bmAddress;
if (is_hub) {
addr.bmHub = 1;
addr.bmAddress = ++hubCounter;
} else {
addr.bmHub = 0;
addr.bmAddress = port;
}
thePool[index].address = *((uint8_t*) & addr);
/*
Serial.print("Addr:");
Serial.print(addr.bmHub, HEX);
Serial.print(".");
Serial.print(addr.bmParent, HEX);
Serial.print(".");
Serial.println(addr.bmAddress, HEX);
*/
return thePool[index].address;
};
// Empties pool entry
virtual void FreeAddress(uint8_t addr) {
// if the root hub is disconnected all the addresses should be initialized
if (addr == 0x41) {
InitAllAddresses();
return;
}
uint8_t index = FindAddressIndex(addr);
FreeAddressByIndex(index);
};
// Returns number of hubs attached
// It can be rather helpfull to find out if there are hubs attached than getting the exact number of hubs.
//uint8_t GetNumHubs()
//{
// return hubCounter;
//};
//uint8_t GetNumDevices()
//{
// uint8_t counter = 0;
// for (uint8_t i=1; i<MAX_DEVICES_ALLOWED; i++)
// if (thePool[i].address != 0);
// counter ++;
// return counter;
//};
}; };
#endif // __ADDRESS_H__ #endif // __ADDRESS_H__

529
adk.cpp
View file

@ -13,371 +13,320 @@ Contact information
Circuits At Home, LTD Circuits At Home, LTD
Web : http://www.circuitsathome.com Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com e-mail : support@circuitsathome.com
*/ */
/* Google ADK interface */ /* Google ADK interface */
#include "adk.h" #include "adk.h"
#define DEBUG // Uncomment to print data for debugging
const uint8_t ADK::epDataInIndex = 1; const uint8_t ADK::epDataInIndex = 1;
const uint8_t ADK::epDataOutIndex = 2; const uint8_t ADK::epDataOutIndex = 2;
ADK::ADK(USB *p, const char* manufacturer, ADK::ADK(USB *p, const char* manufacturer,
const char* model, const char* model,
const char* description, const char* description,
const char* version, const char* version,
const char* uri, const char* uri,
const char* serial) : const char* serial) :
pUsb(p), //pointer to USB class instance - mandatory /* ADK ID Strings */
bAddress(0), //device address - mandatory
bNumEP(1), //if config descriptor needs to be parsed
ready(false),
/* ADK ID Strings */ manufacturer(manufacturer),
model(model),
description(description),
version(version),
uri(uri),
serial(serial),
pUsb(p), //pointer to USB class instance - mandatory
bAddress(0), //device address - mandatory
bConfNum(0), //configuration number
bNumEP(1), //if config descriptor needs to be parsed
ready(false)
{
// initialize endpoint data structures
for (uint8_t i = 0; i < ADK_MAX_ENDPOINTS; i++) {
epInfo[i].epAddr = 0;
epInfo[i].maxPktSize = (i) ? 0 : 8;
epInfo[i].epAttribs = (0xfc & (USB_NAK_MAX_POWER << 2));
}//for(uint8_t i=0; i<ADK_MAX_ENDPOINTS; i++...
manufacturer(manufacturer), //set bulk-IN EP naklimit to 1
model(model), epInfo[epDataInIndex].epAttribs = (0xfc & (USB_NAK_NOWAIT << 2));
description(description),
version(version),
uri(uri),
serial(serial)
{ // register in USB subsystem
// initialize endpoint data structures if (pUsb) {
for(uint8_t i=0; i<ADK_MAX_ENDPOINTS; i++) { pUsb->RegisterDeviceClass(this); //set devConfig[] entry
epInfo[i].epAddr = 0; }
epInfo[i].maxPktSize = (i) ? 0 : 8;
epInfo[i].epAttribs = 0;
epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER;
}//for(uint8_t i=0; i<ADK_MAX_ENDPOINTS; i++...
// register in USB subsystem
if (pUsb) {
pUsb->RegisterDeviceClass(this); //set devConfig[] entry
}
} }
/* Connection initialization of an Android phone */ /* Connection initialization of an Android phone */
uint8_t ADK::Init(uint8_t parent, uint8_t port, bool lowspeed) uint8_t ADK::Init(uint8_t parent, uint8_t port, bool lowspeed) {
{
uint8_t buf[sizeof(USB_DEVICE_DESCRIPTOR)]; uint8_t buf[sizeof (USB_DEVICE_DESCRIPTOR)];
uint8_t rcode; uint8_t rcode;
UsbDevice *p = NULL; UsbDevice *p = NULL;
EpInfo *oldep_ptr = NULL; EpInfo *oldep_ptr = NULL;
uint8_t num_of_conf; // number of configurations uint8_t num_of_conf; // number of configurations
// get memory address of USB device address pool // get memory address of USB device address pool
AddressPool &addrPool = pUsb->GetAddressPool(); AddressPool &addrPool = pUsb->GetAddressPool();
#ifdef DEBUG
USBTRACE("\r\nADK Init");
#endif
// check if address has already been assigned to an instance
if (bAddress) {
#ifdef DEBUG
USBTRACE("\r\nAddress in use");
#endif
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
}
// Get pointer to pseudo device with address 0 assigned USBTRACE("\r\nADK Init");
p = addrPool.GetUsbDevicePtr(0);
if (!p) { // check if address has already been assigned to an instance
#ifdef DEBUG if (bAddress) {
USBTRACE("\r\nAddress not found"); USBTRACE("\r\nAddress in use");
#endif return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; }
}
if (!p->epinfo) { // Get pointer to pseudo device with address 0 assigned
#ifdef DEBUG p = addrPool.GetUsbDevicePtr(0);
USBTRACE("epinfo is null\r\n");
#endif
return USB_ERROR_EPINFO_IS_NULL;
}
// Save old pointer to EP_RECORD of address 0 if (!p) {
oldep_ptr = p->epinfo; USBTRACE("\r\nAddress not found");
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
}
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence if (!p->epinfo) {
p->epinfo = epInfo; USBTRACE("epinfo is null\r\n");
return USB_ERROR_EPINFO_IS_NULL;
}
p->lowspeed = lowspeed; // Save old pointer to EP_RECORD of address 0
oldep_ptr = p->epinfo;
// Get device descriptor // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
rcode = pUsb->getDevDescr( 0, 0, sizeof(USB_DEVICE_DESCRIPTOR), (uint8_t*)buf ); p->epinfo = epInfo;
// Restore p->epinfo p->lowspeed = lowspeed;
p->epinfo = oldep_ptr;
if( rcode ){ // Get device descriptor
goto FailGetDevDescr; rcode = pUsb->getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), (uint8_t*) buf);
}
// Allocate new address according to device class // Restore p->epinfo
bAddress = addrPool.AllocAddress(parent, false, port); p->epinfo = oldep_ptr;
// Extract Max Packet Size from device descriptor if (rcode) {
epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0; goto FailGetDevDescr;
}
// Assign new address to the device // Allocate new address according to device class
rcode = pUsb->setAddr( 0, 0, bAddress ); bAddress = addrPool.AllocAddress(parent, false, port);
if (rcode) {
p->lowspeed = false;
addrPool.FreeAddress(bAddress);
bAddress = 0;
//USBTRACE2("setAddr:",rcode);
return rcode;
}//if (rcode...
//USBTRACE2("\r\nAddr:", bAddress); // Extract Max Packet Size from device descriptor
epInfo[0].maxPktSize = (uint8_t) ((USB_DEVICE_DESCRIPTOR*) buf)->bMaxPacketSize0;
p->lowspeed = false; // Assign new address to the device
rcode = pUsb->setAddr(0, 0, bAddress);
if (rcode) {
p->lowspeed = false;
addrPool.FreeAddress(bAddress);
bAddress = 0;
//USBTRACE2("setAddr:",rcode);
return rcode;
}//if (rcode...
//get pointer to assigned address record //USBTRACE2("\r\nAddr:", bAddress);
p = addrPool.GetUsbDevicePtr(bAddress);
if (!p) {
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
}
p->lowspeed = lowspeed; p->lowspeed = false;
// Assign epInfo to epinfo pointer - only EP0 is known //get pointer to assigned address record
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo); p = addrPool.GetUsbDevicePtr(bAddress);
if (rcode) { if (!p) {
goto FailSetDevTblEntry; return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
} }
//check if ADK device is already in accessory mode; if yes, configure and exit p->lowspeed = lowspeed;
if(((USB_DEVICE_DESCRIPTOR*)buf)->idVendor == ADK_VID &&
(((USB_DEVICE_DESCRIPTOR*)buf)->idProduct == ADK_PID || ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct == ADB_PID)) {
#ifdef DEBUG
USBTRACE("\r\nAcc.mode device detected");
#endif
/* go through configurations, find first bulk-IN, bulk-OUT EP, fill epInfo and quit */
num_of_conf = ((USB_DEVICE_DESCRIPTOR*)buf)->bNumConfigurations;
//USBTRACE2("\r\nNC:",num_of_conf); // Assign epInfo to epinfo pointer - only EP0 is known
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
if (rcode) {
goto FailSetDevTblEntry;
}
for (uint8_t i=0; i<num_of_conf; i++) { //check if ADK device is already in accessory mode; if yes, configure and exit
ConfigDescParser<0, 0, 0, 0> confDescrParser(this); if (((USB_DEVICE_DESCRIPTOR*) buf)->idVendor == ADK_VID &&
delay(1); (((USB_DEVICE_DESCRIPTOR*) buf)->idProduct == ADK_PID || ((USB_DEVICE_DESCRIPTOR*) buf)->idProduct == ADB_PID)) {
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser); USBTRACE("\r\nAcc.mode device detected");
#if defined(XOOM) /* go through configurations, find first bulk-IN, bulk-OUT EP, fill epInfo and quit */
//added by Jaylen Scott Vanorden num_of_conf = ((USB_DEVICE_DESCRIPTOR*) buf)->bNumConfigurations;
if( rcode ) {
#ifdef DEBUG //USBTRACE2("\r\nNC:",num_of_conf);
USBTRACE2("\r\nGot 1st bad code for config: ", rcode);
#endif for (uint8_t i = 0; i < num_of_conf; i++) {
// Try once more ConfigDescParser < 0, 0, 0, 0 > confDescrParser(this);
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser); rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
if (rcode) {
goto FailGetConfDescr;
}
if (bNumEP > 2) {
break;
}
} // for (uint8_t i=0; i<num_of_conf; i++...
if (bNumEP == 3) {
// Assign epInfo to epinfo pointer - this time all 3 endpoins
rcode = pUsb->setEpInfoEntry(bAddress, 3, epInfo);
if (rcode) {
goto FailSetDevTblEntry;
}
} }
#endif
if( rcode ) {
goto FailGetConfDescr;
}
if( bNumEP > 2 ) {
break;
}
} // for (uint8_t i=0; i<num_of_conf; i++...
if( bNumEP == 3 ) {
// Assign epInfo to epinfo pointer - this time all 3 endpoins
rcode = pUsb->setEpInfoEntry(bAddress, 3, epInfo); // Set Configuration Value
rcode = pUsb->setConf(bAddress, 0, bConfNum);
if (rcode) { if (rcode) {
goto FailSetDevTblEntry; goto FailSetConf;
} }
} /* print endpoint structure */
// USBTRACE("\r\nEndpoint Structure:");
// USBTRACE("\r\nEP0:");
// USBTRACE2("\r\nAddr: ", epInfo[0].epAddr );
// USBTRACE2("\r\nMax.pkt.size: ", epInfo[0].maxPktSize );
// USBTRACE2("\r\nAttr: ", epInfo[0].epAttribs );
// USBTRACE("\r\nEpout:");
// USBTRACE2("\r\nAddr: ", epInfo[epDataOutIndex].epAddr );
// USBTRACE2("\r\nMax.pkt.size: ", epInfo[epDataOutIndex].maxPktSize );
// USBTRACE2("\r\nAttr: ", epInfo[epDataOutIndex].epAttribs );
// USBTRACE("\r\nEpin:");
// USBTRACE2("\r\nAddr: ", epInfo[epDataInIndex].epAddr );
// USBTRACE2("\r\nMax.pkt.size: ", epInfo[epDataInIndex].maxPktSize );
// USBTRACE2("\r\nAttr: ", epInfo[epDataInIndex].epAttribs );
USBTRACE("\r\nConfiguration successful");
ready = true;
return 0; //successful configuration
}//if( buf->idVendor == ADK_VID...
//probe device - get accessory protocol revision
{
uint16_t adkproto = -1;
rcode = getProto((uint8_t*) & adkproto);
if (rcode) {
goto FailGetProto; //init fails
}
USBTRACE2("\r\nADK protocol rev. ", adkproto);
}
// Set Configuration Value //sending ID strings
rcode = pUsb->setConf(bAddress, 0, bConfNum); sendStr(ACCESSORY_STRING_MANUFACTURER, manufacturer);
if( rcode ){ sendStr(ACCESSORY_STRING_MODEL, model);
goto FailSetConf; sendStr(ACCESSORY_STRING_DESCRIPTION, description);
} sendStr(ACCESSORY_STRING_VERSION, version);
/* print endpoint structure */ sendStr(ACCESSORY_STRING_URI, uri);
// USBTRACE("\r\nEndpoint Structure:"); sendStr(ACCESSORY_STRING_SERIAL, serial);
// USBTRACE("\r\nEP0:");
// USBTRACE2("\r\nAddr: ", epInfo[0].epAddr );
// USBTRACE2("\r\nMax.pkt.size: ", epInfo[0].maxPktSize );
// USBTRACE2("\r\nAttr: ", epInfo[0].epAttribs );
// USBTRACE("\r\nEpout:");
// USBTRACE2("\r\nAddr: ", epInfo[epDataOutIndex].epAddr );
// USBTRACE2("\r\nMax.pkt.size: ", epInfo[epDataOutIndex].maxPktSize );
// USBTRACE2("\r\nAttr: ", epInfo[epDataOutIndex].epAttribs );
// USBTRACE("\r\nEpin:");
// USBTRACE2("\r\nAddr: ", epInfo[epDataInIndex].epAddr );
// USBTRACE2("\r\nMax.pkt.size: ", epInfo[epDataInIndex].maxPktSize );
// USBTRACE2("\r\nAttr: ", epInfo[epDataInIndex].epAttribs );
#ifdef DEBUG
USBTRACE("\r\nConfiguration successful");
#endif
ready = true;
return 0; //successful configuration
}//if( buf->idVendor == ADK_VID...
//probe device - get accessory protocol revision //switch to accessory mode
{ //the Android phone will reset
uint16_t adkproto = -1; rcode = switchAcc();
delay(1); if (rcode) {
rcode = getProto((uint8_t*)&adkproto ); goto FailSwAcc; //init fails
#if defined(XOOM) }
//added by Jaylen Scott Vanorden rcode = -1;
if( rcode ) { goto SwAttempt; //switch to accessory mode attempted
#ifdef DEBUG
USBTRACE2("\r\nGot 1st bad code for proto: ", rcode);
#endif
// Try once more
rcode = getProto((uint8_t*)&adkproto );
}
#endif
if( rcode ){
goto FailGetProto; //init fails
}
#ifdef DEBUG
USBTRACE2("\r\nADK protocol rev. ", adkproto );
#endif
}
//sending ID strings /* diagnostic messages */
sendStr( ACCESSORY_STRING_MANUFACTURER, manufacturer);
sendStr( ACCESSORY_STRING_MODEL, model);
sendStr( ACCESSORY_STRING_DESCRIPTION, description);
sendStr( ACCESSORY_STRING_VERSION, version);
sendStr( ACCESSORY_STRING_URI, uri);
sendStr( ACCESSORY_STRING_SERIAL, serial);
//switch to accessory mode
//the Android phone will reset
rcode = switchAcc();
if( rcode ) {
goto FailSwAcc; //init fails
}
rcode = -1;
goto SwAttempt; //switch to accessory mode attempted
/* diagnostic messages */
FailGetDevDescr: FailGetDevDescr:
#ifdef DEBUG USBTRACE("\r\ngetDevDescr:");
USBTRACE("\r\ngetDevDescr:"); goto Fail;
#endif
goto Fail;
FailSetDevTblEntry: FailSetDevTblEntry:
#ifdef DEBUG USBTRACE("\r\nsetDevTblEn:");
USBTRACE("\r\nsetDevTblEn:"); goto Fail;
#endif
goto Fail;
FailGetProto: FailGetProto:
#ifdef DEBUG USBTRACE("\r\ngetProto:");
USBTRACE("\r\ngetProto:"); goto Fail;
#endif
goto Fail;
FailSwAcc: FailSwAcc:
#ifdef DEBUG USBTRACE("\r\nswAcc:");
USBTRACE("\r\nswAcc:"); goto Fail;
#endif
goto Fail;
SwAttempt: SwAttempt:
#ifdef DEBUG USBTRACE("\r\nAccessory mode switch attempt");
USBTRACE("\r\nAccessory mode switch attempt"); goto Fail;
#endif
goto Fail;
FailGetConfDescr: FailGetConfDescr:
// USBTRACE("getConf:"); // USBTRACE("getConf:");
goto Fail; goto Fail;
// //
FailSetConf: FailSetConf:
// USBTRACE("setConf:"); // USBTRACE("setConf:");
goto Fail; goto Fail;
// //
//FailOnInit: //FailOnInit:
// USBTRACE("OnInit:"); // USBTRACE("OnInit:");
// goto Fail; // goto Fail;
// //
Fail: Fail:
//USBTRACE2("\r\nADK Init Failed, error code: ", rcode); //USBTRACE2("\r\nADK Init Failed, error code: ", rcode);
Release(); Release();
return rcode; return rcode;
} }
/* Extracts bulk-IN and bulk-OUT endpoint information from config descriptor */ /* Extracts bulk-IN and bulk-OUT endpoint information from config descriptor */
void ADK::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) void ADK::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) {
{ //ErrorMessage<uint8_t>(PSTR("Conf.Val"), conf);
//ErrorMessage<uint8_t>(PSTR("Conf.Val"), conf); //ErrorMessage<uint8_t>(PSTR("Iface Num"),iface);
//ErrorMessage<uint8_t>(PSTR("Iface Num"),iface); //ErrorMessage<uint8_t>(PSTR("Alt.Set"), alt);
//ErrorMessage<uint8_t>(PSTR("Alt.Set"), alt);
//added by Yuuichi Akagawa //added by Yuuichi Akagawa
if( bNumEP == 3 ) { if (bNumEP == 3) {
return; return;
} }
bConfNum = conf; bConfNum = conf;
uint8_t index; uint8_t index;
if ((pep->bmAttributes & 0x02) == 2) { // if ((pep->bmAttributes & 0x02) == 2) {
index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex; index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex;
} // }
// Fill in the endpoint info structure // Fill in the endpoint info structure
epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F); epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize; epInfo[index].maxPktSize = (uint8_t) pep->wMaxPacketSize;
bNumEP ++; bNumEP++;
//PrintEndpointDescriptor(pep); //PrintEndpointDescriptor(pep);
} }
/* Performs a cleanup after failed Init() attempt */ /* Performs a cleanup after failed Init() attempt */
uint8_t ADK::Release() uint8_t ADK::Release() {
{ pUsb->GetAddressPool().FreeAddress(bAddress);
pUsb->GetAddressPool().FreeAddress(bAddress);
bNumEP = 1; //must have to be reset to 1 bNumEP = 1; //must have to be reset to 1
bAddress = 0; bAddress = 0;
ready = false; ready = false;
return 0; return 0;
} }
uint8_t ADK::RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr) uint8_t ADK::RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr) {
{ //USBTRACE2("\r\nAddr: ", bAddress );
//USBTRACE2("\r\nAddr: ", bAddress ); //USBTRACE2("\r\nEP: ",epInfo[epDataInIndex].epAddr);
//USBTRACE2("\r\nEP: ",epInfo[epDataInIndex].epAddr); return pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, dataptr);
return pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, dataptr);
} }
uint8_t ADK::SndData(uint16_t nbytes, uint8_t *dataptr) uint8_t ADK::SndData(uint16_t nbytes, uint8_t *dataptr) {
{ return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, nbytes, dataptr);
return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, nbytes, dataptr);
} }
void ADK::PrintEndpointDescriptor( const USB_ENDPOINT_DESCRIPTOR* ep_ptr ) void ADK::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr) {
{ Notify(PSTR("Endpoint descriptor:"), 0x80);
#ifdef DEBUG Notify(PSTR("\r\nLength:\t\t"), 0x80);
Notify(PSTR("Endpoint descriptor:")); PrintHex<uint8_t > (ep_ptr->bLength, 0x80);
Notify(PSTR("\r\nLength:\t\t")); Notify(PSTR("\r\nType:\t\t"), 0x80);
PrintHex<uint8_t>(ep_ptr->bLength); PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80);
Notify(PSTR("\r\nType:\t\t")); Notify(PSTR("\r\nAddress:\t"), 0x80);
PrintHex<uint8_t>(ep_ptr->bDescriptorType); PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80);
Notify(PSTR("\r\nAddress:\t")); Notify(PSTR("\r\nAttributes:\t"), 0x80);
PrintHex<uint8_t>(ep_ptr->bEndpointAddress); PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80);
Notify(PSTR("\r\nAttributes:\t")); Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
PrintHex<uint8_t>(ep_ptr->bmAttributes); PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80);
Notify(PSTR("\r\nMaxPktSize:\t")); Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
PrintHex<uint16_t>(ep_ptr->wMaxPacketSize); PrintHex<uint8_t > (ep_ptr->bInterval, 0x80);
Notify(PSTR("\r\nPoll Intrv:\t")); Notify(PSTR("\r\n"), 0x80);
PrintHex<uint8_t>(ep_ptr->bInterval);
Notify(PSTR("\r\n"));
#endif
} }

114
adk.h
View file

@ -13,7 +13,7 @@ Contact information
Circuits At Home, LTD Circuits At Home, LTD
Web : http://www.circuitsathome.com Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com e-mail : support@circuitsathome.com
*/ */
/* Google ADK interface support header */ /* Google ADK interface support header */
@ -44,10 +44,6 @@ e-mail : support@circuitsathome.com
#define ADK_PID 0x2D00 #define ADK_PID 0x2D00
#define ADB_PID 0x2D01 #define ADB_PID 0x2D01
#define XOOM //enables repeating getProto() and getConf() attempts
//necessary for slow devices such as Motorola XOOM
//defined by default, can be commented out to save memory
/* requests */ /* requests */
#define ADK_GETPROTO 51 //check USB accessory protocol version #define ADK_GETPROTO 51 //check USB accessory protocol version
@ -68,78 +64,86 @@ e-mail : support@circuitsathome.com
class ADK; class ADK;
class ADK : public USBDeviceConfig, public UsbConfigXtracter class ADK : public USBDeviceConfig, public UsbConfigXtracter {
{
private: private:
/* ID strings */ /* ID strings */
const char* manufacturer; const char* manufacturer;
const char* model; const char* model;
const char* description; const char* description;
const char* version; const char* version;
const char* uri; const char* uri;
const char* serial; const char* serial;
/* ADK proprietary requests */ /* ADK proprietary requests */
uint8_t getProto( uint8_t* adkproto ); uint8_t getProto(uint8_t* adkproto);
uint8_t sendStr( uint8_t index, const char* str ); uint8_t sendStr(uint8_t index, const char* str);
uint8_t switchAcc( void ); uint8_t switchAcc(void);
protected: protected:
static const uint8_t epDataInIndex; // DataIn endpoint index static const uint8_t epDataInIndex; // DataIn endpoint index
static const uint8_t epDataOutIndex; // DataOUT endpoint index static const uint8_t epDataOutIndex; // DataOUT endpoint index
/* mandatory members */ /* mandatory members */
USB *pUsb; USB *pUsb;
uint8_t bAddress; uint8_t bAddress;
uint8_t bConfNum; // configuration number uint8_t bConfNum; // configuration number
uint8_t bNumEP; // total number of EP in the configuration uint8_t bNumEP; // total number of EP in the configuration
bool ready; bool ready;
/* Endpoint data structure */ /* Endpoint data structure */
EpInfo epInfo[ADK_MAX_ENDPOINTS]; EpInfo epInfo[ADK_MAX_ENDPOINTS];
void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr); void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr);
public: public:
ADK(USB *pUsb, const char* manufacturer, ADK(USB *pUsb, const char* manufacturer,
const char* model, const char* model,
const char* description, const char* description,
const char* version, const char* version,
const char* uri, const char* uri,
const char* serial); const char* serial);
// Methods for receiving and sending data // Methods for receiving and sending data
uint8_t RcvData(uint16_t *nbytesptr, uint8_t *dataptr); uint8_t RcvData(uint16_t *nbytesptr, uint8_t *dataptr);
uint8_t SndData(uint16_t nbytes, uint8_t *dataptr); uint8_t SndData(uint16_t nbytes, uint8_t *dataptr);
// USBDeviceConfig implementation // USBDeviceConfig implementation
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed); virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
virtual uint8_t Release(); virtual uint8_t Release();
virtual uint8_t Poll(){}; //not implemented
virtual uint8_t GetAddress() { return bAddress; };
virtual bool isReady() { return ready; };
//UsbConfigXtracter implementation virtual uint8_t Poll() {
virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep); return 0;
};
virtual uint8_t GetAddress() {
return bAddress;
};
virtual bool isReady() {
return ready;
};
//UsbConfigXtracter implementation
virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
}; //class ADK : public USBDeviceConfig ... }; //class ADK : public USBDeviceConfig ...
/* get ADK protocol version */ /* get ADK protocol version */
/* returns 2 bytes in *adkproto */ /* returns 2 bytes in *adkproto */
inline uint8_t ADK::getProto( uint8_t* adkproto ) inline uint8_t ADK::getProto(uint8_t* adkproto) {
{ return ( pUsb->ctrlReq(bAddress, 0, bmREQ_ADK_GET, ADK_GETPROTO, 0, 0, 0, 2, 2, adkproto, NULL));
return( pUsb->ctrlReq(bAddress, 0, bmREQ_ADK_GET, ADK_GETPROTO, 0, 0, 0, 2, 2, adkproto, NULL ));
} }
/* send ADK string */ /* send ADK string */
inline uint8_t ADK::sendStr( uint8_t index, const char* str ) inline uint8_t ADK::sendStr(uint8_t index, const char* str) {
{ return ( pUsb->ctrlReq(bAddress, 0, bmREQ_ADK_SEND, ADK_SENDSTR, 0, 0, index, strlen(str) + 1, strlen(str) + 1, (uint8_t*) str, NULL));
return( pUsb->ctrlReq(bAddress, 0, bmREQ_ADK_SEND, ADK_SENDSTR, 0, 0, index, strlen(str) + 1, strlen(str) + 1, (uint8_t*)str, NULL));
} }
/* switch to accessory mode */ /* switch to accessory mode */
inline uint8_t ADK::switchAcc( void ) inline uint8_t ADK::switchAcc(void) {
{ return ( pUsb->ctrlReq(bAddress, 0, bmREQ_ADK_SEND, ADK_ACCSTART, 0, 0, 0, 0, 0, NULL, NULL));
return( pUsb->ctrlReq(bAddress, 0, bmREQ_ADK_SEND, ADK_ACCSTART, 0, 0, 0, 0, 0, NULL, NULL));
} }
#endif // _ADK_H_ #endif // _ADK_H_

464
avrpins.h
View file

@ -13,24 +13,13 @@ Contact information
Circuits At Home, LTD Circuits At Home, LTD
Web : http://www.circuitsathome.com Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com e-mail : support@circuitsathome.com
*/ */
/* derived from Konstantin Chizhov's AVR port templates */ /* derived from Konstantin Chizhov's AVR port templates */
#ifndef _avrpins_h_ #ifndef _avrpins_h_
#define _avrpins_h_ #define _avrpins_h_
#if defined(__AVR_ATmega1280__) || (__AVR_ATmega2560__)
/* Uncomment the following if you have Arduino Mega ADK board with MAX3421e built-in */
//#define BOARD_MEGA_ADK
#endif
/* Uncomment the following if you are using a Teensy 2.0 */
//#define BOARD_TEENSY
/* Uncomment the following if you are using a Sanguino */
//#define BOARD_SANGUINO
#include <avr/io.h> #include <avr/io.h>
#ifdef PORTA #ifdef PORTA
@ -122,6 +111,7 @@ e-mail : support@circuitsathome.com
}; };
#ifdef USE_PORTA #ifdef USE_PORTA
MAKE_PORT(PORTA, DDRA, PINA, Porta, 'A') MAKE_PORT(PORTA, DDRA, PINA, Porta, 'A')
#endif #endif
#ifdef USE_PORTB #ifdef USE_PORTB
@ -171,238 +161,271 @@ MAKE_TCCR(TCCR1A, Tccr1a)
MAKE_TCCR(TCCR2A, Tccr2a) MAKE_TCCR(TCCR2A, Tccr2a)
#endif #endif
// this class represents one pin in a IO port. // this class represents one pin in a IO port.
// It is fully static. // It is fully static.
template<typename PORT, uint8_t PIN> template<typename PORT, uint8_t PIN>
class TPin class TPin {
{ // BOOST_STATIC_ASSERT(PIN < PORT::Width);
// BOOST_STATIC_ASSERT(PIN < PORT::Width); public:
public: typedef PORT Port;
typedef PORT Port;
enum{Number = PIN};
static void Set() { PORT::Set(1 << PIN); } enum {
Number = PIN
};
static void Set(uint8_t val){ static void Set() {
if(val) PORT::Set(1 << PIN);
Set(); }
else Clear();}
static void SetDir(uint8_t val){ static void Set(uint8_t val) {
if(val) if (val)
SetDirWrite(); Set();
else SetDirRead();} else Clear();
}
static void Clear(){PORT::Clear(1 << PIN);} static void SetDir(uint8_t val) {
if (val)
SetDirWrite();
else SetDirRead();
}
static void Toggle(){PORT::Toggle(1 << PIN);} static void Clear() {
PORT::Clear(1 << PIN);
}
static void SetDirRead(){PORT::DirClear(1 << PIN);} static void Toggle() {
PORT::Toggle(1 << PIN);
}
static void SetDirWrite(){PORT::DirSet(1 << PIN);} static void SetDirRead() {
PORT::DirClear(1 << PIN);
}
static uint8_t IsSet(){return PORT::PinRead() & (uint8_t)(1 << PIN);} static void SetDirWrite() {
PORT::DirSet(1 << PIN);
}
static void WaiteForSet(){ while(IsSet()==0){} } static uint8_t IsSet() {
return PORT::PinRead() & (uint8_t) (1 << PIN);
}
static void WaiteForClear(){ while(IsSet()){} } static void WaiteForSet() {
}; //class TPin... while (IsSet() == 0) {
}
}
// this class represents one bit in TCCR port. static void WaiteForClear() {
// used to set/clear TCCRx bits while (IsSet()) {
// It is fully static. }
template<typename TCCR, uint8_t COM> }
class TCom }; //class TPin...
{
// BOOST_STATIC_ASSERT(PIN < PORT::Width);
public:
typedef TCCR Tccr;
enum{Com = COM};
static void Set() { TCCR::Set(1 << COM); } // this class represents one bit in TCCR port.
// used to set/clear TCCRx bits
// It is fully static.
static void Clear() { TCCR::Clear(1 << COM); } template<typename TCCR, uint8_t COM>
class TCom {
// BOOST_STATIC_ASSERT(PIN < PORT::Width);
public:
typedef TCCR Tccr;
static void Toggle() { TCCR::Toggle(1 << COM); } enum {
}; //class TCom... Com = COM
};
static void Set() {
TCCR::Set(1 << COM);
}
static void Clear() {
TCCR::Clear(1 << COM);
}
static void Toggle() {
TCCR::Toggle(1 << COM);
}
}; //class TCom...
//Short pin definitions //Short pin definitions
#ifdef USE_PORTA #ifdef USE_PORTA
typedef TPin<Porta, 0> Pa0; typedef TPin<Porta, 0 > Pa0;
typedef TPin<Porta, 1> Pa1; typedef TPin<Porta, 1 > Pa1;
typedef TPin<Porta, 2> Pa2; typedef TPin<Porta, 2 > Pa2;
typedef TPin<Porta, 3> Pa3; typedef TPin<Porta, 3 > Pa3;
typedef TPin<Porta, 4> Pa4; typedef TPin<Porta, 4 > Pa4;
typedef TPin<Porta, 5> Pa5; typedef TPin<Porta, 5 > Pa5;
typedef TPin<Porta, 6> Pa6; typedef TPin<Porta, 6 > Pa6;
typedef TPin<Porta, 7> Pa7; typedef TPin<Porta, 7 > Pa7;
#endif #endif
#ifdef USE_PORTB #ifdef USE_PORTB
typedef TPin<Portb, 0> Pb0; typedef TPin<Portb, 0 > Pb0;
typedef TPin<Portb, 1> Pb1; typedef TPin<Portb, 1 > Pb1;
typedef TPin<Portb, 2> Pb2; typedef TPin<Portb, 2 > Pb2;
typedef TPin<Portb, 3> Pb3; typedef TPin<Portb, 3 > Pb3;
typedef TPin<Portb, 4> Pb4; typedef TPin<Portb, 4 > Pb4;
typedef TPin<Portb, 5> Pb5; typedef TPin<Portb, 5 > Pb5;
typedef TPin<Portb, 6> Pb6; typedef TPin<Portb, 6 > Pb6;
typedef TPin<Portb, 7> Pb7; typedef TPin<Portb, 7 > Pb7;
#endif #endif
#ifdef USE_PORTC #ifdef USE_PORTC
typedef TPin<Portc, 0> Pc0; typedef TPin<Portc, 0 > Pc0;
typedef TPin<Portc, 1> Pc1; typedef TPin<Portc, 1 > Pc1;
typedef TPin<Portc, 2> Pc2; typedef TPin<Portc, 2 > Pc2;
typedef TPin<Portc, 3> Pc3; typedef TPin<Portc, 3 > Pc3;
typedef TPin<Portc, 4> Pc4; typedef TPin<Portc, 4 > Pc4;
typedef TPin<Portc, 5> Pc5; typedef TPin<Portc, 5 > Pc5;
typedef TPin<Portc, 6> Pc6; typedef TPin<Portc, 6 > Pc6;
typedef TPin<Portc, 7> Pc7; typedef TPin<Portc, 7 > Pc7;
#endif #endif
#ifdef USE_PORTD #ifdef USE_PORTD
typedef TPin<Portd, 0> Pd0; typedef TPin<Portd, 0 > Pd0;
typedef TPin<Portd, 1> Pd1; typedef TPin<Portd, 1 > Pd1;
typedef TPin<Portd, 2> Pd2; typedef TPin<Portd, 2 > Pd2;
typedef TPin<Portd, 3> Pd3; typedef TPin<Portd, 3 > Pd3;
typedef TPin<Portd, 4> Pd4; typedef TPin<Portd, 4 > Pd4;
typedef TPin<Portd, 5> Pd5; typedef TPin<Portd, 5 > Pd5;
typedef TPin<Portd, 6> Pd6; typedef TPin<Portd, 6 > Pd6;
typedef TPin<Portd, 7> Pd7; typedef TPin<Portd, 7 > Pd7;
#endif #endif
#ifdef USE_PORTE #ifdef USE_PORTE
typedef TPin<Porte, 0> Pe0; typedef TPin<Porte, 0 > Pe0;
typedef TPin<Porte, 1> Pe1; typedef TPin<Porte, 1 > Pe1;
typedef TPin<Porte, 2> Pe2; typedef TPin<Porte, 2 > Pe2;
typedef TPin<Porte, 3> Pe3; typedef TPin<Porte, 3 > Pe3;
typedef TPin<Porte, 4> Pe4; typedef TPin<Porte, 4 > Pe4;
typedef TPin<Porte, 5> Pe5; typedef TPin<Porte, 5 > Pe5;
typedef TPin<Porte, 6> Pe6; typedef TPin<Porte, 6 > Pe6;
typedef TPin<Porte, 7> Pe7; typedef TPin<Porte, 7 > Pe7;
#endif #endif
#ifdef USE_PORTF #ifdef USE_PORTF
typedef TPin<Portf, 0> Pf0; typedef TPin<Portf, 0 > Pf0;
typedef TPin<Portf, 1> Pf1; typedef TPin<Portf, 1 > Pf1;
typedef TPin<Portf, 2> Pf2; typedef TPin<Portf, 2 > Pf2;
typedef TPin<Portf, 3> Pf3; typedef TPin<Portf, 3 > Pf3;
typedef TPin<Portf, 4> Pf4; typedef TPin<Portf, 4 > Pf4;
typedef TPin<Portf, 5> Pf5; typedef TPin<Portf, 5 > Pf5;
typedef TPin<Portf, 6> Pf6; typedef TPin<Portf, 6 > Pf6;
typedef TPin<Portf, 7> Pf7; typedef TPin<Portf, 7 > Pf7;
#endif #endif
#ifdef USE_PORTG #ifdef USE_PORTG
typedef TPin<Portg, 0> Pg0; typedef TPin<Portg, 0 > Pg0;
typedef TPin<Portg, 1> Pg1; typedef TPin<Portg, 1 > Pg1;
typedef TPin<Portg, 2> Pg2; typedef TPin<Portg, 2 > Pg2;
typedef TPin<Portg, 3> Pg3; typedef TPin<Portg, 3 > Pg3;
typedef TPin<Portg, 4> Pg4; typedef TPin<Portg, 4 > Pg4;
typedef TPin<Portg, 5> Pg5; typedef TPin<Portg, 5 > Pg5;
typedef TPin<Portg, 6> Pg6; typedef TPin<Portg, 6 > Pg6;
typedef TPin<Portg, 7> Pg7; typedef TPin<Portg, 7 > Pg7;
#endif #endif
#ifdef USE_PORTH #ifdef USE_PORTH
typedef TPin<Porth, 0> Ph0; typedef TPin<Porth, 0 > Ph0;
typedef TPin<Porth, 1> Ph1; typedef TPin<Porth, 1 > Ph1;
typedef TPin<Porth, 2> Ph2; typedef TPin<Porth, 2 > Ph2;
typedef TPin<Porth, 3> Ph3; typedef TPin<Porth, 3 > Ph3;
typedef TPin<Porth, 4> Ph4; typedef TPin<Porth, 4 > Ph4;
typedef TPin<Porth, 5> Ph5; typedef TPin<Porth, 5 > Ph5;
typedef TPin<Porth, 6> Ph6; typedef TPin<Porth, 6 > Ph6;
typedef TPin<Porth, 7> Ph7; typedef TPin<Porth, 7 > Ph7;
#endif #endif
#ifdef USE_PORTJ #ifdef USE_PORTJ
typedef TPin<Portj, 0> Pj0; typedef TPin<Portj, 0 > Pj0;
typedef TPin<Portj, 1> Pj1; typedef TPin<Portj, 1 > Pj1;
typedef TPin<Portj, 2> Pj2; typedef TPin<Portj, 2 > Pj2;
typedef TPin<Portj, 3> Pj3; typedef TPin<Portj, 3 > Pj3;
typedef TPin<Portj, 4> Pj4; typedef TPin<Portj, 4 > Pj4;
typedef TPin<Portj, 5> Pj5; typedef TPin<Portj, 5 > Pj5;
typedef TPin<Portj, 6> Pj6; typedef TPin<Portj, 6 > Pj6;
typedef TPin<Portj, 7> Pj7; typedef TPin<Portj, 7 > Pj7;
#endif #endif
#ifdef USE_PORTK #ifdef USE_PORTK
typedef TPin<Portk, 0> Pk0; typedef TPin<Portk, 0 > Pk0;
typedef TPin<Portk, 1> Pk1; typedef TPin<Portk, 1 > Pk1;
typedef TPin<Portk, 2> Pk2; typedef TPin<Portk, 2 > Pk2;
typedef TPin<Portk, 3> Pk3; typedef TPin<Portk, 3 > Pk3;
typedef TPin<Portk, 4> Pk4; typedef TPin<Portk, 4 > Pk4;
typedef TPin<Portk, 5> Pk5; typedef TPin<Portk, 5 > Pk5;
typedef TPin<Portk, 6> Pk6; typedef TPin<Portk, 6 > Pk6;
typedef TPin<Portk, 7> Pk7; typedef TPin<Portk, 7 > Pk7;
#endif #endif
#ifdef USE_PORTL #ifdef USE_PORTL
typedef TPin<Portl, 0> Pl0; typedef TPin<Portl, 0 > Pl0;
typedef TPin<Portl, 1> Pl1; typedef TPin<Portl, 1 > Pl1;
typedef TPin<Portl, 2> Pl2; typedef TPin<Portl, 2 > Pl2;
typedef TPin<Portl, 3> Pl3; typedef TPin<Portl, 3 > Pl3;
typedef TPin<Portl, 4> Pl4; typedef TPin<Portl, 4 > Pl4;
typedef TPin<Portl, 5> Pl5; typedef TPin<Portl, 5 > Pl5;
typedef TPin<Portl, 6> Pl6; typedef TPin<Portl, 6 > Pl6;
typedef TPin<Portl, 7> Pl7; typedef TPin<Portl, 7 > Pl7;
#endif #endif
#ifdef USE_PORTQ #ifdef USE_PORTQ
typedef TPin<Portq, 0> Pq0; typedef TPin<Portq, 0 > Pq0;
typedef TPin<Portq, 1> Pq1; typedef TPin<Portq, 1 > Pq1;
typedef TPin<Portq, 2> Pq2; typedef TPin<Portq, 2 > Pq2;
typedef TPin<Portq, 3> Pq3; typedef TPin<Portq, 3 > Pq3;
typedef TPin<Portq, 4> Pq4; typedef TPin<Portq, 4 > Pq4;
typedef TPin<Portq, 5> Pq5; typedef TPin<Portq, 5 > Pq5;
typedef TPin<Portq, 6> Pq6; typedef TPin<Portq, 6 > Pq6;
typedef TPin<Portq, 7> Pq7; typedef TPin<Portq, 7 > Pq7;
#endif #endif
#ifdef USE_PORTR #ifdef USE_PORTR
typedef TPin<Portr, 0> Pr0; typedef TPin<Portr, 0 > Pr0;
typedef TPin<Portr, 1> Pr1; typedef TPin<Portr, 1 > Pr1;
typedef TPin<Portr, 2> Pr2; typedef TPin<Portr, 2 > Pr2;
typedef TPin<Portr, 3> Pr3; typedef TPin<Portr, 3 > Pr3;
typedef TPin<Portr, 4> Pr4; typedef TPin<Portr, 4 > Pr4;
typedef TPin<Portr, 5> Pr5; typedef TPin<Portr, 5 > Pr5;
typedef TPin<Portr, 6> Pr6; typedef TPin<Portr, 6 > Pr6;
typedef TPin<Portr, 7> Pr7; typedef TPin<Portr, 7 > Pr7;
#endif #endif
#ifdef USE_TCCR0A #ifdef USE_TCCR0A
typedef TCom<Tccr0a, COM0A1> Tc0a; //P6 typedef TCom<Tccr0a, COM0A1> Tc0a; //P6
typedef TCom<Tccr0a, COM0B1> Tc0b; //P5 typedef TCom<Tccr0a, COM0B1> Tc0b; //P5
#endif #endif
#ifdef USE_TCCR1A #ifdef USE_TCCR1A
typedef TCom<Tccr1a, COM1A1> Tc1a; //P9 typedef TCom<Tccr1a, COM1A1> Tc1a; //P9
typedef TCom<Tccr1a, COM1B1> Tc1b; //P10 typedef TCom<Tccr1a, COM1B1> Tc1b; //P10
#endif #endif
#ifdef USE_TCCR2A #ifdef USE_TCCR2A
typedef TCom<Tccr2a, COM2A1> Tc2a; //P11 typedef TCom<Tccr2a, COM2A1> Tc2a; //P11
typedef TCom<Tccr2a, COM2B1> Tc2b; //P3 typedef TCom<Tccr2a, COM2B1> Tc2b; //P3
#endif #endif
template<typename Tp_pin, typename Tc_bit> template<typename Tp_pin, typename Tc_bit>
class Tp_Tc class Tp_Tc {
{ public:
public:
static void SetDir(uint8_t val){ static void SetDir(uint8_t val) {
if(val) if (val)
SetDirWrite(); SetDirWrite();
else SetDirRead(); else SetDirRead();
} }
static void SetDirRead(){
Tp_pin::SetDirRead(); //set pin direction static void SetDirRead() {
Tc_bit::Clear(); //disconnect pin from PWM Tp_pin::SetDirRead(); //set pin direction
} Tc_bit::Clear(); //disconnect pin from PWM
static void SetDirWrite(){ }
Tp_pin::SetDirWrite();
Tc_bit::Clear(); static void SetDirWrite() {
} Tp_pin::SetDirWrite();
}; Tc_bit::Clear();
}
};
/* pin definitions for cases where it's necessary to clear compare output mode bits */ /* pin definitions for cases where it's necessary to clear compare output mode bits */
@ -476,7 +499,6 @@ template<typename Tp_pin, typename Tc_bit>
#define P51 Pb2 #define P51 Pb2
#define P52 Pb1 #define P52 Pb1
#define P53 Pb0 #define P53 Pb0
#define P54 Pe6 // INT on Arduino ADK
#endif //"Mega" pin numbers #endif //"Mega" pin numbers
@ -508,47 +530,7 @@ template<typename Tp_pin, typename Tc_bit>
#endif // "Classic" Arduino pin numbers #endif // "Classic" Arduino pin numbers
#if !defined(BOARD_TEENSY) && defined(__AVR_ATmega32U4__) #if defined(__AVR_ATmega32U4__)
// Arduino Leonardo pin numbers
#define P0 Pd2 // D0 - PD2
#define P1 Pd3 // D1 - PD3
#define P2 Pd1 // D2 - PD1
#define P3 Pd0 // D3 - PD0
#define P4 Pd4 // D4 - PD4
#define P5 Pc6 // D5 - PC6
#define P6 Pd7 // D6 - PD7
#define P7 Pe6 // D7 - PE6
#define P8 Pb4 // D8 - PB4
#define P9 Pb5 // D9 - PB5
#define P10 Pb6 // D10 - PB6
#define P11 Pb7 // D11 - PB7
#define P12 Pd6 // D12 - PD6
#define P13 Pc7 // D13 - PC7
#define P14 Pb3 // D14 - MISO - PB3
#define P15 Pb1 // D15 - SCK - PB1
#define P16 Pb2 // D16 - MOSI - PB2
#define P17 Pb0 // D17 - SS - PB0
#define P18 Pf7 // D18 - A0 - PF7
#define P19 Pf6 // D19 - A1 - PF6
#define P20 Pf5 // D20 - A2 - PF5
#define P21 Pf4 // D21 - A3 - PF4
#define P22 Pf1 // D22 - A4 - PF1
#define P23 Pf0 // D23 - A5 - PF0
#define P24 Pd4 // D24 / D4 - A6 - PD4
#define P25 Pd7 // D25 / D6 - A7 - PD7
#define P26 Pb4 // D26 / D8 - A8 - PB4
#define P27 Pb5 // D27 / D9 - A9 - PB5
#define P28 Pb6 // D28 / D10 - A10 - PB6
#define P29 Pd6 // D29 / D12 - A11 - PD6
#endif // Arduino Leonardo pin numbers
#if defined(BOARD_TEENSY) && defined(__AVR_ATmega32U4__)
// Teensy 2.0 pin numbers // Teensy 2.0 pin numbers
// http://www.pjrc.com/teensy/pinout.html // http://www.pjrc.com/teensy/pinout.html
#define P0 Pb0 #define P0 Pb0
@ -629,45 +611,7 @@ template<typename Tp_pin, typename Tc_bit>
#define P45 Pf7 #define P45 Pf7
#endif // Teensy++ 2.0 #endif // Teensy++ 2.0
#if !defined(BOARD_SANGUINO) && (defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__)) #if defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__)
#define BOARD_BALANDUINO
// Balanduino pin numbers
// http://balanduino.net/
#define P0 Pd0 /* 0 - PD0 */
#define P1 Pd1 /* 1 - PD1 */
#define P2 Pb2 /* 2 - PB2 */
#define P3 Pd6 /* 3 - PD6 */
#define P4 Pd7 /* 4 - PD7 */
#define P5 Pb3 /* 5 - PB3 */
#define P6 Pb4 /* 6 - PB4 */
#define P7 Pa0 /* 7 - PA0 */
#define P8 Pa1 /* 8 - PA1 */
#define P9 Pa2 /* 9 - PA2 */
#define P10 Pa3 /* 10 - PA3 */
#define P11 Pa4 /* 11 - PA4 */
#define P12 Pa5 /* 12 - PA5 */
#define P13 Pc0 /* 13 - PC0 */
#define P14 Pc1 /* 14 - PC1 */
#define P15 Pd2 /* 15 - PD2 */
#define P16 Pd3 /* 16 - PD3 */
#define P17 Pd4 /* 17 - PD4 */
#define P18 Pd5 /* 18 - PD5 */
#define P19 Pc2 /* 19 - PC2 */
#define P20 Pc3 /* 20 - PC3 */
#define P21 Pc4 /* 21 - PC4 */
#define P22 Pc5 /* 22 - PC5 */
#define P23 Pc6 /* 23 - PC6 */
#define P24 Pc7 /* 24 - PC7 */
#define P25 Pb0 /* 25 - PB0 */
#define P26 Pb1 /* 26 - PB1 */
#define P27 Pb5 /* 27 - PB5 */
#define P28 Pb6 /* 28 - PB6 */
#define P29 Pb7 /* 29 - PB7 */
#define P30 Pa6 /* 30 - PA6 */
#define P31 Pa7 /* 31 - PA7 */
#endif // Balanduino
#if defined(BOARD_SANGUINO) && (defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__))
// Sanguino pin numbers // Sanguino pin numbers
// http://sanguino.cc/hardware // http://sanguino.cc/hardware
#define P0 Pb0 #define P0 Pb0

View file

@ -13,347 +13,325 @@ Contact information
Circuits At Home, LTD Circuits At Home, LTD
Web : http://www.circuitsathome.com Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com e-mail : support@circuitsathome.com
*/ */
#include "cdcacm.h" #include "cdcacm.h"
const uint8_t ACM::epDataInIndex = 1; const uint8_t ACM::epDataInIndex = 1;
const uint8_t ACM::epDataOutIndex = 2; const uint8_t ACM::epDataOutIndex = 2;
const uint8_t ACM::epInterruptInIndex = 3; const uint8_t ACM::epInterruptInIndex = 3;
ACM::ACM(USB *p, CDCAsyncOper *pasync) : ACM::ACM(USB *p, CDCAsyncOper *pasync) :
pUsb(p), pUsb(p),
pAsync(pasync), pAsync(pasync),
bAddress(0), bAddress(0),
qNextPollTime(0), bControlIface(0),
bPollEnable(false), bDataIface(0),
bControlIface(0), bNumEP(1),
bDataIface(0), qNextPollTime(0),
bNumEP(1), bPollEnable(false) {
ready(false) for (uint8_t i = 0; i < ACM_MAX_ENDPOINTS; i++) {
{ epInfo[i].epAddr = 0;
for(uint8_t i=0; i<ACM_MAX_ENDPOINTS; i++) epInfo[i].maxPktSize = (i) ? 0 : 8;
{ epInfo[i].epAttribs = 0;
epInfo[i].epAddr = 0; //epInfo[i].bmNakPower = USB_NAK_NOWAIT;
epInfo[i].maxPktSize = (i) ? 0 : 8; epInfo[i].bmNakPower = USB_NAK_MAX_POWER;
epInfo[i].epAttribs = 0;
epInfo[i].bmNakPower = USB_NAK_NOWAIT;
//epInfo[i].bmNakPower = USB_NAK_MAX_POWER;
if (!i) //if (!i)
epInfo[i].bmNakPower = USB_NAK_MAX_POWER; epInfo[i].bmNakPower = USB_NAK_MAX_POWER;
}
} if (pUsb)
if (pUsb) pUsb->RegisterDeviceClass(this);
pUsb->RegisterDeviceClass(this);
} }
uint8_t ACM::Init(uint8_t parent, uint8_t port, bool lowspeed) uint8_t ACM::Init(uint8_t parent, uint8_t port, bool lowspeed) {
{ const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR);
const uint8_t constBufSize = sizeof(USB_DEVICE_DESCRIPTOR);
uint8_t buf[constBufSize]; uint8_t buf[constBufSize];
uint8_t rcode; uint8_t rcode;
UsbDevice *p = NULL; UsbDevice *p = NULL;
EpInfo *oldep_ptr = NULL; EpInfo *oldep_ptr = NULL;
uint8_t num_of_conf; // number of configurations uint8_t num_of_conf; // number of configurations
AddressPool &addrPool = pUsb->GetAddressPool(); AddressPool &addrPool = pUsb->GetAddressPool();
USBTRACE("ACM Init\r\n"); USBTRACE("ACM Init\r\n");
if (bAddress) if (bAddress)
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE; return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
// Get pointer to pseudo device with address 0 assigned // Get pointer to pseudo device with address 0 assigned
p = addrPool.GetUsbDevicePtr(0); p = addrPool.GetUsbDevicePtr(0);
if (!p) if (!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
if (!p->epinfo) if (!p->epinfo) {
{ USBTRACE("epinfo\r\n");
USBTRACE("epinfo\r\n"); return USB_ERROR_EPINFO_IS_NULL;
return USB_ERROR_EPINFO_IS_NULL; }
}
// Save old pointer to EP_RECORD of address 0 // Save old pointer to EP_RECORD of address 0
oldep_ptr = p->epinfo; oldep_ptr = p->epinfo;
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
p->epinfo = epInfo; p->epinfo = epInfo;
p->lowspeed = lowspeed; p->lowspeed = lowspeed;
// Get device descriptor // Get device descriptor
rcode = pUsb->getDevDescr( 0, 0, constBufSize, (uint8_t*)buf ); rcode = pUsb->getDevDescr(0, 0, constBufSize, (uint8_t*) buf);
// Restore p->epinfo // Restore p->epinfo
p->epinfo = oldep_ptr; p->epinfo = oldep_ptr;
if( rcode ) if (rcode)
goto FailGetDevDescr; goto FailGetDevDescr;
// Allocate new address according to device class // Allocate new address according to device class
bAddress = addrPool.AllocAddress(parent, false, port); bAddress = addrPool.AllocAddress(parent, false, port);
if (!bAddress) if (!bAddress)
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL; return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
// Extract Max Packet Size from the device descriptor // Extract Max Packet Size from the device descriptor
epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0; epInfo[0].maxPktSize = (uint8_t) ((USB_DEVICE_DESCRIPTOR*) buf)->bMaxPacketSize0;
// Assign new address to the device // Assign new address to the device
rcode = pUsb->setAddr( 0, 0, bAddress ); rcode = pUsb->setAddr(0, 0, bAddress);
if (rcode) if (rcode) {
{ p->lowspeed = false;
p->lowspeed = false; addrPool.FreeAddress(bAddress);
addrPool.FreeAddress(bAddress); bAddress = 0;
bAddress = 0; USBTRACE2("setAddr:", rcode);
USBTRACE2("setAddr:",rcode); return rcode;
return rcode; }
}
USBTRACE2("Addr:", bAddress); USBTRACE2("Addr:", bAddress);
p->lowspeed = false; p->lowspeed = false;
p = addrPool.GetUsbDevicePtr(bAddress); p = addrPool.GetUsbDevicePtr(bAddress);
if (!p) if (!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
p->lowspeed = lowspeed; p->lowspeed = lowspeed;
num_of_conf = ((USB_DEVICE_DESCRIPTOR*)buf)->bNumConfigurations; num_of_conf = ((USB_DEVICE_DESCRIPTOR*) buf)->bNumConfigurations;
// Assign epInfo to epinfo pointer // Assign epInfo to epinfo pointer
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo); rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
if (rcode) if (rcode)
goto FailSetDevTblEntry; goto FailSetDevTblEntry;
USBTRACE2("NC:", num_of_conf); USBTRACE2("NC:", num_of_conf);
for (uint8_t i=0; i<num_of_conf; i++) for (uint8_t i = 0; i < num_of_conf; i++) {
{ ConfigDescParser< USB_CLASS_COM_AND_CDC_CTRL,
ConfigDescParser< USB_CLASS_COM_AND_CDC_CTRL, CDC_SUBCLASS_ACM,
CDC_SUBCLASS_ACM, CDC_PROTOCOL_ITU_T_V_250,
CDC_PROTOCOL_ITU_T_V_250, CP_MASK_COMPARE_CLASS |
CP_MASK_COMPARE_CLASS | CP_MASK_COMPARE_SUBCLASS |
CP_MASK_COMPARE_SUBCLASS | CP_MASK_COMPARE_PROTOCOL > CdcControlParser(this);
CP_MASK_COMPARE_PROTOCOL> CdcControlParser(this);
ConfigDescParser<USB_CLASS_CDC_DATA, 0, 0, ConfigDescParser<USB_CLASS_CDC_DATA, 0, 0,
CP_MASK_COMPARE_CLASS> CdcDataParser(this); CP_MASK_COMPARE_CLASS> CdcDataParser(this);
rcode = pUsb->getConfDescr(bAddress, 0, i, &CdcControlParser); rcode = pUsb->getConfDescr(bAddress, 0, i, &CdcControlParser);
rcode = pUsb->getConfDescr(bAddress, 0, i, &CdcDataParser);
if (bNumEP > 1) if (rcode)
break; goto FailGetConfDescr;
} // for
if (bNumEP < 4) rcode = pUsb->getConfDescr(bAddress, 0, i, &CdcDataParser);
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
// Assign epInfo to epinfo pointer if (rcode)
rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo); goto FailGetConfDescr;
USBTRACE2("Conf:", bConfNum); if (bNumEP > 1)
break;
} // for
// Set Configuration Value if (bNumEP < 4)
rcode = pUsb->setConf(bAddress, 0, bConfNum); return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
if (rcode) // Assign epInfo to epinfo pointer
goto FailSetConf; rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
rcode = pAsync->OnInit(this); USBTRACE2("Conf:", bConfNum);
if (rcode) // Set Configuration Value
goto FailOnInit; rcode = pUsb->setConf(bAddress, 0, bConfNum);
USBTRACE("ACM configured\r\n"); if (rcode)
ready = true; goto FailSetConf;
//bPollEnable = true; rcode = pAsync->OnInit(this);
//USBTRACE("Poll enabled\r\n"); if (rcode)
return 0; goto FailOnInit;
USBTRACE("ACM configured\r\n");
//bPollEnable = true;
//USBTRACE("Poll enabled\r\n");
return 0;
FailGetDevDescr: FailGetDevDescr:
USBTRACE("getDevDescr:"); USBTRACE("getDevDescr:");
goto Fail; goto Fail;
FailSetDevTblEntry: FailSetDevTblEntry:
USBTRACE("setDevTblEn:"); USBTRACE("setDevTblEn:");
goto Fail; goto Fail;
FailGetConfDescr: FailGetConfDescr:
USBTRACE("getConf:"); USBTRACE("getConf:");
goto Fail; goto Fail;
FailSetConf: FailSetConf:
USBTRACE("setConf:"); USBTRACE("setConf:");
goto Fail; goto Fail;
FailOnInit: FailOnInit:
USBTRACE("OnInit:"); USBTRACE("OnInit:");
goto Fail; goto Fail;
Fail: Fail:
Serial.println(rcode, HEX); PrintHex<uint8_t > (rcode, 0x80);
Release(); Notify(PSTR("\r\n"), 0x80);
return rcode; // Serial.println(rcode, HEX);
Release();
return rcode;
} }
void ACM::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) {
ErrorMessage<uint8_t > (PSTR("Conf.Val"), conf);
ErrorMessage<uint8_t > (PSTR("Iface Num"), iface);
ErrorMessage<uint8_t > (PSTR("Alt.Set"), alt);
void ACM::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) bConfNum = conf;
{
//ErrorMessage<uint8_t>(PSTR("Conf.Val"), conf);
//ErrorMessage<uint8_t>(PSTR("Iface Num"),iface);
//ErrorMessage<uint8_t>(PSTR("Alt.Set"), alt);
bConfNum = conf; uint8_t index;
uint8_t index; if ((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80)
index = epInterruptInIndex;
else
if ((pep->bmAttributes & 0x02) == 2)
index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex;
else
return;
if ((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80) // Fill in the endpoint info structure
index = epInterruptInIndex; epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
else epInfo[index].maxPktSize = (uint8_t) pep->wMaxPacketSize;
if ((pep->bmAttributes & 0x02) == 2) epInfo[index].epAttribs = 0;
index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex;
else
return;
// Fill in the endpoint info structure bNumEP++;
epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
//epInfo[index].epAttribs = 0;
bNumEP ++; PrintEndpointDescriptor(pep);
//PrintEndpointDescriptor(pep);
} }
uint8_t ACM::Release() uint8_t ACM::Release() {
{ pUsb->GetAddressPool().FreeAddress(bAddress);
pUsb->GetAddressPool().FreeAddress(bAddress);
bControlIface = 0; bControlIface = 0;
bDataIface = 0; bDataIface = 0;
bNumEP = 1; bNumEP = 1;
bAddress = 0; bAddress = 0;
qNextPollTime = 0; qNextPollTime = 0;
bPollEnable = false; bPollEnable = false;
ready = false; return 0;
return 0;
} }
uint8_t ACM::Poll() uint8_t ACM::Poll() {
{ uint8_t rcode = 0;
uint8_t rcode = 0;
if (!bPollEnable) if (!bPollEnable)
return 0; return 0;
//uint32_t time_now = millis(); //uint32_t time_now = millis();
//if (qNextPollTime <= time_now) //if (qNextPollTime <= time_now)
//{ //{
// qNextPollTime = time_now + 100; // qNextPollTime = time_now + 100;
// uint8_t rcode; // uint8_t rcode;
// const uint8_t constBufSize = 16; // const uint8_t constBufSize = 16;
// uint8_t buf[constBufSize]; // uint8_t buf[constBufSize];
// for (uint8_t i=0; i<constBufSize; i++) // for (uint8_t i=0; i<constBufSize; i++)
// buf[i] = 0; // buf[i] = 0;
// uint16_t read = (constBufSize > epInfo[epInterruptInIndex].maxPktSize) // uint16_t read = (constBufSize > epInfo[epInterruptInIndex].maxPktSize)
// ? epInfo[epInterruptInIndex].maxPktSize : constBufSize; // ? epInfo[epInterruptInIndex].maxPktSize : constBufSize;
// rcode = pUsb->inTransfer(bAddress, epInfo[epInterruptInIndex].epAddr, &read, buf); // rcode = pUsb->inTransfer(bAddress, epInfo[epInterruptInIndex].epAddr, &read, buf);
// if (rcode) // if (rcode)
// return rcode; // return rcode;
// for (uint8_t i=0; i<read; i++) // for (uint8_t i=0; i<read; i++)
// { // {
// PrintHex<uint8_t>(buf[i]); // PrintHex<uint8_t>(buf[i]);
// Serial.print(" "); // Serial.print(" ");
// } // }
// USBTRACE("\r\n"); // USBTRACE("\r\n");
//} //}
return rcode; return rcode;
} }
uint8_t ACM::RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr) uint8_t ACM::RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr) {
{ return pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, dataptr);
return pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, dataptr);
} }
uint8_t ACM::SndData(uint16_t nbytes, uint8_t *dataptr) uint8_t ACM::SndData(uint16_t nbytes, uint8_t *dataptr) {
{ return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, nbytes, dataptr);
return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, nbytes, dataptr);
} }
/* untested */ uint8_t ACM::SetCommFeature(uint16_t fid, uint8_t nbytes, uint8_t *dataptr) {
uint8_t ACM::GetNotif( uint16_t *bytes_rcvd, uint8_t *dataptr ) return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCOUT, CDC_SET_COMM_FEATURE, (fid & 0xff), (fid >> 8), bControlIface, nbytes, nbytes, dataptr, NULL));
{
return pUsb->inTransfer(bAddress, epInfo[epInterruptInIndex].epAddr, bytes_rcvd, dataptr);
} }
uint8_t ACM::SetCommFeature(uint16_t fid, uint8_t nbytes, uint8_t *dataptr) uint8_t ACM::GetCommFeature(uint16_t fid, uint8_t nbytes, uint8_t *dataptr) {
{ return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCIN, CDC_GET_COMM_FEATURE, (fid & 0xff), (fid >> 8), bControlIface, nbytes, nbytes, dataptr, NULL));
return( pUsb->ctrlReq( bAddress, 0, bmREQ_CDCOUT, CDC_SET_COMM_FEATURE, (fid & 0xff), (fid >> 8), bControlIface, nbytes, nbytes, dataptr, NULL ));
} }
uint8_t ACM::GetCommFeature(uint16_t fid, uint8_t nbytes, uint8_t *dataptr) uint8_t ACM::ClearCommFeature(uint16_t fid) {
{ return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCOUT, CDC_CLEAR_COMM_FEATURE, (fid & 0xff), (fid >> 8), bControlIface, 0, 0, NULL, NULL));
return( pUsb->ctrlReq( bAddress, 0, bmREQ_CDCIN, CDC_GET_COMM_FEATURE, (fid & 0xff), (fid >> 8), bControlIface, nbytes, nbytes, dataptr, NULL ));
} }
uint8_t ACM::ClearCommFeature(uint16_t fid) uint8_t ACM::SetLineCoding(const LINE_CODING *dataptr) {
{ return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCOUT, CDC_SET_LINE_CODING, 0x00, 0x00, bControlIface, sizeof (LINE_CODING), sizeof (LINE_CODING), (uint8_t*) dataptr, NULL));
return( pUsb->ctrlReq( bAddress, 0, bmREQ_CDCOUT, CDC_CLEAR_COMM_FEATURE, (fid & 0xff), (fid >> 8), bControlIface, 0, 0, NULL, NULL ));
} }
uint8_t ACM::SetLineCoding(const LINE_CODING *dataptr) uint8_t ACM::GetLineCoding(LINE_CODING *dataptr) {
{ return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCIN, CDC_GET_LINE_CODING, 0x00, 0x00, bControlIface, sizeof (LINE_CODING), sizeof (LINE_CODING), (uint8_t*) dataptr, NULL));
return( pUsb->ctrlReq( bAddress, 0, bmREQ_CDCOUT, CDC_SET_LINE_CODING, 0x00, 0x00, bControlIface, sizeof(LINE_CODING), sizeof(LINE_CODING), (uint8_t*)dataptr, NULL ));
} }
uint8_t ACM::GetLineCoding(LINE_CODING *dataptr) uint8_t ACM::SetControlLineState(uint8_t state) {
{ return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCOUT, CDC_SET_CONTROL_LINE_STATE, state, 0, bControlIface, 0, 0, NULL, NULL));
return( pUsb->ctrlReq( bAddress, 0, bmREQ_CDCIN, CDC_GET_LINE_CODING, 0x00, 0x00, bControlIface, sizeof(LINE_CODING), sizeof(LINE_CODING), (uint8_t*)dataptr, NULL ));
} }
uint8_t ACM::SetControlLineState(uint8_t state) uint8_t ACM::SendBreak(uint16_t duration) {
{ return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCOUT, CDC_SEND_BREAK, (duration & 0xff), (duration >> 8), bControlIface, 0, 0, NULL, NULL));
return( pUsb->ctrlReq( bAddress, 0, bmREQ_CDCOUT, CDC_SET_CONTROL_LINE_STATE, state, 0, bControlIface, 0, 0, NULL, NULL ));
} }
uint8_t ACM::SendBreak(uint16_t duration) void ACM::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr) {
{ Notify(PSTR("Endpoint descriptor:"), 0x80);
return( pUsb->ctrlReq( bAddress, 0, bmREQ_CDCOUT, CDC_SEND_BREAK, (duration & 0xff), (duration >> 8), bControlIface, 0, 0, NULL, NULL )); Notify(PSTR("\r\nLength:\t\t"), 0x80);
} PrintHex<uint8_t > (ep_ptr->bLength, 0x80);
Notify(PSTR("\r\nType:\t\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80);
void ACM::PrintEndpointDescriptor( const USB_ENDPOINT_DESCRIPTOR* ep_ptr ) Notify(PSTR("\r\nAddress:\t"), 0x80);
{ PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80);
Notify(PSTR("Endpoint descriptor:")); Notify(PSTR("\r\nAttributes:\t"), 0x80);
Notify(PSTR("\r\nLength:\t\t")); PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80);
PrintHex<uint8_t>(ep_ptr->bLength); Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
Notify(PSTR("\r\nType:\t\t")); PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80);
PrintHex<uint8_t>(ep_ptr->bDescriptorType); Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
Notify(PSTR("\r\nAddress:\t")); PrintHex<uint8_t > (ep_ptr->bInterval, 0x80);
PrintHex<uint8_t>(ep_ptr->bEndpointAddress); Notify(PSTR("\r\n"), 0x80);
Notify(PSTR("\r\nAttributes:\t"));
PrintHex<uint8_t>(ep_ptr->bmAttributes);
Notify(PSTR("\r\nMaxPktSize:\t"));
PrintHex<uint16_t>(ep_ptr->wMaxPacketSize);
Notify(PSTR("\r\nPoll Intrv:\t"));
PrintHex<uint8_t>(ep_ptr->bInterval);
Notify(PSTR("\r\n"));
} }

156
cdcacm.h
View file

@ -13,7 +13,7 @@ Contact information
Circuits At Home, LTD Circuits At Home, LTD
Web : http://www.circuitsathome.com Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com e-mail : support@circuitsathome.com
*/ */
#if !defined(__CDCACM_H__) #if !defined(__CDCACM_H__)
#define __CDCACM_H__ #define __CDCACM_H__
@ -89,123 +89,97 @@ e-mail : support@circuitsathome.com
#define CDC_GET_LINE_PARMS 0x35 #define CDC_GET_LINE_PARMS 0x35
#define CDC_DIAL_DIGITS 0x36 #define CDC_DIAL_DIGITS 0x36
//Class-Specific Notification Codes
#define NETWORK_CONNECTION 0x00
#define RESPONSE_AVAILABLE 0x01
#define AUX_JACK_HOOK_STATE 0x08
#define RING_DETECT 0x09
#define SERIAL_STATE 0x20
#define CALL_STATE_CHANGE 0x28
#define LINE_STATE_CHANGE 0x29
#define CONNECTION_SPEED_CHANGE 0x2a
// CDC Functional Descriptor Structures // CDC Functional Descriptor Structures
typedef struct
{ typedef struct {
uint8_t bFunctionLength; uint8_t bFunctionLength;
uint8_t bDescriptorType; uint8_t bDescriptorType;
uint8_t bDescriptorSubtype; uint8_t bDescriptorSubtype;
uint8_t bmCapabilities; uint8_t bmCapabilities;
uint8_t bDataInterface; uint8_t bDataInterface;
} CALL_MGMNT_FUNC_DESCR; } CALL_MGMNT_FUNC_DESCR;
typedef struct typedef struct {
{ uint8_t bFunctionLength;
uint8_t bFunctionLength; uint8_t bDescriptorType;
uint8_t bDescriptorType; uint8_t bDescriptorSubtype;
uint8_t bDescriptorSubtype; uint8_t bmCapabilities;
uint8_t bmCapabilities;
} ACM_FUNC_DESCR, DLM_FUNC_DESCR, TEL_OPER_MODES_FUNC_DESCR, } ACM_FUNC_DESCR, DLM_FUNC_DESCR, TEL_OPER_MODES_FUNC_DESCR,
TEL_CALL_STATE_REP_CPBL_FUNC_DESCR; TEL_CALL_STATE_REP_CPBL_FUNC_DESCR;
typedef struct typedef struct {
{ uint8_t bFunctionLength;
uint8_t bFunctionLength; uint8_t bDescriptorType;
uint8_t bDescriptorType; uint8_t bDescriptorSubtype;
uint8_t bDescriptorSubtype; uint8_t bRingerVolSteps;
uint8_t bRingerVolSteps; uint8_t bNumRingerPatterns;
uint8_t bNumRingerPatterns;
} TEL_RINGER_FUNC_DESCR; } TEL_RINGER_FUNC_DESCR;
typedef struct typedef struct {
{ uint32_t dwDTERate; // Data Terminal Rate in bits per second
uint32_t dwDTERate; // Data Terminal Rate in bits per second uint8_t bCharFormat; // 0 - 1 stop bit, 1 - 1.5 stop bits, 2 - 2 stop bits
uint8_t bCharFormat; // 0 - 1 stop bit, 1 - 1.5 stop bits, 2 - 2 stop bits uint8_t bParityType; // 0 - None, 1 - Odd, 2 - Even, 3 - Mark, 4 - Space
uint8_t bParityType; // 0 - None, 1 - Odd, 2 - Even, 3 - Mark, 4 - Space uint8_t bDataBits; // Data bits (5, 6, 7, 8 or 16)
uint8_t bDataBits; // Data bits (5, 6, 7, 8 or 16)
} LINE_CODING; } LINE_CODING;
typedef struct
{
uint8_t bmRequestType; // 0xa1 for class-specific notifications
uint8_t bNotification;
uint16_t wValue;
uint16_t wIndex;
uint16_t wLength;
uint16_t bmState; //UART state bitmap for SERIAL_STATE, other notifications variable length
} CLASS_NOTIFICATION;
class ACM; class ACM;
class CDCAsyncOper class CDCAsyncOper {
{
public: public:
virtual uint8_t OnInit(ACM *pacm) = 0; virtual uint8_t OnInit(ACM *pacm) = 0;
//virtual void OnDataRcvd(ACM *pacm, uint8_t nbytes, uint8_t *dataptr) = 0; //virtual void OnDataRcvd(ACM *pacm, uint8_t nbytes, uint8_t *dataptr) = 0;
//virtual void OnDisconnected(ACM *pacm) = 0; //virtual void OnDisconnected(ACM *pacm) = 0;
}; };
#define ACM_MAX_ENDPOINTS 4 #define ACM_MAX_ENDPOINTS 4
class ACM : public USBDeviceConfig, public UsbConfigXtracter class ACM : public USBDeviceConfig, public UsbConfigXtracter {
{
protected: protected:
static const uint8_t epDataInIndex; // DataIn endpoint index static const uint8_t epDataInIndex; // DataIn endpoint index
static const uint8_t epDataOutIndex; // DataOUT endpoint index static const uint8_t epDataOutIndex; // DataOUT endpoint index
static const uint8_t epInterruptInIndex; // InterruptIN endpoint index static const uint8_t epInterruptInIndex; // InterruptIN endpoint index
USB *pUsb; USB *pUsb;
CDCAsyncOper *pAsync; CDCAsyncOper *pAsync;
uint8_t bAddress; uint8_t bAddress;
uint8_t bConfNum; // configuration number uint8_t bConfNum; // configuration number
uint8_t bControlIface; // Control interface value uint8_t bControlIface; // Control interface value
uint8_t bDataIface; // Data interface value uint8_t bDataIface; // Data interface value
uint8_t bNumEP; // total number of EP in the configuration uint8_t bNumEP; // total number of EP in the configuration
uint32_t qNextPollTime; // next poll time uint32_t qNextPollTime; // next poll time
bool bPollEnable; // poll enable flag bool bPollEnable; // poll enable flag
bool ready; //device ready indicator
EpInfo epInfo[ACM_MAX_ENDPOINTS]; EpInfo epInfo[ACM_MAX_ENDPOINTS];
void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr); void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr);
public: public:
ACM(USB *pusb, CDCAsyncOper *pasync); ACM(USB *pusb, CDCAsyncOper *pasync);
uint8_t SetCommFeature(uint16_t fid, uint8_t nbytes, uint8_t *dataptr); uint8_t SetCommFeature(uint16_t fid, uint8_t nbytes, uint8_t *dataptr);
uint8_t GetCommFeature(uint16_t fid, uint8_t nbytes, uint8_t *dataptr); uint8_t GetCommFeature(uint16_t fid, uint8_t nbytes, uint8_t *dataptr);
uint8_t ClearCommFeature(uint16_t fid); uint8_t ClearCommFeature(uint16_t fid);
uint8_t SetLineCoding(const LINE_CODING *dataptr); uint8_t SetLineCoding(const LINE_CODING *dataptr);
uint8_t GetLineCoding(LINE_CODING *dataptr); uint8_t GetLineCoding(LINE_CODING *dataptr);
uint8_t SetControlLineState(uint8_t state); uint8_t SetControlLineState(uint8_t state);
uint8_t SendBreak(uint16_t duration); uint8_t SendBreak(uint16_t duration);
uint8_t GetNotif( uint16_t *bytes_rcvd, uint8_t *dataptr );
// Methods for recieving and sending data // Methods for recieving and sending data
uint8_t RcvData(uint16_t *nbytesptr, uint8_t *dataptr); uint8_t RcvData(uint16_t *nbytesptr, uint8_t *dataptr);
uint8_t SndData(uint16_t nbytes, uint8_t *dataptr); uint8_t SndData(uint16_t nbytes, uint8_t *dataptr);
// USBDeviceConfig implementation // USBDeviceConfig implementation
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed); virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
virtual uint8_t Release(); virtual uint8_t Release();
virtual uint8_t Poll(); virtual uint8_t Poll();
virtual uint8_t GetAddress() { return bAddress; };
virtual bool isReady() { return ready; };
// UsbConfigXtracter implementation virtual uint8_t GetAddress() {
virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep); return bAddress;
};
// UsbConfigXtracter implementation
virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
}; };
#endif // __CDCACM_H__ #endif // __CDCACM_H__

View file

@ -13,336 +13,320 @@ Contact information
Circuits At Home, LTD Circuits At Home, LTD
Web : http://www.circuitsathome.com Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com e-mail : support@circuitsathome.com
*/ */
#include "cdcftdi.h" #include "cdcftdi.h"
const uint8_t FTDI::epDataInIndex = 1; const uint8_t FTDI::epDataInIndex = 1;
const uint8_t FTDI::epDataOutIndex = 2; const uint8_t FTDI::epDataOutIndex = 2;
const uint8_t FTDI::epInterruptInIndex = 3; const uint8_t FTDI::epInterruptInIndex = 3;
FTDI::FTDI(USB *p, FTDIAsyncOper *pasync) : FTDI::FTDI(USB *p, FTDIAsyncOper *pasync) :
pAsync(pasync), pAsync(pasync),
pUsb(p), pUsb(p),
bAddress(0), bAddress(0),
bNumEP(1), bNumEP(1),
wFTDIType(0) wFTDIType(0) {
{ for (uint8_t i = 0; i < FTDI_MAX_ENDPOINTS; i++) {
for(uint8_t i=0; i<FTDI_MAX_ENDPOINTS; i++) epInfo[i].epAddr = 0;
{ epInfo[i].maxPktSize = (i) ? 0 : 8;
epInfo[i].epAddr = 0; epInfo[i].epAttribs = 0;
epInfo[i].maxPktSize = (i) ? 0 : 8;
epInfo[i].epAttribs = 0;
//if (!i) //if (!i)
epInfo[i].bmNakPower = USB_NAK_MAX_POWER; epInfo[i].bmNakPower = USB_NAK_MAX_POWER;
} }
if (pUsb) if (pUsb)
pUsb->RegisterDeviceClass(this); pUsb->RegisterDeviceClass(this);
} }
uint8_t FTDI::Init(uint8_t parent, uint8_t port, bool lowspeed) uint8_t FTDI::Init(uint8_t parent, uint8_t port, bool lowspeed) {
{ const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR);
const uint8_t constBufSize = sizeof(USB_DEVICE_DESCRIPTOR);
uint8_t buf[constBufSize]; uint8_t buf[constBufSize];
uint8_t rcode; uint8_t rcode;
UsbDevice *p = NULL; UsbDevice *p = NULL;
EpInfo *oldep_ptr = NULL; EpInfo *oldep_ptr = NULL;
uint8_t len = 0; //uint8_t len = 0;
uint16_t cd_len = 0; //uint16_t cd_len = 0;
uint8_t num_of_conf; // number of configurations uint8_t num_of_conf; // number of configurations
uint8_t num_of_intf; // number of interfaces //uint8_t num_of_intf; // number of interfaces
AddressPool &addrPool = pUsb->GetAddressPool(); AddressPool &addrPool = pUsb->GetAddressPool();
USBTRACE("FTDI Init\r\n"); USBTRACE("FTDI Init\r\n");
if (bAddress) if (bAddress)
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE; return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
// Get pointer to pseudo device with address 0 assigned // Get pointer to pseudo device with address 0 assigned
p = addrPool.GetUsbDevicePtr(0); p = addrPool.GetUsbDevicePtr(0);
if (!p) if (!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
if (!p->epinfo) if (!p->epinfo) {
{ USBTRACE("epinfo\r\n");
USBTRACE("epinfo\r\n"); return USB_ERROR_EPINFO_IS_NULL;
return USB_ERROR_EPINFO_IS_NULL; }
}
// Save old pointer to EP_RECORD of address 0 // Save old pointer to EP_RECORD of address 0
oldep_ptr = p->epinfo; oldep_ptr = p->epinfo;
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
p->epinfo = epInfo; p->epinfo = epInfo;
p->lowspeed = lowspeed; p->lowspeed = lowspeed;
// Get device descriptor // Get device descriptor
rcode = pUsb->getDevDescr( 0, 0, sizeof(USB_DEVICE_DESCRIPTOR), (uint8_t*)buf ); rcode = pUsb->getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), (uint8_t*) buf);
// Restore p->epinfo // Restore p->epinfo
p->epinfo = oldep_ptr; p->epinfo = oldep_ptr;
if( rcode ) if (rcode)
goto FailGetDevDescr; goto FailGetDevDescr;
if (((USB_DEVICE_DESCRIPTOR*)buf)->idVendor != FTDI_VID || ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct != FTDI_PID) if (((USB_DEVICE_DESCRIPTOR*) buf)->idVendor != FTDI_VID || ((USB_DEVICE_DESCRIPTOR*) buf)->idProduct != FTDI_PID)
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
// Save type of FTDI chip // Save type of FTDI chip
wFTDIType = ((USB_DEVICE_DESCRIPTOR*)buf)->bcdDevice; wFTDIType = ((USB_DEVICE_DESCRIPTOR*) buf)->bcdDevice;
// Allocate new address according to device class // Allocate new address according to device class
bAddress = addrPool.AllocAddress(parent, false, port); bAddress = addrPool.AllocAddress(parent, false, port);
if (!bAddress) if (!bAddress)
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL; return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
// Extract Max Packet Size from the device descriptor // Extract Max Packet Size from the device descriptor
epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0; epInfo[0].maxPktSize = (uint8_t) ((USB_DEVICE_DESCRIPTOR*) buf)->bMaxPacketSize0;
// Assign new address to the device // Assign new address to the device
rcode = pUsb->setAddr( 0, 0, bAddress ); rcode = pUsb->setAddr(0, 0, bAddress);
if (rcode) if (rcode) {
{ p->lowspeed = false;
p->lowspeed = false; addrPool.FreeAddress(bAddress);
addrPool.FreeAddress(bAddress); bAddress = 0;
bAddress = 0; USBTRACE2("setAddr:", rcode);
USBTRACE2("setAddr:",rcode); return rcode;
return rcode; }
}
USBTRACE2("Addr:", bAddress); USBTRACE2("Addr:", bAddress);
p->lowspeed = false; p->lowspeed = false;
p = addrPool.GetUsbDevicePtr(bAddress); p = addrPool.GetUsbDevicePtr(bAddress);
if (!p) if (!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
p->lowspeed = lowspeed; p->lowspeed = lowspeed;
num_of_conf = ((USB_DEVICE_DESCRIPTOR*)buf)->bNumConfigurations; num_of_conf = ((USB_DEVICE_DESCRIPTOR*) buf)->bNumConfigurations;
// Assign epInfo to epinfo pointer // Assign epInfo to epinfo pointer
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo); rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
if (rcode) if (rcode)
goto FailSetDevTblEntry; goto FailSetDevTblEntry;
USBTRACE2("NC:", num_of_conf); USBTRACE2("NC:", num_of_conf);
for (uint8_t i=0; i<num_of_conf; i++) for (uint8_t i = 0; i < num_of_conf; i++) {
{ HexDumper<USBReadParser, uint16_t, uint16_t> HexDump;
HexDumper<USBReadParser, uint16_t, uint16_t> HexDump; ConfigDescParser < 0xFF, 0xFF, 0xFF, CP_MASK_COMPARE_ALL> confDescrParser(this);
ConfigDescParser<0xFF, 0xFF, 0xFF, CP_MASK_COMPARE_ALL> confDescrParser(this);
rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump); rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump);
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
if (bNumEP > 1) if (rcode)
break; goto FailGetConfDescr;
} // for
if (bNumEP < 2) rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
USBTRACE2("NumEP:", bNumEP); if (rcode)
goto FailGetConfDescr;
// Assign epInfo to epinfo pointer if (bNumEP > 1)
rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo); break;
} // for
USBTRACE2("Conf:", bConfNum); if (bNumEP < 2)
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
// Set Configuration Value USBTRACE2("NumEP:", bNumEP);
rcode = pUsb->setConf(bAddress, 0, bConfNum);
if (rcode) // Assign epInfo to epinfo pointer
goto FailSetConfDescr; rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
rcode = pAsync->OnInit(this); USBTRACE2("Conf:", bConfNum);
if (rcode) // Set Configuration Value
goto FailOnInit; rcode = pUsb->setConf(bAddress, 0, bConfNum);
USBTRACE("FTDI configured\r\n"); if (rcode)
goto FailSetConfDescr;
bPollEnable = true; rcode = pAsync->OnInit(this);
return 0;
if (rcode)
goto FailOnInit;
USBTRACE("FTDI configured\r\n");
bPollEnable = true;
return 0;
FailGetDevDescr: FailGetDevDescr:
USBTRACE("getDevDescr:"); USBTRACE("getDevDescr:");
goto Fail; goto Fail;
FailSetDevTblEntry: FailSetDevTblEntry:
USBTRACE("setDevTblEn:"); USBTRACE("setDevTblEn:");
goto Fail; goto Fail;
FailGetConfDescr: FailGetConfDescr:
USBTRACE("getConf:"); USBTRACE("getConf:");
goto Fail; goto Fail;
FailSetConfDescr: FailSetConfDescr:
USBTRACE("setConf:"); USBTRACE("setConf:");
goto Fail; goto Fail;
FailSetBaudRate:
USBTRACE("SetBaudRate:");
goto Fail;
FailSetFlowControl:
USBTRACE("SetFlowControl:");
goto Fail;
FailOnInit: FailOnInit:
USBTRACE("OnInit:"); USBTRACE("OnInit:");
goto Fail; goto Fail;
Fail: Fail:
Serial.println(rcode, HEX); PrintHex<uint8_t > (rcode, 0x80);
Release(); Notify(PSTR("\r\n"), 0x80);
return rcode; //Serial.println(rcode, HEX);
Release();
return rcode;
} }
void FTDI::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) {
ErrorMessage<uint8_t > (PSTR("Conf.Val"), conf);
ErrorMessage<uint8_t > (PSTR("Iface Num"), iface);
ErrorMessage<uint8_t > (PSTR("Alt.Set"), alt);
void FTDI::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) bConfNum = conf;
{
ErrorMessage<uint8_t>(PSTR("Conf.Val"), conf);
ErrorMessage<uint8_t>(PSTR("Iface Num"),iface);
ErrorMessage<uint8_t>(PSTR("Alt.Set"), alt);
bConfNum = conf; uint8_t index;
uint8_t index; if ((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80)
index = epInterruptInIndex;
else
if ((pep->bmAttributes & 0x02) == 2)
index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex;
else
return;
if ((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80) // Fill in the endpoint info structure
index = epInterruptInIndex; epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
else epInfo[index].maxPktSize = (uint8_t) pep->wMaxPacketSize;
if ((pep->bmAttributes & 0x02) == 2) epInfo[index].epAttribs = 0;
index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex;
else
return;
// Fill in the endpoint info structure bNumEP++;
epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
//epInfo[index].epAttribs = 0;
bNumEP ++; PrintEndpointDescriptor(pep);
PrintEndpointDescriptor(pep);
} }
uint8_t FTDI::Release() uint8_t FTDI::Release() {
{ pUsb->GetAddressPool().FreeAddress(bAddress);
pUsb->GetAddressPool().FreeAddress(bAddress);
bAddress = 0; bAddress = 0;
bNumEP = 1; bNumEP = 1;
qNextPollTime = 0; qNextPollTime = 0;
bPollEnable = false; bPollEnable = false;
return 0; return 0;
} }
uint8_t FTDI::Poll() uint8_t FTDI::Poll() {
{ uint8_t rcode = 0;
uint8_t rcode = 0;
//if (!bPollEnable) //if (!bPollEnable)
// return 0; // return 0;
//if (qNextPollTime <= millis()) //if (qNextPollTime <= millis())
//{ //{
// Serial.println(bAddress, HEX); // Serial.println(bAddress, HEX);
// qNextPollTime = millis() + 100; // qNextPollTime = millis() + 100;
//} //}
return rcode; return rcode;
} }
uint8_t FTDI::SetBaudRate(uint32_t baud) uint8_t FTDI::SetBaudRate(uint32_t baud) {
{ uint16_t baud_value, baud_index = 0;
uint16_t baud_value, baud_index = 0; uint32_t divisor3;
uint32_t divisor3;
divisor3 = 48000000 / 2 / baud; // divisor shifted 3 bits to the left divisor3 = 48000000 / 2 / baud; // divisor shifted 3 bits to the left
if (wFTDIType == FT232AM) if (wFTDIType == FT232AM) {
{ if ((divisor3 & 0x7) == 7)
if ((divisor3 & 0x7) == 7) divisor3++; // round x.7/8 up to x+1
divisor3 ++; // round x.7/8 up to x+1
baud_value = divisor3 >> 3; baud_value = divisor3 >> 3;
divisor3 &= 0x7; divisor3 &= 0x7;
if (divisor3 == 1) baud_value |= 0xc000; else // 0.125 if (divisor3 == 1) baud_value |= 0xc000;
if (divisor3 >= 4) baud_value |= 0x4000; else // 0.5 else // 0.125
if (divisor3 != 0) baud_value |= 0x8000; // 0.25 if (divisor3 >= 4) baud_value |= 0x4000;
if (baud_value == 1) baud_value = 0; /* special case for maximum baud rate */ else // 0.5
} if (divisor3 != 0) baud_value |= 0x8000; // 0.25
else if (baud_value == 1) baud_value = 0; /* special case for maximum baud rate */
{ } else {
static const unsigned char divfrac [8] = { 0, 3, 2, 0, 1, 1, 2, 3 }; static const unsigned char divfrac [8] = {0, 3, 2, 0, 1, 1, 2, 3};
static const unsigned char divindex[8] = { 0, 0, 0, 1, 0, 1, 1, 1 }; static const unsigned char divindex[8] = {0, 0, 0, 1, 0, 1, 1, 1};
baud_value = divisor3 >> 3; baud_value = divisor3 >> 3;
baud_value |= divfrac [divisor3 & 0x7] << 14; baud_value |= divfrac [divisor3 & 0x7] << 14;
baud_index = divindex[divisor3 & 0x7]; baud_index = divindex[divisor3 & 0x7];
/* Deal with special cases for highest baud rates. */ /* Deal with special cases for highest baud rates. */
if (baud_value == 1) baud_value = 0; else // 1.0 if (baud_value == 1) baud_value = 0;
if (baud_value == 0x4001) baud_value = 1; // 1.5 else // 1.0
} if (baud_value == 0x4001) baud_value = 1; // 1.5
USBTRACE2("baud_value:", baud_value); }
USBTRACE2("baud_index:", baud_index); USBTRACE2("baud_value:", baud_value);
return pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_SET_BAUD_RATE, baud_value & 0xff, baud_value >> 8, baud_index, 0, 0, NULL, NULL ); USBTRACE2("baud_index:", baud_index);
return pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_SET_BAUD_RATE, baud_value & 0xff, baud_value >> 8, baud_index, 0, 0, NULL, NULL);
} }
uint8_t FTDI::SetModemControl(uint16_t signal) uint8_t FTDI::SetModemControl(uint16_t signal) {
{ return pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_MODEM_CTRL, signal & 0xff, signal >> 8, 0, 0, 0, NULL, NULL);
return pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_MODEM_CTRL, signal & 0xff, signal >> 8, 0, 0, 0, NULL, NULL);
} }
uint8_t FTDI::SetFlowControl(uint8_t protocol, uint8_t xon, uint8_t xoff) uint8_t FTDI::SetFlowControl(uint8_t protocol, uint8_t xon, uint8_t xoff) {
{ return pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_SET_FLOW_CTRL, xon, xoff, protocol << 8, 0, 0, NULL, NULL);
return pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_SET_FLOW_CTRL, xon, xoff, protocol << 8, 0, 0, NULL, NULL);
} }
uint8_t FTDI::SetData(uint16_t databm) uint8_t FTDI::SetData(uint16_t databm) {
{ return pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_SET_DATA, databm & 0xff, databm >> 8, 0, 0, 0, NULL, NULL);
return pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_SET_DATA, databm & 0xff, databm >> 8, 0, 0, 0, NULL, NULL);
} }
uint8_t FTDI::RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr) uint8_t FTDI::RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr) {
{ return pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, dataptr);
return pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, dataptr);
} }
uint8_t FTDI::SndData(uint16_t nbytes, uint8_t *dataptr) uint8_t FTDI::SndData(uint16_t nbytes, uint8_t *dataptr) {
{ return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, nbytes, dataptr);
return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, nbytes, dataptr);
} }
void FTDI::PrintEndpointDescriptor( const USB_ENDPOINT_DESCRIPTOR* ep_ptr ) void FTDI::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr) {
{ Notify(PSTR("Endpoint descriptor:"), 0x80);
Notify(PSTR("Endpoint descriptor:")); Notify(PSTR("\r\nLength:\t\t"), 0x80);
Notify(PSTR("\r\nLength:\t\t")); PrintHex<uint8_t > (ep_ptr->bLength, 0x80);
PrintHex<uint8_t>(ep_ptr->bLength); Notify(PSTR("\r\nType:\t\t"), 0x80);
Notify(PSTR("\r\nType:\t\t")); PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80);
PrintHex<uint8_t>(ep_ptr->bDescriptorType); Notify(PSTR("\r\nAddress:\t"), 0x80);
Notify(PSTR("\r\nAddress:\t")); PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80);
PrintHex<uint8_t>(ep_ptr->bEndpointAddress); Notify(PSTR("\r\nAttributes:\t"), 0x80);
Notify(PSTR("\r\nAttributes:\t")); PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80);
PrintHex<uint8_t>(ep_ptr->bmAttributes); Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
Notify(PSTR("\r\nMaxPktSize:\t")); PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80);
PrintHex<uint16_t>(ep_ptr->wMaxPacketSize); Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
Notify(PSTR("\r\nPoll Intrv:\t")); PrintHex<uint8_t > (ep_ptr->bInterval, 0x80);
PrintHex<uint8_t>(ep_ptr->bInterval); Notify(PSTR("\r\n"), 0x80);
Notify(PSTR("\r\n"));
} }

View file

@ -13,7 +13,7 @@ Contact information
Circuits At Home, LTD Circuits At Home, LTD
Web : http://www.circuitsathome.com Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com e-mail : support@circuitsathome.com
*/ */
#if !defined(__CDCFTDI_H__) #if !defined(__CDCFTDI_H__)
#define __CDCFTDI_H__ #define __CDCFTDI_H__
@ -94,10 +94,9 @@ e-mail : support@circuitsathome.com
class FTDI; class FTDI;
class FTDIAsyncOper class FTDIAsyncOper {
{
public: public:
virtual uint8_t OnInit(FTDI *pftdi) = 0; virtual uint8_t OnInit(FTDI *pftdi) = 0;
}; };
@ -105,46 +104,48 @@ public:
// so only three endpoints are allocated. // so only three endpoints are allocated.
#define FTDI_MAX_ENDPOINTS 3 #define FTDI_MAX_ENDPOINTS 3
class FTDI : public USBDeviceConfig, public UsbConfigXtracter class FTDI : public USBDeviceConfig, public UsbConfigXtracter {
{ static const uint8_t epDataInIndex; // DataIn endpoint index
static const uint8_t epDataInIndex; // DataIn endpoint index static const uint8_t epDataOutIndex; // DataOUT endpoint index
static const uint8_t epDataOutIndex; // DataOUT endpoint index static const uint8_t epInterruptInIndex; // InterruptIN endpoint index
static const uint8_t epInterruptInIndex; // InterruptIN endpoint index
FTDIAsyncOper *pAsync; FTDIAsyncOper *pAsync;
USB *pUsb; USB *pUsb;
uint8_t bAddress; uint8_t bAddress;
uint8_t bConfNum; // configuration number uint8_t bConfNum; // configuration number
uint8_t bNumIface; // number of interfaces in the configuration uint8_t bNumIface; // number of interfaces in the configuration
uint8_t bNumEP; // total number of EP in the configuration uint8_t bNumEP; // total number of EP in the configuration
uint32_t qNextPollTime; // next poll time uint32_t qNextPollTime; // next poll time
bool bPollEnable; // poll enable flag bool bPollEnable; // poll enable flag
uint16_t wFTDIType; // Type of FTDI chip uint16_t wFTDIType; // Type of FTDI chip
EpInfo epInfo[FTDI_MAX_ENDPOINTS]; EpInfo epInfo[FTDI_MAX_ENDPOINTS];
void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr); void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr);
public: public:
FTDI(USB *pusb, FTDIAsyncOper *pasync); FTDI(USB *pusb, FTDIAsyncOper *pasync);
uint8_t SetBaudRate(uint32_t baud); uint8_t SetBaudRate(uint32_t baud);
uint8_t SetModemControl(uint16_t control); uint8_t SetModemControl(uint16_t control);
uint8_t SetFlowControl(uint8_t protocol, uint8_t xon = 0x11, uint8_t xoff = 0x13); uint8_t SetFlowControl(uint8_t protocol, uint8_t xon = 0x11, uint8_t xoff = 0x13);
uint8_t SetData(uint16_t databm); uint8_t SetData(uint16_t databm);
// Methods for recieving and sending data // Methods for recieving and sending data
uint8_t RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr); uint8_t RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr);
uint8_t SndData(uint16_t nbytes, uint8_t *dataptr); uint8_t SndData(uint16_t nbytes, uint8_t *dataptr);
// USBDeviceConfig implementation // USBDeviceConfig implementation
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed); virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
virtual uint8_t Release(); virtual uint8_t Release();
virtual uint8_t Poll(); virtual uint8_t Poll();
virtual uint8_t GetAddress() { return bAddress; };
// UsbConfigXtracter implementation virtual uint8_t GetAddress() {
virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep); return bAddress;
};
// UsbConfigXtracter implementation
virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
}; };
#endif // __CDCFTDI_H__ #endif // __CDCFTDI_H__

View file

@ -13,215 +13,173 @@ Contact information
Circuits At Home, LTD Circuits At Home, LTD
Web : http://www.circuitsathome.com Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com e-mail : support@circuitsathome.com
*/ */
#include "cdcprolific.h" #include "cdcprolific.h"
PL2303::PL2303(USB *p, CDCAsyncOper *pasync) : PL2303::PL2303(USB *p, CDCAsyncOper *pasync) :
ACM(p, pasync) ACM(p, pasync),
//wPLType(0) wPLType(0) {
{
} }
uint8_t PL2303::Init(uint8_t parent, uint8_t port, bool lowspeed) uint8_t PL2303::Init(uint8_t parent, uint8_t port, bool lowspeed) {
{ const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR);
const uint8_t constBufSize = sizeof(USB_DEVICE_DESCRIPTOR);
uint8_t buf[constBufSize]; uint8_t buf[constBufSize];
uint8_t rcode; uint8_t rcode;
UsbDevice *p = NULL; UsbDevice *p = NULL;
EpInfo *oldep_ptr = NULL; EpInfo *oldep_ptr = NULL;
uint8_t num_of_conf; // number of configurations uint8_t num_of_conf; // number of configurations
enum pl2303_type pltype = unknown;
AddressPool &addrPool = pUsb->GetAddressPool(); AddressPool &addrPool = pUsb->GetAddressPool();
USBTRACE("PL Init\r\n"); USBTRACE("PL Init\r\n");
if (bAddress) if (bAddress)
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE; return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
// Get pointer to pseudo device with address 0 assigned // Get pointer to pseudo device with address 0 assigned
p = addrPool.GetUsbDevicePtr(0); p = addrPool.GetUsbDevicePtr(0);
if (!p) if (!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
if (!p->epinfo) if (!p->epinfo) {
{ USBTRACE("epinfo\r\n");
USBTRACE("epinfo\r\n"); return USB_ERROR_EPINFO_IS_NULL;
return USB_ERROR_EPINFO_IS_NULL; }
}
// Save old pointer to EP_RECORD of address 0 // Save old pointer to EP_RECORD of address 0
oldep_ptr = p->epinfo; oldep_ptr = p->epinfo;
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
p->epinfo = epInfo; p->epinfo = epInfo;
p->lowspeed = lowspeed; p->lowspeed = lowspeed;
// Get device descriptor // Get device descriptor
rcode = pUsb->getDevDescr( 0, 0, sizeof(USB_DEVICE_DESCRIPTOR), (uint8_t*)buf ); rcode = pUsb->getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), (uint8_t*) buf);
// Restore p->epinfo // Restore p->epinfo
p->epinfo = oldep_ptr; p->epinfo = oldep_ptr;
if( rcode ) if (rcode)
goto FailGetDevDescr; goto FailGetDevDescr;
if (((USB_DEVICE_DESCRIPTOR*)buf)->idVendor != PL_VID && ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct != PL_PID ) { if (((USB_DEVICE_DESCRIPTOR*) buf)->idVendor != PL_VID && ((USB_DEVICE_DESCRIPTOR*) buf)->idProduct != PL_PID)
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
}
/* determine chip variant */ // Save type of PL chip
wPLType = ((USB_DEVICE_DESCRIPTOR*) buf)->bcdDevice;
if (((USB_DEVICE_DESCRIPTOR*)buf)->bDeviceClass == 0x02 ) { // Allocate new address according to device class
pltype = type_0; bAddress = addrPool.AllocAddress(parent, false, port);
}
else if (((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0 == 0x40 ) {
pltype = rev_HX;
}
else if (((USB_DEVICE_DESCRIPTOR*)buf)->bDeviceClass == 0x00) {
pltype = type_1;
}
else if (((USB_DEVICE_DESCRIPTOR*)buf)->bDeviceClass == 0xff) {
pltype = type_1;
}
// Allocate new address according to device class if (!bAddress)
bAddress = addrPool.AllocAddress(parent, false, port); return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
if (!bAddress) // Extract Max Packet Size from the device descriptor
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL; epInfo[0].maxPktSize = (uint8_t) ((USB_DEVICE_DESCRIPTOR*) buf)->bMaxPacketSize0;
// Extract Max Packet Size from the device descriptor // Assign new address to the device
epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0; rcode = pUsb->setAddr(0, 0, bAddress);
// Assign new address to the device if (rcode) {
rcode = pUsb->setAddr( 0, 0, bAddress ); p->lowspeed = false;
addrPool.FreeAddress(bAddress);
bAddress = 0;
USBTRACE2("setAddr:", rcode);
return rcode;
}
if (rcode) USBTRACE2("Addr:", bAddress);
{
p->lowspeed = false;
addrPool.FreeAddress(bAddress);
bAddress = 0;
USBTRACE2("setAddr:",rcode);
return rcode;
}
USBTRACE2("Addr:", bAddress); p->lowspeed = false;
p->lowspeed = false; p = addrPool.GetUsbDevicePtr(bAddress);
p = addrPool.GetUsbDevicePtr(bAddress); if (!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
if (!p) p->lowspeed = lowspeed;
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
p->lowspeed = lowspeed; num_of_conf = ((USB_DEVICE_DESCRIPTOR*) buf)->bNumConfigurations;
num_of_conf = ((USB_DEVICE_DESCRIPTOR*)buf)->bNumConfigurations; // Assign epInfo to epinfo pointer
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
// Assign epInfo to epinfo pointer if (rcode)
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo); goto FailSetDevTblEntry;
if (rcode) USBTRACE2("NC:", num_of_conf);
goto FailSetDevTblEntry;
USBTRACE2("NC:", num_of_conf); for (uint8_t i = 0; i < num_of_conf; i++) {
HexDumper<USBReadParser, uint16_t, uint16_t> HexDump;
ConfigDescParser < 0xFF, 0, 0, CP_MASK_COMPARE_CLASS> confDescrParser(this);
for( uint8_t i=0; i<num_of_conf; i++ ) rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump);
{
//HexDumper<USBReadParser, uint16_t, uint16_t> HexDump;
ConfigDescParser<0xFF, 0, 0, CP_MASK_COMPARE_CLASS> confDescrParser(this);
//rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump); if (rcode)
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser); goto FailGetConfDescr;
if (bNumEP > 1) rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
break;
} // for
if ( bNumEP < 2 ) if (rcode)
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; goto FailGetConfDescr;
// Assign epInfo to epinfo pointer if (bNumEP > 1)
rcode = pUsb->setEpInfoEntry( bAddress, bNumEP, epInfo ); break;
} // for
USBTRACE2("Conf:", bConfNum); if (bNumEP < 2)
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
// Set Configuration Value // Assign epInfo to epinfo pointer
rcode = pUsb->setConf(bAddress, 0, bConfNum); rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
if (rcode) USBTRACE2("Conf:", bConfNum);
goto FailSetConfDescr;
#if defined(PL2303_COMPAT) // Set Configuration Value
/* shamanic dance - sending Prolific init data as-is */ rcode = pUsb->setConf(bAddress, 0, bConfNum);
vendorRead( 0x84, 0x84, 0, buf );
vendorWrite( 0x04, 0x04, 0 );
vendorRead( 0x84, 0x84, 0, buf );
vendorRead( 0x83, 0x83, 0, buf );
vendorRead( 0x84, 0x84, 0, buf );
vendorWrite( 0x04, 0x04, 1 );
vendorRead( 0x84, 0x84, 0, buf);
vendorRead( 0x83, 0x83, 0, buf);
vendorWrite( 0, 0, 1 );
vendorWrite( 1, 0, 0 );
if ( pltype == rev_HX ) {
vendorWrite( 2, 0, 0x44 );
vendorWrite( 0x06, 0x06, 0 ); //from W7 init
}
else {
vendorWrite( 2, 0, 0x24 );
}
/* shamanic dance end */
#endif
/* calling post-init callback */ if (rcode)
rcode = pAsync->OnInit(this); goto FailSetConfDescr;
if (rcode) rcode = pAsync->OnInit(this);
goto FailOnInit;
USBTRACE("PL configured\r\n"); if (rcode)
goto FailOnInit;
//bPollEnable = true; USBTRACE("PL configured\r\n");
ready = true;
return 0; bPollEnable = true;
return 0;
FailGetDevDescr: FailGetDevDescr:
USBTRACE("getDevDescr:"); USBTRACE("getDevDescr:");
goto Fail; goto Fail;
FailSetDevTblEntry: FailSetDevTblEntry:
USBTRACE("setDevTblEn:"); USBTRACE("setDevTblEn:");
goto Fail; goto Fail;
FailGetConfDescr: FailGetConfDescr:
USBTRACE("getConf:"); USBTRACE("getConf:");
goto Fail; goto Fail;
FailSetConfDescr: FailSetConfDescr:
USBTRACE("setConf:"); USBTRACE("setConf:");
goto Fail; goto Fail;
FailSetControlLineState:
USBTRACE("SetControlLineState:");
goto Fail;
FailSetLineCoding:
USBTRACE("SetLineCoding:");
goto Fail;
FailOnInit: FailOnInit:
USBTRACE("OnInit:"); USBTRACE("OnInit:");
goto Fail; goto Fail;
Fail: Fail:
Serial.println(rcode, HEX); PrintHex<uint8_t > (rcode, 0x80);
Release(); Notify(PSTR("\r\n"), 0x80);
return rcode; //Serial.println(rcode, HEX);
Release();
return rcode;
} }
//uint8_t PL::Poll() //uint8_t PL::Poll()

View file

@ -13,7 +13,7 @@ Contact information
Circuits At Home, LTD Circuits At Home, LTD
Web : http://www.circuitsathome.com Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com e-mail : support@circuitsathome.com
*/ */
#if !defined(__CDCPROLIFIC_H__) #if !defined(__CDCPROLIFIC_H__)
#define __CDCPROLIFIC_H__ #define __CDCPROLIFIC_H__
@ -38,11 +38,11 @@ e-mail : support@circuitsathome.com
#include "confdescparser.h" #include "confdescparser.h"
#include "cdcacm.h" #include "cdcacm.h"
//#define PL2303_COMPAT //uncomment it if you have compatibility problems
#define PL_VID 0x067B #define PL_VID 0x067B
#define PL_PID ( 0x2303 || 0x0609 ) #define PL_PID ( 0x2303 || 0x0609 )
//#define PL_PID 0x0609
#define PROLIFIC_REV_H 0x0202 #define PROLIFIC_REV_H 0x0202
#define PROLIFIC_REV_X 0x0300 #define PROLIFIC_REV_X 0x0300
#define PROLIFIC_REV_HX_CHIP_D 0x0400 #define PROLIFIC_REV_HX_CHIP_D 0x0400
@ -76,15 +76,13 @@ e-mail : support@circuitsathome.com
#define kCONTROL_DTR 0x01 #define kCONTROL_DTR 0x01
#define kCONTROL_RTS 0x02 #define kCONTROL_RTS 0x02
enum tXO_State {
enum tXO_State kXOnSent = -2,
{ kXOffSent = -1,
kXOnSent = -2, kXO_Idle = 0,
kXOffSent = -1, kXOffNeeded = 1,
kXO_Idle = 0, kXOnNeeded = 2
kXOffNeeded = 1, };
kXOnNeeded = 2
} ;
#define kStateTransientMask 0x74 #define kStateTransientMask 0x74
#define kBreakError 0x04 #define kBreakError 0x04
@ -125,55 +123,31 @@ enum tXO_State
#define RESET_DOWNSTREAM_DATA_PIPE 0x08 #define RESET_DOWNSTREAM_DATA_PIPE 0x08
#define RESET_UPSTREAM_DATA_PIPE 0x09 #define RESET_UPSTREAM_DATA_PIPE 0x09
enum pl2303_type enum pl2303_type {
{ unknown,
unknown, type_1, /* don't know the difference between type 0 and */
type_0, rev_X, /* type 1, until someone from prolific tells us... */
type_1, /* don't know the difference between type 0 and */ rev_HX, /* HX version of the pl2303 chip */
rev_X, /* type 1, until someone from prolific tells us... */ rev_H
rev_HX, /* HX version of the pl2303 chip */
rev_H
}; };
#define PL_MAX_ENDPOINTS 4 #define PL_MAX_ENDPOINTS 4
//class PL2303; class PL2303 : public ACM {
uint16_t wPLType; // Type of chip
class PL2303 : public ACM
{
//uint16_t wPLType; // Type of chip
public: public:
PL2303(USB *pusb, CDCAsyncOper *pasync); PL2303(USB *pusb, CDCAsyncOper *pasync);
// USBDeviceConfig implementation // USBDeviceConfig implementation
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed); virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
//virtual uint8_t Release(); //virtual uint8_t Release();
//virtual uint8_t Poll(); //virtual uint8_t Poll();
//virtual uint8_t GetAddress() { return bAddress; }; //virtual uint8_t GetAddress() { return bAddress; };
//// UsbConfigXtracter implementation //// UsbConfigXtracter implementation
//virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep); //virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
private:
/* Prolific proprietary requests */
uint8_t vendorRead( uint8_t val_lo, uint8_t val_hi, uint16_t index, uint8_t* buf );
uint8_t vendorWrite( uint8_t val_lo, uint8_t val_hi, uint8_t index );
}; };
/* vendor read request */
inline uint8_t PL2303::vendorRead( uint8_t val_lo, uint8_t val_hi, uint16_t index, uint8_t* buf )
{
return( pUsb->ctrlReq(bAddress, 0, VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, val_lo, val_hi, index, 1, 1, buf, NULL ));
}
/* vendor write request */
inline uint8_t PL2303::vendorWrite( uint8_t val_lo, uint8_t val_hi, uint8_t index )
{
return( pUsb->ctrlReq(bAddress, 0, VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, val_lo, val_hi, index, 0, 0, NULL, NULL ));
}
#endif // __CDCPROLIFIC_H__ #endif // __CDCPROLIFIC_H__

View file

@ -13,7 +13,7 @@ Contact information
Circuits At Home, LTD Circuits At Home, LTD
Web : http://www.circuitsathome.com Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com e-mail : support@circuitsathome.com
*/ */
#if !defined(__CONFDESCPARSER_H__) #if !defined(__CONFDESCPARSER_H__)
#define __CONFDESCPARSER_H__ #define __CONFDESCPARSER_H__
@ -27,12 +27,11 @@ e-mail : support@circuitsathome.com
//#include "hid.h" //#include "hid.h"
class UsbConfigXtracter class UsbConfigXtracter {
{
public: public:
//virtual void ConfigXtract(const USB_CONFIGURATION_DESCRIPTOR *conf) = 0; //virtual void ConfigXtract(const USB_CONFIGURATION_DESCRIPTOR *conf) = 0;
//virtual void InterfaceXtract(uint8_t conf, const USB_INTERFACE_DESCRIPTOR *iface) = 0; //virtual void InterfaceXtract(uint8_t conf, const USB_INTERFACE_DESCRIPTOR *iface) = 0;
virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep) = 0; virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep) = 0;
}; };
#define CP_MASK_COMPARE_CLASS 1 #define CP_MASK_COMPARE_CLASS 1
@ -41,180 +40,173 @@ public:
#define CP_MASK_COMPARE_ALL 7 #define CP_MASK_COMPARE_ALL 7
// Configuration Descriptor Parser Class Template // Configuration Descriptor Parser Class Template
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK> template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
class ConfigDescParser : public USBReadParser class ConfigDescParser : public USBReadParser {
{ UsbConfigXtracter *theXtractor;
UsbConfigXtracter *theXtractor; MultiValueBuffer theBuffer;
MultiValueBuffer theBuffer; MultiByteValueParser valParser;
MultiByteValueParser valParser; ByteSkipper theSkipper;
ByteSkipper theSkipper; uint8_t varBuffer[16 /*sizeof(USB_CONFIGURATION_DESCRIPTOR)*/];
uint8_t varBuffer[16 /*sizeof(USB_CONFIGURATION_DESCRIPTOR)*/];
uint8_t stateParseDescr; // ParseDescriptor state uint8_t stateParseDescr; // ParseDescriptor state
uint8_t dscrLen; // Descriptor length uint8_t dscrLen; // Descriptor length
uint8_t dscrType; // Descriptor type uint8_t dscrType; // Descriptor type
bool isGoodInterface; // Apropriate interface flag bool isGoodInterface; // Apropriate interface flag
uint8_t confValue; // Configuration value uint8_t confValue; // Configuration value
uint8_t protoValue; // Protocol value uint8_t protoValue; // Protocol value
uint8_t ifaceNumber; // Interface number uint8_t ifaceNumber; // Interface number
uint8_t ifaceAltSet; // Interface alternate settings uint8_t ifaceAltSet; // Interface alternate settings
bool ParseDescriptor(uint8_t **pp, uint16_t *pcntdn); bool ParseDescriptor(uint8_t **pp, uint16_t *pcntdn);
void PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc); void PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc);
public: public:
ConfigDescParser(UsbConfigXtracter *xtractor); ConfigDescParser(UsbConfigXtracter *xtractor);
virtual void Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset); virtual void Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset);
}; };
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK> template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::ConfigDescParser(UsbConfigXtracter *xtractor) : ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::ConfigDescParser(UsbConfigXtracter *xtractor) :
stateParseDescr(0), theXtractor(xtractor),
dscrLen(0), stateParseDescr(0),
dscrType(0), dscrLen(0),
theXtractor(xtractor) dscrType(0) {
{ theBuffer.pValue = varBuffer;
theBuffer.pValue = varBuffer; valParser.Initialize(&theBuffer);
valParser.Initialize(&theBuffer); theSkipper.Initialize(&theBuffer);
theSkipper.Initialize(&theBuffer);
}; };
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK> template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
void ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset) void ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset) {
{ uint16_t cntdn = (uint16_t) len;
uint16_t cntdn = (uint16_t)len; uint8_t *p = (uint8_t*) pbuf;
uint8_t *p = (uint8_t*)pbuf;
while(cntdn) while (cntdn)
if (!ParseDescriptor(&p, &cntdn)) if (!ParseDescriptor(&p, &cntdn))
return; return;
} }
/* Parser for the configuration descriptor. Takes values for class, subclass, protocol fields in interface descriptor and /* Parser for the configuration descriptor. Takes values for class, subclass, protocol fields in interface descriptor and
compare masks for them. When the match is found, calls EndpointXtract passing buffer containing endpoint descriptor */ compare masks for them. When the match is found, calls EndpointXtract passing buffer containing endpoint descriptor */
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK> template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
bool ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::ParseDescriptor(uint8_t **pp, uint16_t *pcntdn) bool ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::ParseDescriptor(uint8_t **pp, uint16_t *pcntdn) {
{ switch (stateParseDescr) {
switch (stateParseDescr) case 0:
{ theBuffer.valueSize = 2;
case 0: valParser.Initialize(&theBuffer);
theBuffer.valueSize = 2; stateParseDescr = 1;
valParser.Initialize(&theBuffer); case 1:
stateParseDescr = 1; if (!valParser.Parse(pp, pcntdn))
case 1: return false;
if (!valParser.Parse(pp, pcntdn)) dscrLen = *((uint8_t*) theBuffer.pValue);
return false; dscrType = *((uint8_t*) theBuffer.pValue + 1);
dscrLen = *((uint8_t*)theBuffer.pValue); stateParseDescr = 2;
dscrType = *((uint8_t*)theBuffer.pValue + 1); case 2:
stateParseDescr = 2; // This is a sort of hack. Assuming that two bytes are allready in the buffer
case 2: // the pointer is positioned two bytes ahead in order for the rest of descriptor
// This is a sort of hack. Assuming that two bytes are already in the buffer // to be read right after the size and the type fields.
// the pointer is positioned two bytes ahead in order for the rest of descriptor // This should be used carefuly. varBuffer should be used directly to handle data
// to be read right after the size and the type fields. // in the buffer.
// This should be used carefuly. varBuffer should be used directly to handle data theBuffer.pValue = varBuffer + 2;
// in the buffer. stateParseDescr = 3;
theBuffer.pValue = varBuffer + 2; case 3:
stateParseDescr = 3; switch (dscrType) {
case 3: case USB_DESCRIPTOR_INTERFACE:
switch (dscrType) isGoodInterface = false;
{ case USB_DESCRIPTOR_CONFIGURATION:
case USB_DESCRIPTOR_INTERFACE: theBuffer.valueSize = sizeof (USB_CONFIGURATION_DESCRIPTOR) - 2;
isGoodInterface = false; break;
case USB_DESCRIPTOR_CONFIGURATION: case USB_DESCRIPTOR_ENDPOINT:
theBuffer.valueSize = sizeof(USB_CONFIGURATION_DESCRIPTOR) - 2; theBuffer.valueSize = sizeof (USB_ENDPOINT_DESCRIPTOR) - 2;
break; break;
case USB_DESCRIPTOR_ENDPOINT: case HID_DESCRIPTOR_HID:
theBuffer.valueSize = sizeof(USB_ENDPOINT_DESCRIPTOR) - 2; theBuffer.valueSize = dscrLen - 2;
break; break;
case HID_DESCRIPTOR_HID: }
theBuffer.valueSize = dscrLen - 2; valParser.Initialize(&theBuffer);
break; stateParseDescr = 4;
} case 4:
valParser.Initialize(&theBuffer); switch (dscrType) {
stateParseDescr = 4; case USB_DESCRIPTOR_CONFIGURATION:
case 4: if (!valParser.Parse(pp, pcntdn))
switch (dscrType) return false;
{ confValue = ((USB_CONFIGURATION_DESCRIPTOR*) varBuffer)->bConfigurationValue;
case USB_DESCRIPTOR_CONFIGURATION: break;
if (!valParser.Parse(pp, pcntdn)) case USB_DESCRIPTOR_INTERFACE:
return false; if (!valParser.Parse(pp, pcntdn))
confValue = ((USB_CONFIGURATION_DESCRIPTOR*)varBuffer)->bConfigurationValue; return false;
break; if ((MASK & CP_MASK_COMPARE_CLASS) && ((USB_INTERFACE_DESCRIPTOR*) varBuffer)->bInterfaceClass != CLASS_ID)
case USB_DESCRIPTOR_INTERFACE: break;
if (!valParser.Parse(pp, pcntdn)) if ((MASK & CP_MASK_COMPARE_SUBCLASS) && ((USB_INTERFACE_DESCRIPTOR*) varBuffer)->bInterfaceSubClass != SUBCLASS_ID)
return false; break;
if ((MASK & CP_MASK_COMPARE_CLASS) && ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bInterfaceClass != CLASS_ID) if ((MASK & CP_MASK_COMPARE_PROTOCOL) && ((USB_INTERFACE_DESCRIPTOR*) varBuffer)->bInterfaceProtocol != PROTOCOL_ID)
break; break;
if ((MASK & CP_MASK_COMPARE_SUBCLASS) && ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bInterfaceSubClass != SUBCLASS_ID)
break;
if ((MASK & CP_MASK_COMPARE_PROTOCOL) && ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bInterfaceProtocol != PROTOCOL_ID)
break;
isGoodInterface = true; isGoodInterface = true;
ifaceNumber = ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bInterfaceNumber; ifaceNumber = ((USB_INTERFACE_DESCRIPTOR*) varBuffer)->bInterfaceNumber;
ifaceAltSet = ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bAlternateSetting; ifaceAltSet = ((USB_INTERFACE_DESCRIPTOR*) varBuffer)->bAlternateSetting;
protoValue = ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bInterfaceProtocol; protoValue = ((USB_INTERFACE_DESCRIPTOR*) varBuffer)->bInterfaceProtocol;
break; break;
case USB_DESCRIPTOR_ENDPOINT: case USB_DESCRIPTOR_ENDPOINT:
if (!valParser.Parse(pp, pcntdn)) if (!valParser.Parse(pp, pcntdn))
return false; return false;
if (isGoodInterface) if (isGoodInterface)
if (theXtractor) if (theXtractor)
theXtractor->EndpointXtract(confValue, ifaceNumber, ifaceAltSet, protoValue, (USB_ENDPOINT_DESCRIPTOR*)varBuffer); theXtractor->EndpointXtract(confValue, ifaceNumber, ifaceAltSet, protoValue, (USB_ENDPOINT_DESCRIPTOR*) varBuffer);
break; break;
//case HID_DESCRIPTOR_HID: //case HID_DESCRIPTOR_HID:
// if (!valParser.Parse(pp, pcntdn)) // if (!valParser.Parse(pp, pcntdn))
// return false; // return false;
// PrintHidDescriptor((const USB_HID_DESCRIPTOR*)varBuffer); // PrintHidDescriptor((const USB_HID_DESCRIPTOR*)varBuffer);
// break; // break;
default: default:
if (!theSkipper.Skip(pp, pcntdn, dscrLen-2)) if (!theSkipper.Skip(pp, pcntdn, dscrLen - 2))
return false; return false;
} }
theBuffer.pValue = varBuffer; theBuffer.pValue = varBuffer;
stateParseDescr = 0; stateParseDescr = 0;
} }
return true; return true;
} }
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK> template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
void ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc) void ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc) {
{ Notify(PSTR("\r\n\r\nHID Descriptor:\r\n"), 0x80);
Notify(PSTR("\r\n\r\nHID Descriptor:\r\n")); Notify(PSTR("bDescLength:\t\t"), 0x80);
Notify(PSTR("bDescLength:\t\t")); PrintHex<uint8_t > (pDesc->bLength, 0x80);
PrintHex<uint8_t>(pDesc->bLength);
Notify(PSTR("\r\nbDescriptorType:\t")); Notify(PSTR("\r\nbDescriptorType:\t"), 0x80);
PrintHex<uint8_t>(pDesc->bDescriptorType); PrintHex<uint8_t > (pDesc->bDescriptorType, 0x80);
Notify(PSTR("\r\nbcdHID:\t\t\t")); Notify(PSTR("\r\nbcdHID:\t\t\t"), 0x80);
PrintHex<uint16_t>(pDesc->bcdHID); PrintHex<uint16_t > (pDesc->bcdHID, 0x80);
Notify(PSTR("\r\nbCountryCode:\t\t")); Notify(PSTR("\r\nbCountryCode:\t\t"), 0x80);
PrintHex<uint8_t>(pDesc->bCountryCode); PrintHex<uint8_t > (pDesc->bCountryCode, 0x80);
Notify(PSTR("\r\nbNumDescriptors:\t")); Notify(PSTR("\r\nbNumDescriptors:\t"), 0x80);
PrintHex<uint8_t>(pDesc->bNumDescriptors); PrintHex<uint8_t > (pDesc->bNumDescriptors, 0x80);
//Notify(PSTR("\r\nbDescrType:\t\t")); //Notify(PSTR("\r\nbDescrType:\t\t"));
//PrintHex<uint8_t>(pDesc->bDescrType); //PrintHex<uint8_t>(pDesc->bDescrType);
// //
//Notify(PSTR("\r\nwDescriptorLength:\t")); //Notify(PSTR("\r\nwDescriptorLength:\t"));
//PrintHex<uint16_t>(pDesc->wDescriptorLength); //PrintHex<uint16_t>(pDesc->wDescriptorLength);
for (uint8_t i=0; i<pDesc->bNumDescriptors; i++) for (uint8_t i = 0; i < pDesc->bNumDescriptors; i++) {
{ HID_CLASS_DESCRIPTOR_LEN_AND_TYPE *pLT = (HID_CLASS_DESCRIPTOR_LEN_AND_TYPE*)&(pDesc->bDescrType);
HID_CLASS_DESCRIPTOR_LEN_AND_TYPE *pLT = (HID_CLASS_DESCRIPTOR_LEN_AND_TYPE*)&(pDesc->bDescrType);
Notify(PSTR("\r\nbDescrType:\t\t")); Notify(PSTR("\r\nbDescrType:\t\t"), 0x80);
PrintHex<uint8_t>(pLT[i].bDescrType); PrintHex<uint8_t > (pLT[i].bDescrType, 0x80);
Notify(PSTR("\r\nwDescriptorLength:\t")); Notify(PSTR("\r\nwDescriptorLength:\t"), 0x80);
PrintHex<uint16_t>(pLT[i].wDescriptorLength); PrintHex<uint16_t > (pLT[i].wDescriptorLength, 0x80);
} }
Notify(PSTR("\r\n")); Notify(PSTR("\r\n"), 0x80);
} }

View file

@ -13,7 +13,7 @@ Contact information
Circuits At Home, LTD Circuits At Home, LTD
Web : http://www.circuitsathome.com Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com e-mail : support@circuitsathome.com
*/ */
#if !defined(__HEXDUMP_H__) #if !defined(__HEXDUMP_H__)
#define __HEXDUMP_H__ #define __HEXDUMP_H__
@ -22,37 +22,38 @@ e-mail : support@circuitsathome.com
#include "printhex.h" #include "printhex.h"
template <class BASE_CLASS, class LEN_TYPE, class OFFSET_TYPE> template <class BASE_CLASS, class LEN_TYPE, class OFFSET_TYPE>
class HexDumper : public BASE_CLASS class HexDumper : public BASE_CLASS {
{ uint8_t byteCount;
uint8_t byteCount; OFFSET_TYPE byteTotal;
OFFSET_TYPE byteTotal;
public: public:
HexDumper() : byteCount(0), byteTotal(0) {};
void Initialize() { byteCount = 0; byteTotal = 0; };
virtual void Parse(const LEN_TYPE len, const uint8_t *pbuf, const OFFSET_TYPE &offset); HexDumper() : byteCount(0), byteTotal(0) {
};
void Initialize() {
byteCount = 0;
byteTotal = 0;
};
virtual void Parse(const LEN_TYPE len, const uint8_t *pbuf, const OFFSET_TYPE &offset);
}; };
template <class BASE_CLASS, class LEN_TYPE, class OFFSET_TYPE> template <class BASE_CLASS, class LEN_TYPE, class OFFSET_TYPE>
void HexDumper<BASE_CLASS, LEN_TYPE, OFFSET_TYPE>::Parse(const LEN_TYPE len, const uint8_t *pbuf, const OFFSET_TYPE &offset) void HexDumper<BASE_CLASS, LEN_TYPE, OFFSET_TYPE>::Parse(const LEN_TYPE len, const uint8_t *pbuf, const OFFSET_TYPE &offset) {
{ for (LEN_TYPE j = 0; j < len; j++, byteCount++, byteTotal++) {
for (LEN_TYPE j=0; j<len; j++, byteCount++, byteTotal++) if (!byteCount) {
{ SerialPrintHex<OFFSET_TYPE > (byteTotal);
if (!byteCount) Serial.print(": ");
{ }
PrintHex<OFFSET_TYPE>(byteTotal); SerialPrintHex<uint8_t > (pbuf[j]);
Serial.print(": "); Serial.print(" ");
}
PrintHex<uint8_t>(pbuf[j]);
Serial.print(" ");
if (byteCount == 15) if (byteCount == 15) {
{ Serial.println("");
Serial.println(""); byteCount = 0xFF;
byteCount = 0xFF; }
} }
}
} }
#endif // __HEXDUMP_H__ #endif // __HEXDUMP_H__

136
hid.cpp
View file

@ -1,84 +1,82 @@
#include "hid.h" #include "hid.h"
//get HID report descriptor //get HID report descriptor
uint8_t HID::GetReportDescr( uint8_t ep, USBReadParser *parser )
{
const uint8_t constBufLen = 64;
uint8_t buf[constBufLen];
uint8_t rcode = pUsb->ctrlReq( bAddress, ep, bmREQ_HIDREPORT, USB_REQUEST_GET_DESCRIPTOR, 0x00, uint8_t HID::GetReportDescr(uint8_t ep, USBReadParser *parser) {
HID_DESCRIPTOR_REPORT, 0x0000, 128, constBufLen, buf, (USBReadParser*)parser ); const uint8_t constBufLen = 64;
uint8_t buf[constBufLen];
//return ((rcode != hrSTALL) ? rcode : 0); uint8_t rcode = pUsb->ctrlReq(bAddress, ep, bmREQ_HIDREPORT, USB_REQUEST_GET_DESCRIPTOR, 0x00,
return rcode; HID_DESCRIPTOR_REPORT, 0x0000, 128, constBufLen, buf, (USBReadParser*) parser);
//return ((rcode != hrSTALL) ? rcode : 0);
return rcode;
} }
//uint8_t HID::getHidDescr( uint8_t ep, uint16_t nbytes, uint8_t* dataptr ) //uint8_t HID::getHidDescr( uint8_t ep, uint16_t nbytes, uint8_t* dataptr )
//{ //{
// return( pUsb->ctrlReq( bAddress, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, 0x00, HID_DESCRIPTOR_HID, 0x0000, nbytes, dataptr )); // return( pUsb->ctrlReq( bAddress, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, 0x00, HID_DESCRIPTOR_HID, 0x0000, nbytes, dataptr ));
//} //}
uint8_t HID::SetReport( uint8_t ep, uint8_t iface, uint8_t report_type, uint8_t report_id, uint16_t nbytes, uint8_t* dataptr )
{ uint8_t HID::SetReport(uint8_t ep, uint8_t iface, uint8_t report_type, uint8_t report_id, uint16_t nbytes, uint8_t* dataptr) {
return( pUsb->ctrlReq( bAddress, ep, bmREQ_HIDOUT, HID_REQUEST_SET_REPORT, report_id, report_type, iface, nbytes, nbytes, dataptr, NULL )); return ( pUsb->ctrlReq(bAddress, ep, bmREQ_HIDOUT, HID_REQUEST_SET_REPORT, report_id, report_type, iface, nbytes, nbytes, dataptr, NULL));
}
uint8_t HID::GetReport( uint8_t ep, uint8_t iface, uint8_t report_type, uint8_t report_id, uint16_t nbytes, uint8_t* dataptr )
{
return( pUsb->ctrlReq( bAddress, ep, bmREQ_HIDIN, HID_REQUEST_GET_REPORT, report_id, report_type, iface, nbytes, nbytes, dataptr, NULL ));
}
uint8_t HID::GetIdle( uint8_t iface, uint8_t reportID, uint8_t* dataptr )
{
return( pUsb->ctrlReq( bAddress, 0, bmREQ_HIDIN, HID_REQUEST_GET_IDLE, reportID, 0, iface, 0x0001, 0x0001, dataptr, NULL ));
}
uint8_t HID::SetIdle( uint8_t iface, uint8_t reportID, uint8_t duration )
{
return( pUsb->ctrlReq( bAddress, 0, bmREQ_HIDOUT, HID_REQUEST_SET_IDLE, reportID, duration, iface, 0x0000, 0x0000, NULL, NULL ));
}
uint8_t HID::SetProtocol( uint8_t iface, uint8_t protocol )
{
return( pUsb->ctrlReq( bAddress, 0, bmREQ_HIDOUT, HID_REQUEST_SET_PROTOCOL, protocol, 0x00, iface, 0x0000, 0x0000, NULL, NULL ));
}
uint8_t HID::GetProtocol( uint8_t iface, uint8_t* dataptr )
{
return( pUsb->ctrlReq( bAddress, 0, bmREQ_HIDIN, HID_REQUEST_GET_PROTOCOL, 0x00, 0x00, iface, 0x0001, 0x0001, dataptr, NULL ));
} }
void HID::PrintEndpointDescriptor( const USB_ENDPOINT_DESCRIPTOR* ep_ptr ) uint8_t HID::GetReport(uint8_t ep, uint8_t iface, uint8_t report_type, uint8_t report_id, uint16_t nbytes, uint8_t* dataptr) {
{ return ( pUsb->ctrlReq(bAddress, ep, bmREQ_HIDIN, HID_REQUEST_GET_REPORT, report_id, report_type, iface, nbytes, nbytes, dataptr, NULL));
Notify(PSTR("Endpoint descriptor:"));
Notify(PSTR("\r\nLength:\t\t"));
PrintHex<uint8_t>(ep_ptr->bLength);
Notify(PSTR("\r\nType:\t\t"));
PrintHex<uint8_t>(ep_ptr->bDescriptorType);
Notify(PSTR("\r\nAddress:\t"));
PrintHex<uint8_t>(ep_ptr->bEndpointAddress);
Notify(PSTR("\r\nAttributes:\t"));
PrintHex<uint8_t>(ep_ptr->bmAttributes);
Notify(PSTR("\r\nMaxPktSize:\t"));
PrintHex<uint16_t>(ep_ptr->wMaxPacketSize);
Notify(PSTR("\r\nPoll Intrv:\t"));
PrintHex<uint8_t>(ep_ptr->bInterval);
} }
void HID::PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc) uint8_t HID::GetIdle(uint8_t iface, uint8_t reportID, uint8_t* dataptr) {
{ return ( pUsb->ctrlReq(bAddress, 0, bmREQ_HIDIN, HID_REQUEST_GET_IDLE, reportID, 0, iface, 0x0001, 0x0001, dataptr, NULL));
Notify(PSTR("\r\n\r\nHID Descriptor:\r\n")); }
Notify(PSTR("bDescLength:\t\t"));
PrintHex<uint8_t>(pDesc->bLength); uint8_t HID::SetIdle(uint8_t iface, uint8_t reportID, uint8_t duration) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_HIDOUT, HID_REQUEST_SET_IDLE, reportID, duration, iface, 0x0000, 0x0000, NULL, NULL));
Notify(PSTR("\r\nbDescriptorType:\t")); }
PrintHex<uint8_t>(pDesc->bDescriptorType);
uint8_t HID::SetProtocol(uint8_t iface, uint8_t protocol) {
Notify(PSTR("\r\nbcdHID:\t\t\t")); return ( pUsb->ctrlReq(bAddress, 0, bmREQ_HIDOUT, HID_REQUEST_SET_PROTOCOL, protocol, 0x00, iface, 0x0000, 0x0000, NULL, NULL));
PrintHex<uint16_t>(pDesc->bcdHID); }
Notify(PSTR("\r\nbCountryCode:\t\t")); uint8_t HID::GetProtocol(uint8_t iface, uint8_t* dataptr) {
PrintHex<uint8_t>(pDesc->bCountryCode); return ( pUsb->ctrlReq(bAddress, 0, bmREQ_HIDIN, HID_REQUEST_GET_PROTOCOL, 0x00, 0x00, iface, 0x0001, 0x0001, dataptr, NULL));
}
Notify(PSTR("\r\nbNumDescriptors:\t"));
PrintHex<uint8_t>(pDesc->bNumDescriptors); void HID::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr) {
Notify(PSTR("Endpoint descriptor:"), 0x80);
Notify(PSTR("\r\nbDescrType:\t\t")); Notify(PSTR("\r\nLength:\t\t"), 0x80);
PrintHex<uint8_t>(pDesc->bDescrType); PrintHex<uint8_t > (ep_ptr->bLength, 0x80);
Notify(PSTR("\r\nType:\t\t"), 0x80);
Notify(PSTR("\r\nwDescriptorLength:\t")); PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80);
PrintHex<uint16_t>(pDesc->wDescriptorLength); Notify(PSTR("\r\nAddress:\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80);
Notify(PSTR("\r\nAttributes:\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80);
Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80);
Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bInterval, 0x80);
}
void HID::PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc) {
Notify(PSTR("\r\n\r\nHID Descriptor:\r\n"), 0x80);
Notify(PSTR("bDescLength:\t\t"), 0x80);
PrintHex<uint8_t > (pDesc->bLength, 0x80);
Notify(PSTR("\r\nbDescriptorType:\t"), 0x80);
PrintHex<uint8_t > (pDesc->bDescriptorType, 0x80);
Notify(PSTR("\r\nbcdHID:\t\t\t"), 0x80);
PrintHex<uint16_t > (pDesc->bcdHID, 0x80);
Notify(PSTR("\r\nbCountryCode:\t\t"), 0x80);
PrintHex<uint8_t > (pDesc->bCountryCode, 0x80);
Notify(PSTR("\r\nbNumDescriptors:\t"), 0x80);
PrintHex<uint8_t > (pDesc->bNumDescriptors, 0x80);
Notify(PSTR("\r\nbDescrType:\t\t"), 0x80);
PrintHex<uint8_t > (pDesc->bDescrType, 0x80);
Notify(PSTR("\r\nwDescriptorLength:\t"), 0x80);
PrintHex<uint16_t > (pDesc->wDescriptorLength, 0x80);
} }

84
hid.h
View file

@ -13,7 +13,7 @@ Contact information
Circuits At Home, LTD Circuits At Home, LTD
Web : http://www.circuitsathome.com Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com e-mail : support@circuitsathome.com
*/ */
#if !defined(__HID_H__) #if !defined(__HID_H__)
#define __HID_H__ #define __HID_H__
@ -108,11 +108,10 @@ e-mail : support@circuitsathome.com
#define HID_PROTOCOL_KEYBOARD 0x01 #define HID_PROTOCOL_KEYBOARD 0x01
#define HID_PROTOCOL_MOUSE 0x02 #define HID_PROTOCOL_MOUSE 0x02
struct HidItemPrefix struct HidItemPrefix {
{ uint8_t bSize : 2;
uint8_t bSize : 2; uint8_t bType : 2;
uint8_t bType : 2; uint8_t bTag : 4;
uint8_t bTag : 4;
}; };
#define HID_ITEM_TYPE_MAIN 0 #define HID_ITEM_TYPE_MAIN 0
@ -138,64 +137,65 @@ struct HidItemPrefix
#define HID_MAIN_ITEM_COLLECTION_USAGE_SWITCH 5 #define HID_MAIN_ITEM_COLLECTION_USAGE_SWITCH 5
#define HID_MAIN_ITEM_COLLECTION_USAGE_MODIFIER 6 #define HID_MAIN_ITEM_COLLECTION_USAGE_MODIFIER 6
struct MainItemIOFeature struct MainItemIOFeature {
{ uint8_t bmIsConstantOrData : 1;
uint8_t bmIsConstantOrData : 1; uint8_t bmIsArrayOrVariable : 1;
uint8_t bmIsArrayOrVariable : 1; uint8_t bmIsRelativeOrAbsolute : 1;
uint8_t bmIsRelativeOrAbsolute : 1; uint8_t bmIsWrapOrNoWrap : 1;
uint8_t bmIsWrapOrNoWrap : 1; uint8_t bmIsNonLonearOrLinear : 1;
uint8_t bmIsNonLonearOrLinear : 1; uint8_t bmIsNoPreferedOrPrefered : 1;
uint8_t bmIsNoPreferedOrPrefered : 1; uint8_t bmIsNullOrNoNull : 1;
uint8_t bmIsNullOrNoNull : 1; uint8_t bmIsVolatileOrNonVolatile : 1;
uint8_t bmIsVolatileOrNonVolatile : 1;
}; };
class HID; class HID;
class HIDReportParser class HIDReportParser {
{
public: public:
virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) = 0; virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) = 0;
}; };
#define MAX_REPORT_PARSERS 2 #define MAX_REPORT_PARSERS 2
#define HID_MAX_HID_CLASS_DESCRIPTORS 5 #define HID_MAX_HID_CLASS_DESCRIPTORS 5
class HID : public USBDeviceConfig, public UsbConfigXtracter class HID : public USBDeviceConfig, public UsbConfigXtracter {
{
protected: protected:
USB *pUsb; // USB class instance pointer USB *pUsb; // USB class instance pointer
uint8_t bAddress; // address uint8_t bAddress; // address
protected: protected:
static const uint8_t epInterruptInIndex = 1; // InterruptIN endpoint index static const uint8_t epInterruptInIndex = 1; // InterruptIN endpoint index
static const uint8_t epInterruptOutIndex = 2; // InterruptOUT endpoint index static const uint8_t epInterruptOutIndex = 2; // InterruptOUT endpoint index
static const uint8_t maxHidInterfaces = 3; static const uint8_t maxHidInterfaces = 3;
static const uint8_t maxEpPerInterface = 2; static const uint8_t maxEpPerInterface = 2;
static const uint8_t totalEndpoints = (maxHidInterfaces * maxEpPerInterface + 1); static const uint8_t totalEndpoints = (maxHidInterfaces * maxEpPerInterface + 1);
void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr); void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr);
void PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc); void PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc);
virtual HIDReportParser* GetReportParser(uint8_t id); virtual HIDReportParser* GetReportParser(uint8_t id);
public: public:
HID(USB *pusb) : pUsb(pusb) {};
const USB* GetUsb() { return pUsb; }; HID(USB *pusb) : pUsb(pusb) {
virtual bool SetReportParser(uint8_t id, HIDReportParser *prs); };
uint8_t SetProtocol( uint8_t iface, uint8_t protocol ); const USB* GetUsb() {
uint8_t GetProtocol( uint8_t iface, uint8_t* dataptr ); return pUsb;
uint8_t GetIdle( uint8_t iface, uint8_t reportID, uint8_t* dataptr ); };
uint8_t SetIdle( uint8_t iface, uint8_t reportID, uint8_t duration ); virtual bool SetReportParser(uint8_t id, HIDReportParser *prs);
uint8_t GetReportDescr( uint8_t ep, USBReadParser *parser = NULL); uint8_t SetProtocol(uint8_t iface, uint8_t protocol);
uint8_t GetProtocol(uint8_t iface, uint8_t* dataptr);
uint8_t GetIdle(uint8_t iface, uint8_t reportID, uint8_t* dataptr);
uint8_t SetIdle(uint8_t iface, uint8_t reportID, uint8_t duration);
uint8_t GetHidDescr( uint8_t ep, uint16_t nbytes, uint8_t* dataptr ); uint8_t GetReportDescr(uint8_t ep, USBReadParser *parser = NULL);
uint8_t GetReport( uint8_t ep, uint8_t iface, uint8_t report_type, uint8_t report_id, uint16_t nbytes, uint8_t* dataptr );
uint8_t SetReport( uint8_t ep, uint8_t iface, uint8_t report_type, uint8_t report_id, uint16_t nbytes, uint8_t* dataptr ); uint8_t GetHidDescr(uint8_t ep, uint16_t nbytes, uint8_t* dataptr);
uint8_t GetReport(uint8_t ep, uint8_t iface, uint8_t report_type, uint8_t report_id, uint16_t nbytes, uint8_t* dataptr);
uint8_t SetReport(uint8_t ep, uint8_t iface, uint8_t report_type, uint8_t report_id, uint16_t nbytes, uint8_t* dataptr);
}; };
#endif // __HID_H__ #endif // __HID_H__

View file

@ -13,142 +13,127 @@ Contact information
Circuits At Home, LTD Circuits At Home, LTD
Web : http://www.circuitsathome.com Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com e-mail : support@circuitsathome.com
*/ */
#include "hidboot.h" #include "hidboot.h"
void MouseReportParser::Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) void MouseReportParser::Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) {
{ MOUSEINFO *pmi = (MOUSEINFO*) buf;
MOUSEINFO *pmi = (MOUSEINFO*)buf;
if (prevState.mouseInfo.bmLeftButton == 0 && pmi->bmLeftButton == 1) if (prevState.mouseInfo.bmLeftButton == 0 && pmi->bmLeftButton == 1)
OnLeftButtonDown(pmi); OnLeftButtonDown(pmi);
if (prevState.mouseInfo.bmLeftButton == 1 && pmi->bmLeftButton == 0) if (prevState.mouseInfo.bmLeftButton == 1 && pmi->bmLeftButton == 0)
OnLeftButtonUp(pmi); OnLeftButtonUp(pmi);
if (prevState.mouseInfo.bmRightButton == 0 && pmi->bmRightButton == 1) if (prevState.mouseInfo.bmRightButton == 0 && pmi->bmRightButton == 1)
OnRightButtonDown(pmi); OnRightButtonDown(pmi);
if (prevState.mouseInfo.bmRightButton == 1 && pmi->bmRightButton == 0) if (prevState.mouseInfo.bmRightButton == 1 && pmi->bmRightButton == 0)
OnRightButtonUp(pmi); OnRightButtonUp(pmi);
if (prevState.mouseInfo.bmMiddleButton == 0 && pmi->bmMiddleButton == 1) if (prevState.mouseInfo.bmMiddleButton == 0 && pmi->bmMiddleButton == 1)
OnMiddleButtonDown(pmi); OnMiddleButtonDown(pmi);
if (prevState.mouseInfo.bmMiddleButton == 1 && pmi->bmMiddleButton == 0) if (prevState.mouseInfo.bmMiddleButton == 1 && pmi->bmMiddleButton == 0)
OnMiddleButtonUp(pmi); OnMiddleButtonUp(pmi);
if (prevState.mouseInfo.dX != pmi->dX || prevState.mouseInfo.dY != pmi->dY) if (prevState.mouseInfo.dX != pmi->dX || prevState.mouseInfo.dY != pmi->dY)
OnMouseMove(pmi); OnMouseMove(pmi);
for (uint8_t i=0; i<3; i++) if (len > sizeof (MOUSEINFO))
prevState.bInfo[i] = buf[i]; for (uint8_t i = 0; i<sizeof (MOUSEINFO); i++)
prevState.bInfo[i] = buf[i];
}; };
void KeyboardReportParser::Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) void KeyboardReportParser::Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) {
{ // On error - return
// On error - return if (buf[2] == 1)
if (buf[2] == 1) return;
return;
KBDINFO *pki = (KBDINFO*)buf; //KBDINFO *pki = (KBDINFO*)buf;
for (uint8_t i=2; i<8; i++) for (uint8_t i = 2; i < 8; i++) {
{ bool down = false;
bool down = false; bool up = false;
bool up = false;
for (uint8_t j=2; j<8; j++) for (uint8_t j = 2; j < 8; j++) {
{ if (buf[i] == prevState.bInfo[j] && buf[i] != 1)
if (buf[i] == prevState.bInfo[j] && buf[i] != 1) down = true;
down = true; if (buf[j] == prevState.bInfo[i] && prevState.bInfo[i] != 1)
if (buf[j] == prevState.bInfo[i] && prevState.bInfo[i] != 1) up = true;
up = true; }
} if (!down) {
if (!down) HandleLockingKeys(hid, buf[i]);
{ OnKeyDown(*buf, buf[i]);
HandleLockingKeys(hid, buf[i]); }
OnKeyDown(*buf, buf[i]); if (!up)
} OnKeyUp(prevState.bInfo[0], prevState.bInfo[i]);
if (!up) }
OnKeyUp(prevState.bInfo[0], prevState.bInfo[i]); for (uint8_t i = 0; i < 8; i++)
} prevState.bInfo[i] = buf[i];
for (uint8_t i=0; i<8; i++)
prevState.bInfo[i] = buf[i];
}; };
uint8_t KeyboardReportParser::HandleLockingKeys(HID *hid, uint8_t key) uint8_t KeyboardReportParser::HandleLockingKeys(HID *hid, uint8_t key) {
{ uint8_t old_keys = kbdLockingKeys.bLeds;
uint8_t old_keys = kbdLockingKeys.bLeds;
switch (key) switch (key) {
{ case KEY_NUM_LOCK:
case KEY_NUM_LOCK: kbdLockingKeys.kbdLeds.bmNumLock = ~kbdLockingKeys.kbdLeds.bmNumLock;
kbdLockingKeys.kbdLeds.bmNumLock = ~kbdLockingKeys.kbdLeds.bmNumLock; break;
break; case KEY_CAPS_LOCK:
case KEY_CAPS_LOCK: kbdLockingKeys.kbdLeds.bmCapsLock = ~kbdLockingKeys.kbdLeds.bmCapsLock;
kbdLockingKeys.kbdLeds.bmCapsLock = ~kbdLockingKeys.kbdLeds.bmCapsLock; break;
break; case KEY_SCROLL_LOCK:
case KEY_SCROLL_LOCK: kbdLockingKeys.kbdLeds.bmScrollLock = ~kbdLockingKeys.kbdLeds.bmScrollLock;
kbdLockingKeys.kbdLeds.bmScrollLock = ~kbdLockingKeys.kbdLeds.bmScrollLock; break;
break; }
}
if (old_keys != kbdLockingKeys.bLeds && hid) if (old_keys != kbdLockingKeys.bLeds && hid)
return (hid->SetReport(0, 0/*hid->GetIface()*/, 2, 0, 1, &kbdLockingKeys.bLeds)); return (hid->SetReport(0, 0/*hid->GetIface()*/, 2, 0, 1, &kbdLockingKeys.bLeds));
return 0; return 0;
} }
const uint8_t KeyboardReportParser::numKeys[] PROGMEM = { '!', '@', '#', '$', '%', '^', '&', '*', '(', ')' }; const uint8_t KeyboardReportParser::numKeys[] PROGMEM = {'!', '@', '#', '$', '%', '^', '&', '*', '(', ')'};
const uint8_t KeyboardReportParser::symKeysUp[] PROGMEM = { '_', '+', '{', '}', '|', '~', ':', '"', '~', '<', '>', '?' }; const uint8_t KeyboardReportParser::symKeysUp[] PROGMEM = {'_', '+', '{', '}', '|', '~', ':', '"', '~', '<', '>', '?'};
const uint8_t KeyboardReportParser::symKeysLo[] PROGMEM = { '-', '=', '[', ']', '\\', ' ', ';', '\'', '`', ',', '.', '/' }; const uint8_t KeyboardReportParser::symKeysLo[] PROGMEM = {'-', '=', '[', ']', '\\', ' ', ';', '\'', '`', ',', '.', '/'};
const uint8_t KeyboardReportParser::padKeys[] PROGMEM = { '/', '*', '-', '+', 0x13 }; const uint8_t KeyboardReportParser::padKeys[] PROGMEM = {'/', '*', '-', '+', 0x13};
uint8_t KeyboardReportParser::OemToAscii(uint8_t mod, uint8_t key) uint8_t KeyboardReportParser::OemToAscii(uint8_t mod, uint8_t key) {
{ uint8_t shift = (mod & 0x22);
uint8_t shift = (mod & 0x22);
// [a-z] // [a-z]
if (key > 0x03 && key < 0x1e) if (key > 0x03 && key < 0x1e) {
{ // Upper case letters
// Upper case letters if ((kbdLockingKeys.kbdLeds.bmCapsLock == 0 && (mod & 2)) ||
if ( (kbdLockingKeys.kbdLeds.bmCapsLock == 0 && (mod & 2)) || (kbdLockingKeys.kbdLeds.bmCapsLock == 1 && (mod & 2) == 0))
(kbdLockingKeys.kbdLeds.bmCapsLock == 1 && (mod & 2) == 0) ) return (key - 4 + 'A');
return (key - 4 + 'A');
// Lower case letters // Lower case letters
else else
return (key - 4 + 'a'); return (key - 4 + 'a');
} } // Numbers
// Numbers else if (key > 0x1d && key < 0x27) {
else if (key > 0x1d && key < 0x27) if (shift)
{ return ((uint8_t) pgm_read_byte(&numKeys[key - 0x1e]));
if (shift) else
return ((uint8_t)pgm_read_byte(&numKeys[key - 0x1e])); return (key - 0x1e + '1');
else } // Keypad Numbers
return (key - 0x1e + '1'); else if (key > 0x58 && key < 0x62) {
} if (kbdLockingKeys.kbdLeds.bmNumLock == 1)
// Keypad Numbers return (key - 0x59 + '1');
else if (key > 0x58 && key < 0x62) } else if (key > 0x2c && key < 0x39)
{ return ((shift) ? (uint8_t) pgm_read_byte(&symKeysUp[key - 0x2d]) : (uint8_t) pgm_read_byte(&symKeysLo[key - 0x2d]));
if (kbdLockingKeys.kbdLeds.bmNumLock == 1) else if (key > 0x53 && key < 0x59)
return (key - 0x59 + '1'); return (uint8_t) pgm_read_byte(&padKeys[key - 0x54]);
} else {
else if (key > 0x2c && key < 0x39) switch (key) {
return ((shift) ? (uint8_t)pgm_read_byte(&symKeysUp[key-0x2d]) : (uint8_t)pgm_read_byte(&symKeysLo[key-0x2d])); case KEY_SPACE: return (0x20);
else if (key > 0x53 && key < 0x59) case KEY_ENTER: return (0x13);
return (uint8_t)pgm_read_byte(&padKeys[key - 0x54]); case KEY_ZERO: return ((shift) ? ')': '0');
else case KEY_ZERO2: return ((kbdLockingKeys.kbdLeds.bmNumLock == 1) ? '0': 0);
{ case KEY_PERIOD: return ((kbdLockingKeys.kbdLeds.bmNumLock == 1) ? '.': 0);
switch (key) }
{ }
case KEY_SPACE: return(0x20); return ( 0);
case KEY_ENTER: return(0x13);
case KEY_ZERO: return((shift) ? ')' : '0');
case KEY_ZERO2: return((kbdLockingKeys.kbdLeds.bmNumLock == 1) ? '0' : 0);
case KEY_PERIOD: return((kbdLockingKeys.kbdLeds.bmNumLock == 1) ? '.' : 0);
}
}
return( 0 );
} }

619
hidboot.h
View file

@ -13,7 +13,7 @@ Contact information
Circuits At Home, LTD Circuits At Home, LTD
Web : http://www.circuitsathome.com Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com e-mail : support@circuitsathome.com
*/ */
#if !defined(__HIDBOOT_H__) #if !defined(__HIDBOOT_H__)
#define __HIDBOOT_H__ #define __HIDBOOT_H__
@ -44,115 +44,128 @@ e-mail : support@circuitsathome.com
#define KEY_ENTER 0x28 #define KEY_ENTER 0x28
#define KEY_PERIOD 0x63 #define KEY_PERIOD 0x63
struct MOUSEINFO struct MOUSEINFO {
{
struct struct {
{ uint8_t bmLeftButton : 1;
uint8_t bmLeftButton : 1; uint8_t bmRightButton : 1;
uint8_t bmRightButton : 1; uint8_t bmMiddleButton : 1;
uint8_t bmMiddleButton : 1; uint8_t bmDummy : 1;
uint8_t bmDummy : 1; };
}; int8_t dX;
int8_t dX; int8_t dY;
int8_t dY;
}; };
class MouseReportParser : public HIDReportParser class MouseReportParser : public HIDReportParser {
{
union union {
{ MOUSEINFO mouseInfo;
MOUSEINFO mouseInfo; uint8_t bInfo[sizeof (MOUSEINFO)];
uint8_t bInfo[3]; } prevState;
} prevState;
public: public:
virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf); virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf);
protected: protected:
virtual void OnMouseMove (MOUSEINFO *mi) {};
virtual void OnLeftButtonUp (MOUSEINFO *mi) {}; virtual void OnMouseMove(MOUSEINFO *mi) {
virtual void OnLeftButtonDown (MOUSEINFO *mi) {}; };
virtual void OnRightButtonUp (MOUSEINFO *mi) {};
virtual void OnRightButtonDown (MOUSEINFO *mi) {}; virtual void OnLeftButtonUp(MOUSEINFO *mi) {
virtual void OnMiddleButtonUp (MOUSEINFO *mi) {}; };
virtual void OnMiddleButtonDown (MOUSEINFO *mi) {};
virtual void OnLeftButtonDown(MOUSEINFO *mi) {
};
virtual void OnRightButtonUp(MOUSEINFO *mi) {
};
virtual void OnRightButtonDown(MOUSEINFO *mi) {
};
virtual void OnMiddleButtonUp(MOUSEINFO *mi) {
};
virtual void OnMiddleButtonDown(MOUSEINFO *mi) {
};
}; };
struct MODIFIERKEYS struct MODIFIERKEYS {
{ uint8_t bmLeftCtrl : 1;
uint8_t bmLeftCtrl : 1; uint8_t bmLeftShift : 1;
uint8_t bmLeftShift : 1; uint8_t bmLeftAlt : 1;
uint8_t bmLeftAlt : 1; uint8_t bmLeftGUI : 1;
uint8_t bmLeftGUI : 1; uint8_t bmRightCtrl : 1;
uint8_t bmRightCtrl : 1; uint8_t bmRightShift : 1;
uint8_t bmRightShift : 1; uint8_t bmRightAlt : 1;
uint8_t bmRightAlt : 1; uint8_t bmRightGUI : 1;
uint8_t bmRightGUI : 1;
}; };
struct KBDINFO struct KBDINFO {
{
struct struct {
{ uint8_t bmLeftCtrl : 1;
uint8_t bmLeftCtrl : 1; uint8_t bmLeftShift : 1;
uint8_t bmLeftShift : 1; uint8_t bmLeftAlt : 1;
uint8_t bmLeftAlt : 1; uint8_t bmLeftGUI : 1;
uint8_t bmLeftGUI : 1; uint8_t bmRightCtrl : 1;
uint8_t bmRightCtrl : 1; uint8_t bmRightShift : 1;
uint8_t bmRightShift : 1; uint8_t bmRightAlt : 1;
uint8_t bmRightAlt : 1; uint8_t bmRightGUI : 1;
uint8_t bmRightGUI : 1; };
}; uint8_t bReserved;
uint8_t bReserved; uint8_t Keys[6];
uint8_t Keys[6];
}; };
struct KBDLEDS struct KBDLEDS {
{ uint8_t bmNumLock : 1;
uint8_t bmNumLock : 1; uint8_t bmCapsLock : 1;
uint8_t bmCapsLock : 1; uint8_t bmScrollLock : 1;
uint8_t bmScrollLock : 1; uint8_t bmCompose : 1;
uint8_t bmCompose : 1; uint8_t bmKana : 1;
uint8_t bmKana : 1; uint8_t bmReserved : 3;
uint8_t bmReserved : 3;
}; };
#define KEY_NUM_LOCK 0x53 #define KEY_NUM_LOCK 0x53
#define KEY_CAPS_LOCK 0x39 #define KEY_CAPS_LOCK 0x39
#define KEY_SCROLL_LOCK 0x47 #define KEY_SCROLL_LOCK 0x47
class KeyboardReportParser : public HIDReportParser class KeyboardReportParser : public HIDReportParser {
{ static const uint8_t numKeys[];
static const uint8_t numKeys[]; static const uint8_t symKeysUp[];
static const uint8_t symKeysUp[]; static const uint8_t symKeysLo[];
static const uint8_t symKeysLo[]; static const uint8_t padKeys[];
static const uint8_t padKeys[];
protected: protected:
union
{
KBDINFO kbdInfo;
uint8_t bInfo[sizeof(KBDINFO)];
} prevState;
union union {
{ KBDINFO kbdInfo;
KBDLEDS kbdLeds; uint8_t bInfo[sizeof (KBDINFO)];
uint8_t bLeds; } prevState;
} kbdLockingKeys;
uint8_t OemToAscii(uint8_t mod, uint8_t key); union {
KBDLEDS kbdLeds;
uint8_t bLeds;
} kbdLockingKeys;
uint8_t OemToAscii(uint8_t mod, uint8_t key);
public: public:
KeyboardReportParser() { kbdLockingKeys.bLeds = 0; };
virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf); KeyboardReportParser() {
kbdLockingKeys.bLeds = 0;
};
virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf);
protected: protected:
uint8_t HandleLockingKeys(HID* hid, uint8_t key); uint8_t HandleLockingKeys(HID* hid, uint8_t key);
virtual void OnKeyDown (uint8_t mod, uint8_t key) {}; virtual void OnKeyDown(uint8_t mod, uint8_t key) {
virtual void OnKeyUp (uint8_t mod, uint8_t key) {}; };
virtual void OnKeyUp(uint8_t mod, uint8_t key) {
};
}; };
#define totalEndpoints 2 #define totalEndpoints 2
@ -162,333 +175,319 @@ protected:
template <const uint8_t BOOT_PROTOCOL> template <const uint8_t BOOT_PROTOCOL>
class HIDBoot : public HID //public USBDeviceConfig, public UsbConfigXtracter class HIDBoot : public HID //public USBDeviceConfig, public UsbConfigXtracter
{ {
EpInfo epInfo[totalEndpoints]; EpInfo epInfo[totalEndpoints];
HIDReportParser *pRptParser; HIDReportParser *pRptParser;
uint8_t bConfNum; // configuration number uint8_t bConfNum; // configuration number
uint8_t bIfaceNum; // Interface Number uint8_t bIfaceNum; // Interface Number
uint8_t bNumIface; // number of interfaces in the configuration uint8_t bNumIface; // number of interfaces in the configuration
uint8_t bNumEP; // total number of EP in the configuration uint8_t bNumEP; // total number of EP in the configuration
uint32_t qNextPollTime; // next poll time uint32_t qNextPollTime; // next poll time
bool bPollEnable; // poll enable flag bool bPollEnable; // poll enable flag
void Initialize(); void Initialize();
virtual HIDReportParser* GetReportParser(uint8_t id) { return pRptParser; }; virtual HIDReportParser* GetReportParser(uint8_t id) {
return pRptParser;
};
public: public:
HIDBoot(USB *p); HIDBoot(USB *p);
virtual bool SetReportParser(uint8_t id, HIDReportParser *prs) { pRptParser = prs; }; virtual bool SetReportParser(uint8_t id, HIDReportParser *prs) {
pRptParser = prs;
return true;
};
// USBDeviceConfig implementation // USBDeviceConfig implementation
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed); virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
virtual uint8_t Release(); virtual uint8_t Release();
virtual uint8_t Poll(); virtual uint8_t Poll();
virtual uint8_t GetAddress() { return bAddress; };
// UsbConfigXtracter implementation virtual uint8_t GetAddress() {
virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep); return bAddress;
};
// UsbConfigXtracter implementation
virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
}; };
template <const uint8_t BOOT_PROTOCOL> template <const uint8_t BOOT_PROTOCOL>
HIDBoot<BOOT_PROTOCOL>::HIDBoot(USB *p) : HIDBoot<BOOT_PROTOCOL>::HIDBoot(USB *p) :
HID(p), HID(p),
qNextPollTime(0), qNextPollTime(0),
bPollEnable(false), bPollEnable(false),
pRptParser(NULL) pRptParser(NULL) {
{ Initialize();
Initialize();
if (pUsb) if (pUsb)
pUsb->RegisterDeviceClass(this); pUsb->RegisterDeviceClass(this);
} }
template <const uint8_t BOOT_PROTOCOL> template <const uint8_t BOOT_PROTOCOL>
void HIDBoot<BOOT_PROTOCOL>::Initialize() void HIDBoot<BOOT_PROTOCOL>::Initialize() {
{ for (uint8_t i = 0; i < totalEndpoints; i++) {
for(uint8_t i=0; i<totalEndpoints; i++) epInfo[i].epAddr = 0;
{ epInfo[i].maxPktSize = (i) ? 0 : 8;
epInfo[i].epAddr = 0; epInfo[i].epAttribs = 0;
epInfo[i].maxPktSize = (i) ? 0 : 8; epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER;
epInfo[i].epAttribs = 0; }
epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER; bNumEP = 1;
} bNumIface = 0;
bNumEP = 1; bConfNum = 0;
bNumIface = 0;
bConfNum = 0;
} }
template <const uint8_t BOOT_PROTOCOL> template <const uint8_t BOOT_PROTOCOL>
uint8_t HIDBoot<BOOT_PROTOCOL>::Init(uint8_t parent, uint8_t port, bool lowspeed) uint8_t HIDBoot<BOOT_PROTOCOL>::Init(uint8_t parent, uint8_t port, bool lowspeed) {
{ const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR);
const uint8_t constBufSize = sizeof(USB_DEVICE_DESCRIPTOR);
uint8_t buf[constBufSize]; uint8_t buf[constBufSize];
uint8_t rcode; uint8_t rcode;
UsbDevice *p = NULL; UsbDevice *p = NULL;
EpInfo *oldep_ptr = NULL; EpInfo *oldep_ptr = NULL;
uint8_t len = 0; uint8_t len = 0;
uint16_t cd_len = 0; uint16_t cd_len = 0;
uint8_t num_of_conf; // number of configurations uint8_t num_of_conf; // number of configurations
uint8_t num_of_intf; // number of interfaces uint8_t num_of_intf; // number of interfaces
AddressPool &addrPool = pUsb->GetAddressPool(); AddressPool &addrPool = pUsb->GetAddressPool();
USBTRACE("BM Init\r\n"); USBTRACE("BM Init\r\n");
if (bAddress) if (bAddress)
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE; return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
// Get pointer to pseudo device with address 0 assigned // Get pointer to pseudo device with address 0 assigned
p = addrPool.GetUsbDevicePtr(0); p = addrPool.GetUsbDevicePtr(0);
if (!p) if (!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
if (!p->epinfo) if (!p->epinfo) {
{ USBTRACE("epinfo\r\n");
USBTRACE("epinfo\r\n"); return USB_ERROR_EPINFO_IS_NULL;
return USB_ERROR_EPINFO_IS_NULL; }
}
// Save old pointer to EP_RECORD of address 0 // Save old pointer to EP_RECORD of address 0
oldep_ptr = p->epinfo; oldep_ptr = p->epinfo;
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
p->epinfo = epInfo; p->epinfo = epInfo;
p->lowspeed = lowspeed; p->lowspeed = lowspeed;
// Get device descriptor // Get device descriptor
rcode = pUsb->getDevDescr( 0, 0, 8, (uint8_t*)buf ); rcode = pUsb->getDevDescr(0, 0, 8, (uint8_t*) buf);
if (!rcode) if (!rcode)
len = (buf[0] > constBufSize) ? constBufSize : buf[0]; len = (buf[0] > constBufSize) ? constBufSize : buf[0];
if( rcode ) if (rcode) {
{ // Restore p->epinfo
// Restore p->epinfo p->epinfo = oldep_ptr;
p->epinfo = oldep_ptr;
goto FailGetDevDescr; goto FailGetDevDescr;
} }
// Restore p->epinfo // Restore p->epinfo
p->epinfo = oldep_ptr; p->epinfo = oldep_ptr;
// Allocate new address according to device class // Allocate new address according to device class
bAddress = addrPool.AllocAddress(parent, false, port); bAddress = addrPool.AllocAddress(parent, false, port);
if (!bAddress) if (!bAddress)
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL; return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
// Extract Max Packet Size from the device descriptor // Extract Max Packet Size from the device descriptor
epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0; epInfo[0].maxPktSize = (uint8_t) ((USB_DEVICE_DESCRIPTOR*) buf)->bMaxPacketSize0;
// Assign new address to the device // Assign new address to the device
rcode = pUsb->setAddr( 0, 0, bAddress ); rcode = pUsb->setAddr(0, 0, bAddress);
if (rcode) if (rcode) {
{ p->lowspeed = false;
p->lowspeed = false; addrPool.FreeAddress(bAddress);
addrPool.FreeAddress(bAddress); bAddress = 0;
bAddress = 0; USBTRACE2("setAddr:", rcode);
USBTRACE2("setAddr:",rcode); return rcode;
return rcode; }
}
USBTRACE2("Addr:", bAddress); USBTRACE2("Addr:", bAddress);
p->lowspeed = false; p->lowspeed = false;
p = addrPool.GetUsbDevicePtr(bAddress); p = addrPool.GetUsbDevicePtr(bAddress);
if (!p) if (!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
p->lowspeed = lowspeed; p->lowspeed = lowspeed;
if (len) if (len)
rcode = pUsb->getDevDescr( bAddress, 0, len, (uint8_t*)buf ); rcode = pUsb->getDevDescr(bAddress, 0, len, (uint8_t*) buf);
if(rcode) if (rcode)
goto FailGetDevDescr; goto FailGetDevDescr;
num_of_conf = ((USB_DEVICE_DESCRIPTOR*)buf)->bNumConfigurations; num_of_conf = ((USB_DEVICE_DESCRIPTOR*) buf)->bNumConfigurations;
// Assign epInfo to epinfo pointer // Assign epInfo to epinfo pointer
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo); rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
if (rcode) if (rcode)
goto FailSetDevTblEntry; goto FailSetDevTblEntry;
//USBTRACE2("NC:", num_of_conf); //USBTRACE2("NC:", num_of_conf);
for (uint8_t i=0; i<num_of_conf; i++) for (uint8_t i = 0; i < num_of_conf; i++) {
{ ConfigDescParser<
//HexDumper<USBReadParser, uint16_t, uint16_t> HexDump; USB_CLASS_HID,
ConfigDescParser< HID_BOOT_INTF_SUBCLASS,
USB_CLASS_HID, BOOT_PROTOCOL,
HID_BOOT_INTF_SUBCLASS, CP_MASK_COMPARE_ALL> confDescrParser(this);
BOOT_PROTOCOL,
CP_MASK_COMPARE_ALL> confDescrParser(this);
//rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump); rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
if (bNumEP > 1) if (bNumEP > 1)
break; break;
} // for } // for
if (bNumEP < 2) if (bNumEP < 2)
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
//USBTRACE2("\r\nbAddr:", bAddress); //USBTRACE2("\r\nbAddr:", bAddress);
//USBTRACE2("\r\nbNumEP:", bNumEP); //USBTRACE2("\r\nbNumEP:", bNumEP);
// Assign epInfo to epinfo pointer // Assign epInfo to epinfo pointer
rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo); rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
//USBTRACE2("\r\nCnf:", bConfNum); //USBTRACE2("\r\nCnf:", bConfNum);
// Set Configuration Value // Set Configuration Value
rcode = pUsb->setConf(bAddress, 0, bConfNum); rcode = pUsb->setConf(bAddress, 0, bConfNum);
if (rcode) if (rcode)
goto FailSetConfDescr; goto FailSetConfDescr;
//USBTRACE2("\r\nIf:", bIfaceNum); //USBTRACE2("\r\nIf:", bIfaceNum);
rcode = SetProtocol(bIfaceNum, HID_BOOT_PROTOCOL); rcode = SetProtocol(bIfaceNum, HID_BOOT_PROTOCOL);
if (rcode) if (rcode)
goto FailSetProtocol; goto FailSetProtocol;
if (BOOT_PROTOCOL == 1) if (BOOT_PROTOCOL == 1) {
{ rcode = SetIdle(bIfaceNum, 0, 0);
rcode = SetIdle(bIfaceNum, 0, 0);
if (rcode) if (rcode)
goto FailSetIdle; goto FailSetIdle;
} }
USBTRACE("BM configured\r\n"); USBTRACE("BM configured\r\n");
bPollEnable = true; bPollEnable = true;
return 0; return 0;
FailGetDevDescr: FailGetDevDescr:
USBTRACE("getDevDescr:"); USBTRACE("getDevDescr:");
goto Fail; goto Fail;
FailSetDevTblEntry: FailSetDevTblEntry:
USBTRACE("setDevTblEn:"); USBTRACE("setDevTblEn:");
goto Fail; goto Fail;
FailGetConfDescr: FailGetConfDescr:
USBTRACE("getConf:"); USBTRACE("getConf:");
goto Fail; goto Fail;
FailSetProtocol: FailSetProtocol:
USBTRACE("SetProto:"); USBTRACE("SetProto:");
goto Fail; goto Fail;
FailSetIdle: FailSetIdle:
USBTRACE("SetIdle:"); USBTRACE("SetIdle:");
goto Fail; goto Fail;
FailSetConfDescr: FailSetConfDescr:
USBTRACE("setConf:"); USBTRACE("setConf:");
goto Fail; goto Fail;
Fail: Fail:
Serial.println(rcode, HEX); PrintHex<uint8_t > (rcode, 0x80);
Release(); Notify(PSTR("\n"), 0x80);
return rcode; // Serial.println(rcode, HEX);
Release();
return rcode;
} }
template <const uint8_t BOOT_PROTOCOL> template <const uint8_t BOOT_PROTOCOL>
void HIDBoot<BOOT_PROTOCOL>::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) void HIDBoot<BOOT_PROTOCOL>::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) {
{ // If the first configuration satisfies, the others are not concidered.
// If the first configuration satisfies, the others are not concidered. if (bNumEP > 1 && conf != bConfNum)
if (bNumEP > 1 && conf != bConfNum) return;
return;
//ErrorMessage<uint8_t>(PSTR("\r\nConf.Val"), conf); bConfNum = conf;
//ErrorMessage<uint8_t>(PSTR("Iface Num"), iface); bIfaceNum = iface;
//ErrorMessage<uint8_t>(PSTR("Alt.Set"), alt);
bConfNum = conf; uint8_t index;
bIfaceNum = iface;
uint8_t index; if ((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80) {
index = epInterruptInIndex;
if ((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80) // Fill in the endpoint info structure
{ epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
index = epInterruptInIndex; epInfo[index].maxPktSize = (uint8_t) pep->wMaxPacketSize;
epInfo[index].epAttribs = 0;
// Fill in the endpoint info structure bNumEP++;
epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F); }
epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
epInfo[index].epAttribs = 0;
bNumEP ++;
//PrintEndpointDescriptor(pep);
}
}
template <const uint8_t BOOT_PROTOCOL>
uint8_t HIDBoot<BOOT_PROTOCOL>::Release()
{
pUsb->GetAddressPool().FreeAddress(bAddress);
bConfNum = 0;
bIfaceNum = 0;
bNumEP = 1;
bAddress = 0;
qNextPollTime = 0;
bPollEnable = false;
return 0;
} }
template <const uint8_t BOOT_PROTOCOL> template <const uint8_t BOOT_PROTOCOL>
uint8_t HIDBoot<BOOT_PROTOCOL>::Poll() uint8_t HIDBoot<BOOT_PROTOCOL>::Release() {
{ pUsb->GetAddressPool().FreeAddress(bAddress);
uint8_t rcode = 0;
if (!bPollEnable) bConfNum = 0;
return 0; bIfaceNum = 0;
bNumEP = 1;
bAddress = 0;
qNextPollTime = 0;
bPollEnable = false;
return 0;
}
if (qNextPollTime <= millis()) template <const uint8_t BOOT_PROTOCOL>
{ uint8_t HIDBoot<BOOT_PROTOCOL>::Poll() {
qNextPollTime = millis() + 10; uint8_t rcode = 0;
const uint8_t const_buff_len = 16; if (!bPollEnable)
uint8_t buf[const_buff_len]; return 0;
uint16_t read = (uint16_t)epInfo[epInterruptInIndex].maxPktSize; if (qNextPollTime <= millis()) {
qNextPollTime = millis() + 10;
uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[epInterruptInIndex].epAddr, &read, buf); const uint8_t const_buff_len = 16;
uint8_t buf[const_buff_len];
if (rcode) uint16_t read = (uint16_t) epInfo[epInterruptInIndex].maxPktSize;
{
if (rcode != hrNAK)
USBTRACE2("Poll:", rcode);
return rcode;
}
//for (uint8_t i=0; i<read; i++)
// PrintHex<uint8_t>(buf[i]);
//if (read)
// Serial.println("");
if (pRptParser) uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[epInterruptInIndex].epAddr, &read, buf);
pRptParser->Parse((HID*)this, 0, (uint8_t)read, buf);
} if (rcode) {
return rcode; if (rcode != hrNAK)
USBTRACE2("Poll:", rcode);
return rcode;
}
//for (uint8_t i=0; i<read; i++)
// PrintHex<uint8_t>(buf[i]);
//if (read)
// Serial.println("");
if (pRptParser)
pRptParser->Parse((HID*)this, 0, (uint8_t) read, buf);
}
return rcode;
} }

File diff suppressed because it is too large Load diff

View file

@ -13,7 +13,7 @@ Contact information
Circuits At Home, LTD Circuits At Home, LTD
Web : http://www.circuitsathome.com Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com e-mail : support@circuitsathome.com
*/ */
#if !defined(__HIDDESCRIPTORPARSER_H__) #if !defined(__HIDDESCRIPTORPARSER_H__)
#define __HIDDESCRIPTORPARSER_H__ #define __HIDDESCRIPTORPARSER_H__
@ -37,159 +37,155 @@ e-mail : support@circuitsathome.com
#include "confdescparser.h" #include "confdescparser.h"
#include "hid.h" #include "hid.h"
class ReportDescParserBase : public USBReadParser class ReportDescParserBase : public USBReadParser {
{
public: public:
typedef void (*UsagePageFunc)(uint16_t usage); typedef void (*UsagePageFunc)(uint16_t usage);
static void PrintGenericDesktopPageUsage(uint16_t usage); static void PrintGenericDesktopPageUsage(uint16_t usage);
static void PrintSimulationControlsPageUsage(uint16_t usage); static void PrintSimulationControlsPageUsage(uint16_t usage);
static void PrintVRControlsPageUsage(uint16_t usage); static void PrintVRControlsPageUsage(uint16_t usage);
static void PrintSportsControlsPageUsage(uint16_t usage); static void PrintSportsControlsPageUsage(uint16_t usage);
static void PrintGameControlsPageUsage(uint16_t usage); static void PrintGameControlsPageUsage(uint16_t usage);
static void PrintGenericDeviceControlsPageUsage(uint16_t usage); static void PrintGenericDeviceControlsPageUsage(uint16_t usage);
static void PrintLEDPageUsage(uint16_t usage); static void PrintLEDPageUsage(uint16_t usage);
static void PrintButtonPageUsage(uint16_t usage); static void PrintButtonPageUsage(uint16_t usage);
static void PrintOrdinalPageUsage(uint16_t usage); static void PrintOrdinalPageUsage(uint16_t usage);
static void PrintTelephonyPageUsage(uint16_t usage); static void PrintTelephonyPageUsage(uint16_t usage);
static void PrintConsumerPageUsage(uint16_t usage); static void PrintConsumerPageUsage(uint16_t usage);
static void PrintDigitizerPageUsage(uint16_t usage); static void PrintDigitizerPageUsage(uint16_t usage);
static void PrintAlphanumDisplayPageUsage(uint16_t usage); static void PrintAlphanumDisplayPageUsage(uint16_t usage);
static void PrintMedicalInstrumentPageUsage(uint16_t usage); static void PrintMedicalInstrumentPageUsage(uint16_t usage);
static void PrintValue(uint8_t *p, uint8_t len); static void PrintValue(uint8_t *p, uint8_t len);
static void PrintByteValue(uint8_t data); static void PrintByteValue(uint8_t data);
static void PrintItemTitle(uint8_t prefix); static void PrintItemTitle(uint8_t prefix);
static const char *usagePageTitles0[]; static const char * const usagePageTitles0[];
static const char *usagePageTitles1[]; static const char * const usagePageTitles1[];
static const char *genDesktopTitles0[]; static const char * const genDesktopTitles0[];
static const char *genDesktopTitles1[]; static const char * const genDesktopTitles1[];
static const char *genDesktopTitles2[]; static const char * const genDesktopTitles2[];
static const char *genDesktopTitles3[]; static const char * const genDesktopTitles3[];
static const char *genDesktopTitles4[]; static const char * const genDesktopTitles4[];
static const char *simuTitles0[]; static const char * const simuTitles0[];
static const char *simuTitles1[]; static const char * const simuTitles1[];
static const char *simuTitles2[]; static const char * const simuTitles2[];
static const char *vrTitles0[]; static const char * const vrTitles0[];
static const char *vrTitles1[]; static const char * const vrTitles1[];
static const char *sportsCtrlTitles0[]; static const char * const sportsCtrlTitles0[];
static const char *sportsCtrlTitles1[]; static const char * const sportsCtrlTitles1[];
static const char *sportsCtrlTitles2[]; static const char * const sportsCtrlTitles2[];
static const char *gameTitles0[]; static const char * const gameTitles0[];
static const char *gameTitles1[]; static const char * const gameTitles1[];
static const char *genDevCtrlTitles[]; static const char * const genDevCtrlTitles[];
static const char *ledTitles[]; static const char * const ledTitles[];
static const char *telTitles0[]; static const char * const telTitles0[];
static const char *telTitles1[]; static const char * const telTitles1[];
static const char *telTitles2[]; static const char * const telTitles2[];
static const char *telTitles3[]; static const char * const telTitles3[];
static const char *telTitles4[]; static const char * const telTitles4[];
static const char *telTitles5[]; static const char * const telTitles5[];
static const char *consTitles0[]; static const char * const consTitles0[];
static const char *consTitles1[]; static const char * const consTitles1[];
static const char *consTitles2[]; static const char * const consTitles2[];
static const char *consTitles3[]; static const char * const consTitles3[];
static const char *consTitles4[]; static const char * const consTitles4[];
static const char *consTitles5[]; static const char * const consTitles5[];
static const char *consTitles6[]; static const char * const consTitles6[];
static const char *consTitles7[]; static const char * const consTitles7[];
static const char *consTitles8[]; static const char * const consTitles8[];
static const char *consTitles9[]; static const char * const consTitles9[];
static const char *consTitlesA[]; static const char * const consTitlesA[];
static const char *consTitlesB[]; static const char * const consTitlesB[];
static const char *consTitlesC[]; static const char * const consTitlesC[];
static const char *consTitlesD[]; static const char * const consTitlesD[];
static const char *consTitlesE[]; static const char * const consTitlesE[];
static const char *digitTitles0[]; static const char * const digitTitles0[];
static const char *digitTitles1[]; static const char * const digitTitles1[];
static const char *digitTitles2[]; static const char * const digitTitles2[];
static const char *aplphanumTitles0[]; static const char * const aplphanumTitles0[];
static const char *aplphanumTitles1[]; static const char * const aplphanumTitles1[];
static const char *aplphanumTitles2[]; static const char * const aplphanumTitles2[];
static const char *medInstrTitles0[]; static const char * const medInstrTitles0[];
static const char *medInstrTitles1[]; static const char * const medInstrTitles1[];
static const char *medInstrTitles2[]; static const char * const medInstrTitles2[];
static const char *medInstrTitles3[]; static const char * const medInstrTitles3[];
static const char *medInstrTitles4[]; static const char * const medInstrTitles4[];
protected: protected:
static UsagePageFunc usagePageFunctions[]; static UsagePageFunc usagePageFunctions[];
MultiValueBuffer theBuffer; MultiValueBuffer theBuffer;
MultiByteValueParser valParser; MultiByteValueParser valParser;
ByteSkipper theSkipper; ByteSkipper theSkipper;
uint8_t varBuffer[sizeof(USB_CONFIGURATION_DESCRIPTOR)]; uint8_t varBuffer[sizeof (USB_CONFIGURATION_DESCRIPTOR)];
uint8_t itemParseState; // Item parser state variable uint8_t itemParseState; // Item parser state variable
uint8_t itemSize; // Item size uint8_t itemSize; // Item size
uint8_t itemPrefix; // Item prefix (first byte) uint8_t itemPrefix; // Item prefix (first byte)
uint8_t rptSize; // Report Size uint8_t rptSize; // Report Size
uint8_t rptCount; // Report Count uint8_t rptCount; // Report Count
uint16_t totalSize; // Report size in bits uint16_t totalSize; // Report size in bits
virtual uint8_t ParseItem(uint8_t **pp, uint16_t *pcntdn); virtual uint8_t ParseItem(uint8_t **pp, uint16_t *pcntdn);
UsagePageFunc pfUsage; UsagePageFunc pfUsage;
static void PrintUsagePage(uint16_t page); static void PrintUsagePage(uint16_t page);
void SetUsagePage(uint16_t page); void SetUsagePage(uint16_t page);
public: public:
ReportDescParserBase() :
itemParseState(0),
itemSize(0),
itemPrefix(0),
rptSize(0),
rptCount(0),
pfUsage(NULL)
{
theBuffer.pValue = varBuffer;
valParser.Initialize(&theBuffer);
theSkipper.Initialize(&theBuffer);
};
virtual void Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset); ReportDescParserBase() :
itemParseState(0),
itemSize(0),
itemPrefix(0),
rptSize(0),
rptCount(0),
pfUsage(NULL) {
theBuffer.pValue = varBuffer;
valParser.Initialize(&theBuffer);
theSkipper.Initialize(&theBuffer);
};
enum virtual void Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset);
{
enErrorSuccess = 0 enum {
, enErrorIncomplete // value or record is partialy read in buffer enErrorSuccess = 0
, enErrorBufferTooSmall , enErrorIncomplete // value or record is partialy read in buffer
}; , enErrorBufferTooSmall
};
}; };
class ReportDescParser : public ReportDescParserBase class ReportDescParser : public ReportDescParserBase {
{
}; };
class ReportDescParser2 : public ReportDescParserBase class ReportDescParser2 : public ReportDescParserBase {
{ uint8_t rptId; // Report ID
uint8_t rptId; // Report ID uint8_t useMin; // Usage Minimum
uint8_t useMin; // Usage Minimum uint8_t useMax; // Usage Maximum
uint8_t useMax; // Usage Maximum uint8_t fieldCount; // Number of field being currently processed
uint8_t fieldCount; // Number of field being currently processed
void OnInputItem(uint8_t itm); // Method which is called every time Input item is found void OnInputItem(uint8_t itm); // Method which is called every time Input item is found
uint8_t *pBuf; // Report buffer pointer uint8_t *pBuf; // Report buffer pointer
uint8_t bLen; // Report length uint8_t bLen; // Report length
protected: protected:
virtual uint8_t ParseItem(uint8_t **pp, uint16_t *pcntdn); virtual uint8_t ParseItem(uint8_t **pp, uint16_t *pcntdn);
public: public:
ReportDescParser2(uint16_t len, uint8_t *pbuf) :
ReportDescParserBase(), bLen(len), pBuf(pbuf), rptId(0), useMin(0), useMax(0), fieldCount(0) ReportDescParser2(uint16_t len, uint8_t *pbuf) :
{}; ReportDescParserBase(), rptId(0), useMin(0), useMax(0), fieldCount(0), pBuf(pbuf), bLen(len) {
};
}; };
class UniversalReportParser : public HIDReportParser class UniversalReportParser : public HIDReportParser {
{
public: public:
virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf); virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf);
}; };
#endif // __HIDDESCRIPTORPARSER_H__ #endif // __HIDDESCRIPTORPARSER_H__

View file

@ -1,418 +1,378 @@
#include "hiduniversal.h" #include "hiduniversal.h"
HIDUniversal::HIDUniversal(USB *p) : HIDUniversal::HIDUniversal(USB *p) :
HID(p), HID(p),
qNextPollTime(0), qNextPollTime(0),
bPollEnable(false), bPollEnable(false),
bHasReportId(false) bHasReportId(false) {
{ Initialize();
Initialize();
if (pUsb) if (pUsb)
pUsb->RegisterDeviceClass(this); pUsb->RegisterDeviceClass(this);
} }
uint16_t HIDUniversal::GetHidClassDescrLen(uint8_t type, uint8_t num) uint16_t HIDUniversal::GetHidClassDescrLen(uint8_t type, uint8_t num) {
{ for (uint8_t i = 0, n = 0; i < HID_MAX_HID_CLASS_DESCRIPTORS; i++) {
for (uint8_t i=0, n=0; i<HID_MAX_HID_CLASS_DESCRIPTORS; i++) if (descrInfo[i].bDescrType == type) {
{ if (n == num)
if (descrInfo[i].bDescrType == type) return descrInfo[i].wDescriptorLength;
{ n++;
if (n == num) }
return descrInfo[i].wDescriptorLength; }
n ++; return 0;
}
}
return 0;
} }
void HIDUniversal::Initialize() void HIDUniversal::Initialize() {
{ for (uint8_t i = 0; i < MAX_REPORT_PARSERS; i++) {
for (uint8_t i=0; i<MAX_REPORT_PARSERS; i++) rptParsers[i].rptId = 0;
{ rptParsers[i].rptParser = NULL;
rptParsers[i].rptId = 0; }
rptParsers[i].rptParser = NULL; for (uint8_t i = 0; i < HID_MAX_HID_CLASS_DESCRIPTORS; i++) {
} descrInfo[i].bDescrType = 0;
for (uint8_t i=0; i<HID_MAX_HID_CLASS_DESCRIPTORS; i++) descrInfo[i].wDescriptorLength = 0;
{ }
descrInfo[i].bDescrType = 0; for (uint8_t i = 0; i < maxHidInterfaces; i++) {
descrInfo[i].wDescriptorLength = 0; hidInterfaces[i].bmInterface = 0;
} hidInterfaces[i].bmProtocol = 0;
for (uint8_t i=0; i<maxHidInterfaces; i++)
{
hidInterfaces[i].bmInterface = 0;
hidInterfaces[i].bmProtocol = 0;
for (uint8_t j=0; j<maxEpPerInterface; j++) for (uint8_t j = 0; j < maxEpPerInterface; j++)
hidInterfaces[i].epIndex[j] = 0; hidInterfaces[i].epIndex[j] = 0;
} }
for(uint8_t i=0; i<totalEndpoints; i++) for (uint8_t i = 0; i < totalEndpoints; i++) {
{ epInfo[i].epAddr = 0;
epInfo[i].epAddr = 0; epInfo[i].maxPktSize = (i) ? 0 : 8;
epInfo[i].maxPktSize = (i) ? 0 : 8; epInfo[i].epAttribs = 0;
epInfo[i].epAttribs = 0; epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER;
epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER; }
} bNumEP = 1;
bNumEP = 1; bNumIface = 0;
bNumIface = 0; bConfNum = 0;
bConfNum = 0;
ZeroMemory(constBuffLen, prevBuf); ZeroMemory(constBuffLen, prevBuf);
} }
bool HIDUniversal::SetReportParser(uint8_t id, HIDReportParser *prs) bool HIDUniversal::SetReportParser(uint8_t id, HIDReportParser *prs) {
{ for (uint8_t i = 0; i < MAX_REPORT_PARSERS; i++) {
for (uint8_t i=0; i<MAX_REPORT_PARSERS; i++) if (rptParsers[i].rptId == 0 && rptParsers[i].rptParser == NULL) {
{ rptParsers[i].rptId = id;
if (rptParsers[i].rptId == 0 && rptParsers[i].rptParser == NULL) rptParsers[i].rptParser = prs;
{ return true;
rptParsers[i].rptId = id; }
rptParsers[i].rptParser = prs; }
return true; return false;
}
}
return false;
} }
HIDReportParser* HIDUniversal::GetReportParser(uint8_t id) HIDReportParser* HIDUniversal::GetReportParser(uint8_t id) {
{ if (!bHasReportId)
if (!bHasReportId) return ((rptParsers[0].rptParser) ? rptParsers[0].rptParser : NULL);
return ((rptParsers[0].rptParser) ? rptParsers[0].rptParser : NULL);
for (uint8_t i=0; i<MAX_REPORT_PARSERS; i++) for (uint8_t i = 0; i < MAX_REPORT_PARSERS; i++) {
{ if (rptParsers[i].rptId == id)
if (rptParsers[i].rptId == id) return rptParsers[i].rptParser;
return rptParsers[i].rptParser; }
} return NULL;
return NULL;
} }
uint8_t HIDUniversal::Init(uint8_t parent, uint8_t port, bool lowspeed) uint8_t HIDUniversal::Init(uint8_t parent, uint8_t port, bool lowspeed) {
{ const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR);
const uint8_t constBufSize = sizeof(USB_DEVICE_DESCRIPTOR);
uint8_t buf[constBufSize]; uint8_t buf[constBufSize];
uint8_t rcode; uint8_t rcode;
UsbDevice *p = NULL; UsbDevice *p = NULL;
EpInfo *oldep_ptr = NULL; EpInfo *oldep_ptr = NULL;
uint8_t len = 0; uint8_t len = 0;
uint8_t num_of_conf; // number of configurations uint8_t num_of_conf; // number of configurations
uint8_t num_of_intf; // number of interfaces //uint8_t num_of_intf; // number of interfaces
AddressPool &addrPool = pUsb->GetAddressPool(); AddressPool &addrPool = pUsb->GetAddressPool();
USBTRACE("HU Init\r\n"); USBTRACE("HU Init\r\n");
if (bAddress) if (bAddress)
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE; return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
// Get pointer to pseudo device with address 0 assigned // Get pointer to pseudo device with address 0 assigned
p = addrPool.GetUsbDevicePtr(0); p = addrPool.GetUsbDevicePtr(0);
if (!p) if (!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
if (!p->epinfo) if (!p->epinfo) {
{ USBTRACE("epinfo\r\n");
USBTRACE("epinfo\r\n"); return USB_ERROR_EPINFO_IS_NULL;
return USB_ERROR_EPINFO_IS_NULL; }
}
// Save old pointer to EP_RECORD of address 0 // Save old pointer to EP_RECORD of address 0
oldep_ptr = p->epinfo; oldep_ptr = p->epinfo;
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
p->epinfo = epInfo; p->epinfo = epInfo;
p->lowspeed = lowspeed; p->lowspeed = lowspeed;
//delay(200); // Get device descriptor
rcode = pUsb->getDevDescr(0, 0, 8, (uint8_t*) buf);
// Get device descriptor if (!rcode)
rcode = pUsb->getDevDescr( 0, 0, 8, (uint8_t*)buf ); len = (buf[0] > constBufSize) ? constBufSize : buf[0];
if (!rcode) if (rcode) {
len = (buf[0] > constBufSize) ? constBufSize : buf[0]; // Restore p->epinfo
p->epinfo = oldep_ptr;
if( rcode ) goto FailGetDevDescr;
{ }
// Restore p->epinfo
p->epinfo = oldep_ptr;
goto FailGetDevDescr; // Restore p->epinfo
} p->epinfo = oldep_ptr;
// Restore p->epinfo // Allocate new address according to device class
p->epinfo = oldep_ptr; bAddress = addrPool.AllocAddress(parent, false, port);
// Allocate new address according to device class if (!bAddress)
bAddress = addrPool.AllocAddress(parent, false, port); return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
if (!bAddress) // Extract Max Packet Size from the device descriptor
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL; epInfo[0].maxPktSize = (uint8_t) ((USB_DEVICE_DESCRIPTOR*) buf)->bMaxPacketSize0;
// Extract Max Packet Size from the device descriptor // Assign new address to the device
epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0; rcode = pUsb->setAddr(0, 0, bAddress);
// Assign new address to the device if (rcode) {
rcode = pUsb->setAddr( 0, 0, bAddress ); p->lowspeed = false;
addrPool.FreeAddress(bAddress);
bAddress = 0;
USBTRACE2("setAddr:", rcode);
return rcode;
}
if (rcode) USBTRACE2("Addr:", bAddress);
{
p->lowspeed = false;
addrPool.FreeAddress(bAddress);
bAddress = 0;
USBTRACE2("setAddr:",rcode);
return rcode;
}
USBTRACE2("Addr:", bAddress); p->lowspeed = false;
p->lowspeed = false; p = addrPool.GetUsbDevicePtr(bAddress);
p = addrPool.GetUsbDevicePtr(bAddress); if (!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
if (!p) p->lowspeed = lowspeed;
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
p->lowspeed = lowspeed; if (len)
rcode = pUsb->getDevDescr(bAddress, 0, len, (uint8_t*) buf);
delay(500); if (rcode)
goto FailGetDevDescr;
if (len) num_of_conf = ((USB_DEVICE_DESCRIPTOR*) buf)->bNumConfigurations;
rcode = pUsb->getDevDescr( bAddress, 0, len, (uint8_t*)buf );
if(rcode) // Assign epInfo to epinfo pointer
goto FailGetDevDescr; rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
num_of_conf = ((USB_DEVICE_DESCRIPTOR*)buf)->bNumConfigurations; if (rcode)
goto FailSetDevTblEntry;
// Assign epInfo to epinfo pointer USBTRACE2("NC:", num_of_conf);
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
if (rcode) for (uint8_t i = 0; i < num_of_conf; i++) {
goto FailSetDevTblEntry; //HexDumper<USBReadParser, uint16_t, uint16_t> HexDump;
ConfigDescParser<USB_CLASS_HID, 0, 0,
CP_MASK_COMPARE_CLASS> confDescrParser(this);
USBTRACE2("NC:", num_of_conf); //rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump);
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
for (uint8_t i=0; i<num_of_conf; i++) if (rcode)
{ goto FailGetConfDescr;
//delay(1000);
//HexDumper<USBReadParser, uint16_t, uint16_t> HexDump;
ConfigDescParser<USB_CLASS_HID, 0, 0,
CP_MASK_COMPARE_CLASS> confDescrParser(this);
//rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump); if (bNumEP > 1)
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser); break;
} // for
if (bNumEP > 1) if (bNumEP < 2)
break; return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
} // for
if (bNumEP < 2) // Assign epInfo to epinfo pointer
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
// Assign epInfo to epinfo pointer USBTRACE2("\r\nCnf:", bConfNum);
rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
USBTRACE2("\r\nCnf:", bConfNum); // Set Configuration Value
rcode = pUsb->setConf(bAddress, 0, bConfNum);
// Set Configuration Value if (rcode)
rcode = pUsb->setConf(bAddress, 0, bConfNum); goto FailSetConfDescr;
if (rcode) for (uint8_t i = 0; i < bNumIface; i++) {
goto FailSetConfDescr; if (hidInterfaces[i].epIndex[epInterruptInIndex] == 0)
continue;
for (uint8_t i=0; i<bNumIface; i++) rcode = SetIdle(hidInterfaces[i].bmInterface, 0, 0);
{
if (hidInterfaces[i].epIndex[epInterruptInIndex] == 0)
continue;
rcode = SetIdle(hidInterfaces[i].bmInterface, 0, 0); if (rcode && rcode != hrSTALL)
goto FailSetIdle;
}
if (rcode && rcode != hrSTALL) USBTRACE("HU configured\r\n");
goto FailSetIdle;
}
USBTRACE("HU configured\r\n"); OnInitSuccessful();
OnInitSuccessful(); bPollEnable = true;
return 0;
bPollEnable = true;
return 0;
FailGetDevDescr: FailGetDevDescr:
USBTRACE("getDevDescr:"); USBTRACE("getDevDescr:");
goto Fail; goto Fail;
FailSetDevTblEntry: FailSetDevTblEntry:
USBTRACE("setDevTblEn:"); USBTRACE("setDevTblEn:");
goto Fail; goto Fail;
FailGetConfDescr: FailGetConfDescr:
USBTRACE("getConf:"); USBTRACE("getConf:");
goto Fail; goto Fail;
FailSetConfDescr: FailSetConfDescr:
USBTRACE("setConf:"); USBTRACE("setConf:");
goto Fail; goto Fail;
FailSetProtocol:
USBTRACE("SetProto:");
goto Fail;
FailSetIdle: FailSetIdle:
USBTRACE("SetIdle:"); USBTRACE("SetIdle:");
goto Fail; goto Fail;
FailGetReportDescr:
USBTRACE("GetReportDescr:");
goto Fail;
Fail: Fail:
Serial.println(rcode, HEX); PrintHex<uint8_t > (rcode, 0x80);
Release(); Notify(PSTR("\r\n"), 0x80);
return rcode; //Serial.println(rcode, HEX);
Release();
return rcode;
} }
HIDUniversal::HIDInterface* HIDUniversal::FindInterface(uint8_t iface, uint8_t alt, uint8_t proto) HIDUniversal::HIDInterface* HIDUniversal::FindInterface(uint8_t iface, uint8_t alt, uint8_t proto) {
{ for (uint8_t i = 0; i < bNumIface && i < maxHidInterfaces; i++)
for (uint8_t i=0; i<bNumIface && i<maxHidInterfaces; i++) if (hidInterfaces[i].bmInterface == iface && hidInterfaces[i].bmAltSet == alt
if (hidInterfaces[i].bmInterface == iface && hidInterfaces[i].bmAltSet == alt && hidInterfaces[i].bmProtocol == proto)
&& hidInterfaces[i].bmProtocol == proto) return hidInterfaces + i;
return hidInterfaces + i; return NULL;
return NULL;
} }
void HIDUniversal::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) void HIDUniversal::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) {
{ // If the first configuration satisfies, the others are not concidered.
// If the first configuration satisfies, the others are not concidered. if (bNumEP > 1 && conf != bConfNum)
if (bNumEP > 1 && conf != bConfNum) return;
return;
//ErrorMessage<uint8_t>(PSTR("\r\nConf.Val"), conf); //ErrorMessage<uint8_t>(PSTR("\r\nConf.Val"), conf);
//ErrorMessage<uint8_t>(PSTR("Iface Num"), iface); //ErrorMessage<uint8_t>(PSTR("Iface Num"), iface);
//ErrorMessage<uint8_t>(PSTR("Alt.Set"), alt); //ErrorMessage<uint8_t>(PSTR("Alt.Set"), alt);
bConfNum = conf; bConfNum = conf;
uint8_t index = 0; uint8_t index = 0;
HIDInterface *piface = FindInterface(iface, alt, proto); HIDInterface *piface = FindInterface(iface, alt, proto);
// Fill in interface structure in case of new interface // Fill in interface structure in case of new interface
if (!piface) if (!piface) {
{ piface = hidInterfaces + bNumIface;
piface = hidInterfaces + bNumIface; piface->bmInterface = iface;
piface->bmInterface = iface; piface->bmAltSet = alt;
piface->bmAltSet = alt; piface->bmProtocol = proto;
piface->bmProtocol = proto; bNumIface++;
bNumIface ++; }
}
if ((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80) if ((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80)
index = epInterruptInIndex; index = epInterruptInIndex;
else else
index = epInterruptOutIndex; index = epInterruptOutIndex;
if (index) if (index) {
{ // Fill in the endpoint info structure
// Fill in the endpoint info structure epInfo[bNumEP].epAddr = (pep->bEndpointAddress & 0x0F);
epInfo[bNumEP].epAddr = (pep->bEndpointAddress & 0x0F); epInfo[bNumEP].maxPktSize = (uint8_t) pep->wMaxPacketSize;
epInfo[bNumEP].maxPktSize = (uint8_t)pep->wMaxPacketSize; epInfo[bNumEP].epAttribs = 0;
epInfo[bNumEP].epAttribs = 0; epInfo[bNumEP].bmNakPower = USB_NAK_NOWAIT;
epInfo[bNumEP].bmNakPower = USB_NAK_NOWAIT;
// Fill in the endpoint index list // Fill in the endpoint index list
piface->epIndex[index] = bNumEP; //(pep->bEndpointAddress & 0x0F); piface->epIndex[index] = bNumEP; //(pep->bEndpointAddress & 0x0F);
bNumEP ++; bNumEP++;
} }
//PrintEndpointDescriptor(pep); //PrintEndpointDescriptor(pep);
} }
uint8_t HIDUniversal::Release() {
pUsb->GetAddressPool().FreeAddress(bAddress);
uint8_t HIDUniversal::Release() bNumEP = 1;
{ bAddress = 0;
pUsb->GetAddressPool().FreeAddress(bAddress); qNextPollTime = 0;
bPollEnable = false;
bNumEP = 1; return 0;
bAddress = 0;
qNextPollTime = 0;
bPollEnable = false;
return 0;
} }
bool HIDUniversal::BuffersIdentical(uint8_t len, uint8_t *buf1, uint8_t *buf2) bool HIDUniversal::BuffersIdentical(uint8_t len, uint8_t *buf1, uint8_t *buf2) {
{ for (uint8_t i = 0; i < len; i++)
for (uint8_t i=0; i<len; i++) if (buf1[i] != buf2[i])
if (buf1[i] != buf2[i]) return false;
return false; return true;
return true;
} }
void HIDUniversal::ZeroMemory(uint8_t len, uint8_t *buf) void HIDUniversal::ZeroMemory(uint8_t len, uint8_t *buf) {
{ for (uint8_t i = 0; i < len; i++)
for (uint8_t i=0; i<len; i++) buf[i] = 0;
buf[i] = 0;
}
void HIDUniversal::SaveBuffer(uint8_t len, uint8_t *src, uint8_t *dest)
{
for (uint8_t i=0; i<len; i++)
dest[i] = src[i];
} }
uint8_t HIDUniversal::Poll() void HIDUniversal::SaveBuffer(uint8_t len, uint8_t *src, uint8_t *dest) {
{ for (uint8_t i = 0; i < len; i++)
uint8_t rcode = 0; dest[i] = src[i];
}
if (!bPollEnable)
return 0; uint8_t HIDUniversal::Poll() {
uint8_t rcode = 0;
if (qNextPollTime <= millis())
{ if (!bPollEnable)
qNextPollTime = millis() + 50; return 0;
uint8_t buf[constBuffLen]; if (qNextPollTime <= millis()) {
qNextPollTime = millis() + 50;
for (uint8_t i=0; i<bNumIface; i++)
{ uint8_t buf[constBuffLen];
uint8_t index = hidInterfaces[i].epIndex[epInterruptInIndex];
uint16_t read = (uint16_t)epInfo[index].maxPktSize; for (uint8_t i = 0; i < bNumIface; i++) {
uint8_t index = hidInterfaces[i].epIndex[epInterruptInIndex];
ZeroMemory(constBuffLen, buf); uint16_t read = (uint16_t) epInfo[index].maxPktSize;
uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[index].epAddr, &read, buf); ZeroMemory(constBuffLen, buf);
if (rcode) uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[index].epAddr, &read, buf);
{
if (rcode != hrNAK) if (rcode) {
USBTRACE2("Poll:", rcode); if (rcode != hrNAK)
return rcode; USBTRACE2("Poll:", rcode);
} return rcode;
}
if (read > constBuffLen)
read = constBuffLen; if (read > constBuffLen)
read = constBuffLen;
bool identical = BuffersIdentical(read, buf, prevBuf);
bool identical = BuffersIdentical(read, buf, prevBuf);
SaveBuffer(read, buf, prevBuf);
SaveBuffer(read, buf, prevBuf);
if (identical)
return 0; if (identical)
return 0;
Serial.print("\r\nBuf: ");
Notify(PSTR("\r\nBuf: "), 0x80);
for (uint8_t i=0; i<read; i++)
PrintHex<uint8_t>(buf[i]); for (uint8_t i = 0; i < read; i++)
PrintHex<uint8_t > (buf[i], 0x80);
Serial.println("");
Notify(PSTR("\r\n"), 0x80);
HIDReportParser *prs = GetReportParser( ((bHasReportId) ? *buf : 0) );
HIDReportParser *prs = GetReportParser(((bHasReportId) ? *buf : 0));
if (prs)
prs->Parse(this, bHasReportId, (uint8_t)read, buf); if (prs)
} prs->Parse(this, bHasReportId, (uint8_t) read, buf);
} }
return rcode; }
return rcode;
} }

View file

@ -4,72 +4,76 @@
#include "hid.h" #include "hid.h"
//#include "hidescriptorparser.h" //#include "hidescriptorparser.h"
class HIDUniversal : public HID class HIDUniversal : public HID {
{
struct ReportParser
{
uint8_t rptId;
HIDReportParser *rptParser;
} rptParsers[MAX_REPORT_PARSERS];
// HID class specific descriptor type and length info obtained from HID descriptor struct ReportParser {
HID_CLASS_DESCRIPTOR_LEN_AND_TYPE descrInfo[HID_MAX_HID_CLASS_DESCRIPTORS]; uint8_t rptId;
HIDReportParser *rptParser;
} rptParsers[MAX_REPORT_PARSERS];
// Returns HID class specific descriptor length by its type and order number // HID class specific descriptor type and length info obtained from HID descriptor
uint16_t GetHidClassDescrLen(uint8_t type, uint8_t num); HID_CLASS_DESCRIPTOR_LEN_AND_TYPE descrInfo[HID_MAX_HID_CLASS_DESCRIPTORS];
EpInfo epInfo[totalEndpoints]; // Returns HID class specific descriptor length by its type and order number
uint16_t GetHidClassDescrLen(uint8_t type, uint8_t num);
struct HIDInterface EpInfo epInfo[totalEndpoints];
{
struct
{
uint8_t bmInterface : 3;
uint8_t bmAltSet : 3;
uint8_t bmProtocol : 2;
};
uint8_t epIndex[maxEpPerInterface];
};
HIDInterface hidInterfaces[maxHidInterfaces]; struct HIDInterface {
uint8_t bConfNum; // configuration number struct {
uint8_t bNumIface; // number of interfaces in the configuration uint8_t bmInterface : 3;
uint8_t bNumEP; // total number of EP in the configuration uint8_t bmAltSet : 3;
uint32_t qNextPollTime; // next poll time uint8_t bmProtocol : 2;
bool bPollEnable; // poll enable flag };
uint8_t epIndex[maxEpPerInterface];
};
static const uint16_t constBuffLen = 64; // event buffer length HIDInterface hidInterfaces[maxHidInterfaces];
uint8_t prevBuf[constBuffLen]; // previous event buffer
void Initialize(); uint8_t bConfNum; // configuration number
HIDInterface* FindInterface(uint8_t iface, uint8_t alt, uint8_t proto); uint8_t bNumIface; // number of interfaces in the configuration
uint8_t bNumEP; // total number of EP in the configuration
uint32_t qNextPollTime; // next poll time
bool bPollEnable; // poll enable flag
void ZeroMemory(uint8_t len, uint8_t *buf); static const uint16_t constBuffLen = 64; // event buffer length
bool BuffersIdentical(uint8_t len, uint8_t *buf1, uint8_t *buf2); uint8_t prevBuf[constBuffLen]; // previous event buffer
void SaveBuffer(uint8_t len, uint8_t *src, uint8_t *dest);
void Initialize();
HIDInterface* FindInterface(uint8_t iface, uint8_t alt, uint8_t proto);
void ZeroMemory(uint8_t len, uint8_t *buf);
bool BuffersIdentical(uint8_t len, uint8_t *buf1, uint8_t *buf2);
void SaveBuffer(uint8_t len, uint8_t *src, uint8_t *dest);
protected: protected:
bool bHasReportId; bool bHasReportId;
// HID implementation // HID implementation
virtual HIDReportParser* GetReportParser(uint8_t id); virtual HIDReportParser* GetReportParser(uint8_t id);
virtual uint8_t OnInitSuccessful() { return 0; };
virtual uint8_t OnInitSuccessful() {
return 0;
};
public: public:
HIDUniversal(USB *p); HIDUniversal(USB *p);
// HID implementation // HID implementation
virtual bool SetReportParser(uint8_t id, HIDReportParser *prs); virtual bool SetReportParser(uint8_t id, HIDReportParser *prs);
// USBDeviceConfig implementation // USBDeviceConfig implementation
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed); virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
virtual uint8_t Release(); virtual uint8_t Release();
virtual uint8_t Poll(); virtual uint8_t Poll();
virtual uint8_t GetAddress() { return bAddress; };
// UsbConfigXtracter implementation virtual uint8_t GetAddress() {
virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep); return bAddress;
};
// UsbConfigXtracter implementation
virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
}; };
#endif // __HIDUNIVERSAL_H__ #endif // __HIDUNIVERSAL_H__

File diff suppressed because it is too large Load diff

View file

@ -13,7 +13,7 @@ Contact information
Circuits At Home, LTD Circuits At Home, LTD
Web : http://www.circuitsathome.com Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com e-mail : support@circuitsathome.com
*/ */
#if !defined(__HIDUSAGETITLEARRAYS_H__) #if !defined(__HIDUSAGETITLEARRAYS_H__)
#define __HIDUSAGETITLEARRAYS_H__ #define __HIDUSAGETITLEARRAYS_H__

File diff suppressed because it is too large Load diff

View file

@ -2,8 +2,8 @@
#define __MASSTORAGE_H__ #define __MASSTORAGE_H__
#include <inttypes.h> #include <inttypes.h>
#include <avr/pgmspace.h>
#include "avrpins.h" #include "avrpins.h"
#include <avr/pgmspace.h>
#include "max3421e.h" #include "max3421e.h"
#include "usbhost.h" #include "usbhost.h"
#include "usb_ch9.h" #include "usb_ch9.h"
@ -19,7 +19,7 @@
#include "hexdump.h" #include "hexdump.h"
#include "message.h" #include "message.h"
#include "confdescparser.h" #include <confdescparser.h>
#define SWAP(a, b) (((a) ^= (b)), ((b) ^= (a)), ((a) ^= (b))) #define SWAP(a, b) (((a) ^= (b)), ((b) ^= (a)), ((a) ^= (b)))
@ -27,226 +27,250 @@
#define bmREQ_MASSIN USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE #define bmREQ_MASSIN USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
// Mass Storage Subclass Constants // Mass Storage Subclass Constants
#define MASS_SUBCLASS_SCSI_NOT_REPORTED 0x00 // De facto use #define MASS_SUBCLASS_SCSI_NOT_REPORTED 0x00 // De facto use
#define MASS_SUBCLASS_RBC 0x01 #define MASS_SUBCLASS_RBC 0x01
#define MASS_SUBCLASS_ATAPI 0x02 // MMC-5 (ATAPI) #define MASS_SUBCLASS_ATAPI 0x02 // MMC-5 (ATAPI)
#define MASS_SUBCLASS_OBSOLETE1 0x03 // Was QIC-157 #define MASS_SUBCLASS_OBSOLETE1 0x03 // Was QIC-157
#define MASS_SUBCLASS_UFI 0x04 // Specifies how to interface Floppy Disk Drives to USB #define MASS_SUBCLASS_UFI 0x04 // Specifies how to interface Floppy Disk Drives to USB
#define MASS_SUBCLASS_OBSOLETE2 0x05 // Was SFF-8070i #define MASS_SUBCLASS_OBSOLETE2 0x05 // Was SFF-8070i
#define MASS_SUBCLASS_SCSI 0x06 // SCSI Transparent Command Set #define MASS_SUBCLASS_SCSI 0x06 // SCSI Transparent Command Set
#define MASS_SUBCLASS_LSDFS 0x07 // Specifies how host has to negotiate access before trying SCSI #define MASS_SUBCLASS_LSDFS 0x07 // Specifies how host has to negotiate access before trying SCSI
#define MASS_SUBCLASS_IEEE1667 0x08 #define MASS_SUBCLASS_IEEE1667 0x08
// Mass Storage Class Protocols // Mass Storage Class Protocols
#define MASS_PROTO_CBI 0x00 // CBI (with command completion interrupt) #define MASS_PROTO_CBI 0x00 // CBI (with command completion interrupt)
#define MASS_PROTO_CBI_NO_INT 0x01 // CBI (without command completion interrupt) #define MASS_PROTO_CBI_NO_INT 0x01 // CBI (without command completion interrupt)
#define MASS_PROTO_OBSOLETE 0x02 #define MASS_PROTO_OBSOLETE 0x02
#define MASS_PROTO_BBB 0x50 // Bulk Only Transport #define MASS_PROTO_BBB 0x50 // Bulk Only Transport
#define MASS_PROTO_UAS 0x62 #define MASS_PROTO_UAS 0x62
// Request Codes // Request Codes
#define MASS_REQ_ADSC 0x00 #define MASS_REQ_ADSC 0x00
#define MASS_REQ_GET 0xFC #define MASS_REQ_GET 0xFC
#define MASS_REQ_PUT 0xFD #define MASS_REQ_PUT 0xFD
#define MASS_REQ_GET_MAX_LUN 0xFE #define MASS_REQ_GET_MAX_LUN 0xFE
#define MASS_REQ_BOMSR 0xFF // Bulk-Only Mass Storage Reset #define MASS_REQ_BOMSR 0xFF // Bulk-Only Mass Storage Reset
#define MASS_CBW_SIGNATURE 0x43425355 #define MASS_CBW_SIGNATURE 0x43425355
#define MASS_CSW_SIGNATURE 0x53425355 #define MASS_CSW_SIGNATURE 0x53425355
#define MASS_CMD_DIR_OUT (0 << 7) #define MASS_CMD_DIR_OUT (0 << 7)
#define MASS_CMD_DIR_IN (1 << 7) #define MASS_CMD_DIR_IN (1 << 7)
#define SCSI_CMD_INQUIRY 0x12 #define SCSI_CMD_INQUIRY 0x12
#define SCSI_CMD_REPORT_LUNS 0xA0 #define SCSI_CMD_REPORT_LUNS 0xA0
#define SCSI_CMD_REQUEST_SENSE 0x03 #define SCSI_CMD_REQUEST_SENSE 0x03
#define SCSI_CMD_FORMAT_UNIT 0x04 #define SCSI_CMD_FORMAT_UNIT 0x04
#define SCSI_CMD_READ_6 0x08 #define SCSI_CMD_READ_6 0x08
#define SCSI_CMD_READ_10 0x28 #define SCSI_CMD_READ_10 0x28
#define SCSI_CMD_READ_CAPACITY_10 0x25 #define SCSI_CMD_READ_CAPACITY_10 0x25
#define SCSI_CMD_TEST_UNIT_READY 0x00 #define SCSI_CMD_TEST_UNIT_READY 0x00
#define SCSI_CMD_WRITE_6 0x0A #define SCSI_CMD_WRITE_6 0x0A
#define SCSI_CMD_WRITE_10 0x2A #define SCSI_CMD_WRITE_10 0x2A
#define SCSI_CMD_MODE_SENSE_6 0x1A #define SCSI_CMD_MODE_SENSE_6 0x1A
#define SCSI_CMD_MODE_SENSE_10 0x5A #define SCSI_CMD_MODE_SENSE_10 0x5A
#define SCSI_CMD_START_STOP_UNIT 0x1B
#define MASS_ERR_SUCCESS 0x00 #define SCSI_S_NOT_READY 0x02
#define MASS_ERR_PHASE_ERROR 0x01 #define SCSI_S_MEDIUM_ERROR 0x03
#define MASS_ERR_DEVICE_DISCONNECTED 0x11 #define SCSI_S_ILLEGAL_REQUEST 0x05
#define MASS_ERR_UNABLE_TO_RECOVER 0x12 // Reset recovery error #define SCSI_S_UNIT_ATTENTION 0x06
#define MASS_ERR_GENERAL_USB_ERROR 0xFF
#define MASS_TRANS_FLG_CALLBACK 0x01 // Callback is involved #define SCSI_ASC_MEDIUM_NOT_PRESENT 0x3A
#define MASS_TRANS_FLG_NO_STALL_CHECK 0x02 // STALL condition is not checked #define SCSI_ASC_LBA_OUT_OF_RANGE 0x21
#define MASS_TRANS_FLG_NO_PHASE_CHECK 0x04 // PHASE_ERROR is not checked
struct Capacity #define MASS_ERR_SUCCESS 0x00
{ #define MASS_ERR_PHASE_ERROR 0x02
uint8_t data[8]; #define MASS_ERR_UNIT_NOT_READY 0x03
//uint32_t dwBlockAddress; #define MASS_ERR_UNIT_BUSY 0x04
//uint32_t dwBlockLength; #define MASS_ERR_STALL 0x05
}; #define MASS_ERR_CMD_NOT_SUPPORTED 0x06
#define MASS_ERR_INVALID_CSW 0x07
#define MASS_ERR_NO_MEDIA 0x08
#define MASS_ERR_BAD_LBA 0x09
#define MASS_ERR_DEVICE_DISCONNECTED 0x11
#define MASS_ERR_UNABLE_TO_RECOVER 0x12 // Reset recovery error
#define MASS_ERR_INVALID_LUN 0x13
#define MASS_ERR_GENERAL_SCSI_ERROR 0xFE
#define MASS_ERR_GENERAL_USB_ERROR 0xFF
#define MASS_ERR_USER 0xA0 // For subclasses to define their own error codes
struct InquiryResponse #define MASS_TRANS_FLG_CALLBACK 0x01 // Callback is involved
{ #define MASS_TRANS_FLG_NO_STALL_CHECK 0x02 // STALL condition is not checked
uint8_t DeviceType : 5; #define MASS_TRANS_FLG_NO_PHASE_CHECK 0x04 // PHASE_ERROR is not checked
uint8_t PeripheralQualifier : 3;
unsigned Reserved : 7; struct Capacity {
unsigned Removable : 1; uint8_t data[8];
//uint32_t dwBlockAddress;
//uint32_t dwBlockLength;
}__attribute__((packed));
uint8_t Version; struct InquiryResponse {
uint8_t DeviceType : 5;
uint8_t PeripheralQualifier : 3;
unsigned ResponseDataFormat : 4; unsigned Reserved : 7;
unsigned Reserved2 : 1; unsigned Removable : 1;
unsigned NormACA : 1;
unsigned TrmTsk : 1;
unsigned AERC : 1;
uint8_t AdditionalLength; uint8_t Version;
uint8_t Reserved3[2];
unsigned SoftReset : 1; unsigned ResponseDataFormat : 4;
unsigned CmdQue : 1; unsigned Reserved2 : 1;
unsigned Reserved4 : 1; unsigned NormACA : 1;
unsigned Linked : 1; unsigned TrmTsk : 1;
unsigned Sync : 1; unsigned AERC : 1;
unsigned WideBus16Bit : 1;
unsigned WideBus32Bit : 1;
unsigned RelAddr : 1;
uint8_t VendorID[8]; uint8_t AdditionalLength;
uint8_t ProductID[16]; uint8_t Reserved3[2];
uint8_t RevisionID[4];
};
struct CommandBlockWrapper unsigned SoftReset : 1;
{ unsigned CmdQue : 1;
uint32_t dCBWSignature; unsigned Reserved4 : 1;
uint32_t dCBWTag; unsigned Linked : 1;
uint32_t dCBWDataTransferLength; unsigned Sync : 1;
uint8_t bmCBWFlags; unsigned WideBus16Bit : 1;
unsigned WideBus32Bit : 1;
unsigned RelAddr : 1;
struct uint8_t VendorID[8];
{ uint8_t ProductID[16];
uint8_t bmCBWLUN : 4; uint8_t RevisionID[4];
uint8_t bmReserved1 : 4; }__attribute__((packed));
};
struct
{
uint8_t bmCBWCBLength : 4;
uint8_t bmReserved2 : 4;
};
uint8_t CBWCB[16]; struct CommandBlockWrapperBase {
} ; uint32_t dCBWSignature;
uint32_t dCBWTag;
uint32_t dCBWDataTransferLength;
uint8_t bmCBWFlags;
}__attribute__((packed));
struct CommandStatusWrapper struct CommandBlockWrapper : public CommandBlockWrapperBase {
{
uint32_t dCSWSignature;
uint32_t dCSWTag;
uint32_t dCSWDataResidue;
uint8_t bCSWStatus;
};
struct RequestSenseResponce struct {
{ uint8_t bmCBWLUN : 4;
uint8_t bResponseCode; uint8_t bmReserved1 : 4;
uint8_t bSegmentNumber; };
uint8_t bmSenseKey : 4; struct {
uint8_t bmReserved : 1; uint8_t bmCBWCBLength : 4;
uint8_t bmILI : 1; uint8_t bmReserved2 : 4;
uint8_t bmEOM : 1; };
uint8_t bmFileMark : 1;
uint8_t Information[4]; uint8_t CBWCB[16];
uint8_t bAdditionalLength; }__attribute__((packed));
uint8_t CmdSpecificInformation[4];
uint8_t bAdditionalSenseCode;
uint8_t bAdditionalSenseQualifier;
uint8_t bFieldReplaceableUnitCode;
uint8_t SenseKeySpecific[3];
};
//class BulkReadParser : public USBReadParser struct CommandStatusWrapper {
//{ uint32_t dCSWSignature;
//protected: uint32_t dCSWTag;
// bool IsValidCSW(uint8_t size, uint8_t *pcsw); uint32_t dCSWDataResidue;
// bool IsMeaningfulCSW(uint8_t size, uint8_t *pcsw); uint8_t bCSWStatus;
// }__attribute__((packed));
//public:
// virtual void Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset) = 0; struct RequestSenseResponce {
//}; uint8_t bResponseCode;
uint8_t bSegmentNumber;
uint8_t bmSenseKey : 4;
uint8_t bmReserved : 1;
uint8_t bmILI : 1;
uint8_t bmEOM : 1;
uint8_t bmFileMark : 1;
uint8_t Information[4];
uint8_t bAdditionalLength;
uint8_t CmdSpecificInformation[4];
uint8_t bAdditionalSenseCode;
uint8_t bAdditionalSenseQualifier;
uint8_t bFieldReplaceableUnitCode;
uint8_t SenseKeySpecific[3];
}__attribute__((packed));
#define MASS_MAX_ENDPOINTS 3 #define MASS_MAX_ENDPOINTS 3
class BulkOnly : public USBDeviceConfig, public UsbConfigXtracter class BulkOnly : public USBDeviceConfig, public UsbConfigXtracter {
{
protected: protected:
static const uint8_t epDataInIndex; // DataIn endpoint index static const uint8_t epDataInIndex; // DataIn endpoint index
static const uint8_t epDataOutIndex; // DataOUT endpoint index static const uint8_t epDataOutIndex; // DataOUT endpoint index
static const uint8_t epInterruptInIndex; // InterruptIN endpoint index static const uint8_t epInterruptInIndex; // InterruptIN endpoint index
USB *pUsb; USB *pUsb;
uint8_t bAddress; uint8_t bAddress;
uint8_t bConfNum; // configuration number uint8_t bConfNum; // configuration number
uint8_t bIface; // interface value uint8_t bIface; // interface value
uint8_t bNumEP; // total number of EP in the configuration uint8_t bNumEP; // total number of EP in the configuration
uint32_t qNextPollTime; // next poll time uint32_t qNextPollTime; // next poll time
bool bPollEnable; // poll enable flag bool bPollEnable; // poll enable flag
EpInfo epInfo[MASS_MAX_ENDPOINTS]; EpInfo epInfo[MASS_MAX_ENDPOINTS];
uint32_t dCBWTag; // Tag uint32_t dCBWTag; // Tag
uint32_t dCBWDataTransferLength; // Data Transfer Length uint32_t dCBWDataTransferLength; // Data Transfer Length
uint8_t bMaxLUN; // Max LUN uint8_t bLastUsbError; // Last USB error
uint8_t bLastUsbError; // Last USB error uint8_t bMaxLUN; // Max LUN
uint8_t bTheLUN; // Active LUN
protected: protected:
//union TransFlags void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr);
//{
// uint8_t nValue;
// struct { bool IsValidCBW(uint8_t size, uint8_t *pcbw);
// uint8_t bmCallback : 1; bool IsMeaningfulCBW(uint8_t size, uint8_t *pcbw);
// uint8_t bmCheckPhaseErr : 1;
// uint8_t bmDummy : 6;
// };
//};
void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr);
bool IsValidCBW(uint8_t size, uint8_t *pcbw); bool IsValidCSW(CommandStatusWrapper *pcsw, CommandBlockWrapperBase *pcbw);
bool IsMeaningfulCBW(uint8_t size, uint8_t *pcbw);
uint8_t ClearEpHalt(uint8_t index); uint8_t ClearEpHalt(uint8_t index);
uint8_t Transaction(CommandBlockWrapper *cbw, uint16_t bsize, void *buf, uint8_t flags); uint8_t Transaction(CommandBlockWrapper *cbw, uint16_t bsize, void *buf, uint8_t flags);
uint8_t HandleUsbError(uint8_t index); uint8_t HandleUsbError(uint8_t error, uint8_t index);
uint8_t HandleSCSIError(uint8_t status);
public: public:
BulkOnly(USB *p); BulkOnly(USB *p);
uint8_t GetLastUsbError() { return bLastUsbError; };
uint8_t Reset(); uint8_t GetLastUsbError() {
uint8_t GetMaxLUN(uint8_t *max_lun); return bLastUsbError;
};
uint8_t ResetRecovery(); uint8_t GetbMaxLUN() {
uint8_t Inquiry(uint8_t lun, uint16_t size, uint8_t *buf); return bMaxLUN; // Max LUN
uint8_t TestUnitReady(uint8_t lun); }
uint8_t ReadCapacity(uint8_t lun, uint16_t size, uint8_t *buf);
uint8_t RequestSense(uint8_t lun, uint16_t size, uint8_t *buf);
//uint8_t Read(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t *buf);
uint8_t Read(uint8_t lun, uint32_t addr, uint16_t bsize, USBReadParser *prs);
// USBDeviceConfig implementation uint8_t GetbTheLUN() {
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed); return bTheLUN; // Active LUN
virtual uint8_t Release(); }
virtual uint8_t Poll();
virtual uint8_t GetAddress() { return bAddress; };
// UsbConfigXtracter implementation uint8_t Reset();
virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep); uint8_t GetMaxLUN(uint8_t *max_lun);
uint8_t SetCurLUN(uint8_t lun);
uint8_t ResetRecovery();
uint8_t Inquiry(uint8_t lun, uint16_t size, uint8_t *buf);
uint8_t TestUnitReady(uint8_t lun);
uint8_t ReadCapacity(uint8_t lun, uint16_t size, uint8_t *buf);
uint8_t RequestSense(uint8_t lun, uint16_t size, uint8_t *buf);
uint8_t ModeSense(uint8_t lun, uint8_t pc, uint8_t page, uint8_t subpage, uint8_t len, uint8_t *buf);
uint8_t MediaCTL(uint8_t lun, uint8_t ctl);
uint8_t Read(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, uint8_t *buf);
uint8_t Read(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, USBReadParser *prs);
uint8_t Write(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, const uint8_t *buf);
// USBDeviceConfig implementation
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
virtual uint8_t Release();
virtual uint8_t Poll();
virtual uint8_t GetAddress() {
return bAddress;
};
// UsbConfigXtracter implementation
virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
protected:
// Additional Initialization Method for Subclasses
virtual uint8_t OnInit() {
return 0;
};
}; };
#endif // __MASSTORAGE_H__ #endif // __MASSTORAGE_H__

View file

@ -13,7 +13,7 @@ Contact information
Circuits At Home, LTD Circuits At Home, LTD
Web : http://www.circuitsathome.com Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com e-mail : support@circuitsathome.com
*/ */
/* MAX3421E register/bit names and bitmasks */ /* MAX3421E register/bit names and bitmasks */
#ifndef _max3421e_h_ #ifndef _max3421e_h_

View file

@ -13,7 +13,7 @@ Contact information
Circuits At Home, LTD Circuits At Home, LTD
Web : http://www.circuitsathome.com Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com e-mail : support@circuitsathome.com
*/ */
#include "max_LCD.h" #include "max_LCD.h"
#include "max3421e.h" #include "max3421e.h"
@ -47,204 +47,210 @@ e-mail : support@circuitsathome.com
sendbyte(a); \ sendbyte(a); \
} }
static byte lcdPins; //copy of LCD pins static byte lcdPins; //copy of LCD pins
Max_LCD::Max_LCD(USB *pusb) : pUsb(pusb) Max_LCD::Max_LCD(USB *pusb) : pUsb(pusb) {
{ lcdPins = 0;
lcdPins = 0;
} }
void Max_LCD::init() {
_displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
void Max_LCD::init() // MAX3421E::gpioWr(0x55);
{
_displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
// MAX3421E::gpioWr(0x55); begin(16, 1);
begin(16, 1);
} }
void Max_LCD::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) { void Max_LCD::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) {
if (lines > 1) { if (lines > 1) {
_displayfunction |= LCD_2LINE; _displayfunction |= LCD_2LINE;
} }
_numlines = lines; _numlines = lines;
_currline = 0; _currline = 0;
// for some 1 line displays you can select a 10 pixel high font // for some 1 line displays you can select a 10 pixel high font
if ((dotsize != 0) && (lines == 1)) { if ((dotsize != 0) && (lines == 1)) {
_displayfunction |= LCD_5x10DOTS; _displayfunction |= LCD_5x10DOTS;
} }
// SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION! // SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION!
// according to datasheet, we need at least 40ms after power rises above 2.7V // 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 // before sending commands. Arduino can turn on way befer 4.5V so we'll wait 50
delayMicroseconds(50000); delayMicroseconds(50000);
lcdPins = 0x30; lcdPins = 0x30;
SET_E; SET_E;
SENDlcdPins(); SENDlcdPins();
CLR_E; CLR_E;
SENDlcdPins(); SENDlcdPins();
delayMicroseconds(10000); // wait min 4.1ms delayMicroseconds(10000); // wait min 4.1ms
//second try //second try
SET_E; SET_E;
SENDlcdPins(); SENDlcdPins();
CLR_E; CLR_E;
SENDlcdPins(); SENDlcdPins();
delayMicroseconds(10000); // wait min 4.1ms delayMicroseconds(10000); // wait min 4.1ms
// third go! // third go!
SET_E; SET_E;
SENDlcdPins(); SENDlcdPins();
CLR_E; CLR_E;
SENDlcdPins(); SENDlcdPins();
delayMicroseconds(10000); delayMicroseconds(10000);
// finally, set to 4-bit interface // finally, set to 4-bit interface
lcdPins = 0x20; lcdPins = 0x20;
//SET_RS; //SET_RS;
SET_E; SET_E;
SENDlcdPins(); SENDlcdPins();
//CLR_RS; //CLR_RS;
CLR_E; CLR_E;
SENDlcdPins(); SENDlcdPins();
delayMicroseconds(10000); delayMicroseconds(10000);
// finally, set # lines, font size, etc. // finally, set # lines, font size, etc.
command(LCD_FUNCTIONSET | _displayfunction); command(LCD_FUNCTIONSET | _displayfunction);
// turn the display on with no cursor or blinking default // turn the display on with no cursor or blinking default
_displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF; _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
display(); display();
// clear it off // clear it off
clear(); clear();
// Initialize to default text direction (for romance languages) // Initialize to default text direction (for romance languages)
_displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT; _displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
// set the entry mode // set the entry mode
command(LCD_ENTRYMODESET | _displaymode); command(LCD_ENTRYMODESET | _displaymode);
} }
/********** high level commands, for the user! */ /********** high level commands, for the user! */
void Max_LCD::clear() void Max_LCD::clear() {
{ command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero
command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero delayMicroseconds(2000); // this command takes a long time!
delayMicroseconds(2000); // this command takes a long time!
} }
void Max_LCD::home() void Max_LCD::home() {
{ command(LCD_RETURNHOME); // set cursor position to zero
command(LCD_RETURNHOME); // set cursor position to zero delayMicroseconds(2000); // this command takes a long time!
delayMicroseconds(2000); // this command takes a long time!
} }
void Max_LCD::setCursor(uint8_t col, uint8_t row) void Max_LCD::setCursor(uint8_t col, uint8_t row) {
{ int row_offsets[] = {0x00, 0x40, 0x14, 0x54};
int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 }; if (row > _numlines) {
if ( row > _numlines ) { row = _numlines - 1; // we count rows starting w/0
row = _numlines-1; // we count rows starting w/0 }
}
command(LCD_SETDDRAMADDR | (col + row_offsets[row])); command(LCD_SETDDRAMADDR | (col + row_offsets[row]));
} }
// Turn the display on/off (quickly) // Turn the display on/off (quickly)
void Max_LCD::noDisplay() { void Max_LCD::noDisplay() {
_displaycontrol &= ~LCD_DISPLAYON; _displaycontrol &= ~LCD_DISPLAYON;
command(LCD_DISPLAYCONTROL | _displaycontrol); command(LCD_DISPLAYCONTROL | _displaycontrol);
} }
void Max_LCD::display() { void Max_LCD::display() {
_displaycontrol |= LCD_DISPLAYON; _displaycontrol |= LCD_DISPLAYON;
command(LCD_DISPLAYCONTROL | _displaycontrol); command(LCD_DISPLAYCONTROL | _displaycontrol);
} }
// Turns the underline cursor on/off // Turns the underline cursor on/off
void Max_LCD::noCursor() { void Max_LCD::noCursor() {
_displaycontrol &= ~LCD_CURSORON; _displaycontrol &= ~LCD_CURSORON;
command(LCD_DISPLAYCONTROL | _displaycontrol); command(LCD_DISPLAYCONTROL | _displaycontrol);
} }
void Max_LCD::cursor() { void Max_LCD::cursor() {
_displaycontrol |= LCD_CURSORON; _displaycontrol |= LCD_CURSORON;
command(LCD_DISPLAYCONTROL | _displaycontrol); command(LCD_DISPLAYCONTROL | _displaycontrol);
} }
// Turn on and off the blinking cursor // Turn on and off the blinking cursor
void Max_LCD::noBlink() { void Max_LCD::noBlink() {
_displaycontrol &= ~LCD_BLINKON; _displaycontrol &= ~LCD_BLINKON;
command(LCD_DISPLAYCONTROL | _displaycontrol); command(LCD_DISPLAYCONTROL | _displaycontrol);
} }
void Max_LCD::blink() { void Max_LCD::blink() {
_displaycontrol |= LCD_BLINKON; _displaycontrol |= LCD_BLINKON;
command(LCD_DISPLAYCONTROL | _displaycontrol); command(LCD_DISPLAYCONTROL | _displaycontrol);
} }
// These commands scroll the display without changing the RAM // These commands scroll the display without changing the RAM
void Max_LCD::scrollDisplayLeft(void) { void Max_LCD::scrollDisplayLeft(void) {
command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT); command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);
} }
void Max_LCD::scrollDisplayRight(void) { void Max_LCD::scrollDisplayRight(void) {
command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT); command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);
} }
// This is for text that flows Left to Right // This is for text that flows Left to Right
void Max_LCD::leftToRight(void) { void Max_LCD::leftToRight(void) {
_displaymode |= LCD_ENTRYLEFT; _displaymode |= LCD_ENTRYLEFT;
command(LCD_ENTRYMODESET | _displaymode); command(LCD_ENTRYMODESET | _displaymode);
} }
// This is for text that flows Right to Left // This is for text that flows Right to Left
void Max_LCD::rightToLeft(void) { void Max_LCD::rightToLeft(void) {
_displaymode &= ~LCD_ENTRYLEFT; _displaymode &= ~LCD_ENTRYLEFT;
command(LCD_ENTRYMODESET | _displaymode); command(LCD_ENTRYMODESET | _displaymode);
} }
// This will 'right justify' text from the cursor // This will 'right justify' text from the cursor
void Max_LCD::autoscroll(void) { void Max_LCD::autoscroll(void) {
_displaymode |= LCD_ENTRYSHIFTINCREMENT; _displaymode |= LCD_ENTRYSHIFTINCREMENT;
command(LCD_ENTRYMODESET | _displaymode); command(LCD_ENTRYMODESET | _displaymode);
} }
// This will 'left justify' text from the cursor // This will 'left justify' text from the cursor
void Max_LCD::noAutoscroll(void) { void Max_LCD::noAutoscroll(void) {
_displaymode &= ~LCD_ENTRYSHIFTINCREMENT; _displaymode &= ~LCD_ENTRYSHIFTINCREMENT;
command(LCD_ENTRYMODESET | _displaymode); command(LCD_ENTRYMODESET | _displaymode);
} }
// Allows us to fill the first 8 CGRAM locations // Allows us to fill the first 8 CGRAM locations
// with custom characters // with custom characters
void Max_LCD::createChar(uint8_t location, uint8_t charmap[]) { void Max_LCD::createChar(uint8_t location, uint8_t charmap[]) {
location &= 0x7; // we only have 8 locations 0-7 location &= 0x7; // we only have 8 locations 0-7
command(LCD_SETCGRAMADDR | (location << 3)); command(LCD_SETCGRAMADDR | (location << 3));
for (int i=0; i<8; i++) { for (int i = 0; i < 8; i++) {
write(charmap[i]); write(charmap[i]);
} }
} }
/*********** mid level commands, for sending data/cmds */ /*********** mid level commands, for sending data/cmds */
inline void Max_LCD::command(uint8_t value) { inline void Max_LCD::command(uint8_t value) {
LCD_sendcmd(value); LCD_sendcmd(value);
delayMicroseconds(100); delayMicroseconds(100);
} }
inline void Max_LCD::write(uint8_t value) { inline void Max_LCD::write(uint8_t value) {
LCD_sendchar(value); LCD_sendchar(value);
} }
void Max_LCD::sendbyte( uint8_t val ) void Max_LCD::sendbyte(uint8_t val) {
{ lcdPins &= 0x0f; //prepare place for the upper nibble
lcdPins &= 0x0f; //prepare place for the upper nibble lcdPins |= (val & 0xf0); //copy upper nibble to LCD variable
lcdPins |= ( val & 0xf0 ); //copy upper nibble to LCD variable SET_E; //send
SET_E; //send SENDlcdPins();
SENDlcdPins(); delayMicroseconds(2);
delayMicroseconds(2); CLR_E;
CLR_E; delayMicroseconds(2);
delayMicroseconds(2); SENDlcdPins();
SENDlcdPins(); lcdPins &= 0x0f; //prepare place for the lower nibble
lcdPins &= 0x0f; //prepare place for the lower nibble lcdPins |= (val << 4) & 0xf0; //copy lower nibble to LCD variable
lcdPins |= ( val << 4 ) & 0xf0; //copy lower nibble to LCD variable SET_E; //send
SET_E; //send SENDlcdPins();
SENDlcdPins(); CLR_E;
CLR_E; SENDlcdPins();
SENDlcdPins(); delayMicroseconds(100);
delayMicroseconds(100);
} }

View file

@ -13,7 +13,7 @@ Contact information
Circuits At Home, LTD Circuits At Home, LTD
Web : http://www.circuitsathome.com Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com e-mail : support@circuitsathome.com
*/ */
//HD44780 compatible LCD display via MAX3421E GPOUT support header //HD44780 compatible LCD display via MAX3421E GPOUT support header
//pinout: D[4-7] -> GPOUT[4-7], RS-> GPOUT[2], E ->GPOUT[3] //pinout: D[4-7] -> GPOUT[4-7], RS-> GPOUT[2], E ->GPOUT[3]
// //
@ -65,38 +65,38 @@ e-mail : support@circuitsathome.com
class Max_LCD //: public Print class Max_LCD //: public Print
{ {
USB *pUsb; USB *pUsb;
public: public:
Max_LCD(USB *pusb); Max_LCD(USB *pusb);
void init(); void init();
void begin(uint8_t cols, uint8_t rows, uint8_t charsize = LCD_5x8DOTS); void begin(uint8_t cols, uint8_t rows, uint8_t charsize = LCD_5x8DOTS);
void clear(); void clear();
void home(); void home();
void noDisplay(); void noDisplay();
void display(); void display();
void noBlink(); void noBlink();
void blink(); void blink();
void noCursor(); void noCursor();
void cursor(); void cursor();
void scrollDisplayLeft(); void scrollDisplayLeft();
void scrollDisplayRight(); void scrollDisplayRight();
void leftToRight(); void leftToRight();
void rightToLeft(); void rightToLeft();
void autoscroll(); void autoscroll();
void noAutoscroll(); void noAutoscroll();
void createChar(uint8_t, uint8_t[]); void createChar(uint8_t, uint8_t[]);
void setCursor(uint8_t, uint8_t); void setCursor(uint8_t, uint8_t);
virtual void write(uint8_t); virtual void write(uint8_t);
void command(uint8_t); void command(uint8_t);
private: private:
void sendbyte( uint8_t val ); void sendbyte(uint8_t val);
uint8_t _displayfunction; //tokill uint8_t _displayfunction; //tokill
uint8_t _displaycontrol; uint8_t _displaycontrol;
uint8_t _displaymode; uint8_t _displaymode;
uint8_t _initialized; uint8_t _initialized;
uint8_t _numlines,_currline; uint8_t _numlines, _currline;
}; };
#endif #endif

View file

@ -13,19 +13,35 @@ Contact information
Circuits At Home, LTD Circuits At Home, LTD
Web : http://www.circuitsathome.com Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com e-mail : support@circuitsathome.com
*/ */
#include "message.h" #include "message.h"
// 0x80 is the default (i.e. trace) to turn off set this global to something lower.
// this allows for 126 other debugging levels.
// TO-DO: Allow assignment to a different serial port
int UsbDEBUGlvl = 0x80;
void Notify(char const * msg) void Notifyc(char c, int lvl) {
//void Notify(const char* msg) if (UsbDEBUGlvl < lvl) return;
{
if(!msg) return;
char c;
while((c = pgm_read_byte(msg++)))
#if defined(ARDUINO) && ARDUINO >=100 #if defined(ARDUINO) && ARDUINO >=100
Serial.print(c); Serial.print(c);
#else #else
Serial.print(c,BYTE); Serial.print(c, BYTE);
#endif #endif
Serial.flush();
}
void Notify(char const * msg, int lvl) {
if (UsbDEBUGlvl < lvl) return;
if (!msg) return;
char c;
while ((c = pgm_read_byte(msg++))) Notifyc(c, lvl);
}
void NotifyStr(char const * msg, int lvl) {
if (UsbDEBUGlvl < lvl) return;
if (!msg) return;
char c;
while (c = *msg++) Notifyc(c, lvl);
} }

View file

@ -13,24 +13,26 @@ Contact information
Circuits At Home, LTD Circuits At Home, LTD
Web : http://www.circuitsathome.com Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com e-mail : support@circuitsathome.com
*/ */
#if !defined(__MESSAGE_H__) #if !defined(__MESSAGE_H__)
#define __MESSAGE_H__ #define __MESSAGE_H__
#include <inttypes.h> #include <inttypes.h>
#include <avr/pgmspace.h> #include <avr/pgmspace.h>
void Notify(char const * msg, int lvl);
void NotifyStr(char const * msg, int lvl);
#include "printhex.h" #include "printhex.h"
void Notify(char const * msg);
//void Notify(const char* msg); //void Notify(const char* msg);
template <class ERROR_TYPE> template <class ERROR_TYPE>
void ErrorMessage(char const * msg, ERROR_TYPE rcode = 0) void ErrorMessage(char const * msg, ERROR_TYPE rcode = 0) {
{ Notify(msg, 0x80);
Notify(msg); Notify(PSTR(": "), 0x80);
Notify(PSTR(": ")); PrintHex<ERROR_TYPE > (rcode, 0x80);
PrintHex<ERROR_TYPE>(rcode); Notify(PSTR("\r\n"), 0x80);
Notify(PSTR("\r\n"));
} }

View file

@ -13,60 +13,55 @@ Contact information
Circuits At Home, LTD Circuits At Home, LTD
Web : http://www.circuitsathome.com Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com e-mail : support@circuitsathome.com
*/ */
#include "parsetools.h" #include "parsetools.h"
bool MultiByteValueParser::Parse(uint8_t **pp, uint16_t *pcntdn) bool MultiByteValueParser::Parse(uint8_t **pp, uint16_t *pcntdn) {
{ if (!pBuf) {
if (!pBuf) Notify(PSTR("Buffer pointer is NULL!\r\n"), 0x80);
{ return false;
Notify(PSTR("Buffer pointer is NULL!\r\n")); }
return false; for (; countDown && (*pcntdn); countDown--, (*pcntdn)--, (*pp)++)
} pBuf[valueSize - countDown] = (**pp);
for (; countDown && (*pcntdn); countDown--, (*pcntdn)--, (*pp)++)
pBuf[valueSize-countDown] = (**pp);
if (countDown) if (countDown)
return false; return false;
countDown = valueSize; countDown = valueSize;
return true; return true;
} }
bool PTPListParser::Parse(uint8_t **pp, uint16_t *pcntdn, PTP_ARRAY_EL_FUNC pf, const void *me) bool PTPListParser::Parse(uint8_t **pp, uint16_t *pcntdn, PTP_ARRAY_EL_FUNC pf, const void *me) {
{ switch (nStage) {
switch (nStage) case 0:
{ pBuf->valueSize = lenSize;
case 0: theParser.Initialize(pBuf);
pBuf->valueSize = lenSize; nStage = 1;
theParser.Initialize(pBuf);
nStage = 1;
case 1: case 1:
if (!theParser.Parse(pp, pcntdn)) if (!theParser.Parse(pp, pcntdn))
return false; return false;
arLen = 0; arLen = 0;
arLen = (pBuf->valueSize >= 4) ? *((uint32_t*)pBuf->pValue) : (uint32_t)(*((uint16_t*)pBuf->pValue)); arLen = (pBuf->valueSize >= 4) ? *((uint32_t*) pBuf->pValue) : (uint32_t) (*((uint16_t*) pBuf->pValue));
arLenCntdn = arLen; arLenCntdn = arLen;
nStage = 2; nStage = 2;
case 2: case 2:
pBuf->valueSize = valSize; pBuf->valueSize = valSize;
theParser.Initialize(pBuf); theParser.Initialize(pBuf);
nStage = 3; nStage = 3;
case 3: case 3:
for (; arLenCntdn; arLenCntdn--) for (; arLenCntdn; arLenCntdn--) {
{ if (!theParser.Parse(pp, pcntdn))
if (!theParser.Parse(pp, pcntdn)) return false;
return false;
if (pf) if (pf)
pf(pBuf, (arLen - arLenCntdn), me); pf(pBuf, (arLen - arLenCntdn), me);
} }
nStage = 0; nStage = 0;
} }
return true; return true;
} }

View file

@ -13,7 +13,7 @@ Contact information
Circuits At Home, LTD Circuits At Home, LTD
Web : http://www.circuitsathome.com Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com e-mail : support@circuitsathome.com
*/ */
#if !defined(__PARSETOOLS_H__) #if !defined(__PARSETOOLS_H__)
#define __PARSETOOLS_H__ #define __PARSETOOLS_H__
@ -29,123 +29,121 @@ e-mail : support@circuitsathome.com
#include <WProgram.h> #include <WProgram.h>
#endif #endif
struct MultiValueBuffer struct MultiValueBuffer {
{ uint8_t valueSize;
uint8_t valueSize; void *pValue;
void *pValue; }__attribute__((packed));
};
class MultiByteValueParser class MultiByteValueParser {
{ uint8_t * pBuf;
uint8_t * pBuf; uint8_t countDown;
uint8_t countDown; uint8_t valueSize;
uint8_t valueSize;
public: public:
MultiByteValueParser() : pBuf(NULL), countDown(0), valueSize(0) {};
const uint8_t* GetBuffer() { return pBuf; }; MultiByteValueParser() : pBuf(NULL), countDown(0), valueSize(0) {
};
void Initialize(MultiValueBuffer * const pbuf) const uint8_t* GetBuffer() {
{ return pBuf;
pBuf = (uint8_t*)pbuf->pValue; };
countDown = valueSize = pbuf->valueSize;
};
bool Parse(uint8_t **pp, uint16_t *pcntdn); void Initialize(MultiValueBuffer * const pbuf) {
pBuf = (uint8_t*) pbuf->pValue;
countDown = valueSize = pbuf->valueSize;
};
bool Parse(uint8_t **pp, uint16_t *pcntdn);
}; };
class ByteSkipper class ByteSkipper {
{ uint8_t *pBuf;
uint8_t *pBuf; uint8_t nStage;
uint8_t nStage; uint16_t countDown;
uint16_t countDown;
public: public:
ByteSkipper() : pBuf(NULL), nStage(0), countDown(0) {};
void Initialize(MultiValueBuffer *pbuf) ByteSkipper() : pBuf(NULL), nStage(0), countDown(0) {
{ };
pBuf = (uint8_t*)pbuf->pValue;
countDown = 0;
};
bool Skip(uint8_t **pp, uint16_t *pcntdn, uint16_t bytes_to_skip) void Initialize(MultiValueBuffer *pbuf) {
{ pBuf = (uint8_t*) pbuf->pValue;
switch (nStage) countDown = 0;
{ };
case 0:
countDown = bytes_to_skip;
nStage ++;
case 1:
for (; countDown && (*pcntdn); countDown--, (*pp)++, (*pcntdn)--);
if (!countDown) bool Skip(uint8_t **pp, uint16_t *pcntdn, uint16_t bytes_to_skip) {
nStage = 0; switch (nStage) {
}; case 0:
return (!countDown); countDown = bytes_to_skip;
}; nStage++;
case 1:
for (; countDown && (*pcntdn); countDown--, (*pp)++, (*pcntdn)--);
if (!countDown)
nStage = 0;
};
return (!countDown);
};
}; };
// Pointer to a callback function triggered for each element of PTP array when used with PTPArrayParser // Pointer to a callback function triggered for each element of PTP array when used with PTPArrayParser
typedef void (*PTP_ARRAY_EL_FUNC)(const MultiValueBuffer * const p, uint32_t count, const void *me); typedef void (*PTP_ARRAY_EL_FUNC)(const MultiValueBuffer * const p, uint32_t count, const void *me);
class PTPListParser class PTPListParser {
{
public: public:
enum ParseMode { modeArray, modeRange/*, modeEnum*/ };
enum ParseMode {
modeArray, modeRange/*, modeEnum*/
};
private: private:
uint8_t nStage; uint8_t nStage;
uint8_t enStage; uint8_t enStage;
uint32_t arLen; uint32_t arLen;
uint32_t arLenCntdn; uint32_t arLenCntdn;
uint8_t lenSize; // size of the array length field in bytes uint8_t lenSize; // size of the array length field in bytes
uint8_t valSize; // size of the array element in bytes uint8_t valSize; // size of the array element in bytes
MultiValueBuffer *pBuf; MultiValueBuffer *pBuf;
// The only parser for both size and array element parsing // The only parser for both size and array element parsing
MultiByteValueParser theParser; MultiByteValueParser theParser;
uint8_t /*ParseMode*/ prsMode; uint8_t /*ParseMode*/ prsMode;
public: public:
PTPListParser() :
pBuf(NULL),
nStage(0),
enStage(0),
arLenCntdn(0),
arLen(0),
lenSize(0),
valSize(0),
prsMode(modeArray)
{};
void Initialize(const uint8_t len_size, const uint8_t val_size, MultiValueBuffer * const p, const uint8_t mode = modeArray) PTPListParser() :
{ nStage(0),
pBuf = p; enStage(0),
lenSize = len_size; arLen(0),
valSize = val_size; arLenCntdn(0),
prsMode = mode; lenSize(0),
valSize(0),
pBuf(NULL),
prsMode(modeArray) {
};
if (prsMode == modeRange) void Initialize(const uint8_t len_size, const uint8_t val_size, MultiValueBuffer * const p, const uint8_t mode = modeArray) {
{ pBuf = p;
arLenCntdn = arLen = 3; lenSize = len_size;
nStage = 2; valSize = val_size;
} prsMode = mode;
else
{
arLenCntdn = arLen = 0;
nStage = 0;
}
enStage = 0;
theParser.Initialize(p);
};
bool Parse(uint8_t **pp, uint16_t *pcntdn, PTP_ARRAY_EL_FUNC pf, const void *me = NULL); if (prsMode == modeRange) {
arLenCntdn = arLen = 3;
nStage = 2;
} else {
arLenCntdn = arLen = 0;
nStage = 0;
}
enStage = 0;
theParser.Initialize(p);
};
bool Parse(uint8_t **pp, uint16_t *pcntdn, PTP_ARRAY_EL_FUNC pf, const void *me = NULL);
}; };
#endif // __PARSETOOLS_H__ #endif // __PARSETOOLS_H__

View file

@ -13,7 +13,7 @@ Contact information
Circuits At Home, LTD Circuits At Home, LTD
Web : http://www.circuitsathome.com Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com e-mail : support@circuitsathome.com
*/ */
#if !defined(__PRINTHEX_H__) #if !defined(__PRINTHEX_H__)
#define __PRINTHEX_H__ #define __PRINTHEX_H__
@ -22,45 +22,50 @@ e-mail : support@circuitsathome.com
#else #else
#include <WProgram.h> #include <WProgram.h>
#endif #endif
void Notifyc(char c, int lvl);
template <class T> template <class T>
void PrintHex(T val) void PrintHex(T val, int lvl) {
{ int num_nibbles = sizeof (T) * 2;
T mask = (((T)1) << (((sizeof(T) << 1) - 1) << 2));
while (mask > 1) do {
{ char v = 48 + (((val >> (num_nibbles - 1) * 4)) & 0x0f);
if (val < mask) if (v > 57) v += 7;
Serial.print("0"); Notifyc(v, lvl);
} while (--num_nibbles);
mask >>= 4;
}
Serial.print((T)val, HEX);
} }
template <class T> template <class T>
void PrintHex2(Print *prn, T val) void PrintBin(T val, int lvl) {
{ for (T mask = (((T) 1) << ((sizeof (T) << 3) - 1)); mask; mask >>= 1)
T mask = (((T)1) << (((sizeof(T) << 1) - 1) << 2)); if (val & mask)
Notifyc('1', lvl);
while (mask > 1) else
{ Notifyc('0', lvl);
if (val < mask)
prn->print("0");
mask >>= 4;
}
prn->print((T)val, HEX);
} }
template <class T> template <class T>
void PrintBin(T val) void SerialPrintHex(T val) {
{ int num_nibbles = sizeof (T) * 2;
for (T mask = (((T)1) << (sizeof(T) << 3)-1); mask; mask>>=1)
if (val & mask) do {
Serial.print("1"); char v = 48 + (((val >> (num_nibbles - 1) * 4)) & 0x0f);
else if (v > 57) v += 7;
Serial.print("0"); Serial.print(v);
} while (--num_nibbles);
}
template <class T>
void PrintHex2(Print *prn, T val) {
T mask = (((T) 1) << (((sizeof (T) << 1) - 1) << 2));
while (mask > 1) {
if (val < mask)
prn->print("0");
mask >>= 4;
}
prn->print((T) val, HEX);
} }
#endif // __PRINTHEX_H__ #endif // __PRINTHEX_H__

122
usb_ch9.h
View file

@ -13,7 +13,7 @@ Contact information
Circuits At Home, LTD Circuits At Home, LTD
Web : http://www.circuitsathome.com Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com e-mail : support@circuitsathome.com
*/ */
/* USB chapter 9 structures */ /* USB chapter 9 structures */
#ifndef _ch9_h_ #ifndef _ch9_h_
#define _ch9_h_ #define _ch9_h_
@ -94,77 +94,71 @@ e-mail : support@circuitsathome.com
/* Device descriptor structure */ /* Device descriptor structure */
typedef struct { typedef struct {
uint8_t bLength; // Length of this descriptor. uint8_t bLength; // Length of this descriptor.
uint8_t bDescriptorType; // DEVICE descriptor type (USB_DESCRIPTOR_DEVICE). uint8_t bDescriptorType; // DEVICE descriptor type (USB_DESCRIPTOR_DEVICE).
uint16_t bcdUSB; // USB Spec Release Number (BCD). uint16_t bcdUSB; // USB Spec Release Number (BCD).
uint8_t bDeviceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific. uint8_t bDeviceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific.
uint8_t bDeviceSubClass; // Subclass code (assigned by the USB-IF). uint8_t bDeviceSubClass; // Subclass code (assigned by the USB-IF).
uint8_t bDeviceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific. uint8_t bDeviceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific.
uint8_t bMaxPacketSize0; // Maximum packet size for endpoint 0. uint8_t bMaxPacketSize0; // Maximum packet size for endpoint 0.
uint16_t idVendor; // Vendor ID (assigned by the USB-IF). uint16_t idVendor; // Vendor ID (assigned by the USB-IF).
uint16_t idProduct; // Product ID (assigned by the manufacturer). uint16_t idProduct; // Product ID (assigned by the manufacturer).
uint16_t bcdDevice; // Device release number (BCD). uint16_t bcdDevice; // Device release number (BCD).
uint8_t iManufacturer; // Index of String Descriptor describing the manufacturer. uint8_t iManufacturer; // Index of String Descriptor describing the manufacturer.
uint8_t iProduct; // Index of String Descriptor describing the product. uint8_t iProduct; // Index of String Descriptor describing the product.
uint8_t iSerialNumber; // Index of String Descriptor with the device's serial number. uint8_t iSerialNumber; // Index of String Descriptor with the device's serial number.
uint8_t bNumConfigurations; // Number of possible configurations. uint8_t bNumConfigurations; // Number of possible configurations.
} USB_DEVICE_DESCRIPTOR; }__attribute__((packed)) USB_DEVICE_DESCRIPTOR;
/* Configuration descriptor structure */ /* Configuration descriptor structure */
typedef struct typedef struct {
{ uint8_t bLength; // Length of this descriptor.
uint8_t bLength; // Length of this descriptor. uint8_t bDescriptorType; // CONFIGURATION descriptor type (USB_DESCRIPTOR_CONFIGURATION).
uint8_t bDescriptorType; // CONFIGURATION descriptor type (USB_DESCRIPTOR_CONFIGURATION). uint16_t wTotalLength; // Total length of all descriptors for this configuration.
uint16_t wTotalLength; // Total length of all descriptors for this configuration. uint8_t bNumInterfaces; // Number of interfaces in this configuration.
uint8_t bNumInterfaces; // Number of interfaces in this configuration. uint8_t bConfigurationValue; // Value of this configuration (1 based).
uint8_t bConfigurationValue; // Value of this configuration (1 based). uint8_t iConfiguration; // Index of String Descriptor describing the configuration.
uint8_t iConfiguration; // Index of String Descriptor describing the configuration. uint8_t bmAttributes; // Configuration characteristics.
uint8_t bmAttributes; // Configuration characteristics. uint8_t bMaxPower; // Maximum power consumed by this configuration.
uint8_t bMaxPower; // Maximum power consumed by this configuration. }__attribute__((packed)) USB_CONFIGURATION_DESCRIPTOR;
} USB_CONFIGURATION_DESCRIPTOR;
/* Interface descriptor structure */ /* Interface descriptor structure */
typedef struct typedef struct {
{ uint8_t bLength; // Length of this descriptor.
uint8_t bLength; // Length of this descriptor. uint8_t bDescriptorType; // INTERFACE descriptor type (USB_DESCRIPTOR_INTERFACE).
uint8_t bDescriptorType; // INTERFACE descriptor type (USB_DESCRIPTOR_INTERFACE). uint8_t bInterfaceNumber; // Number of this interface (0 based).
uint8_t bInterfaceNumber; // Number of this interface (0 based). uint8_t bAlternateSetting; // Value of this alternate interface setting.
uint8_t bAlternateSetting; // Value of this alternate interface setting. uint8_t bNumEndpoints; // Number of endpoints in this interface.
uint8_t bNumEndpoints; // Number of endpoints in this interface. uint8_t bInterfaceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific.
uint8_t bInterfaceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific. uint8_t bInterfaceSubClass; // Subclass code (assigned by the USB-IF).
uint8_t bInterfaceSubClass; // Subclass code (assigned by the USB-IF). uint8_t bInterfaceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific.
uint8_t bInterfaceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific. uint8_t iInterface; // Index of String Descriptor describing the interface.
uint8_t iInterface; // Index of String Descriptor describing the interface. }__attribute__((packed)) USB_INTERFACE_DESCRIPTOR;
} USB_INTERFACE_DESCRIPTOR;
/* Endpoint descriptor structure */ /* Endpoint descriptor structure */
typedef struct typedef struct {
{ uint8_t bLength; // Length of this descriptor.
uint8_t bLength; // Length of this descriptor. uint8_t bDescriptorType; // ENDPOINT descriptor type (USB_DESCRIPTOR_ENDPOINT).
uint8_t bDescriptorType; // ENDPOINT descriptor type (USB_DESCRIPTOR_ENDPOINT). uint8_t bEndpointAddress; // Endpoint address. Bit 7 indicates direction (0=OUT, 1=IN).
uint8_t bEndpointAddress; // Endpoint address. Bit 7 indicates direction (0=OUT, 1=IN). uint8_t bmAttributes; // Endpoint transfer type.
uint8_t bmAttributes; // Endpoint transfer type. uint16_t wMaxPacketSize; // Maximum packet size.
uint16_t wMaxPacketSize; // Maximum packet size. uint8_t bInterval; // Polling interval in frames.
uint8_t bInterval; // Polling interval in frames. }__attribute__((packed)) USB_ENDPOINT_DESCRIPTOR;
} USB_ENDPOINT_DESCRIPTOR;
/* HID descriptor */ /* HID descriptor */
typedef struct typedef struct {
{ uint8_t bLength;
uint8_t bLength; uint8_t bDescriptorType;
uint8_t bDescriptorType; uint16_t bcdHID; // HID class specification release
uint16_t bcdHID; // HID class specification release uint8_t bCountryCode;
uint8_t bCountryCode; uint8_t bNumDescriptors; // Number of additional class specific descriptors
uint8_t bNumDescriptors; // Number of additional class specific descriptors uint8_t bDescrType; // Type of class descriptor
uint8_t bDescrType; // Type of class descriptor uint16_t wDescriptorLength; // Total size of the Report descriptor
uint16_t wDescriptorLength; // Total size of the Report descriptor }__attribute__((packed)) USB_HID_DESCRIPTOR;
} USB_HID_DESCRIPTOR;
typedef struct typedef struct {
{ uint8_t bDescrType; // Type of class descriptor
uint8_t bDescrType; // Type of class descriptor uint16_t wDescriptorLength; // Total size of the Report descriptor
uint16_t wDescriptorLength; // Total size of the Report descriptor }__attribute__((packed)) HID_CLASS_DESCRIPTOR_LEN_AND_TYPE;
} HID_CLASS_DESCRIPTOR_LEN_AND_TYPE;
#endif // _ch9_h_ #endif // _ch9_h_

392
usbhost.h
View file

@ -13,7 +13,7 @@ Contact information
Circuits At Home, LTD Circuits At Home, LTD
Web : http://www.circuitsathome.com Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com e-mail : support@circuitsathome.com
*/ */
/* MAX3421E-based USB Host Library header file */ /* MAX3421E-based USB Host Library header file */
#ifndef _USBHOST_H_ #ifndef _USBHOST_H_
#define _USBHOST_H_ #define _USBHOST_H_
@ -22,24 +22,23 @@ e-mail : support@circuitsathome.com
#include "max3421e.h" #include "max3421e.h"
#include "usb_ch9.h" #include "usb_ch9.h"
/* SPI initialization */ /* SPI initialization */
template< typename CLK, typename MOSI, typename MISO, typename SPI_SS > class SPi template< typename CLK, typename MOSI, typename MISO, typename SPI_SS > class SPi {
{ public:
public:
static void init() { static void init() {
uint8_t tmp; //uint8_t tmp;
CLK::SetDirWrite(); CLK::SetDirWrite();
MOSI::SetDirWrite(); MOSI::SetDirWrite();
MISO::SetDirRead(); MISO::SetDirRead();
SPI_SS::SetDirWrite(); SPI_SS::SetDirWrite();
/* mode 00 (CPOL=0, CPHA=0) master, fclk/2. Mode 11 (CPOL=11, CPHA=11) is also supported by MAX3421E */ /* mode 00 (CPOL=0, CPHA=0) master, fclk/2. Mode 11 (CPOL=11, CPHA=11) is also supported by MAX3421E */
SPCR = 0x50; SPCR = 0x50;
SPSR = 0x01; SPSR = 0x01;
/**/ /**/
tmp = SPSR; //tmp = SPSR;
tmp = SPDR; //tmp = SPDR;
} }
}; };
/* SPI pin definitions. see avrpins.h */ /* SPI pin definitions. see avrpins.h */
@ -53,143 +52,138 @@ typedef SPi< Pb5, Pb3, Pb4, Pb2 > spi;
typedef SPi< Pb7, Pb5, Pb6, Pb4 > spi; typedef SPi< Pb7, Pb5, Pb6, Pb4 > spi;
#endif #endif
template< typename SS, typename INTR > class MAX3421e /* : public spi */ template< typename SS, typename INTR > class MAX3421e /* : public spi */ {
{ static uint8_t vbusState;
static uint8_t vbusState;
public: public:
MAX3421e(); MAX3421e();
void regWr( uint8_t reg, uint8_t data ); void regWr(uint8_t reg, uint8_t data);
uint8_t* bytesWr( uint8_t reg, uint8_t nbytes, uint8_t* data_p ); uint8_t* bytesWr(uint8_t reg, uint8_t nbytes, uint8_t* data_p);
void gpioWr( uint8_t data ); void gpioWr(uint8_t data);
uint8_t regRd( uint8_t reg ); uint8_t regRd(uint8_t reg);
uint8_t* bytesRd( uint8_t reg, uint8_t nbytes, uint8_t* data_p ); uint8_t* bytesRd(uint8_t reg, uint8_t nbytes, uint8_t* data_p);
uint8_t gpioRd(); uint8_t gpioRd();
uint16_t reset(); uint16_t reset();
int8_t Init(); int8_t Init();
uint8_t getVbusState( void ) { return vbusState; };
void busprobe(); uint8_t getVbusState(void) {
uint8_t GpxHandler(); return vbusState;
uint8_t IntHandler(); };
uint8_t Task(); void busprobe();
uint8_t GpxHandler();
uint8_t IntHandler();
uint8_t Task();
}; };
template< typename SS, typename INTR > template< typename SS, typename INTR >
uint8_t MAX3421e< SS, INTR >::vbusState = 0; uint8_t MAX3421e< SS, INTR >::vbusState = 0;
/* constructor */ /* constructor */
template< typename SS, typename INTR > template< typename SS, typename INTR >
MAX3421e< SS, INTR >::MAX3421e() MAX3421e< SS, INTR >::MAX3421e() {
{ /* pin and peripheral setup */
/* pin and peripheral setup */ SS::SetDirWrite();
SS::SetDirWrite(); SS::Set();
SS::Set(); spi::init();
spi::init(); INTR::SetDirRead();
INTR::SetDirRead();
#ifdef BOARD_MEGA_ADK
/* For Mega ADK, which has Max3421e on-board, set MAX_RESET to Output mode, and pull Reset to HIGH */
DDRJ |= _BV(PJ2);
PORTJ &= ~_BV(PJ2);
PORTJ |= _BV(PJ2);
#endif
/* MAX3421E - full-duplex SPI, level interrupt */ /* MAX3421E - full-duplex SPI, level interrupt */
regWr( rPINCTL,( bmFDUPSPI + bmINTLEVEL )); regWr(rPINCTL, (bmFDUPSPI + bmINTLEVEL));
}; };
/* write single byte into MAX3421 register */ /* write single byte into MAX3421 register */
template< typename SS, typename INTR > template< typename SS, typename INTR >
void MAX3421e< SS, INTR >::regWr( uint8_t reg, uint8_t data ) void MAX3421e< SS, INTR >::regWr(uint8_t reg, uint8_t data) {
{ SS::Clear();
SS::Clear(); SPDR = (reg | 0x02);
SPDR = ( reg | 0x02 ); while (!(SPSR & (1 << SPIF)));
while(!( SPSR & ( 1 << SPIF ))); SPDR = data;
SPDR = data; while (!(SPSR & (1 << SPIF)));
while(!( SPSR & ( 1 << SPIF ))); SS::Set();
SS::Set(); return;
return;
}; };
/* multiple-byte write */ /* multiple-byte write */
/* returns a pointer to memory position after last written */ /* returns a pointer to memory position after last written */
template< typename SS, typename INTR > template< typename SS, typename INTR >
uint8_t* MAX3421e< SS, INTR >::bytesWr( uint8_t reg, uint8_t nbytes, uint8_t* data_p ) uint8_t* MAX3421e< SS, INTR >::bytesWr(uint8_t reg, uint8_t nbytes, uint8_t* data_p) {
{ SS::Clear();
SS::Clear(); SPDR = (reg | 0x02); //set WR bit and send register number
SPDR = ( reg | 0x02 ); //set WR bit and send register number while (nbytes--) {
while( nbytes-- ) { while (!(SPSR & (1 << SPIF))); //check if previous byte was sent
while(!( SPSR & ( 1 << SPIF ))); //check if previous byte was sent SPDR = (*data_p); // send next data byte
SPDR = ( *data_p ); // send next data byte data_p++; // advance data pointer
data_p++; // advance data pointer }
} while (!(SPSR & (1 << SPIF)));
while(!( SPSR & ( 1 << SPIF ))); SS::Set();
SS::Set(); return ( data_p);
return( data_p );
} }
/* GPIO write */ /* GPIO write */
/*GPIO byte is split between 2 registers, so two writes are needed to write one byte */ /*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 */ /* GPOUT bits are in the low nibble. 0-3 in IOPINS1, 4-7 in IOPINS2 */
template< typename SS, typename INTR > template< typename SS, typename INTR >
void MAX3421e< SS, INTR >::gpioWr( uint8_t data ) void MAX3421e< SS, INTR >::gpioWr(uint8_t data) {
{ regWr(rIOPINS1, data);
regWr( rIOPINS1, data ); data >>= 4;
data >>= 4; regWr(rIOPINS2, data);
regWr( rIOPINS2, data ); return;
return;
} }
/* single host register read */ /* single host register read */
template< typename SS, typename INTR > template< typename SS, typename INTR >
uint8_t MAX3421e< SS, INTR >::regRd( uint8_t reg ) uint8_t MAX3421e< SS, INTR >::regRd(uint8_t reg) {
{ SS::Clear();
SS::Clear(); SPDR = reg;
SPDR = reg; while (!(SPSR & (1 << SPIF)));
while(!( SPSR & ( 1 << SPIF ))); SPDR = 0; //send empty byte
SPDR = 0; //send empty byte while (!(SPSR & (1 << SPIF)));
while(!( SPSR & ( 1 << SPIF ))); SS::Set();
SS::Set(); return ( SPDR);
return( SPDR );
} }
/* multiple-byte register read */ /* multiple-byte register read */
/* returns a pointer to a memory position after last read */ /* returns a pointer to a memory position after last read */
template< typename SS, typename INTR > template< typename SS, typename INTR >
uint8_t* MAX3421e< SS, INTR >::bytesRd( uint8_t reg, uint8_t nbytes, uint8_t* data_p ) uint8_t* MAX3421e< SS, INTR >::bytesRd(uint8_t reg, uint8_t nbytes, uint8_t* data_p) {
{ SS::Clear();
SS::Clear(); SPDR = reg;
SPDR = reg; while (!(SPSR & (1 << SPIF))); //wait
while(!( SPSR & ( 1 << SPIF ))); //wait while (nbytes) {
while( nbytes ) { SPDR = 0; //send empty byte
SPDR = 0; //send empty byte nbytes--;
nbytes--; while (!(SPSR & (1 << SPIF)));
while(!( SPSR & ( 1 << SPIF ))); *data_p = SPDR;
*data_p = SPDR; data_p++;
data_p++; }
} SS::Set();
SS::Set(); return ( data_p);
return( data_p );
} }
/* GPIO read. See gpioWr for explanation */ /* GPIO read. See gpioWr for explanation */
/* GPIN pins are in high nibbles of IOPINS1, IOPINS2 */ /* GPIN pins are in high nibbles of IOPINS1, IOPINS2 */
template< typename SS, typename INTR > template< typename SS, typename INTR >
uint8_t MAX3421e< SS, INTR >::gpioRd() uint8_t MAX3421e< SS, INTR >::gpioRd() {
{ uint8_t gpin = 0;
uint8_t gpin = 0; gpin = regRd(rIOPINS2); //pins 4-7
gpin = regRd( rIOPINS2 ); //pins 4-7 gpin &= 0xf0; //clean lower nibble
gpin &= 0xf0; //clean lower nibble gpin |= (regRd(rIOPINS1) >> 4); //shift low bits and OR with upper from previous operation.
gpin |= ( regRd( rIOPINS1 ) >>4 ) ; //shift low bits and OR with upper from previous operation. return ( gpin);
return( gpin );
} }
/* reset MAX3421E. Returns number of cycles it took for PLL to stabilize after reset /* reset MAX3421E. Returns number of cycles it took for PLL to stabilize after reset
or zero if PLL haven't stabilized in 65535 cycles */ or zero if PLL haven't stabilized in 65535 cycles */
template< typename SS, typename INTR > template< typename SS, typename INTR >
uint16_t MAX3421e< SS, INTR >::reset() uint16_t MAX3421e< SS, INTR >::reset() {
{ uint16_t i = 0;
uint16_t i = 0; regWr(rUSBCTL, bmCHIPRES);
regWr( rUSBCTL, bmCHIPRES ); regWr(rUSBCTL, 0x00);
regWr( rUSBCTL, 0x00 ); while (++i) {
while( ++i ) { if ((regRd(rUSBIRQ) & bmOSCOKIRQ)) {
if(( regRd( rUSBIRQ ) & bmOSCOKIRQ )) { break;
break; }
} }
} return ( i);
return( i );
} }
///* initialize MAX3421E. Set Host mode, pullups, and stuff. Returns 0 if success, -1 if not */ ///* initialize MAX3421E. Set Host mode, pullups, and stuff. Returns 0 if success, -1 if not */
//template< typename SS, typename INTR > //template< typename SS, typename INTR >
@ -202,102 +196,98 @@ uint16_t MAX3421e< SS, INTR >::reset()
// //
// return( 0 ); // return( 0 );
//} //}
/* initialize MAX3421E. Set Host mode, pullups, and stuff. Returns 0 if success, -1 if not */ /* initialize MAX3421E. Set Host mode, pullups, and stuff. Returns 0 if success, -1 if not */
template< typename SS, typename INTR > template< typename SS, typename INTR >
int8_t MAX3421e< SS, INTR >::Init() int8_t MAX3421e< SS, INTR >::Init() {
{ if (reset() == 0) { //OSCOKIRQ hasn't asserted in time
if( reset() == 0 ) return ( -1);
{ //OSCOKIRQ hasn't asserted in time }
return ( -1 ); regWr(rMODE, bmDPPULLDN | bmDMPULLDN | bmHOST); // set pull-downs, Host
}
regWr( rMODE, bmDPPULLDN|bmDMPULLDN|bmHOST ); // set pull-downs, Host
regWr( rHIEN, bmCONDETIE|bmFRAMEIE ); //connection detection regWr(rHIEN, bmCONDETIE | bmFRAMEIE); //connection detection
/* check if device is connected */ /* check if device is connected */
regWr( rHCTL,bmSAMPLEBUS ); // sample USB bus regWr(rHCTL, bmSAMPLEBUS); // sample USB bus
while(!(regRd( rHCTL ) & bmSAMPLEBUS )); //wait for sample operation to finish while (!(regRd(rHCTL) & bmSAMPLEBUS)); //wait for sample operation to finish
busprobe(); //check if anything is connected busprobe(); //check if anything is connected
regWr( rHIRQ, bmCONDETIRQ ); //clear connection detect interrupt regWr(rHIRQ, bmCONDETIRQ); //clear connection detect interrupt
regWr( rCPUCTL, 0x01 ); //enable interrupt pin regWr(rCPUCTL, 0x01); //enable interrupt pin
return( 0 ); return ( 0);
} }
/* probe bus to determine device presense and speed and switch host to this speed */ /* probe bus to determine device presence and speed and switch host to this speed */
template< typename SS, typename INTR > template< typename SS, typename INTR >
void MAX3421e< SS, INTR >::busprobe() void MAX3421e< SS, INTR >::busprobe() {
{ uint8_t bus_sample;
uint8_t bus_sample; bus_sample = regRd(rHRSL); //Get J,K status
bus_sample = regRd( rHRSL ); //Get J,K status bus_sample &= (bmJSTATUS | bmKSTATUS); //zero the rest of the byte
bus_sample &= ( bmJSTATUS|bmKSTATUS ); //zero the rest of the byte switch (bus_sample) { //start full-speed or low-speed host
switch( bus_sample ) { //start full-speed or low-speed host case( bmJSTATUS):
case( bmJSTATUS ): if ((regRd(rMODE) & bmLOWSPEED) == 0) {
if(( regRd( rMODE ) & bmLOWSPEED ) == 0 ) { regWr(rMODE, MODE_FS_HOST); //start full-speed host
regWr( rMODE, MODE_FS_HOST ); //start full-speed host vbusState = FSHOST;
vbusState = FSHOST; } else {
} regWr(rMODE, MODE_LS_HOST); //start low-speed host
else { vbusState = LSHOST;
regWr( rMODE, MODE_LS_HOST); //start low-speed host }
vbusState = LSHOST; break;
} case( bmKSTATUS):
break; if ((regRd(rMODE) & bmLOWSPEED) == 0) {
case( bmKSTATUS ): regWr(rMODE, MODE_LS_HOST); //start low-speed host
if(( regRd( rMODE ) & bmLOWSPEED ) == 0 ) { vbusState = LSHOST;
regWr( rMODE, MODE_LS_HOST ); //start low-speed host } else {
vbusState = LSHOST; regWr(rMODE, MODE_FS_HOST); //start full-speed host
} vbusState = FSHOST;
else { }
regWr( rMODE, MODE_FS_HOST ); //start full-speed host break;
vbusState = FSHOST; case( bmSE1): //illegal state
} vbusState = SE1;
break; break;
case( bmSE1 ): //illegal state case( bmSE0): //disconnected state
vbusState = SE1; regWr(rMODE, bmDPPULLDN | bmDMPULLDN | bmHOST | bmSEPIRQ);
break; vbusState = SE0;
case( bmSE0 ): //disconnected state break;
regWr( rMODE, bmDPPULLDN|bmDMPULLDN|bmHOST|bmSEPIRQ);
vbusState = SE0;
break;
}//end switch( bus_sample ) }//end switch( bus_sample )
} }
/* MAX3421 state change task and interrupt handler */ /* MAX3421 state change task and interrupt handler */
template< typename SS, typename INTR > template< typename SS, typename INTR >
uint8_t MAX3421e< SS, INTR >::Task( void ) uint8_t MAX3421e< SS, INTR >::Task(void) {
{ uint8_t rcode = 0;
uint8_t rcode = 0; uint8_t pinvalue;
uint8_t pinvalue; //Serial.print("Vbus state: ");
//Serial.print("Vbus state: "); //Serial.println( vbusState, HEX );
//Serial.println( vbusState, HEX ); pinvalue = INTR::IsSet(); //Read();
pinvalue = INTR::IsSet(); //Read(); //pinvalue = digitalRead( MAX_INT );
//pinvalue = digitalRead( MAX_INT ); if (pinvalue == 0) {
if( pinvalue == 0 ) { rcode = IntHandler();
rcode = IntHandler(); }
} // pinvalue = digitalRead( MAX_GPX );
// pinvalue = digitalRead( MAX_GPX ); // if( pinvalue == LOW ) {
// if( pinvalue == LOW ) { // GpxHandler();
// GpxHandler(); // }
// } // usbSM(); //USB state machine
// usbSM(); //USB state machine return ( rcode);
return( rcode );
} }
template< typename SS, typename INTR > template< typename SS, typename INTR >
uint8_t MAX3421e< SS, INTR >::IntHandler() uint8_t MAX3421e< SS, INTR >::IntHandler() {
{ uint8_t HIRQ;
uint8_t HIRQ; uint8_t HIRQ_sendback = 0x00;
uint8_t HIRQ_sendback = 0x00; HIRQ = regRd(rHIRQ); //determine interrupt source
HIRQ = regRd( rHIRQ ); //determine interrupt source //if( HIRQ & bmFRAMEIRQ ) { //->1ms SOF interrupt handler
//if( HIRQ & bmFRAMEIRQ ) { //->1ms SOF interrupt handler // HIRQ_sendback |= bmFRAMEIRQ;
// HIRQ_sendback |= bmFRAMEIRQ; //}//end FRAMEIRQ handling
//}//end FRAMEIRQ handling if (HIRQ & bmCONDETIRQ) {
if( HIRQ & bmCONDETIRQ ) { busprobe();
busprobe(); HIRQ_sendback |= bmCONDETIRQ;
HIRQ_sendback |= bmCONDETIRQ; }
} /* End HIRQ interrupts handling, clear serviced IRQs */
/* End HIRQ interrupts handling, clear serviced IRQs */ regWr(rHIRQ, HIRQ_sendback);
regWr( rHIRQ, HIRQ_sendback ); return ( HIRQ_sendback);
return( HIRQ_sendback );
} }
//template< typename SS, typename INTR > //template< typename SS, typename INTR >
//uint8_t MAX3421e< SS, INTR >::GpxHandler() //uint8_t MAX3421e< SS, INTR >::GpxHandler()

View file

@ -13,402 +13,382 @@ Contact information
Circuits At Home, LTD Circuits At Home, LTD
Web : http://www.circuitsathome.com Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com e-mail : support@circuitsathome.com
*/ */
#include "usbhub.h" #include "usbhub.h"
bool USBHub::bResetInitiated = false; bool USBHub::bResetInitiated = false;
USBHub::USBHub(USB *p) : USBHub::USBHub(USB *p) :
pUsb(p), pUsb(p),
bAddress(0), bAddress(0),
bNbrPorts(0), bNbrPorts(0),
bInitState(0), bInitState(0),
qNextPollTime(0), qNextPollTime(0),
bPollEnable(false) bPollEnable(false) {
{ epInfo[0].epAddr = 0;
epInfo[0].epAddr = 0; epInfo[0].maxPktSize = 8;
epInfo[0].maxPktSize = 8; epInfo[0].epAttribs = 0;
epInfo[0].epAttribs = 0; epInfo[0].bmNakPower = USB_NAK_MAX_POWER;
epInfo[0].bmNakPower = USB_NAK_MAX_POWER;
epInfo[1].epAddr = 1; epInfo[1].epAddr = 1;
epInfo[1].maxPktSize = 8; //kludge epInfo[1].maxPktSize = 8; //kludge
epInfo[1].epAttribs = 0; epInfo[1].epAttribs = 0;
epInfo[1].bmNakPower = USB_NAK_NOWAIT; epInfo[1].bmNakPower = USB_NAK_NOWAIT;
if (pUsb) if (pUsb)
pUsb->RegisterDeviceClass(this); pUsb->RegisterDeviceClass(this);
} }
uint8_t USBHub::Init(uint8_t parent, uint8_t port, bool lowspeed) uint8_t USBHub::Init(uint8_t parent, uint8_t port, bool lowspeed) {
{ uint8_t buf[32];
uint8_t buf[32]; uint8_t rcode;
uint8_t rcode; UsbDevice *p = NULL;
UsbDevice *p = NULL; EpInfo *oldep_ptr = NULL;
EpInfo *oldep_ptr = NULL; uint8_t len = 0;
uint8_t len = 0; uint16_t cd_len = 0;
uint16_t cd_len = 0;
//USBTRACE("\r\nHub Init Start"); //USBTRACE("\r\nHub Init Start");
AddressPool &addrPool = pUsb->GetAddressPool(); AddressPool &addrPool = pUsb->GetAddressPool();
switch (bInitState) switch (bInitState) {
{ case 0:
case 0: if (bAddress)
if (bAddress) return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
// Get pointer to pseudo device with address 0 assigned // Get pointer to pseudo device with address 0 assigned
p = addrPool.GetUsbDevicePtr(0); p = addrPool.GetUsbDevicePtr(0);
if (!p) if (!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
if (!p->epinfo) if (!p->epinfo)
return USB_ERROR_EPINFO_IS_NULL; return USB_ERROR_EPINFO_IS_NULL;
// Save old pointer to EP_RECORD of address 0 // Save old pointer to EP_RECORD of address 0
oldep_ptr = p->epinfo; oldep_ptr = p->epinfo;
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
p->epinfo = epInfo; p->epinfo = epInfo;
p->lowspeed = lowspeed; p->lowspeed = lowspeed;
// Get device descriptor // Get device descriptor
rcode = pUsb->getDevDescr( 0, 0, 8, (uint8_t*)buf ); rcode = pUsb->getDevDescr(0, 0, 8, (uint8_t*) buf);
p->lowspeed = false; p->lowspeed = false;
if (!rcode) if (!rcode)
len = (buf[0] > 32) ? 32 : buf[0]; len = (buf[0] > 32) ? 32 : buf[0];
if( rcode ) if (rcode) {
{ // Restore p->epinfo
// Restore p->epinfo p->epinfo = oldep_ptr;
p->epinfo = oldep_ptr; return rcode;
return rcode; }
}
// Extract device class from device descriptor // Extract device class from device descriptor
// If device class is not a hub return // If device class is not a hub return
if (((USB_DEVICE_DESCRIPTOR*)buf)->bDeviceClass != 0x09) if (((USB_DEVICE_DESCRIPTOR*) buf)->bDeviceClass != 0x09)
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
// Allocate new address according to device class // Allocate new address according to device class
bAddress = addrPool.AllocAddress(parent, (((USB_DEVICE_DESCRIPTOR*)buf)->bDeviceClass == 0x09) ? true : false, port); bAddress = addrPool.AllocAddress(parent, (((USB_DEVICE_DESCRIPTOR*) buf)->bDeviceClass == 0x09) ? true : false, port);
if (!bAddress) if (!bAddress)
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL; return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
// Extract Max Packet Size from the device descriptor // Extract Max Packet Size from the device descriptor
epInfo[0].maxPktSize = ((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0; epInfo[0].maxPktSize = ((USB_DEVICE_DESCRIPTOR*) buf)->bMaxPacketSize0;
// Assign new address to the device // Assign new address to the device
rcode = pUsb->setAddr( 0, 0, bAddress ); rcode = pUsb->setAddr(0, 0, bAddress);
if (rcode) if (rcode) {
{ // Restore p->epinfo
// Restore p->epinfo p->epinfo = oldep_ptr;
p->epinfo = oldep_ptr; addrPool.FreeAddress(bAddress);
addrPool.FreeAddress(bAddress); bAddress = 0;
bAddress = 0; return rcode;
return rcode; }
}
//USBTRACE2("\r\nHub address: ", bAddress ); //USBTRACE2("\r\nHub address: ", bAddress );
// Restore p->epinfo // Restore p->epinfo
p->epinfo = oldep_ptr; p->epinfo = oldep_ptr;
if (len) if (len)
rcode = pUsb->getDevDescr( bAddress, 0, len, (uint8_t*)buf ); rcode = pUsb->getDevDescr(bAddress, 0, len, (uint8_t*) buf);
if(rcode) if (rcode)
goto FailGetDevDescr; goto FailGetDevDescr;
// Assign epInfo to epinfo pointer // Assign epInfo to epinfo pointer
rcode = pUsb->setEpInfoEntry(bAddress, 2, epInfo); rcode = pUsb->setEpInfoEntry(bAddress, 2, epInfo);
if (rcode) if (rcode)
goto FailSetDevTblEntry; goto FailSetDevTblEntry;
bInitState = 1; bInitState = 1;
case 1: case 1:
// Get hub descriptor // Get hub descriptor
rcode = GetHubDescriptor(0, 8, buf); rcode = GetHubDescriptor(0, 8, buf);
if (rcode) if (rcode)
goto FailGetHubDescr; goto FailGetHubDescr;
// Save number of ports for future use // Save number of ports for future use
bNbrPorts = ((HubDescriptor*)buf)->bNbrPorts; bNbrPorts = ((HubDescriptor*) buf)->bNbrPorts;
bInitState = 2; bInitState = 2;
case 2: case 2:
// Read configuration Descriptor in Order To Obtain Proper Configuration Value // Read configuration Descriptor in Order To Obtain Proper Configuration Value
rcode = pUsb->getConfDescr(bAddress, 0, 8, 0, buf); rcode = pUsb->getConfDescr(bAddress, 0, 8, 0, buf);
if (!rcode) if (!rcode) {
{ cd_len = ((USB_CONFIGURATION_DESCRIPTOR*) buf)->wTotalLength;
cd_len = ((USB_CONFIGURATION_DESCRIPTOR*)buf)->wTotalLength; rcode = pUsb->getConfDescr(bAddress, 0, cd_len, 0, buf);
rcode = pUsb->getConfDescr(bAddress, 0, cd_len, 0, buf); }
} if (rcode)
if (rcode) goto FailGetConfDescr;
goto FailGetConfDescr;
// The following code is of no practical use in real life applications. // The following code is of no practical use in real life applications.
// It only intended for the usb protocol sniffer to properly parse hub-class requests. // It only intended for the usb protocol sniffer to properly parse hub-class requests.
{ {
uint8_t buf2[24]; uint8_t buf2[24];
rcode = pUsb->getConfDescr(bAddress, 0, buf[0], 0, buf2); rcode = pUsb->getConfDescr(bAddress, 0, buf[0], 0, buf2);
if (rcode) if (rcode)
goto FailGetConfDescr; goto FailGetConfDescr;
} }
// Set Configuration Value // Set Configuration Value
rcode = pUsb->setConf(bAddress, 0, buf[5]); rcode = pUsb->setConf(bAddress, 0, buf[5]);
if (rcode) if (rcode)
goto FailSetConfDescr; goto FailSetConfDescr;
bInitState = 3; bInitState = 3;
case 3: case 3:
// Power on all ports // Power on all ports
for (uint8_t j=1; j<=bNbrPorts; j++) for (uint8_t j = 1; j <= bNbrPorts; j++)
SetPortFeature(HUB_FEATURE_PORT_POWER, j, 0); //HubPortPowerOn(j); SetPortFeature(HUB_FEATURE_PORT_POWER, j, 0); //HubPortPowerOn(j);
pUsb->SetHubPreMask(); pUsb->SetHubPreMask();
bPollEnable = true; bPollEnable = true;
bInitState = 0; bInitState = 0;
} }
bInitState = 0; bInitState = 0;
return 0; return 0;
FailGetDevDescr: FailGetDevDescr:
goto Fail; goto Fail;
FailSetDevTblEntry: FailSetDevTblEntry:
goto Fail; goto Fail;
FailGetHubDescr: FailGetHubDescr:
goto Fail; goto Fail;
FailGetConfDescr: FailGetConfDescr:
goto Fail; goto Fail;
FailSetConfDescr: FailSetConfDescr:
goto Fail; goto Fail;
FailGetPortStatus:
goto Fail;
Fail: Fail:
return rcode; return rcode;
} }
uint8_t USBHub::Release() uint8_t USBHub::Release() {
{ pUsb->GetAddressPool().FreeAddress(bAddress);
pUsb->GetAddressPool().FreeAddress(bAddress);
if (bAddress == 0x41) if (bAddress == 0x41)
pUsb->SetHubPreMask(); pUsb->SetHubPreMask();
bAddress = 0; bAddress = 0;
bNbrPorts = 0; bNbrPorts = 0;
qNextPollTime = 0; qNextPollTime = 0;
bPollEnable = false; bPollEnable = false;
return 0; return 0;
} }
uint8_t USBHub::Poll() uint8_t USBHub::Poll() {
{ uint8_t rcode = 0;
uint8_t rcode = 0;
if (!bPollEnable) if (!bPollEnable)
return 0; return 0;
if (qNextPollTime <= millis()) if (qNextPollTime <= millis()) {
{ rcode = CheckHubStatus();
rcode = CheckHubStatus(); qNextPollTime = millis() + 100;
qNextPollTime = millis() + 100; }
} return rcode;
return rcode;
} }
uint8_t USBHub::CheckHubStatus() uint8_t USBHub::CheckHubStatus() {
{ uint8_t rcode;
uint8_t rcode; uint8_t buf[8];
uint8_t buf[8]; uint16_t read = 1;
uint16_t read = 1;
rcode = pUsb->inTransfer(bAddress, 1, &read, buf); rcode = pUsb->inTransfer(bAddress, 1, &read, buf);
if (rcode) if (rcode)
return rcode; return rcode;
if (buf[0] & 0x01) // Hub Status Change if (buf[0] & 0x01) // Hub Status Change
{ {
//pUsb->PrintHubStatus(addr); //pUsb->PrintHubStatus(addr);
//rcode = GetHubStatus(1, 0, 1, 4, buf); //rcode = GetHubStatus(1, 0, 1, 4, buf);
//if (rcode) //if (rcode)
//{ //{
// Serial.print("GetHubStatus Error"); // Serial.print("GetHubStatus Error");
// Serial.println(rcode, HEX); // Serial.println(rcode, HEX);
// return rcode; // return rcode;
//} //}
} }
for (uint8_t port=1,mask=0x02; port<8; mask<<=1, port++) for (uint8_t port = 1, mask = 0x02; port < 8; mask <<= 1, port++) {
{ if (buf[0] & mask) {
if (buf[0] & mask) HubEvent evt;
{ evt.bmEvent = 0;
HubEvent evt;
evt.bmEvent = 0;
rcode = GetPortStatus(port, 4, evt.evtBuff); rcode = GetPortStatus(port, 4, evt.evtBuff);
if (rcode) if (rcode)
continue; continue;
rcode = PortStatusChange(port, evt); rcode = PortStatusChange(port, evt);
if (rcode == HUB_ERROR_PORT_HAS_BEEN_RESET) if (rcode == HUB_ERROR_PORT_HAS_BEEN_RESET)
return 0; return 0;
if (rcode) if (rcode)
return rcode; return rcode;
} }
} // for } // for
for (uint8_t port=1; port<=bNbrPorts; port++) for (uint8_t port = 1; port <= bNbrPorts; port++) {
{ HubEvent evt;
HubEvent evt; evt.bmEvent = 0;
evt.bmEvent = 0;
rcode = GetPortStatus(port, 4, evt.evtBuff); rcode = GetPortStatus(port, 4, evt.evtBuff);
if (rcode) if (rcode)
continue; continue;
if ((evt.bmStatus & bmHUB_PORT_STATE_CHECK_DISABLED) != bmHUB_PORT_STATE_DISABLED) if ((evt.bmStatus & bmHUB_PORT_STATE_CHECK_DISABLED) != bmHUB_PORT_STATE_DISABLED)
continue; continue;
// Emulate connection event for the port // Emulate connection event for the port
evt.bmChange |= bmHUB_PORT_STATUS_C_PORT_CONNECTION; evt.bmChange |= bmHUB_PORT_STATUS_C_PORT_CONNECTION;
rcode = PortStatusChange(port, evt); rcode = PortStatusChange(port, evt);
if (rcode == HUB_ERROR_PORT_HAS_BEEN_RESET) if (rcode == HUB_ERROR_PORT_HAS_BEEN_RESET)
return 0; return 0;
if (rcode) if (rcode)
return rcode; return rcode;
} // for } // for
return 0; return 0;
} }
uint8_t USBHub::PortStatusChange(uint8_t port, HubEvent &evt) uint8_t USBHub::PortStatusChange(uint8_t port, HubEvent &evt) {
{ switch (evt.bmEvent) {
switch (evt.bmEvent) // Device connected event
{ case bmHUB_PORT_EVENT_CONNECT:
// Device connected event case bmHUB_PORT_EVENT_LS_CONNECT:
case bmHUB_PORT_EVENT_CONNECT: if (bResetInitiated)
case bmHUB_PORT_EVENT_LS_CONNECT: return 0;
if (bResetInitiated)
return 0;
ClearPortFeature(HUB_FEATURE_C_PORT_ENABLE, port, 0); ClearPortFeature(HUB_FEATURE_C_PORT_ENABLE, port, 0);
ClearPortFeature(HUB_FEATURE_C_PORT_CONNECTION, port, 0); ClearPortFeature(HUB_FEATURE_C_PORT_CONNECTION, port, 0);
SetPortFeature(HUB_FEATURE_PORT_RESET, port, 0); SetPortFeature(HUB_FEATURE_PORT_RESET, port, 0);
bResetInitiated = true; bResetInitiated = true;
return HUB_ERROR_PORT_HAS_BEEN_RESET; return HUB_ERROR_PORT_HAS_BEEN_RESET;
// Device disconnected event // Device disconnected event
case bmHUB_PORT_EVENT_DISCONNECT: case bmHUB_PORT_EVENT_DISCONNECT:
ClearPortFeature(HUB_FEATURE_C_PORT_ENABLE, port, 0); ClearPortFeature(HUB_FEATURE_C_PORT_ENABLE, port, 0);
ClearPortFeature(HUB_FEATURE_C_PORT_CONNECTION, port, 0); ClearPortFeature(HUB_FEATURE_C_PORT_CONNECTION, port, 0);
bResetInitiated = false; bResetInitiated = false;
UsbDeviceAddress a; UsbDeviceAddress a;
a.bmHub = 0; a.bmHub = 0;
a.bmParent = bAddress; a.bmParent = bAddress;
a.bmAddress = port; a.bmAddress = port;
pUsb->ReleaseDevice(a.devAddress); pUsb->ReleaseDevice(a.devAddress);
return 0; return 0;
// Reset complete event // Reset complete event
case bmHUB_PORT_EVENT_RESET_COMPLETE: case bmHUB_PORT_EVENT_RESET_COMPLETE:
case bmHUB_PORT_EVENT_LS_RESET_COMPLETE: case bmHUB_PORT_EVENT_LS_RESET_COMPLETE:
ClearPortFeature(HUB_FEATURE_C_PORT_RESET, port, 0); ClearPortFeature(HUB_FEATURE_C_PORT_RESET, port, 0);
ClearPortFeature(HUB_FEATURE_C_PORT_CONNECTION, port, 0); ClearPortFeature(HUB_FEATURE_C_PORT_CONNECTION, port, 0);
delay(20); delay(20);
a.devAddress = bAddress; a.devAddress = bAddress;
pUsb->Configuring(a.bmAddress, port, (evt.bmStatus & bmHUB_PORT_STATUS_PORT_LOW_SPEED) ); pUsb->Configuring(a.bmAddress, port, (evt.bmStatus & bmHUB_PORT_STATUS_PORT_LOW_SPEED));
bResetInitiated = false; bResetInitiated = false;
break; break;
} // switch (evt.bmEvent) } // switch (evt.bmEvent)
return 0; return 0;
} }
void PrintHubPortStatus(USBHub *hubptr, uint8_t addr, uint8_t port, bool print_changes) void PrintHubPortStatus(USBHub *hubptr, uint8_t addr, uint8_t port, bool print_changes) {
{ uint8_t rcode = 0;
uint8_t rcode = 0; HubEvent evt;
HubEvent evt;
rcode = hubptr->GetPortStatus(port, 4, evt.evtBuff); rcode = hubptr->GetPortStatus(port, 4, evt.evtBuff);
if (rcode) if (rcode) {
{ Serial.println("ERROR!");
Serial.println("ERROR!"); return;
return; }
} Serial.print("\r\nPort ");
Serial.print("\r\nPort "); Serial.println(port, DEC);
Serial.println(port, DEC);
Serial.println("Status"); Serial.println("Status");
Serial.print("CONNECTION:\t"); Serial.print("CONNECTION:\t");
Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_CONNECTION) > 0, DEC); Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_CONNECTION) > 0, DEC);
Serial.print("ENABLE:\t\t"); Serial.print("ENABLE:\t\t");
Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_ENABLE) > 0, DEC); Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_ENABLE) > 0, DEC);
Serial.print("SUSPEND:\t"); Serial.print("SUSPEND:\t");
Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_SUSPEND) > 0, DEC); Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_SUSPEND) > 0, DEC);
Serial.print("OVER_CURRENT:\t"); Serial.print("OVER_CURRENT:\t");
Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_OVER_CURRENT) > 0, DEC); Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_OVER_CURRENT) > 0, DEC);
Serial.print("RESET:\t\t"); Serial.print("RESET:\t\t");
Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_RESET) > 0, DEC); Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_RESET) > 0, DEC);
Serial.print("POWER:\t\t"); Serial.print("POWER:\t\t");
Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_POWER) > 0, DEC); Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_POWER) > 0, DEC);
Serial.print("LOW_SPEED:\t"); Serial.print("LOW_SPEED:\t");
Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_LOW_SPEED) > 0, DEC); Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_LOW_SPEED) > 0, DEC);
Serial.print("HIGH_SPEED:\t"); Serial.print("HIGH_SPEED:\t");
Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_HIGH_SPEED) > 0, DEC); Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_HIGH_SPEED) > 0, DEC);
Serial.print("TEST:\t\t"); Serial.print("TEST:\t\t");
Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_TEST) > 0, DEC); Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_TEST) > 0, DEC);
Serial.print("INDICATOR:\t"); Serial.print("INDICATOR:\t");
Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_INDICATOR) > 0, DEC); Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_INDICATOR) > 0, DEC);
if (!print_changes) if (!print_changes)
return; return;
Serial.println("\nChange"); Serial.println("\r\nChange");
Serial.print("CONNECTION:\t"); Serial.print("CONNECTION:\t");
Serial.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_CONNECTION) > 0, DEC); Serial.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_CONNECTION) > 0, DEC);
Serial.print("ENABLE:\t\t"); Serial.print("ENABLE:\t\t");
Serial.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_ENABLE) > 0, DEC); Serial.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_ENABLE) > 0, DEC);
Serial.print("SUSPEND:\t"); Serial.print("SUSPEND:\t");
Serial.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_SUSPEND) > 0, DEC); Serial.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_SUSPEND) > 0, DEC);
Serial.print("OVER_CURRENT:\t"); Serial.print("OVER_CURRENT:\t");
Serial.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_OVER_CURRENT) > 0, DEC); Serial.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_OVER_CURRENT) > 0, DEC);
Serial.print("RESET:\t\t"); Serial.print("RESET:\t\t");
Serial.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_RESET) > 0, DEC); Serial.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_RESET) > 0, DEC);
} }

162
usbhub.h
View file

@ -13,7 +13,7 @@ Contact information
Circuits At Home, LTD Circuits At Home, LTD
Web : http://www.circuitsathome.com Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com e-mail : support@circuitsathome.com
*/ */
#if !defined(__USBHUB_H__) #if !defined(__USBHUB_H__)
#define __USBHUB_H__ #define __USBHUB_H__
@ -25,6 +25,7 @@ e-mail : support@circuitsathome.com
#include "usb_ch9.h" #include "usb_ch9.h"
#include "Usb.h" #include "Usb.h"
#if defined(ARDUINO) && ARDUINO >=100 #if defined(ARDUINO) && ARDUINO >=100
#include "Arduino.h" #include "Arduino.h"
#else #else
@ -142,116 +143,115 @@ e-mail : support@circuitsathome.com
#define bmHUB_PORT_EVENT_LS_RESET_COMPLETE (((0UL | bmHUB_PORT_STATUS_C_PORT_RESET) << 16) | bmHUB_PORT_STATUS_PORT_POWER | bmHUB_PORT_STATUS_PORT_ENABLE | bmHUB_PORT_STATUS_PORT_CONNECTION | bmHUB_PORT_STATUS_PORT_LOW_SPEED) #define bmHUB_PORT_EVENT_LS_RESET_COMPLETE (((0UL | bmHUB_PORT_STATUS_C_PORT_RESET) << 16) | bmHUB_PORT_STATUS_PORT_POWER | bmHUB_PORT_STATUS_PORT_ENABLE | bmHUB_PORT_STATUS_PORT_CONNECTION | bmHUB_PORT_STATUS_PORT_LOW_SPEED)
#define bmHUB_PORT_EVENT_LS_PORT_ENABLED (((0UL | bmHUB_PORT_STATUS_C_PORT_CONNECTION | bmHUB_PORT_STATUS_C_PORT_ENABLE) << 16) | bmHUB_PORT_STATUS_PORT_POWER | bmHUB_PORT_STATUS_PORT_ENABLE | bmHUB_PORT_STATUS_PORT_CONNECTION | bmHUB_PORT_STATUS_PORT_LOW_SPEED) #define bmHUB_PORT_EVENT_LS_PORT_ENABLED (((0UL | bmHUB_PORT_STATUS_C_PORT_CONNECTION | bmHUB_PORT_STATUS_C_PORT_ENABLE) << 16) | bmHUB_PORT_STATUS_PORT_POWER | bmHUB_PORT_STATUS_PORT_ENABLE | bmHUB_PORT_STATUS_PORT_CONNECTION | bmHUB_PORT_STATUS_PORT_LOW_SPEED)
struct HubDescriptor struct HubDescriptor {
{ uint8_t bDescLength; // descriptor length
uint8_t bDescLength; // descriptor length uint8_t bDescriptorType; // descriptor type
uint8_t bDescriptorType; // descriptor type uint8_t bNbrPorts; // number of ports a hub equiped with
uint8_t bNbrPorts; // number of ports a hub equiped with
struct struct {
{ uint16_t LogPwrSwitchMode : 2;
uint16_t LogPwrSwitchMode : 2; uint16_t CompoundDevice : 1;
uint16_t CompoundDevice : 1; uint16_t OverCurrentProtectMode : 2;
uint16_t OverCurrentProtectMode : 2; uint16_t TTThinkTime : 2;
uint16_t TTThinkTime : 2; uint16_t PortIndicatorsSupported : 1;
uint16_t PortIndicatorsSupported : 1; uint16_t Reserved : 8;
uint16_t Reserved : 8; }__attribute__((packed));
};
uint8_t bPwrOn2PwrGood; uint8_t bPwrOn2PwrGood;
uint8_t bHubContrCurrent; uint8_t bHubContrCurrent;
}; }__attribute__((packed));
struct HubEvent struct HubEvent {
{
union
{
struct
{
uint16_t bmStatus; // port status bits
uint16_t bmChange; // port status change bits
};
uint32_t bmEvent;
uint8_t evtBuff[4];
};
};
class USBHub : USBDeviceConfig union {
{
static bool bResetInitiated; // True when reset is triggered
USB *pUsb; // USB class instance pointer struct {
uint16_t bmStatus; // port status bits
uint16_t bmChange; // port status change bits
}__attribute__((packed));
uint32_t bmEvent;
uint8_t evtBuff[4];
};
}__attribute__((packed));
EpInfo epInfo[2]; // interrupt endpoint info structure class USBHub : USBDeviceConfig {
static bool bResetInitiated; // True when reset is triggered
uint8_t bAddress; // address USB *pUsb; // USB class instance pointer
uint8_t bNbrPorts; // number of ports
uint8_t bInitState; // initialization state variable
uint32_t qNextPollTime; // next poll time
bool bPollEnable; // poll enable flag
uint8_t CheckHubStatus(); EpInfo epInfo[2]; // interrupt endpoint info structure
uint8_t PortStatusChange(uint8_t port, HubEvent &evt);
uint8_t bAddress; // address
uint8_t bNbrPorts; // number of ports
uint8_t bInitState; // initialization state variable
uint32_t qNextPollTime; // next poll time
bool bPollEnable; // poll enable flag
uint8_t CheckHubStatus();
uint8_t PortStatusChange(uint8_t port, HubEvent &evt);
public: public:
USBHub(USB *p); USBHub(USB *p);
uint8_t ClearHubFeature( uint8_t fid ); uint8_t ClearHubFeature(uint8_t fid);
uint8_t ClearPortFeature( uint8_t fid, uint8_t port, uint8_t sel = 0 ); uint8_t ClearPortFeature(uint8_t fid, uint8_t port, uint8_t sel = 0);
uint8_t GetHubDescriptor( uint8_t index, uint16_t nbytes, uint8_t *dataptr ); uint8_t GetHubDescriptor(uint8_t index, uint16_t nbytes, uint8_t *dataptr);
uint8_t GetHubStatus( uint16_t nbytes, uint8_t* dataptr ); uint8_t GetHubStatus(uint16_t nbytes, uint8_t* dataptr);
uint8_t GetPortStatus( uint8_t port, uint16_t nbytes, uint8_t* dataptr ); uint8_t GetPortStatus(uint8_t port, uint16_t nbytes, uint8_t* dataptr);
uint8_t SetHubDescriptor( uint8_t port, uint16_t nbytes, uint8_t* dataptr ); uint8_t SetHubDescriptor(uint8_t port, uint16_t nbytes, uint8_t* dataptr);
uint8_t SetHubFeature( uint8_t fid ); uint8_t SetHubFeature(uint8_t fid);
uint8_t SetPortFeature( uint8_t fid, uint8_t port, uint8_t sel = 0 ); uint8_t SetPortFeature(uint8_t fid, uint8_t port, uint8_t sel = 0);
void PrintHubStatus(); void PrintHubStatus();
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed); virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
virtual uint8_t Release(); virtual uint8_t Release();
virtual uint8_t Poll(); virtual uint8_t Poll();
virtual uint8_t GetAddress() { return bAddress; };
virtual uint8_t GetAddress() {
return bAddress;
};
}; };
// Clear Hub Feature // Clear Hub Feature
inline uint8_t USBHub::ClearHubFeature( uint8_t fid )
{ inline uint8_t USBHub::ClearHubFeature(uint8_t fid) {
return( pUsb->ctrlReq( bAddress, 0, bmREQ_CLEAR_HUB_FEATURE, USB_REQUEST_CLEAR_FEATURE, fid, 0, 0, 0, 0, NULL, NULL )); return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CLEAR_HUB_FEATURE, USB_REQUEST_CLEAR_FEATURE, fid, 0, 0, 0, 0, NULL, NULL));
} }
// Clear Port Feature // Clear Port Feature
inline uint8_t USBHub::ClearPortFeature( uint8_t fid, uint8_t port, uint8_t sel )
{ inline uint8_t USBHub::ClearPortFeature(uint8_t fid, uint8_t port, uint8_t sel) {
return( pUsb->ctrlReq( bAddress, 0, bmREQ_CLEAR_PORT_FEATURE, USB_REQUEST_CLEAR_FEATURE, fid, 0, ((0x0000|port)|(sel<<8)), 0, 0, NULL, NULL )); return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CLEAR_PORT_FEATURE, USB_REQUEST_CLEAR_FEATURE, fid, 0, ((0x0000 | port) | (sel << 8)), 0, 0, NULL, NULL));
} }
// Get Hub Descriptor // Get Hub Descriptor
inline uint8_t USBHub::GetHubDescriptor( uint8_t index, uint16_t nbytes, uint8_t *dataptr )
{ inline uint8_t USBHub::GetHubDescriptor(uint8_t index, uint16_t nbytes, uint8_t *dataptr) {
return( pUsb->ctrlReq( bAddress, 0, bmREQ_GET_HUB_DESCRIPTOR, USB_REQUEST_GET_DESCRIPTOR, index, 0x29, 0, nbytes, nbytes, dataptr, NULL )); return ( pUsb->ctrlReq(bAddress, 0, bmREQ_GET_HUB_DESCRIPTOR, USB_REQUEST_GET_DESCRIPTOR, index, 0x29, 0, nbytes, nbytes, dataptr, NULL));
} }
// Get Hub Status // Get Hub Status
inline uint8_t USBHub::GetHubStatus( uint16_t nbytes, uint8_t* dataptr )
{ inline uint8_t USBHub::GetHubStatus(uint16_t nbytes, uint8_t* dataptr) {
return( pUsb->ctrlReq( bAddress, 0, bmREQ_GET_HUB_STATUS, USB_REQUEST_GET_STATUS, 0, 0, 0x0000, nbytes, nbytes, dataptr, NULL )); return ( pUsb->ctrlReq(bAddress, 0, bmREQ_GET_HUB_STATUS, USB_REQUEST_GET_STATUS, 0, 0, 0x0000, nbytes, nbytes, dataptr, NULL));
} }
// Get Port Status // Get Port Status
inline uint8_t USBHub::GetPortStatus( uint8_t port, uint16_t nbytes, uint8_t* dataptr )
{ inline uint8_t USBHub::GetPortStatus(uint8_t port, uint16_t nbytes, uint8_t* dataptr) {
return( pUsb->ctrlReq( bAddress, 0, bmREQ_GET_PORT_STATUS, USB_REQUEST_GET_STATUS, 0, 0, port, nbytes, nbytes, dataptr, NULL )); return ( pUsb->ctrlReq(bAddress, 0, bmREQ_GET_PORT_STATUS, USB_REQUEST_GET_STATUS, 0, 0, port, nbytes, nbytes, dataptr, NULL));
} }
// Set Hub Descriptor // Set Hub Descriptor
inline uint8_t USBHub::SetHubDescriptor( uint8_t port, uint16_t nbytes, uint8_t* dataptr )
{ inline uint8_t USBHub::SetHubDescriptor(uint8_t port, uint16_t nbytes, uint8_t* dataptr) {
return( pUsb->ctrlReq( bAddress, 0, bmREQ_SET_HUB_DESCRIPTOR, USB_REQUEST_SET_DESCRIPTOR, 0, 0, port, nbytes, nbytes, dataptr, NULL )); return ( pUsb->ctrlReq(bAddress, 0, bmREQ_SET_HUB_DESCRIPTOR, USB_REQUEST_SET_DESCRIPTOR, 0, 0, port, nbytes, nbytes, dataptr, NULL));
} }
// Set Hub Feature // Set Hub Feature
inline uint8_t USBHub::SetHubFeature( uint8_t fid )
{ inline uint8_t USBHub::SetHubFeature(uint8_t fid) {
return( pUsb->ctrlReq( bAddress, 0, bmREQ_SET_HUB_FEATURE, USB_REQUEST_SET_FEATURE, fid, 0, 0, 0, 0, NULL, NULL )); return ( pUsb->ctrlReq(bAddress, 0, bmREQ_SET_HUB_FEATURE, USB_REQUEST_SET_FEATURE, fid, 0, 0, 0, 0, NULL, NULL));
} }
// Set Port Feature // Set Port Feature
inline uint8_t USBHub::SetPortFeature( uint8_t fid, uint8_t port, uint8_t sel )
{ inline uint8_t USBHub::SetPortFeature(uint8_t fid, uint8_t port, uint8_t sel) {
return( pUsb->ctrlReq( bAddress, 0, bmREQ_SET_PORT_FEATURE, USB_REQUEST_SET_FEATURE, fid, 0, (((0x0000|sel)<<8)|port), 0, 0, NULL, NULL )); return ( pUsb->ctrlReq(bAddress, 0, bmREQ_SET_PORT_FEATURE, USB_REQUEST_SET_FEATURE, fid, 0, (((0x0000 | sel) << 8) | port), 0, 0, NULL, NULL));
} }
void PrintHubPortStatus(USB *usbptr, uint8_t addr, uint8_t port, bool print_changes = false); void PrintHubPortStatus(USB *usbptr, uint8_t addr, uint8_t port, bool print_changes = false);