mirror of
https://github.com/felis/USB_Host_Shield_2.0.git
synced 2024-03-22 11:31:26 +01:00
Merge my debug changes.
Merge my format sanity changes. Track everything.
This commit is contained in:
parent
f5856c72bc
commit
629594f957
39 changed files with 11136 additions and 11344 deletions
279
Usb.h
279
Usb.h
|
@ -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,42 +94,41 @@ 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
|
||||||
|
|
||||||
#define USB_STATE_DETACHED 0x10
|
#define USB_STATE_DETACHED 0x10
|
||||||
#define USB_DETACHED_SUBSTATE_INITIALIZE 0x11
|
#define USB_DETACHED_SUBSTATE_INITIALIZE 0x11
|
||||||
#define USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE 0x12
|
#define USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE 0x12
|
||||||
#define USB_DETACHED_SUBSTATE_ILLEGAL 0x13
|
#define USB_DETACHED_SUBSTATE_ILLEGAL 0x13
|
||||||
#define USB_ATTACHED_SUBSTATE_SETTLE 0x20
|
#define USB_ATTACHED_SUBSTATE_SETTLE 0x20
|
||||||
#define USB_ATTACHED_SUBSTATE_RESET_DEVICE 0x30
|
#define USB_ATTACHED_SUBSTATE_RESET_DEVICE 0x30
|
||||||
#define USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE 0x40
|
#define USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE 0x40
|
||||||
#define USB_ATTACHED_SUBSTATE_WAIT_SOF 0x50
|
#define USB_ATTACHED_SUBSTATE_WAIT_SOF 0x50
|
||||||
#define USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE 0x60
|
#define USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE 0x60
|
||||||
|
@ -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,
|
|
||||||
uint16_t wInd, uint16_t total, uint16_t nbytes, uint8_t* dataptr, USBReadParser *p);
|
|
||||||
|
|
||||||
private:
|
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);
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
400
address.h
400
address.h
|
@ -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++)
|
uint8_t FindChildIndex(UsbDeviceAddress addr, uint8_t start = 1) {
|
||||||
InitEntry(i);
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
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
|
|
||||||
void ForEachUsbDevice(UsbDeviceHandleFunc pfunc)
|
|
||||||
{
|
|
||||||
if (!pfunc)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (uint8_t i=1; i<MAX_DEVICES_ALLOWED; i++)
|
uint8_t index = FindAddressIndex(addr);
|
||||||
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)
|
return (!index) ? NULL : thePool + index;
|
||||||
return 0;
|
};
|
||||||
|
|
||||||
if (is_hub && hubCounter == 7)
|
// Performs an operation specified by pfunc for each addressed device
|
||||||
return 0;
|
|
||||||
|
|
||||||
// finds first empty address entry starting from one
|
void ForEachUsbDevice(UsbDeviceHandleFunc pfunc) {
|
||||||
uint8_t index = FindAddressIndex(0);
|
if (!pfunc)
|
||||||
|
return;
|
||||||
|
|
||||||
if (!index) // if empty entry is not found
|
for (uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++)
|
||||||
return 0;
|
if (thePool[i].address)
|
||||||
|
pfunc(thePool + i);
|
||||||
|
};
|
||||||
|
// Allocates new address
|
||||||
|
|
||||||
if (parent == 0)
|
virtual uint8_t AllocAddress(uint8_t parent, bool is_hub = false, uint8_t port = 0) {
|
||||||
{
|
/* if (parent != 0 && port == 0)
|
||||||
if (is_hub)
|
Serial.println("PRT:0"); */
|
||||||
{
|
|
||||||
thePool[index].address = 0x41;
|
|
||||||
hubCounter ++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
thePool[index].address = 1;
|
|
||||||
|
|
||||||
return thePool[index].address;
|
if (parent > 127 || port > 7)
|
||||||
}
|
return 0;
|
||||||
|
|
||||||
UsbDeviceAddress addr;
|
if (is_hub && hubCounter == 7)
|
||||||
|
return 0;
|
||||||
|
|
||||||
addr.bmParent = ((UsbDeviceAddress*)&parent)->bmAddress;
|
// finds first empty address entry starting from one
|
||||||
|
uint8_t index = FindAddressIndex(0);
|
||||||
|
|
||||||
if (is_hub)
|
if (!index) // if empty entry is not found
|
||||||
{
|
return 0;
|
||||||
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 (parent == 0) {
|
||||||
// if (thePool[i].address != 0);
|
if (is_hub) {
|
||||||
// counter ++;
|
thePool[index].address = 0x41;
|
||||||
|
hubCounter++;
|
||||||
|
} else
|
||||||
|
thePool[index].address = 1;
|
||||||
|
|
||||||
// return counter;
|
return thePool[index].address;
|
||||||
//};
|
}
|
||||||
|
|
||||||
|
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__
|
||||||
|
|
715
adk.cpp
715
adk.cpp
|
@ -1,383 +1,332 @@
|
||||||
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||||
|
|
||||||
This software may be distributed and modified under the terms of the GNU
|
This software may be distributed and modified under the terms of the GNU
|
||||||
General Public License version 2 (GPL2) as published by the Free Software
|
General Public License version 2 (GPL2) as published by the Free Software
|
||||||
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
||||||
this file. Please note that GPL2 Section 2[b] requires that all works based
|
this file. Please note that GPL2 Section 2[b] requires that all works based
|
||||||
on this software must also be made publicly available under the terms of
|
on this software must also be made publicly available under the terms of
|
||||||
the GPL2 ("Copyleft").
|
the GPL2 ("Copyleft").
|
||||||
|
|
||||||
Contact information
|
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) :
|
|
||||||
|
/* ADK ID Strings */
|
||||||
pUsb(p), //pointer to USB class instance - mandatory
|
|
||||||
bAddress(0), //device address - mandatory
|
manufacturer(manufacturer),
|
||||||
bNumEP(1), //if config descriptor needs to be parsed
|
model(model),
|
||||||
ready(false),
|
description(description),
|
||||||
|
version(version),
|
||||||
/* ADK ID Strings */
|
uri(uri),
|
||||||
|
serial(serial),
|
||||||
manufacturer(manufacturer),
|
pUsb(p), //pointer to USB class instance - mandatory
|
||||||
model(model),
|
bAddress(0), //device address - mandatory
|
||||||
description(description),
|
bConfNum(0), //configuration number
|
||||||
version(version),
|
bNumEP(1), //if config descriptor needs to be parsed
|
||||||
uri(uri),
|
ready(false)
|
||||||
serial(serial)
|
{
|
||||||
|
// initialize endpoint data structures
|
||||||
{
|
for (uint8_t i = 0; i < ADK_MAX_ENDPOINTS; i++) {
|
||||||
// initialize endpoint data structures
|
epInfo[i].epAddr = 0;
|
||||||
for(uint8_t i=0; i<ADK_MAX_ENDPOINTS; i++) {
|
epInfo[i].maxPktSize = (i) ? 0 : 8;
|
||||||
epInfo[i].epAddr = 0;
|
epInfo[i].epAttribs = (0xfc & (USB_NAK_MAX_POWER << 2));
|
||||||
epInfo[i].maxPktSize = (i) ? 0 : 8;
|
}//for(uint8_t i=0; i<ADK_MAX_ENDPOINTS; i++...
|
||||||
epInfo[i].epAttribs = 0;
|
|
||||||
epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER;
|
//set bulk-IN EP naklimit to 1
|
||||||
}//for(uint8_t i=0; i<ADK_MAX_ENDPOINTS; i++...
|
epInfo[epDataInIndex].epAttribs = (0xfc & (USB_NAK_NOWAIT << 2));
|
||||||
|
|
||||||
// register in USB subsystem
|
// register in USB subsystem
|
||||||
if (pUsb) {
|
if (pUsb) {
|
||||||
pUsb->RegisterDeviceClass(this); //set devConfig[] entry
|
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");
|
||||||
USBTRACE("\r\nADK Init");
|
|
||||||
#endif
|
// check if address has already been assigned to an instance
|
||||||
// check if address has already been assigned to an instance
|
if (bAddress) {
|
||||||
if (bAddress) {
|
USBTRACE("\r\nAddress in use");
|
||||||
#ifdef DEBUG
|
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
|
||||||
USBTRACE("\r\nAddress in use");
|
}
|
||||||
#endif
|
|
||||||
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
|
// Get pointer to pseudo device with address 0 assigned
|
||||||
}
|
p = addrPool.GetUsbDevicePtr(0);
|
||||||
|
|
||||||
// Get pointer to pseudo device with address 0 assigned
|
if (!p) {
|
||||||
p = addrPool.GetUsbDevicePtr(0);
|
USBTRACE("\r\nAddress not found");
|
||||||
|
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||||
if (!p) {
|
}
|
||||||
#ifdef DEBUG
|
|
||||||
USBTRACE("\r\nAddress not found");
|
if (!p->epinfo) {
|
||||||
#endif
|
USBTRACE("epinfo is null\r\n");
|
||||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
return USB_ERROR_EPINFO_IS_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!p->epinfo) {
|
// Save old pointer to EP_RECORD of address 0
|
||||||
#ifdef DEBUG
|
oldep_ptr = p->epinfo;
|
||||||
USBTRACE("epinfo is null\r\n");
|
|
||||||
#endif
|
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
|
||||||
return USB_ERROR_EPINFO_IS_NULL;
|
p->epinfo = epInfo;
|
||||||
}
|
|
||||||
|
p->lowspeed = lowspeed;
|
||||||
// Save old pointer to EP_RECORD of address 0
|
|
||||||
oldep_ptr = p->epinfo;
|
// Get device descriptor
|
||||||
|
rcode = pUsb->getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), (uint8_t*) buf);
|
||||||
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
|
|
||||||
p->epinfo = epInfo;
|
// Restore p->epinfo
|
||||||
|
p->epinfo = oldep_ptr;
|
||||||
p->lowspeed = lowspeed;
|
|
||||||
|
if (rcode) {
|
||||||
// Get device descriptor
|
goto FailGetDevDescr;
|
||||||
rcode = pUsb->getDevDescr( 0, 0, sizeof(USB_DEVICE_DESCRIPTOR), (uint8_t*)buf );
|
}
|
||||||
|
|
||||||
// Restore p->epinfo
|
// Allocate new address according to device class
|
||||||
p->epinfo = oldep_ptr;
|
bAddress = addrPool.AllocAddress(parent, false, port);
|
||||||
|
|
||||||
if( rcode ){
|
// Extract Max Packet Size from device descriptor
|
||||||
goto FailGetDevDescr;
|
epInfo[0].maxPktSize = (uint8_t) ((USB_DEVICE_DESCRIPTOR*) buf)->bMaxPacketSize0;
|
||||||
}
|
|
||||||
|
// 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;
|
||||||
// Extract Max Packet Size from device descriptor
|
addrPool.FreeAddress(bAddress);
|
||||||
epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0;
|
bAddress = 0;
|
||||||
|
//USBTRACE2("setAddr:",rcode);
|
||||||
// Assign new address to the device
|
return rcode;
|
||||||
rcode = pUsb->setAddr( 0, 0, bAddress );
|
}//if (rcode...
|
||||||
if (rcode) {
|
|
||||||
p->lowspeed = false;
|
//USBTRACE2("\r\nAddr:", bAddress);
|
||||||
addrPool.FreeAddress(bAddress);
|
|
||||||
bAddress = 0;
|
p->lowspeed = false;
|
||||||
//USBTRACE2("setAddr:",rcode);
|
|
||||||
return rcode;
|
//get pointer to assigned address record
|
||||||
}//if (rcode...
|
p = addrPool.GetUsbDevicePtr(bAddress);
|
||||||
|
if (!p) {
|
||||||
//USBTRACE2("\r\nAddr:", bAddress);
|
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||||
|
}
|
||||||
p->lowspeed = false;
|
|
||||||
|
p->lowspeed = lowspeed;
|
||||||
//get pointer to assigned address record
|
|
||||||
p = addrPool.GetUsbDevicePtr(bAddress);
|
// Assign epInfo to epinfo pointer - only EP0 is known
|
||||||
if (!p) {
|
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
|
||||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
if (rcode) {
|
||||||
}
|
goto FailSetDevTblEntry;
|
||||||
|
}
|
||||||
p->lowspeed = lowspeed;
|
|
||||||
|
//check if ADK device is already in accessory mode; if yes, configure and exit
|
||||||
// Assign epInfo to epinfo pointer - only EP0 is known
|
if (((USB_DEVICE_DESCRIPTOR*) buf)->idVendor == ADK_VID &&
|
||||||
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
|
(((USB_DEVICE_DESCRIPTOR*) buf)->idProduct == ADK_PID || ((USB_DEVICE_DESCRIPTOR*) buf)->idProduct == ADB_PID)) {
|
||||||
if (rcode) {
|
USBTRACE("\r\nAcc.mode device detected");
|
||||||
goto FailSetDevTblEntry;
|
/* go through configurations, find first bulk-IN, bulk-OUT EP, fill epInfo and quit */
|
||||||
}
|
num_of_conf = ((USB_DEVICE_DESCRIPTOR*) buf)->bNumConfigurations;
|
||||||
|
|
||||||
//check if ADK device is already in accessory mode; if yes, configure and exit
|
//USBTRACE2("\r\nNC:",num_of_conf);
|
||||||
if(((USB_DEVICE_DESCRIPTOR*)buf)->idVendor == ADK_VID &&
|
|
||||||
(((USB_DEVICE_DESCRIPTOR*)buf)->idProduct == ADK_PID || ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct == ADB_PID)) {
|
for (uint8_t i = 0; i < num_of_conf; i++) {
|
||||||
#ifdef DEBUG
|
ConfigDescParser < 0, 0, 0, 0 > confDescrParser(this);
|
||||||
USBTRACE("\r\nAcc.mode device detected");
|
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
|
||||||
#endif
|
if (rcode) {
|
||||||
/* go through configurations, find first bulk-IN, bulk-OUT EP, fill epInfo and quit */
|
goto FailGetConfDescr;
|
||||||
num_of_conf = ((USB_DEVICE_DESCRIPTOR*)buf)->bNumConfigurations;
|
}
|
||||||
|
if (bNumEP > 2) {
|
||||||
//USBTRACE2("\r\nNC:",num_of_conf);
|
break;
|
||||||
|
}
|
||||||
for (uint8_t i=0; i<num_of_conf; i++) {
|
} // for (uint8_t i=0; i<num_of_conf; i++...
|
||||||
ConfigDescParser<0, 0, 0, 0> confDescrParser(this);
|
|
||||||
delay(1);
|
if (bNumEP == 3) {
|
||||||
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
|
// Assign epInfo to epinfo pointer - this time all 3 endpoins
|
||||||
#if defined(XOOM)
|
rcode = pUsb->setEpInfoEntry(bAddress, 3, epInfo);
|
||||||
//added by Jaylen Scott Vanorden
|
if (rcode) {
|
||||||
if( rcode ) {
|
goto FailSetDevTblEntry;
|
||||||
#ifdef DEBUG
|
}
|
||||||
USBTRACE2("\r\nGot 1st bad code for config: ", rcode);
|
}
|
||||||
#endif
|
|
||||||
// Try once more
|
|
||||||
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
|
|
||||||
}
|
// Set Configuration Value
|
||||||
#endif
|
rcode = pUsb->setConf(bAddress, 0, bConfNum);
|
||||||
if( rcode ) {
|
if (rcode) {
|
||||||
goto FailGetConfDescr;
|
goto FailSetConf;
|
||||||
}
|
}
|
||||||
if( bNumEP > 2 ) {
|
/* print endpoint structure */
|
||||||
break;
|
// USBTRACE("\r\nEndpoint Structure:");
|
||||||
}
|
// USBTRACE("\r\nEP0:");
|
||||||
} // for (uint8_t i=0; i<num_of_conf; i++...
|
// USBTRACE2("\r\nAddr: ", epInfo[0].epAddr );
|
||||||
|
// USBTRACE2("\r\nMax.pkt.size: ", epInfo[0].maxPktSize );
|
||||||
if( bNumEP == 3 ) {
|
// USBTRACE2("\r\nAttr: ", epInfo[0].epAttribs );
|
||||||
// Assign epInfo to epinfo pointer - this time all 3 endpoins
|
// USBTRACE("\r\nEpout:");
|
||||||
rcode = pUsb->setEpInfoEntry(bAddress, 3, epInfo);
|
// USBTRACE2("\r\nAddr: ", epInfo[epDataOutIndex].epAddr );
|
||||||
if (rcode) {
|
// USBTRACE2("\r\nMax.pkt.size: ", epInfo[epDataOutIndex].maxPktSize );
|
||||||
goto FailSetDevTblEntry;
|
// 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 );
|
||||||
|
|
||||||
// Set Configuration Value
|
USBTRACE("\r\nConfiguration successful");
|
||||||
rcode = pUsb->setConf(bAddress, 0, bConfNum);
|
ready = true;
|
||||||
if( rcode ){
|
return 0; //successful configuration
|
||||||
goto FailSetConf;
|
}//if( buf->idVendor == ADK_VID...
|
||||||
}
|
|
||||||
/* print endpoint structure */
|
//probe device - get accessory protocol revision
|
||||||
// USBTRACE("\r\nEndpoint Structure:");
|
{
|
||||||
// USBTRACE("\r\nEP0:");
|
uint16_t adkproto = -1;
|
||||||
// USBTRACE2("\r\nAddr: ", epInfo[0].epAddr );
|
rcode = getProto((uint8_t*) & adkproto);
|
||||||
// USBTRACE2("\r\nMax.pkt.size: ", epInfo[0].maxPktSize );
|
if (rcode) {
|
||||||
// USBTRACE2("\r\nAttr: ", epInfo[0].epAttribs );
|
goto FailGetProto; //init fails
|
||||||
// USBTRACE("\r\nEpout:");
|
}
|
||||||
// USBTRACE2("\r\nAddr: ", epInfo[epDataOutIndex].epAddr );
|
USBTRACE2("\r\nADK protocol rev. ", adkproto);
|
||||||
// USBTRACE2("\r\nMax.pkt.size: ", epInfo[epDataOutIndex].maxPktSize );
|
}
|
||||||
// USBTRACE2("\r\nAttr: ", epInfo[epDataOutIndex].epAttribs );
|
|
||||||
// USBTRACE("\r\nEpin:");
|
//sending ID strings
|
||||||
// USBTRACE2("\r\nAddr: ", epInfo[epDataInIndex].epAddr );
|
sendStr(ACCESSORY_STRING_MANUFACTURER, manufacturer);
|
||||||
// USBTRACE2("\r\nMax.pkt.size: ", epInfo[epDataInIndex].maxPktSize );
|
sendStr(ACCESSORY_STRING_MODEL, model);
|
||||||
// USBTRACE2("\r\nAttr: ", epInfo[epDataInIndex].epAttribs );
|
sendStr(ACCESSORY_STRING_DESCRIPTION, description);
|
||||||
#ifdef DEBUG
|
sendStr(ACCESSORY_STRING_VERSION, version);
|
||||||
USBTRACE("\r\nConfiguration successful");
|
sendStr(ACCESSORY_STRING_URI, uri);
|
||||||
#endif
|
sendStr(ACCESSORY_STRING_SERIAL, serial);
|
||||||
ready = true;
|
|
||||||
return 0; //successful configuration
|
//switch to accessory mode
|
||||||
}//if( buf->idVendor == ADK_VID...
|
//the Android phone will reset
|
||||||
|
rcode = switchAcc();
|
||||||
//probe device - get accessory protocol revision
|
if (rcode) {
|
||||||
{
|
goto FailSwAcc; //init fails
|
||||||
uint16_t adkproto = -1;
|
}
|
||||||
delay(1);
|
rcode = -1;
|
||||||
rcode = getProto((uint8_t*)&adkproto );
|
goto SwAttempt; //switch to accessory mode attempted
|
||||||
#if defined(XOOM)
|
|
||||||
//added by Jaylen Scott Vanorden
|
/* diagnostic messages */
|
||||||
if( rcode ) {
|
FailGetDevDescr:
|
||||||
#ifdef DEBUG
|
USBTRACE("\r\ngetDevDescr:");
|
||||||
USBTRACE2("\r\nGot 1st bad code for proto: ", rcode);
|
goto Fail;
|
||||||
#endif
|
|
||||||
// Try once more
|
FailSetDevTblEntry:
|
||||||
rcode = getProto((uint8_t*)&adkproto );
|
USBTRACE("\r\nsetDevTblEn:");
|
||||||
}
|
goto Fail;
|
||||||
#endif
|
|
||||||
if( rcode ){
|
FailGetProto:
|
||||||
goto FailGetProto; //init fails
|
USBTRACE("\r\ngetProto:");
|
||||||
}
|
goto Fail;
|
||||||
#ifdef DEBUG
|
|
||||||
USBTRACE2("\r\nADK protocol rev. ", adkproto );
|
FailSwAcc:
|
||||||
#endif
|
USBTRACE("\r\nswAcc:");
|
||||||
}
|
goto Fail;
|
||||||
|
|
||||||
//sending ID strings
|
SwAttempt:
|
||||||
sendStr( ACCESSORY_STRING_MANUFACTURER, manufacturer);
|
USBTRACE("\r\nAccessory mode switch attempt");
|
||||||
sendStr( ACCESSORY_STRING_MODEL, model);
|
goto Fail;
|
||||||
sendStr( ACCESSORY_STRING_DESCRIPTION, description);
|
|
||||||
sendStr( ACCESSORY_STRING_VERSION, version);
|
FailGetConfDescr:
|
||||||
sendStr( ACCESSORY_STRING_URI, uri);
|
// USBTRACE("getConf:");
|
||||||
sendStr( ACCESSORY_STRING_SERIAL, serial);
|
goto Fail;
|
||||||
|
//
|
||||||
//switch to accessory mode
|
FailSetConf:
|
||||||
//the Android phone will reset
|
// USBTRACE("setConf:");
|
||||||
rcode = switchAcc();
|
goto Fail;
|
||||||
if( rcode ) {
|
//
|
||||||
goto FailSwAcc; //init fails
|
//FailOnInit:
|
||||||
}
|
// USBTRACE("OnInit:");
|
||||||
rcode = -1;
|
// goto Fail;
|
||||||
goto SwAttempt; //switch to accessory mode attempted
|
//
|
||||||
|
Fail:
|
||||||
/* diagnostic messages */
|
//USBTRACE2("\r\nADK Init Failed, error code: ", rcode);
|
||||||
FailGetDevDescr:
|
Release();
|
||||||
#ifdef DEBUG
|
return rcode;
|
||||||
USBTRACE("\r\ngetDevDescr:");
|
}
|
||||||
#endif
|
|
||||||
goto Fail;
|
/* 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) {
|
||||||
FailSetDevTblEntry:
|
//ErrorMessage<uint8_t>(PSTR("Conf.Val"), conf);
|
||||||
#ifdef DEBUG
|
//ErrorMessage<uint8_t>(PSTR("Iface Num"),iface);
|
||||||
USBTRACE("\r\nsetDevTblEn:");
|
//ErrorMessage<uint8_t>(PSTR("Alt.Set"), alt);
|
||||||
#endif
|
|
||||||
goto Fail;
|
//added by Yuuichi Akagawa
|
||||||
|
if (bNumEP == 3) {
|
||||||
FailGetProto:
|
return;
|
||||||
#ifdef DEBUG
|
}
|
||||||
USBTRACE("\r\ngetProto:");
|
|
||||||
#endif
|
bConfNum = conf;
|
||||||
goto Fail;
|
|
||||||
|
uint8_t index;
|
||||||
FailSwAcc:
|
|
||||||
#ifdef DEBUG
|
// if ((pep->bmAttributes & 0x02) == 2) {
|
||||||
USBTRACE("\r\nswAcc:");
|
index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex;
|
||||||
#endif
|
// }
|
||||||
goto Fail;
|
|
||||||
|
// Fill in the endpoint info structure
|
||||||
SwAttempt:
|
epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
|
||||||
#ifdef DEBUG
|
epInfo[index].maxPktSize = (uint8_t) pep->wMaxPacketSize;
|
||||||
USBTRACE("\r\nAccessory mode switch attempt");
|
|
||||||
#endif
|
bNumEP++;
|
||||||
goto Fail;
|
|
||||||
|
//PrintEndpointDescriptor(pep);
|
||||||
FailGetConfDescr:
|
}
|
||||||
// USBTRACE("getConf:");
|
|
||||||
goto Fail;
|
/* Performs a cleanup after failed Init() attempt */
|
||||||
//
|
uint8_t ADK::Release() {
|
||||||
FailSetConf:
|
pUsb->GetAddressPool().FreeAddress(bAddress);
|
||||||
// USBTRACE("setConf:");
|
|
||||||
goto Fail;
|
bNumEP = 1; //must have to be reset to 1
|
||||||
//
|
|
||||||
//FailOnInit:
|
bAddress = 0;
|
||||||
// USBTRACE("OnInit:");
|
ready = false;
|
||||||
// goto Fail;
|
return 0;
|
||||||
//
|
}
|
||||||
Fail:
|
|
||||||
//USBTRACE2("\r\nADK Init Failed, error code: ", rcode);
|
uint8_t ADK::RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr) {
|
||||||
Release();
|
//USBTRACE2("\r\nAddr: ", bAddress );
|
||||||
return rcode;
|
//USBTRACE2("\r\nEP: ",epInfo[epDataInIndex].epAddr);
|
||||||
}
|
return pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, dataptr);
|
||||||
|
}
|
||||||
/* 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)
|
uint8_t ADK::SndData(uint16_t nbytes, uint8_t *dataptr) {
|
||||||
{
|
return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, nbytes, dataptr);
|
||||||
//ErrorMessage<uint8_t>(PSTR("Conf.Val"), conf);
|
}
|
||||||
//ErrorMessage<uint8_t>(PSTR("Iface Num"),iface);
|
|
||||||
//ErrorMessage<uint8_t>(PSTR("Alt.Set"), alt);
|
void ADK::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr) {
|
||||||
|
Notify(PSTR("Endpoint descriptor:"), 0x80);
|
||||||
//added by Yuuichi Akagawa
|
Notify(PSTR("\r\nLength:\t\t"), 0x80);
|
||||||
if( bNumEP == 3 ) {
|
PrintHex<uint8_t > (ep_ptr->bLength, 0x80);
|
||||||
return;
|
Notify(PSTR("\r\nType:\t\t"), 0x80);
|
||||||
}
|
PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80);
|
||||||
|
Notify(PSTR("\r\nAddress:\t"), 0x80);
|
||||||
bConfNum = conf;
|
PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80);
|
||||||
|
Notify(PSTR("\r\nAttributes:\t"), 0x80);
|
||||||
uint8_t index;
|
PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80);
|
||||||
|
Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
|
||||||
if ((pep->bmAttributes & 0x02) == 2) {
|
PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80);
|
||||||
index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex;
|
Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
|
||||||
}
|
PrintHex<uint8_t > (ep_ptr->bInterval, 0x80);
|
||||||
|
Notify(PSTR("\r\n"), 0x80);
|
||||||
// Fill in the endpoint info structure
|
}
|
||||||
epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
|
|
||||||
epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
|
|
||||||
|
|
||||||
bNumEP ++;
|
|
||||||
|
|
||||||
//PrintEndpointDescriptor(pep);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Performs a cleanup after failed Init() attempt */
|
|
||||||
uint8_t ADK::Release()
|
|
||||||
{
|
|
||||||
pUsb->GetAddressPool().FreeAddress(bAddress);
|
|
||||||
|
|
||||||
bNumEP = 1; //must have to be reset to 1
|
|
||||||
|
|
||||||
bAddress = 0;
|
|
||||||
ready = false;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t ADK::RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr)
|
|
||||||
{
|
|
||||||
//USBTRACE2("\r\nAddr: ", bAddress );
|
|
||||||
//USBTRACE2("\r\nEP: ",epInfo[epDataInIndex].epAddr);
|
|
||||||
return pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, dataptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t ADK::SndData(uint16_t nbytes, uint8_t *dataptr)
|
|
||||||
{
|
|
||||||
return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, nbytes, dataptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ADK::PrintEndpointDescriptor( const USB_ENDPOINT_DESCRIPTOR* ep_ptr )
|
|
||||||
{
|
|
||||||
#ifdef DEBUG
|
|
||||||
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);
|
|
||||||
Notify(PSTR("\r\n"));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
292
adk.h
292
adk.h
|
@ -1,145 +1,149 @@
|
||||||
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||||
|
|
||||||
This software may be distributed and modified under the terms of the GNU
|
This software may be distributed and modified under the terms of the GNU
|
||||||
General Public License version 2 (GPL2) as published by the Free Software
|
General Public License version 2 (GPL2) as published by the Free Software
|
||||||
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
||||||
this file. Please note that GPL2 Section 2[b] requires that all works based
|
this file. Please note that GPL2 Section 2[b] requires that all works based
|
||||||
on this software must also be made publicly available under the terms of
|
on this software must also be made publicly available under the terms of
|
||||||
the GPL2 ("Copyleft").
|
the GPL2 ("Copyleft").
|
||||||
|
|
||||||
Contact information
|
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 */
|
||||||
|
|
||||||
#if !defined(_ADK_H_)
|
#if !defined(_ADK_H_)
|
||||||
#define _ADK_H_
|
#define _ADK_H_
|
||||||
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <avr/pgmspace.h>
|
#include <avr/pgmspace.h>
|
||||||
#include "avrpins.h"
|
#include "avrpins.h"
|
||||||
#include "max3421e.h"
|
#include "max3421e.h"
|
||||||
#include "usbhost.h"
|
#include "usbhost.h"
|
||||||
#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
|
||||||
#include <WProgram.h>
|
#include <WProgram.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "printhex.h"
|
#include "printhex.h"
|
||||||
#include "hexdump.h"
|
#include "hexdump.h"
|
||||||
#include "message.h"
|
#include "message.h"
|
||||||
|
|
||||||
#include "confdescparser.h"
|
#include "confdescparser.h"
|
||||||
|
|
||||||
#define ADK_VID 0x18D1
|
#define ADK_VID 0x18D1
|
||||||
#define ADK_PID 0x2D00
|
#define ADK_PID 0x2D00
|
||||||
#define ADB_PID 0x2D01
|
#define ADB_PID 0x2D01
|
||||||
|
|
||||||
#define XOOM //enables repeating getProto() and getConf() attempts
|
/* requests */
|
||||||
//necessary for slow devices such as Motorola XOOM
|
|
||||||
//defined by default, can be commented out to save memory
|
#define ADK_GETPROTO 51 //check USB accessory protocol version
|
||||||
|
#define ADK_SENDSTR 52 //send identifying string
|
||||||
/* requests */
|
#define ADK_ACCSTART 53 //start device in accessory mode
|
||||||
|
|
||||||
#define ADK_GETPROTO 51 //check USB accessory protocol version
|
#define bmREQ_ADK_GET USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_VENDOR|USB_SETUP_RECIPIENT_DEVICE
|
||||||
#define ADK_SENDSTR 52 //send identifying string
|
#define bmREQ_ADK_SEND USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_VENDOR|USB_SETUP_RECIPIENT_DEVICE
|
||||||
#define ADK_ACCSTART 53 //start device in accessory mode
|
|
||||||
|
#define ACCESSORY_STRING_MANUFACTURER 0
|
||||||
#define bmREQ_ADK_GET USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_VENDOR|USB_SETUP_RECIPIENT_DEVICE
|
#define ACCESSORY_STRING_MODEL 1
|
||||||
#define bmREQ_ADK_SEND USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_VENDOR|USB_SETUP_RECIPIENT_DEVICE
|
#define ACCESSORY_STRING_DESCRIPTION 2
|
||||||
|
#define ACCESSORY_STRING_VERSION 3
|
||||||
#define ACCESSORY_STRING_MANUFACTURER 0
|
#define ACCESSORY_STRING_URI 4
|
||||||
#define ACCESSORY_STRING_MODEL 1
|
#define ACCESSORY_STRING_SERIAL 5
|
||||||
#define ACCESSORY_STRING_DESCRIPTION 2
|
|
||||||
#define ACCESSORY_STRING_VERSION 3
|
#define ADK_MAX_ENDPOINTS 3 //endpoint 0, bulk_IN, bulk_OUT
|
||||||
#define ACCESSORY_STRING_URI 4
|
|
||||||
#define ACCESSORY_STRING_SERIAL 5
|
class ADK;
|
||||||
|
|
||||||
#define ADK_MAX_ENDPOINTS 3 //endpoint 0, bulk_IN, bulk_OUT
|
class ADK : public USBDeviceConfig, public UsbConfigXtracter {
|
||||||
|
private:
|
||||||
class ADK;
|
/* ID strings */
|
||||||
|
const char* manufacturer;
|
||||||
class ADK : public USBDeviceConfig, public UsbConfigXtracter
|
const char* model;
|
||||||
{
|
const char* description;
|
||||||
private:
|
const char* version;
|
||||||
/* ID strings */
|
const char* uri;
|
||||||
const char* manufacturer;
|
const char* serial;
|
||||||
const char* model;
|
|
||||||
const char* description;
|
/* ADK proprietary requests */
|
||||||
const char* version;
|
uint8_t getProto(uint8_t* adkproto);
|
||||||
const char* uri;
|
uint8_t sendStr(uint8_t index, const char* str);
|
||||||
const char* serial;
|
uint8_t switchAcc(void);
|
||||||
|
|
||||||
/* ADK proprietary requests */
|
protected:
|
||||||
uint8_t getProto( uint8_t* adkproto );
|
static const uint8_t epDataInIndex; // DataIn endpoint index
|
||||||
uint8_t sendStr( uint8_t index, const char* str );
|
static const uint8_t epDataOutIndex; // DataOUT endpoint index
|
||||||
uint8_t switchAcc( void );
|
|
||||||
|
/* mandatory members */
|
||||||
protected:
|
USB *pUsb;
|
||||||
static const uint8_t epDataInIndex; // DataIn endpoint index
|
uint8_t bAddress;
|
||||||
static const uint8_t epDataOutIndex; // DataOUT endpoint index
|
uint8_t bConfNum; // configuration number
|
||||||
|
|
||||||
/* mandatory members */
|
uint8_t bNumEP; // total number of EP in the configuration
|
||||||
USB *pUsb;
|
bool ready;
|
||||||
uint8_t bAddress;
|
|
||||||
uint8_t bConfNum; // configuration number
|
/* Endpoint data structure */
|
||||||
|
EpInfo epInfo[ADK_MAX_ENDPOINTS];
|
||||||
uint8_t bNumEP; // total number of EP in the configuration
|
|
||||||
bool ready;
|
void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr);
|
||||||
|
|
||||||
/* Endpoint data structure */
|
public:
|
||||||
EpInfo epInfo[ADK_MAX_ENDPOINTS];
|
ADK(USB *pUsb, const char* manufacturer,
|
||||||
|
const char* model,
|
||||||
void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr);
|
const char* description,
|
||||||
|
const char* version,
|
||||||
public:
|
const char* uri,
|
||||||
ADK(USB *pUsb, const char* manufacturer,
|
const char* serial);
|
||||||
const char* model,
|
|
||||||
const char* description,
|
// Methods for receiving and sending data
|
||||||
const char* version,
|
uint8_t RcvData(uint16_t *nbytesptr, uint8_t *dataptr);
|
||||||
const char* uri,
|
uint8_t SndData(uint16_t nbytes, uint8_t *dataptr);
|
||||||
const char* serial);
|
|
||||||
|
|
||||||
// Methods for receiving and sending data
|
// USBDeviceConfig implementation
|
||||||
uint8_t RcvData(uint16_t *nbytesptr, uint8_t *dataptr);
|
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
|
||||||
uint8_t SndData(uint16_t nbytes, uint8_t *dataptr);
|
virtual uint8_t Release();
|
||||||
|
|
||||||
|
virtual uint8_t Poll() {
|
||||||
// USBDeviceConfig implementation
|
return 0;
|
||||||
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
|
};
|
||||||
virtual uint8_t Release();
|
|
||||||
virtual uint8_t Poll(){}; //not implemented
|
virtual uint8_t GetAddress() {
|
||||||
virtual uint8_t GetAddress() { return bAddress; };
|
return bAddress;
|
||||||
virtual bool isReady() { return ready; };
|
};
|
||||||
|
|
||||||
//UsbConfigXtracter implementation
|
virtual bool isReady() {
|
||||||
virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
|
return ready;
|
||||||
}; //class ADK : public USBDeviceConfig ...
|
};
|
||||||
|
|
||||||
/* get ADK protocol version */
|
//UsbConfigXtracter implementation
|
||||||
/* returns 2 bytes in *adkproto */
|
virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
|
||||||
inline uint8_t ADK::getProto( uint8_t* adkproto )
|
}; //class ADK : public USBDeviceConfig ...
|
||||||
{
|
|
||||||
return( pUsb->ctrlReq(bAddress, 0, bmREQ_ADK_GET, ADK_GETPROTO, 0, 0, 0, 2, 2, adkproto, NULL ));
|
/* get ADK protocol version */
|
||||||
}
|
|
||||||
/* send ADK string */
|
/* returns 2 bytes in *adkproto */
|
||||||
inline uint8_t ADK::sendStr( uint8_t index, const char* str )
|
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_SEND, ADK_SENDSTR, 0, 0, index, strlen(str) + 1, strlen(str) + 1, (uint8_t*)str, NULL));
|
}
|
||||||
}
|
|
||||||
/* switch to accessory mode */
|
/* send ADK string */
|
||||||
inline uint8_t ADK::switchAcc( void )
|
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_ACCSTART, 0, 0, 0, 0, 0, NULL, NULL));
|
}
|
||||||
}
|
|
||||||
|
/* switch to accessory mode */
|
||||||
|
inline uint8_t ADK::switchAcc(void) {
|
||||||
|
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_ADK_SEND, ADK_ACCSTART, 0, 0, 0, 0, 0, NULL, NULL));
|
||||||
|
}
|
||||||
|
|
||||||
#endif // _ADK_H_
|
#endif // _ADK_H_
|
476
avrpins.h
476
avrpins.h
|
@ -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 void WaiteForClear(){ while(IsSet()){} }
|
static uint8_t IsSet() {
|
||||||
}; //class TPin...
|
return PORT::PinRead() & (uint8_t) (1 << PIN);
|
||||||
|
}
|
||||||
|
|
||||||
// this class represents one bit in TCCR port.
|
static void WaiteForSet() {
|
||||||
// used to set/clear TCCRx bits
|
while (IsSet() == 0) {
|
||||||
// It is fully static.
|
}
|
||||||
template<typename TCCR, uint8_t COM>
|
}
|
||||||
class TCom
|
|
||||||
{
|
|
||||||
// BOOST_STATIC_ASSERT(PIN < PORT::Width);
|
|
||||||
public:
|
|
||||||
typedef TCCR Tccr;
|
|
||||||
enum{Com = COM};
|
|
||||||
|
|
||||||
static void Set() { TCCR::Set(1 << COM); }
|
static void WaiteForClear() {
|
||||||
|
while (IsSet()) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}; //class TPin...
|
||||||
|
|
||||||
static void Clear() { TCCR::Clear(1 << COM); }
|
// this class represents one bit in TCCR port.
|
||||||
|
// used to set/clear TCCRx bits
|
||||||
|
// It is fully static.
|
||||||
|
|
||||||
static void Toggle() { TCCR::Toggle(1 << COM); }
|
template<typename TCCR, uint8_t COM>
|
||||||
}; //class TCom...
|
class TCom {
|
||||||
|
// BOOST_STATIC_ASSERT(PIN < PORT::Width);
|
||||||
|
public:
|
||||||
|
typedef TCCR Tccr;
|
||||||
|
|
||||||
//Short pin definitions
|
enum {
|
||||||
|
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
|
||||||
#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 */
|
||||||
|
|
||||||
|
@ -416,7 +439,7 @@ template<typename Tp_pin, typename Tc_bit>
|
||||||
/* Arduino pin definitions */
|
/* Arduino pin definitions */
|
||||||
#if defined(__AVR_ATmega1280__) || (__AVR_ATmega2560__)
|
#if defined(__AVR_ATmega1280__) || (__AVR_ATmega2560__)
|
||||||
|
|
||||||
// "Mega" Arduino pin numbers
|
// "Mega" Arduino pin numbers
|
||||||
|
|
||||||
#define P0 Pe0
|
#define P0 Pe0
|
||||||
#define P1 Pe1
|
#define P1 Pe1
|
||||||
|
@ -424,7 +447,7 @@ template<typename Tp_pin, typename Tc_bit>
|
||||||
#define P3 Pe5
|
#define P3 Pe5
|
||||||
#define P4 Pg5
|
#define P4 Pg5
|
||||||
#define P5 Pe5
|
#define P5 Pe5
|
||||||
#define P6 Ph3
|
#define P6 Ph3
|
||||||
#define P7 Ph4
|
#define P7 Ph4
|
||||||
|
|
||||||
#define P8 Ph5
|
#define P8 Ph5
|
||||||
|
@ -441,7 +464,7 @@ template<typename Tp_pin, typename Tc_bit>
|
||||||
#define P18 Pd3
|
#define P18 Pd3
|
||||||
#define P19 Pd2
|
#define P19 Pd2
|
||||||
#define P20 Pd1
|
#define P20 Pd1
|
||||||
#define P21 Pd0
|
#define P21 Pd0
|
||||||
|
|
||||||
#define P22 Pa0
|
#define P22 Pa0
|
||||||
#define P23 Pa1
|
#define P23 Pa1
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -489,7 +511,7 @@ template<typename Tp_pin, typename Tc_bit>
|
||||||
#define P3 Pd3
|
#define P3 Pd3
|
||||||
#define P4 Pd4
|
#define P4 Pd4
|
||||||
#define P5 Pd5
|
#define P5 Pd5
|
||||||
#define P6 Pd6
|
#define P6 Pd6
|
||||||
#define P7 Pd7
|
#define P7 Pd7
|
||||||
|
|
||||||
#define P8 Pb0
|
#define P8 Pb0
|
||||||
|
@ -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
|
||||||
|
|
696
cdcacm.cpp
696
cdcacm.cpp
|
@ -1,359 +1,337 @@
|
||||||
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||||
|
|
||||||
This software may be distributed and modified under the terms of the GNU
|
This software may be distributed and modified under the terms of the GNU
|
||||||
General Public License version 2 (GPL2) as published by the Free Software
|
General Public License version 2 (GPL2) as published by the Free Software
|
||||||
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
||||||
this file. Please note that GPL2 Section 2[b] requires that all works based
|
this file. Please note that GPL2 Section 2[b] requires that all works based
|
||||||
on this software must also be made publicly available under the terms of
|
on this software must also be made publicly available under the terms of
|
||||||
the GPL2 ("Copyleft").
|
the GPL2 ("Copyleft").
|
||||||
|
|
||||||
Contact information
|
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;
|
//if (!i)
|
||||||
//epInfo[i].bmNakPower = USB_NAK_MAX_POWER;
|
epInfo[i].bmNakPower = USB_NAK_MAX_POWER;
|
||||||
|
}
|
||||||
if (!i)
|
if (pUsb)
|
||||||
epInfo[i].bmNakPower = USB_NAK_MAX_POWER;
|
pUsb->RegisterDeviceClass(this);
|
||||||
|
}
|
||||||
}
|
|
||||||
if (pUsb)
|
uint8_t ACM::Init(uint8_t parent, uint8_t port, bool lowspeed) {
|
||||||
pUsb->RegisterDeviceClass(this);
|
const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR);
|
||||||
}
|
|
||||||
|
uint8_t buf[constBufSize];
|
||||||
uint8_t ACM::Init(uint8_t parent, uint8_t port, bool lowspeed)
|
uint8_t rcode;
|
||||||
{
|
UsbDevice *p = NULL;
|
||||||
const uint8_t constBufSize = sizeof(USB_DEVICE_DESCRIPTOR);
|
EpInfo *oldep_ptr = NULL;
|
||||||
|
uint8_t num_of_conf; // number of configurations
|
||||||
uint8_t buf[constBufSize];
|
|
||||||
uint8_t rcode;
|
AddressPool &addrPool = pUsb->GetAddressPool();
|
||||||
UsbDevice *p = NULL;
|
|
||||||
EpInfo *oldep_ptr = NULL;
|
USBTRACE("ACM Init\r\n");
|
||||||
uint8_t num_of_conf; // number of configurations
|
|
||||||
|
if (bAddress)
|
||||||
AddressPool &addrPool = pUsb->GetAddressPool();
|
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
|
||||||
|
|
||||||
USBTRACE("ACM Init\r\n");
|
// Get pointer to pseudo device with address 0 assigned
|
||||||
|
p = addrPool.GetUsbDevicePtr(0);
|
||||||
if (bAddress)
|
|
||||||
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
|
if (!p)
|
||||||
|
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||||
// Get pointer to pseudo device with address 0 assigned
|
|
||||||
p = addrPool.GetUsbDevicePtr(0);
|
if (!p->epinfo) {
|
||||||
|
USBTRACE("epinfo\r\n");
|
||||||
if (!p)
|
return USB_ERROR_EPINFO_IS_NULL;
|
||||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
}
|
||||||
|
|
||||||
if (!p->epinfo)
|
// Save old pointer to EP_RECORD of address 0
|
||||||
{
|
oldep_ptr = p->epinfo;
|
||||||
USBTRACE("epinfo\r\n");
|
|
||||||
return USB_ERROR_EPINFO_IS_NULL;
|
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
|
||||||
}
|
p->epinfo = epInfo;
|
||||||
|
|
||||||
// Save old pointer to EP_RECORD of address 0
|
p->lowspeed = lowspeed;
|
||||||
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, constBufSize, (uint8_t*) buf);
|
||||||
p->epinfo = epInfo;
|
|
||||||
|
// Restore p->epinfo
|
||||||
p->lowspeed = lowspeed;
|
p->epinfo = oldep_ptr;
|
||||||
|
|
||||||
// Get device descriptor
|
if (rcode)
|
||||||
rcode = pUsb->getDevDescr( 0, 0, constBufSize, (uint8_t*)buf );
|
goto FailGetDevDescr;
|
||||||
|
|
||||||
// Restore p->epinfo
|
// Allocate new address according to device class
|
||||||
p->epinfo = oldep_ptr;
|
bAddress = addrPool.AllocAddress(parent, false, port);
|
||||||
|
|
||||||
if( rcode )
|
if (!bAddress)
|
||||||
goto FailGetDevDescr;
|
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
|
||||||
|
|
||||||
// Allocate new address according to device class
|
// Extract Max Packet Size from the device descriptor
|
||||||
bAddress = addrPool.AllocAddress(parent, false, port);
|
epInfo[0].maxPktSize = (uint8_t) ((USB_DEVICE_DESCRIPTOR*) buf)->bMaxPacketSize0;
|
||||||
|
|
||||||
if (!bAddress)
|
// Assign new address to the device
|
||||||
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
|
rcode = pUsb->setAddr(0, 0, bAddress);
|
||||||
|
|
||||||
// Extract Max Packet Size from the device descriptor
|
if (rcode) {
|
||||||
epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0;
|
p->lowspeed = false;
|
||||||
|
addrPool.FreeAddress(bAddress);
|
||||||
// Assign new address to the device
|
bAddress = 0;
|
||||||
rcode = pUsb->setAddr( 0, 0, bAddress );
|
USBTRACE2("setAddr:", rcode);
|
||||||
|
return rcode;
|
||||||
if (rcode)
|
}
|
||||||
{
|
|
||||||
p->lowspeed = false;
|
USBTRACE2("Addr:", bAddress);
|
||||||
addrPool.FreeAddress(bAddress);
|
|
||||||
bAddress = 0;
|
p->lowspeed = false;
|
||||||
USBTRACE2("setAddr:",rcode);
|
|
||||||
return rcode;
|
p = addrPool.GetUsbDevicePtr(bAddress);
|
||||||
}
|
|
||||||
|
if (!p)
|
||||||
USBTRACE2("Addr:", bAddress);
|
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||||
|
|
||||||
p->lowspeed = false;
|
p->lowspeed = lowspeed;
|
||||||
|
|
||||||
p = addrPool.GetUsbDevicePtr(bAddress);
|
num_of_conf = ((USB_DEVICE_DESCRIPTOR*) buf)->bNumConfigurations;
|
||||||
|
|
||||||
if (!p)
|
// Assign epInfo to epinfo pointer
|
||||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
|
||||||
|
|
||||||
p->lowspeed = lowspeed;
|
if (rcode)
|
||||||
|
goto FailSetDevTblEntry;
|
||||||
num_of_conf = ((USB_DEVICE_DESCRIPTOR*)buf)->bNumConfigurations;
|
|
||||||
|
USBTRACE2("NC:", num_of_conf);
|
||||||
// Assign epInfo to epinfo pointer
|
|
||||||
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
|
for (uint8_t i = 0; i < num_of_conf; i++) {
|
||||||
|
ConfigDescParser< USB_CLASS_COM_AND_CDC_CTRL,
|
||||||
if (rcode)
|
CDC_SUBCLASS_ACM,
|
||||||
goto FailSetDevTblEntry;
|
CDC_PROTOCOL_ITU_T_V_250,
|
||||||
|
CP_MASK_COMPARE_CLASS |
|
||||||
USBTRACE2("NC:", num_of_conf);
|
CP_MASK_COMPARE_SUBCLASS |
|
||||||
|
CP_MASK_COMPARE_PROTOCOL > CdcControlParser(this);
|
||||||
for (uint8_t i=0; i<num_of_conf; i++)
|
|
||||||
{
|
ConfigDescParser<USB_CLASS_CDC_DATA, 0, 0,
|
||||||
ConfigDescParser< USB_CLASS_COM_AND_CDC_CTRL,
|
CP_MASK_COMPARE_CLASS> CdcDataParser(this);
|
||||||
CDC_SUBCLASS_ACM,
|
|
||||||
CDC_PROTOCOL_ITU_T_V_250,
|
rcode = pUsb->getConfDescr(bAddress, 0, i, &CdcControlParser);
|
||||||
CP_MASK_COMPARE_CLASS |
|
|
||||||
CP_MASK_COMPARE_SUBCLASS |
|
if (rcode)
|
||||||
CP_MASK_COMPARE_PROTOCOL> CdcControlParser(this);
|
goto FailGetConfDescr;
|
||||||
|
|
||||||
ConfigDescParser<USB_CLASS_CDC_DATA, 0, 0,
|
rcode = pUsb->getConfDescr(bAddress, 0, i, &CdcDataParser);
|
||||||
CP_MASK_COMPARE_CLASS> CdcDataParser(this);
|
|
||||||
|
if (rcode)
|
||||||
rcode = pUsb->getConfDescr(bAddress, 0, i, &CdcControlParser);
|
goto FailGetConfDescr;
|
||||||
rcode = pUsb->getConfDescr(bAddress, 0, i, &CdcDataParser);
|
|
||||||
|
if (bNumEP > 1)
|
||||||
if (bNumEP > 1)
|
break;
|
||||||
break;
|
} // for
|
||||||
} // for
|
|
||||||
|
if (bNumEP < 4)
|
||||||
if (bNumEP < 4)
|
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
|
||||||
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
|
|
||||||
|
// Assign epInfo to epinfo pointer
|
||||||
// Assign epInfo to epinfo pointer
|
rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
|
||||||
rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
|
|
||||||
|
USBTRACE2("Conf:", bConfNum);
|
||||||
USBTRACE2("Conf:", bConfNum);
|
|
||||||
|
// Set Configuration Value
|
||||||
// Set Configuration Value
|
rcode = pUsb->setConf(bAddress, 0, bConfNum);
|
||||||
rcode = pUsb->setConf(bAddress, 0, bConfNum);
|
|
||||||
|
if (rcode)
|
||||||
if (rcode)
|
goto FailSetConf;
|
||||||
goto FailSetConf;
|
|
||||||
|
rcode = pAsync->OnInit(this);
|
||||||
rcode = pAsync->OnInit(this);
|
|
||||||
|
if (rcode)
|
||||||
if (rcode)
|
goto FailOnInit;
|
||||||
goto FailOnInit;
|
|
||||||
|
USBTRACE("ACM configured\r\n");
|
||||||
USBTRACE("ACM configured\r\n");
|
|
||||||
ready = true;
|
//bPollEnable = true;
|
||||||
|
|
||||||
//bPollEnable = true;
|
//USBTRACE("Poll enabled\r\n");
|
||||||
|
return 0;
|
||||||
//USBTRACE("Poll enabled\r\n");
|
|
||||||
return 0;
|
FailGetDevDescr:
|
||||||
|
USBTRACE("getDevDescr:");
|
||||||
FailGetDevDescr:
|
goto Fail;
|
||||||
USBTRACE("getDevDescr:");
|
|
||||||
goto Fail;
|
FailSetDevTblEntry:
|
||||||
|
USBTRACE("setDevTblEn:");
|
||||||
FailSetDevTblEntry:
|
goto Fail;
|
||||||
USBTRACE("setDevTblEn:");
|
|
||||||
goto Fail;
|
FailGetConfDescr:
|
||||||
|
USBTRACE("getConf:");
|
||||||
FailGetConfDescr:
|
goto Fail;
|
||||||
USBTRACE("getConf:");
|
|
||||||
goto Fail;
|
FailSetConf:
|
||||||
|
USBTRACE("setConf:");
|
||||||
FailSetConf:
|
goto Fail;
|
||||||
USBTRACE("setConf:");
|
|
||||||
goto Fail;
|
FailOnInit:
|
||||||
|
USBTRACE("OnInit:");
|
||||||
FailOnInit:
|
goto Fail;
|
||||||
USBTRACE("OnInit:");
|
|
||||||
goto Fail;
|
Fail:
|
||||||
|
PrintHex<uint8_t > (rcode, 0x80);
|
||||||
Fail:
|
Notify(PSTR("\r\n"), 0x80);
|
||||||
Serial.println(rcode, HEX);
|
// Serial.println(rcode, HEX);
|
||||||
Release();
|
Release();
|
||||||
return rcode;
|
return rcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ACM::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) {
|
||||||
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("Conf.Val"), conf);
|
ErrorMessage<uint8_t > (PSTR("Alt.Set"), alt);
|
||||||
//ErrorMessage<uint8_t>(PSTR("Iface Num"),iface);
|
|
||||||
//ErrorMessage<uint8_t>(PSTR("Alt.Set"), alt);
|
bConfNum = conf;
|
||||||
|
|
||||||
bConfNum = conf;
|
uint8_t index;
|
||||||
|
|
||||||
uint8_t index;
|
if ((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80)
|
||||||
|
index = epInterruptInIndex;
|
||||||
if ((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80)
|
else
|
||||||
index = epInterruptInIndex;
|
if ((pep->bmAttributes & 0x02) == 2)
|
||||||
else
|
index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex;
|
||||||
if ((pep->bmAttributes & 0x02) == 2)
|
else
|
||||||
index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex;
|
return;
|
||||||
else
|
|
||||||
return;
|
// Fill in the endpoint info structure
|
||||||
|
epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
|
||||||
// Fill in the endpoint info structure
|
epInfo[index].maxPktSize = (uint8_t) pep->wMaxPacketSize;
|
||||||
epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
|
epInfo[index].epAttribs = 0;
|
||||||
epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
|
|
||||||
//epInfo[index].epAttribs = 0;
|
bNumEP++;
|
||||||
|
|
||||||
bNumEP ++;
|
PrintEndpointDescriptor(pep);
|
||||||
|
}
|
||||||
//PrintEndpointDescriptor(pep);
|
|
||||||
}
|
uint8_t ACM::Release() {
|
||||||
|
pUsb->GetAddressPool().FreeAddress(bAddress);
|
||||||
uint8_t ACM::Release()
|
|
||||||
{
|
bControlIface = 0;
|
||||||
pUsb->GetAddressPool().FreeAddress(bAddress);
|
bDataIface = 0;
|
||||||
|
bNumEP = 1;
|
||||||
bControlIface = 0;
|
|
||||||
bDataIface = 0;
|
bAddress = 0;
|
||||||
bNumEP = 1;
|
qNextPollTime = 0;
|
||||||
|
bPollEnable = false;
|
||||||
bAddress = 0;
|
return 0;
|
||||||
qNextPollTime = 0;
|
}
|
||||||
bPollEnable = false;
|
|
||||||
ready = false;
|
uint8_t ACM::Poll() {
|
||||||
return 0;
|
uint8_t rcode = 0;
|
||||||
}
|
|
||||||
|
if (!bPollEnable)
|
||||||
uint8_t ACM::Poll()
|
return 0;
|
||||||
{
|
|
||||||
uint8_t rcode = 0;
|
//uint32_t time_now = millis();
|
||||||
|
|
||||||
if (!bPollEnable)
|
//if (qNextPollTime <= time_now)
|
||||||
return 0;
|
//{
|
||||||
|
// qNextPollTime = time_now + 100;
|
||||||
//uint32_t time_now = millis();
|
|
||||||
|
// uint8_t rcode;
|
||||||
//if (qNextPollTime <= time_now)
|
// const uint8_t constBufSize = 16;
|
||||||
//{
|
// uint8_t buf[constBufSize];
|
||||||
// qNextPollTime = time_now + 100;
|
|
||||||
|
// for (uint8_t i=0; i<constBufSize; i++)
|
||||||
// uint8_t rcode;
|
// buf[i] = 0;
|
||||||
// const uint8_t constBufSize = 16;
|
|
||||||
// uint8_t buf[constBufSize];
|
// uint16_t read = (constBufSize > epInfo[epInterruptInIndex].maxPktSize)
|
||||||
|
// ? epInfo[epInterruptInIndex].maxPktSize : constBufSize;
|
||||||
// for (uint8_t i=0; i<constBufSize; i++)
|
// rcode = pUsb->inTransfer(bAddress, epInfo[epInterruptInIndex].epAddr, &read, buf);
|
||||||
// buf[i] = 0;
|
|
||||||
|
// if (rcode)
|
||||||
// uint16_t read = (constBufSize > epInfo[epInterruptInIndex].maxPktSize)
|
// return rcode;
|
||||||
// ? epInfo[epInterruptInIndex].maxPktSize : constBufSize;
|
|
||||||
// rcode = pUsb->inTransfer(bAddress, epInfo[epInterruptInIndex].epAddr, &read, buf);
|
// for (uint8_t i=0; i<read; i++)
|
||||||
|
// {
|
||||||
// if (rcode)
|
// PrintHex<uint8_t>(buf[i]);
|
||||||
// return rcode;
|
// Serial.print(" ");
|
||||||
|
// }
|
||||||
// for (uint8_t i=0; i<read; i++)
|
// USBTRACE("\r\n");
|
||||||
// {
|
//}
|
||||||
// PrintHex<uint8_t>(buf[i]);
|
return rcode;
|
||||||
// Serial.print(" ");
|
}
|
||||||
// }
|
|
||||||
// USBTRACE("\r\n");
|
uint8_t ACM::RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr) {
|
||||||
//}
|
return pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, dataptr);
|
||||||
return rcode;
|
}
|
||||||
}
|
|
||||||
|
uint8_t ACM::SndData(uint16_t nbytes, uint8_t *dataptr) {
|
||||||
uint8_t ACM::RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr)
|
return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, nbytes, dataptr);
|
||||||
{
|
}
|
||||||
return pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, dataptr);
|
|
||||||
}
|
uint8_t ACM::SetCommFeature(uint16_t fid, uint8_t nbytes, uint8_t *dataptr) {
|
||||||
|
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCOUT, CDC_SET_COMM_FEATURE, (fid & 0xff), (fid >> 8), bControlIface, nbytes, nbytes, dataptr, NULL));
|
||||||
uint8_t ACM::SndData(uint16_t nbytes, uint8_t *dataptr)
|
}
|
||||||
{
|
|
||||||
return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, nbytes, 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));
|
||||||
|
}
|
||||||
/* untested */
|
|
||||||
uint8_t ACM::GetNotif( uint16_t *bytes_rcvd, 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->inTransfer(bAddress, epInfo[epInterruptInIndex].epAddr, bytes_rcvd, dataptr);
|
}
|
||||||
}
|
|
||||||
|
uint8_t ACM::SetLineCoding(const LINE_CODING *dataptr) {
|
||||||
uint8_t ACM::SetCommFeature(uint16_t fid, uint8_t nbytes, uint8_t *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_SET_COMM_FEATURE, (fid & 0xff), (fid >> 8), bControlIface, nbytes, nbytes, dataptr, NULL ));
|
|
||||||
}
|
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));
|
||||||
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 ));
|
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));
|
||||||
|
}
|
||||||
uint8_t ACM::ClearCommFeature(uint16_t fid)
|
|
||||||
{
|
uint8_t ACM::SendBreak(uint16_t duration) {
|
||||||
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_CDCOUT, CDC_SEND_BREAK, (duration & 0xff), (duration >> 8), bControlIface, 0, 0, NULL, NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t ACM::SetLineCoding(const LINE_CODING *dataptr)
|
void ACM::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr) {
|
||||||
{
|
Notify(PSTR("Endpoint descriptor:"), 0x80);
|
||||||
return( pUsb->ctrlReq( bAddress, 0, bmREQ_CDCOUT, CDC_SET_LINE_CODING, 0x00, 0x00, bControlIface, sizeof(LINE_CODING), sizeof(LINE_CODING), (uint8_t*)dataptr, NULL ));
|
Notify(PSTR("\r\nLength:\t\t"), 0x80);
|
||||||
}
|
PrintHex<uint8_t > (ep_ptr->bLength, 0x80);
|
||||||
|
Notify(PSTR("\r\nType:\t\t"), 0x80);
|
||||||
uint8_t ACM::GetLineCoding(LINE_CODING *dataptr)
|
PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80);
|
||||||
{
|
Notify(PSTR("\r\nAddress:\t"), 0x80);
|
||||||
return( pUsb->ctrlReq( bAddress, 0, bmREQ_CDCIN, CDC_GET_LINE_CODING, 0x00, 0x00, bControlIface, sizeof(LINE_CODING), sizeof(LINE_CODING), (uint8_t*)dataptr, NULL ));
|
PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80);
|
||||||
}
|
Notify(PSTR("\r\nAttributes:\t"), 0x80);
|
||||||
|
PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80);
|
||||||
uint8_t ACM::SetControlLineState(uint8_t state)
|
Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
|
||||||
{
|
PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80);
|
||||||
return( pUsb->ctrlReq( bAddress, 0, bmREQ_CDCOUT, CDC_SET_CONTROL_LINE_STATE, state, 0, bControlIface, 0, 0, NULL, NULL ));
|
Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
|
||||||
}
|
PrintHex<uint8_t > (ep_ptr->bInterval, 0x80);
|
||||||
|
Notify(PSTR("\r\n"), 0x80);
|
||||||
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 ));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void ACM::PrintEndpointDescriptor( const USB_ENDPOINT_DESCRIPTOR* ep_ptr )
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
Notify(PSTR("\r\n"));
|
|
||||||
}
|
|
||||||
|
|
394
cdcacm.h
394
cdcacm.h
|
@ -1,211 +1,185 @@
|
||||||
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||||
|
|
||||||
This software may be distributed and modified under the terms of the GNU
|
This software may be distributed and modified under the terms of the GNU
|
||||||
General Public License version 2 (GPL2) as published by the Free Software
|
General Public License version 2 (GPL2) as published by the Free Software
|
||||||
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
||||||
this file. Please note that GPL2 Section 2[b] requires that all works based
|
this file. Please note that GPL2 Section 2[b] requires that all works based
|
||||||
on this software must also be made publicly available under the terms of
|
on this software must also be made publicly available under the terms of
|
||||||
the GPL2 ("Copyleft").
|
the GPL2 ("Copyleft").
|
||||||
|
|
||||||
Contact information
|
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__
|
||||||
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <avr/pgmspace.h>
|
#include <avr/pgmspace.h>
|
||||||
#include "avrpins.h"
|
#include "avrpins.h"
|
||||||
#include "max3421e.h"
|
#include "max3421e.h"
|
||||||
#include "usbhost.h"
|
#include "usbhost.h"
|
||||||
#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
|
||||||
#include <WProgram.h>
|
#include <WProgram.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "printhex.h"
|
#include "printhex.h"
|
||||||
#include "hexdump.h"
|
#include "hexdump.h"
|
||||||
#include "message.h"
|
#include "message.h"
|
||||||
|
|
||||||
#include "confdescparser.h"
|
#include "confdescparser.h"
|
||||||
|
|
||||||
#define bmREQ_CDCOUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
|
#define bmREQ_CDCOUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
|
||||||
#define bmREQ_CDCIN USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
|
#define bmREQ_CDCIN USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
|
||||||
|
|
||||||
// CDC Subclass Constants
|
// CDC Subclass Constants
|
||||||
#define CDC_SUBCLASS_DLCM 0x01 // Direct Line Control Model
|
#define CDC_SUBCLASS_DLCM 0x01 // Direct Line Control Model
|
||||||
#define CDC_SUBCLASS_ACM 0x02 // Abstract Control Model
|
#define CDC_SUBCLASS_ACM 0x02 // Abstract Control Model
|
||||||
#define CDC_SUBCLASS_TCM 0x03 // Telephone Control Model
|
#define CDC_SUBCLASS_TCM 0x03 // Telephone Control Model
|
||||||
#define CDC_SUBCLASS_MCCM 0x04 // Multi Channel Control Model
|
#define CDC_SUBCLASS_MCCM 0x04 // Multi Channel Control Model
|
||||||
#define CDC_SUBCLASS_CAPI 0x05 // CAPI Control Model
|
#define CDC_SUBCLASS_CAPI 0x05 // CAPI Control Model
|
||||||
#define CDC_SUBCLASS_ETHERNET 0x06 // Ethernet Network Control Model
|
#define CDC_SUBCLASS_ETHERNET 0x06 // Ethernet Network Control Model
|
||||||
#define CDC_SUBCLASS_ATM 0x07 // ATM Network Control Model
|
#define CDC_SUBCLASS_ATM 0x07 // ATM Network Control Model
|
||||||
#define CDC_SUBCLASS_WIRELESS_HANDSET 0x08 // Wireless Handset Control Model
|
#define CDC_SUBCLASS_WIRELESS_HANDSET 0x08 // Wireless Handset Control Model
|
||||||
#define CDC_SUBCLASS_DEVICE_MANAGEMENT 0x09 // Device Management
|
#define CDC_SUBCLASS_DEVICE_MANAGEMENT 0x09 // Device Management
|
||||||
#define CDC_SUBCLASS_MOBILE_DIRECT_LINE 0x0A // Mobile Direct Line Model
|
#define CDC_SUBCLASS_MOBILE_DIRECT_LINE 0x0A // Mobile Direct Line Model
|
||||||
#define CDC_SUBCLASS_OBEX 0x0B // OBEX
|
#define CDC_SUBCLASS_OBEX 0x0B // OBEX
|
||||||
#define CDC_SUBCLASS_ETHERNET_EMU 0x0C // Ethernet Emulation Model
|
#define CDC_SUBCLASS_ETHERNET_EMU 0x0C // Ethernet Emulation Model
|
||||||
|
|
||||||
// Communication Interface Class Control Protocol Codes
|
// Communication Interface Class Control Protocol Codes
|
||||||
#define CDC_PROTOCOL_ITU_T_V_250 0x01 // AT Commands defined by ITU-T V.250
|
#define CDC_PROTOCOL_ITU_T_V_250 0x01 // AT Commands defined by ITU-T V.250
|
||||||
#define CDC_PROTOCOL_PCCA_101 0x02 // AT Commands defined by PCCA-101
|
#define CDC_PROTOCOL_PCCA_101 0x02 // AT Commands defined by PCCA-101
|
||||||
#define CDC_PROTOCOL_PCCA_101_O 0x03 // AT Commands defined by PCCA-101 & Annex O
|
#define CDC_PROTOCOL_PCCA_101_O 0x03 // AT Commands defined by PCCA-101 & Annex O
|
||||||
#define CDC_PROTOCOL_GSM_7_07 0x04 // AT Commands defined by GSM 7.07
|
#define CDC_PROTOCOL_GSM_7_07 0x04 // AT Commands defined by GSM 7.07
|
||||||
#define CDC_PROTOCOL_3GPP_27_07 0x05 // AT Commands defined by 3GPP 27.007
|
#define CDC_PROTOCOL_3GPP_27_07 0x05 // AT Commands defined by 3GPP 27.007
|
||||||
#define CDC_PROTOCOL_C_S0017_0 0x06 // AT Commands defined by TIA for CDMA
|
#define CDC_PROTOCOL_C_S0017_0 0x06 // AT Commands defined by TIA for CDMA
|
||||||
#define CDC_PROTOCOL_USB_EEM 0x07 // Ethernet Emulation Model
|
#define CDC_PROTOCOL_USB_EEM 0x07 // Ethernet Emulation Model
|
||||||
|
|
||||||
// CDC Commands defined by CDC 1.2
|
// CDC Commands defined by CDC 1.2
|
||||||
#define CDC_SEND_ENCAPSULATED_COMMAND 0x00
|
#define CDC_SEND_ENCAPSULATED_COMMAND 0x00
|
||||||
#define CDC_GET_ENCAPSULATED_RESPONSE 0x01
|
#define CDC_GET_ENCAPSULATED_RESPONSE 0x01
|
||||||
|
|
||||||
// CDC Commands defined by PSTN 1.2
|
// CDC Commands defined by PSTN 1.2
|
||||||
#define CDC_SET_COMM_FEATURE 0x02
|
#define CDC_SET_COMM_FEATURE 0x02
|
||||||
#define CDC_GET_COMM_FEATURE 0x03
|
#define CDC_GET_COMM_FEATURE 0x03
|
||||||
#define CDC_CLEAR_COMM_FEATURE 0x04
|
#define CDC_CLEAR_COMM_FEATURE 0x04
|
||||||
#define CDC_SET_AUX_LINE_STATE 0x10
|
#define CDC_SET_AUX_LINE_STATE 0x10
|
||||||
#define CDC_SET_HOOK_STATE 0x11
|
#define CDC_SET_HOOK_STATE 0x11
|
||||||
#define CDC_PULSE_SETUP 0x12
|
#define CDC_PULSE_SETUP 0x12
|
||||||
#define CDC_SEND_PULSE 0x13
|
#define CDC_SEND_PULSE 0x13
|
||||||
#define CDC_SET_PULSE_TIME 0x14
|
#define CDC_SET_PULSE_TIME 0x14
|
||||||
#define CDC_RING_AUX_JACK 0x15
|
#define CDC_RING_AUX_JACK 0x15
|
||||||
#define CDC_SET_LINE_CODING 0x20
|
#define CDC_SET_LINE_CODING 0x20
|
||||||
#define CDC_GET_LINE_CODING 0x21
|
#define CDC_GET_LINE_CODING 0x21
|
||||||
#define CDC_SET_CONTROL_LINE_STATE 0x22
|
#define CDC_SET_CONTROL_LINE_STATE 0x22
|
||||||
#define CDC_SEND_BREAK 0x23
|
#define CDC_SEND_BREAK 0x23
|
||||||
#define CDC_SET_RINGER_PARMS 0x30
|
#define CDC_SET_RINGER_PARMS 0x30
|
||||||
#define CDC_GET_RINGER_PARMS 0x31
|
#define CDC_GET_RINGER_PARMS 0x31
|
||||||
#define CDC_SET_OPERATION_PARMS 0x32
|
#define CDC_SET_OPERATION_PARMS 0x32
|
||||||
#define CDC_GET_OPERATION_PARMS 0x33
|
#define CDC_GET_OPERATION_PARMS 0x33
|
||||||
#define CDC_SET_LINE_PARMS 0x34
|
#define CDC_SET_LINE_PARMS 0x34
|
||||||
#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
|
// CDC Functional Descriptor Structures
|
||||||
#define NETWORK_CONNECTION 0x00
|
|
||||||
#define RESPONSE_AVAILABLE 0x01
|
typedef struct {
|
||||||
#define AUX_JACK_HOOK_STATE 0x08
|
uint8_t bFunctionLength;
|
||||||
#define RING_DETECT 0x09
|
uint8_t bDescriptorType;
|
||||||
#define SERIAL_STATE 0x20
|
uint8_t bDescriptorSubtype;
|
||||||
#define CALL_STATE_CHANGE 0x28
|
uint8_t bmCapabilities;
|
||||||
#define LINE_STATE_CHANGE 0x29
|
uint8_t bDataInterface;
|
||||||
#define CONNECTION_SPEED_CHANGE 0x2a
|
} CALL_MGMNT_FUNC_DESCR;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
// CDC Functional Descriptor Structures
|
uint8_t bFunctionLength;
|
||||||
typedef struct
|
uint8_t bDescriptorType;
|
||||||
{
|
uint8_t bDescriptorSubtype;
|
||||||
uint8_t bFunctionLength;
|
uint8_t bmCapabilities;
|
||||||
uint8_t bDescriptorType;
|
} ACM_FUNC_DESCR, DLM_FUNC_DESCR, TEL_OPER_MODES_FUNC_DESCR,
|
||||||
uint8_t bDescriptorSubtype;
|
TEL_CALL_STATE_REP_CPBL_FUNC_DESCR;
|
||||||
uint8_t bmCapabilities;
|
|
||||||
uint8_t bDataInterface;
|
typedef struct {
|
||||||
} CALL_MGMNT_FUNC_DESCR;
|
uint8_t bFunctionLength;
|
||||||
|
uint8_t bDescriptorType;
|
||||||
typedef struct
|
uint8_t bDescriptorSubtype;
|
||||||
{
|
uint8_t bRingerVolSteps;
|
||||||
uint8_t bFunctionLength;
|
uint8_t bNumRingerPatterns;
|
||||||
uint8_t bDescriptorType;
|
} TEL_RINGER_FUNC_DESCR;
|
||||||
uint8_t bDescriptorSubtype;
|
|
||||||
uint8_t bmCapabilities;
|
typedef struct {
|
||||||
} ACM_FUNC_DESCR, DLM_FUNC_DESCR, TEL_OPER_MODES_FUNC_DESCR,
|
uint32_t dwDTERate; // Data Terminal Rate in bits per second
|
||||||
TEL_CALL_STATE_REP_CPBL_FUNC_DESCR;
|
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
|
||||||
typedef struct
|
uint8_t bDataBits; // Data bits (5, 6, 7, 8 or 16)
|
||||||
{
|
} LINE_CODING;
|
||||||
uint8_t bFunctionLength;
|
|
||||||
uint8_t bDescriptorType;
|
class ACM;
|
||||||
uint8_t bDescriptorSubtype;
|
|
||||||
uint8_t bRingerVolSteps;
|
class CDCAsyncOper {
|
||||||
uint8_t bNumRingerPatterns;
|
public:
|
||||||
} TEL_RINGER_FUNC_DESCR;
|
virtual uint8_t OnInit(ACM *pacm) = 0;
|
||||||
|
//virtual void OnDataRcvd(ACM *pacm, uint8_t nbytes, uint8_t *dataptr) = 0;
|
||||||
typedef struct
|
//virtual void OnDisconnected(ACM *pacm) = 0;
|
||||||
{
|
};
|
||||||
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 bParityType; // 0 - None, 1 - Odd, 2 - Even, 3 - Mark, 4 - Space
|
#define ACM_MAX_ENDPOINTS 4
|
||||||
uint8_t bDataBits; // Data bits (5, 6, 7, 8 or 16)
|
|
||||||
} LINE_CODING;
|
class ACM : public USBDeviceConfig, public UsbConfigXtracter {
|
||||||
|
protected:
|
||||||
typedef struct
|
static const uint8_t epDataInIndex; // DataIn endpoint index
|
||||||
{
|
static const uint8_t epDataOutIndex; // DataOUT endpoint index
|
||||||
uint8_t bmRequestType; // 0xa1 for class-specific notifications
|
static const uint8_t epInterruptInIndex; // InterruptIN endpoint index
|
||||||
uint8_t bNotification;
|
|
||||||
uint16_t wValue;
|
USB *pUsb;
|
||||||
uint16_t wIndex;
|
CDCAsyncOper *pAsync;
|
||||||
uint16_t wLength;
|
uint8_t bAddress;
|
||||||
uint16_t bmState; //UART state bitmap for SERIAL_STATE, other notifications variable length
|
uint8_t bConfNum; // configuration number
|
||||||
} CLASS_NOTIFICATION;
|
uint8_t bControlIface; // Control interface value
|
||||||
|
uint8_t bDataIface; // Data interface value
|
||||||
class ACM;
|
uint8_t bNumEP; // total number of EP in the configuration
|
||||||
|
uint32_t qNextPollTime; // next poll time
|
||||||
class CDCAsyncOper
|
bool bPollEnable; // poll enable flag
|
||||||
{
|
|
||||||
public:
|
EpInfo epInfo[ACM_MAX_ENDPOINTS];
|
||||||
virtual uint8_t OnInit(ACM *pacm) = 0;
|
|
||||||
//virtual void OnDataRcvd(ACM *pacm, uint8_t nbytes, uint8_t *dataptr) = 0;
|
void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr);
|
||||||
//virtual void OnDisconnected(ACM *pacm) = 0;
|
|
||||||
};
|
public:
|
||||||
|
ACM(USB *pusb, CDCAsyncOper *pasync);
|
||||||
|
|
||||||
#define ACM_MAX_ENDPOINTS 4
|
uint8_t SetCommFeature(uint16_t fid, uint8_t nbytes, uint8_t *dataptr);
|
||||||
|
uint8_t GetCommFeature(uint16_t fid, uint8_t nbytes, uint8_t *dataptr);
|
||||||
class ACM : public USBDeviceConfig, public UsbConfigXtracter
|
uint8_t ClearCommFeature(uint16_t fid);
|
||||||
{
|
uint8_t SetLineCoding(const LINE_CODING *dataptr);
|
||||||
protected:
|
uint8_t GetLineCoding(LINE_CODING *dataptr);
|
||||||
static const uint8_t epDataInIndex; // DataIn endpoint index
|
uint8_t SetControlLineState(uint8_t state);
|
||||||
static const uint8_t epDataOutIndex; // DataOUT endpoint index
|
uint8_t SendBreak(uint16_t duration);
|
||||||
static const uint8_t epInterruptInIndex; // InterruptIN endpoint index
|
|
||||||
|
// Methods for recieving and sending data
|
||||||
USB *pUsb;
|
uint8_t RcvData(uint16_t *nbytesptr, uint8_t *dataptr);
|
||||||
CDCAsyncOper *pAsync;
|
uint8_t SndData(uint16_t nbytes, uint8_t *dataptr);
|
||||||
uint8_t bAddress;
|
|
||||||
uint8_t bConfNum; // configuration number
|
// USBDeviceConfig implementation
|
||||||
uint8_t bControlIface; // Control interface value
|
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
|
||||||
uint8_t bDataIface; // Data interface value
|
virtual uint8_t Release();
|
||||||
uint8_t bNumEP; // total number of EP in the configuration
|
virtual uint8_t Poll();
|
||||||
uint32_t qNextPollTime; // next poll time
|
|
||||||
bool bPollEnable; // poll enable flag
|
virtual uint8_t GetAddress() {
|
||||||
bool ready; //device ready indicator
|
return bAddress;
|
||||||
|
};
|
||||||
EpInfo epInfo[ACM_MAX_ENDPOINTS];
|
|
||||||
|
// UsbConfigXtracter implementation
|
||||||
void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr);
|
virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
|
||||||
|
};
|
||||||
public:
|
|
||||||
ACM(USB *pusb, CDCAsyncOper *pasync);
|
|
||||||
|
|
||||||
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 ClearCommFeature(uint16_t fid);
|
|
||||||
uint8_t SetLineCoding(const LINE_CODING *dataptr);
|
|
||||||
uint8_t GetLineCoding(LINE_CODING *dataptr);
|
|
||||||
uint8_t SetControlLineState(uint8_t state);
|
|
||||||
uint8_t SendBreak(uint16_t duration);
|
|
||||||
uint8_t GetNotif( uint16_t *bytes_rcvd, uint8_t *dataptr );
|
|
||||||
|
|
||||||
// Methods for recieving and sending data
|
|
||||||
uint8_t RcvData(uint16_t *nbytesptr, uint8_t *dataptr);
|
|
||||||
uint8_t SndData(uint16_t nbytes, uint8_t *dataptr);
|
|
||||||
|
|
||||||
// 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; };
|
|
||||||
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);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // __CDCACM_H__
|
#endif // __CDCACM_H__
|
680
cdcftdi.cpp
680
cdcftdi.cpp
|
@ -1,348 +1,332 @@
|
||||||
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||||
|
|
||||||
This software may be distributed and modified under the terms of the GNU
|
This software may be distributed and modified under the terms of the GNU
|
||||||
General Public License version 2 (GPL2) as published by the Free Software
|
General Public License version 2 (GPL2) as published by the Free Software
|
||||||
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
||||||
this file. Please note that GPL2 Section 2[b] requires that all works based
|
this file. Please note that GPL2 Section 2[b] requires that all works based
|
||||||
on this software must also be made publicly available under the terms of
|
on this software must also be made publicly available under the terms of
|
||||||
the GPL2 ("Copyleft").
|
the GPL2 ("Copyleft").
|
||||||
|
|
||||||
Contact information
|
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)
|
||||||
|
epInfo[i].bmNakPower = USB_NAK_MAX_POWER;
|
||||||
//if (!i)
|
}
|
||||||
epInfo[i].bmNakPower = USB_NAK_MAX_POWER;
|
if (pUsb)
|
||||||
}
|
pUsb->RegisterDeviceClass(this);
|
||||||
if (pUsb)
|
}
|
||||||
pUsb->RegisterDeviceClass(this);
|
|
||||||
}
|
uint8_t FTDI::Init(uint8_t parent, uint8_t port, bool lowspeed) {
|
||||||
|
const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR);
|
||||||
uint8_t FTDI::Init(uint8_t parent, uint8_t port, bool lowspeed)
|
|
||||||
{
|
uint8_t buf[constBufSize];
|
||||||
const uint8_t constBufSize = sizeof(USB_DEVICE_DESCRIPTOR);
|
uint8_t rcode;
|
||||||
|
UsbDevice *p = NULL;
|
||||||
uint8_t buf[constBufSize];
|
EpInfo *oldep_ptr = NULL;
|
||||||
uint8_t rcode;
|
//uint8_t len = 0;
|
||||||
UsbDevice *p = NULL;
|
//uint16_t cd_len = 0;
|
||||||
EpInfo *oldep_ptr = NULL;
|
|
||||||
uint8_t len = 0;
|
uint8_t num_of_conf; // number of configurations
|
||||||
uint16_t cd_len = 0;
|
//uint8_t num_of_intf; // number of interfaces
|
||||||
|
|
||||||
uint8_t num_of_conf; // number of configurations
|
AddressPool &addrPool = pUsb->GetAddressPool();
|
||||||
uint8_t num_of_intf; // number of interfaces
|
|
||||||
|
USBTRACE("FTDI Init\r\n");
|
||||||
AddressPool &addrPool = pUsb->GetAddressPool();
|
|
||||||
|
if (bAddress)
|
||||||
USBTRACE("FTDI Init\r\n");
|
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
|
||||||
|
|
||||||
if (bAddress)
|
// Get pointer to pseudo device with address 0 assigned
|
||||||
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
|
p = addrPool.GetUsbDevicePtr(0);
|
||||||
|
|
||||||
// Get pointer to pseudo device with address 0 assigned
|
if (!p)
|
||||||
p = addrPool.GetUsbDevicePtr(0);
|
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||||
|
|
||||||
if (!p)
|
if (!p->epinfo) {
|
||||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
USBTRACE("epinfo\r\n");
|
||||||
|
return USB_ERROR_EPINFO_IS_NULL;
|
||||||
if (!p->epinfo)
|
}
|
||||||
{
|
|
||||||
USBTRACE("epinfo\r\n");
|
// Save old pointer to EP_RECORD of address 0
|
||||||
return USB_ERROR_EPINFO_IS_NULL;
|
oldep_ptr = p->epinfo;
|
||||||
}
|
|
||||||
|
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
|
||||||
// Save old pointer to EP_RECORD of address 0
|
p->epinfo = epInfo;
|
||||||
oldep_ptr = p->epinfo;
|
|
||||||
|
p->lowspeed = lowspeed;
|
||||||
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
|
|
||||||
p->epinfo = epInfo;
|
// Get device descriptor
|
||||||
|
rcode = pUsb->getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), (uint8_t*) buf);
|
||||||
p->lowspeed = lowspeed;
|
|
||||||
|
// Restore p->epinfo
|
||||||
// Get device descriptor
|
p->epinfo = oldep_ptr;
|
||||||
rcode = pUsb->getDevDescr( 0, 0, sizeof(USB_DEVICE_DESCRIPTOR), (uint8_t*)buf );
|
|
||||||
|
if (rcode)
|
||||||
// Restore p->epinfo
|
goto FailGetDevDescr;
|
||||||
p->epinfo = oldep_ptr;
|
|
||||||
|
if (((USB_DEVICE_DESCRIPTOR*) buf)->idVendor != FTDI_VID || ((USB_DEVICE_DESCRIPTOR*) buf)->idProduct != FTDI_PID)
|
||||||
if( rcode )
|
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
|
||||||
goto FailGetDevDescr;
|
|
||||||
|
// Save type of FTDI chip
|
||||||
if (((USB_DEVICE_DESCRIPTOR*)buf)->idVendor != FTDI_VID || ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct != FTDI_PID)
|
wFTDIType = ((USB_DEVICE_DESCRIPTOR*) buf)->bcdDevice;
|
||||||
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
|
|
||||||
|
// Allocate new address according to device class
|
||||||
// Save type of FTDI chip
|
bAddress = addrPool.AllocAddress(parent, false, port);
|
||||||
wFTDIType = ((USB_DEVICE_DESCRIPTOR*)buf)->bcdDevice;
|
|
||||||
|
if (!bAddress)
|
||||||
// Allocate new address according to device class
|
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
|
||||||
bAddress = addrPool.AllocAddress(parent, false, port);
|
|
||||||
|
// Extract Max Packet Size from the device descriptor
|
||||||
if (!bAddress)
|
epInfo[0].maxPktSize = (uint8_t) ((USB_DEVICE_DESCRIPTOR*) buf)->bMaxPacketSize0;
|
||||||
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
|
|
||||||
|
// Assign new address to the device
|
||||||
// Extract Max Packet Size from the device descriptor
|
rcode = pUsb->setAddr(0, 0, bAddress);
|
||||||
epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0;
|
|
||||||
|
if (rcode) {
|
||||||
// Assign new address to the device
|
p->lowspeed = false;
|
||||||
rcode = pUsb->setAddr( 0, 0, bAddress );
|
addrPool.FreeAddress(bAddress);
|
||||||
|
bAddress = 0;
|
||||||
if (rcode)
|
USBTRACE2("setAddr:", rcode);
|
||||||
{
|
return rcode;
|
||||||
p->lowspeed = false;
|
}
|
||||||
addrPool.FreeAddress(bAddress);
|
|
||||||
bAddress = 0;
|
USBTRACE2("Addr:", bAddress);
|
||||||
USBTRACE2("setAddr:",rcode);
|
|
||||||
return rcode;
|
p->lowspeed = false;
|
||||||
}
|
|
||||||
|
p = addrPool.GetUsbDevicePtr(bAddress);
|
||||||
USBTRACE2("Addr:", bAddress);
|
|
||||||
|
if (!p)
|
||||||
p->lowspeed = false;
|
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||||
|
|
||||||
p = addrPool.GetUsbDevicePtr(bAddress);
|
p->lowspeed = lowspeed;
|
||||||
|
|
||||||
if (!p)
|
num_of_conf = ((USB_DEVICE_DESCRIPTOR*) buf)->bNumConfigurations;
|
||||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
|
||||||
|
// Assign epInfo to epinfo pointer
|
||||||
p->lowspeed = lowspeed;
|
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
|
||||||
|
|
||||||
num_of_conf = ((USB_DEVICE_DESCRIPTOR*)buf)->bNumConfigurations;
|
if (rcode)
|
||||||
|
goto FailSetDevTblEntry;
|
||||||
// Assign epInfo to epinfo pointer
|
|
||||||
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
|
USBTRACE2("NC:", num_of_conf);
|
||||||
|
|
||||||
if (rcode)
|
for (uint8_t i = 0; i < num_of_conf; i++) {
|
||||||
goto FailSetDevTblEntry;
|
HexDumper<USBReadParser, uint16_t, uint16_t> HexDump;
|
||||||
|
ConfigDescParser < 0xFF, 0xFF, 0xFF, CP_MASK_COMPARE_ALL> confDescrParser(this);
|
||||||
USBTRACE2("NC:", num_of_conf);
|
|
||||||
|
rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump);
|
||||||
for (uint8_t i=0; i<num_of_conf; i++)
|
|
||||||
{
|
if (rcode)
|
||||||
HexDumper<USBReadParser, uint16_t, uint16_t> HexDump;
|
goto FailGetConfDescr;
|
||||||
ConfigDescParser<0xFF, 0xFF, 0xFF, CP_MASK_COMPARE_ALL> confDescrParser(this);
|
|
||||||
|
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
|
||||||
rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump);
|
|
||||||
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
|
if (rcode)
|
||||||
|
goto FailGetConfDescr;
|
||||||
if (bNumEP > 1)
|
|
||||||
break;
|
if (bNumEP > 1)
|
||||||
} // for
|
break;
|
||||||
|
} // for
|
||||||
if (bNumEP < 2)
|
|
||||||
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
|
if (bNumEP < 2)
|
||||||
|
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
|
||||||
USBTRACE2("NumEP:", bNumEP);
|
|
||||||
|
USBTRACE2("NumEP:", bNumEP);
|
||||||
// Assign epInfo to epinfo pointer
|
|
||||||
rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
|
// Assign epInfo to epinfo pointer
|
||||||
|
rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
|
||||||
USBTRACE2("Conf:", bConfNum);
|
|
||||||
|
USBTRACE2("Conf:", bConfNum);
|
||||||
// Set Configuration Value
|
|
||||||
rcode = pUsb->setConf(bAddress, 0, bConfNum);
|
// Set Configuration Value
|
||||||
|
rcode = pUsb->setConf(bAddress, 0, bConfNum);
|
||||||
if (rcode)
|
|
||||||
goto FailSetConfDescr;
|
if (rcode)
|
||||||
|
goto FailSetConfDescr;
|
||||||
rcode = pAsync->OnInit(this);
|
|
||||||
|
rcode = pAsync->OnInit(this);
|
||||||
if (rcode)
|
|
||||||
goto FailOnInit;
|
if (rcode)
|
||||||
|
goto FailOnInit;
|
||||||
USBTRACE("FTDI configured\r\n");
|
|
||||||
|
USBTRACE("FTDI configured\r\n");
|
||||||
bPollEnable = true;
|
|
||||||
return 0;
|
bPollEnable = true;
|
||||||
|
return 0;
|
||||||
FailGetDevDescr:
|
|
||||||
USBTRACE("getDevDescr:");
|
FailGetDevDescr:
|
||||||
goto Fail;
|
USBTRACE("getDevDescr:");
|
||||||
|
goto Fail;
|
||||||
FailSetDevTblEntry:
|
|
||||||
USBTRACE("setDevTblEn:");
|
FailSetDevTblEntry:
|
||||||
goto Fail;
|
USBTRACE("setDevTblEn:");
|
||||||
|
goto Fail;
|
||||||
FailGetConfDescr:
|
|
||||||
USBTRACE("getConf:");
|
FailGetConfDescr:
|
||||||
goto Fail;
|
USBTRACE("getConf:");
|
||||||
|
goto Fail;
|
||||||
FailSetConfDescr:
|
|
||||||
USBTRACE("setConf:");
|
FailSetConfDescr:
|
||||||
goto Fail;
|
USBTRACE("setConf:");
|
||||||
|
goto Fail;
|
||||||
FailSetBaudRate:
|
|
||||||
USBTRACE("SetBaudRate:");
|
FailOnInit:
|
||||||
goto Fail;
|
USBTRACE("OnInit:");
|
||||||
|
goto Fail;
|
||||||
FailSetFlowControl:
|
|
||||||
USBTRACE("SetFlowControl:");
|
Fail:
|
||||||
goto Fail;
|
PrintHex<uint8_t > (rcode, 0x80);
|
||||||
|
Notify(PSTR("\r\n"), 0x80);
|
||||||
FailOnInit:
|
//Serial.println(rcode, HEX);
|
||||||
USBTRACE("OnInit:");
|
Release();
|
||||||
goto Fail;
|
return rcode;
|
||||||
|
}
|
||||||
Fail:
|
|
||||||
Serial.println(rcode, HEX);
|
void FTDI::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) {
|
||||||
Release();
|
ErrorMessage<uint8_t > (PSTR("Conf.Val"), conf);
|
||||||
return rcode;
|
ErrorMessage<uint8_t > (PSTR("Iface Num"), iface);
|
||||||
}
|
ErrorMessage<uint8_t > (PSTR("Alt.Set"), alt);
|
||||||
|
|
||||||
|
bConfNum = conf;
|
||||||
void FTDI::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep)
|
|
||||||
{
|
uint8_t index;
|
||||||
ErrorMessage<uint8_t>(PSTR("Conf.Val"), conf);
|
|
||||||
ErrorMessage<uint8_t>(PSTR("Iface Num"),iface);
|
if ((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80)
|
||||||
ErrorMessage<uint8_t>(PSTR("Alt.Set"), alt);
|
index = epInterruptInIndex;
|
||||||
|
else
|
||||||
bConfNum = conf;
|
if ((pep->bmAttributes & 0x02) == 2)
|
||||||
|
index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex;
|
||||||
uint8_t index;
|
else
|
||||||
|
return;
|
||||||
if ((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80)
|
|
||||||
index = epInterruptInIndex;
|
// Fill in the endpoint info structure
|
||||||
else
|
epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
|
||||||
if ((pep->bmAttributes & 0x02) == 2)
|
epInfo[index].maxPktSize = (uint8_t) pep->wMaxPacketSize;
|
||||||
index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex;
|
epInfo[index].epAttribs = 0;
|
||||||
else
|
|
||||||
return;
|
bNumEP++;
|
||||||
|
|
||||||
// Fill in the endpoint info structure
|
PrintEndpointDescriptor(pep);
|
||||||
epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
|
}
|
||||||
epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
|
|
||||||
//epInfo[index].epAttribs = 0;
|
uint8_t FTDI::Release() {
|
||||||
|
pUsb->GetAddressPool().FreeAddress(bAddress);
|
||||||
bNumEP ++;
|
|
||||||
|
bAddress = 0;
|
||||||
PrintEndpointDescriptor(pep);
|
bNumEP = 1;
|
||||||
}
|
qNextPollTime = 0;
|
||||||
|
bPollEnable = false;
|
||||||
uint8_t FTDI::Release()
|
return 0;
|
||||||
{
|
}
|
||||||
pUsb->GetAddressPool().FreeAddress(bAddress);
|
|
||||||
|
uint8_t FTDI::Poll() {
|
||||||
bAddress = 0;
|
uint8_t rcode = 0;
|
||||||
bNumEP = 1;
|
|
||||||
qNextPollTime = 0;
|
//if (!bPollEnable)
|
||||||
bPollEnable = false;
|
// return 0;
|
||||||
return 0;
|
|
||||||
}
|
//if (qNextPollTime <= millis())
|
||||||
|
//{
|
||||||
uint8_t FTDI::Poll()
|
// Serial.println(bAddress, HEX);
|
||||||
{
|
|
||||||
uint8_t rcode = 0;
|
// qNextPollTime = millis() + 100;
|
||||||
|
//}
|
||||||
//if (!bPollEnable)
|
return rcode;
|
||||||
// return 0;
|
}
|
||||||
|
|
||||||
//if (qNextPollTime <= millis())
|
uint8_t FTDI::SetBaudRate(uint32_t baud) {
|
||||||
//{
|
uint16_t baud_value, baud_index = 0;
|
||||||
// Serial.println(bAddress, HEX);
|
uint32_t divisor3;
|
||||||
|
|
||||||
// qNextPollTime = millis() + 100;
|
divisor3 = 48000000 / 2 / baud; // divisor shifted 3 bits to the left
|
||||||
//}
|
|
||||||
return rcode;
|
if (wFTDIType == FT232AM) {
|
||||||
}
|
if ((divisor3 & 0x7) == 7)
|
||||||
|
divisor3++; // round x.7/8 up to x+1
|
||||||
uint8_t FTDI::SetBaudRate(uint32_t baud)
|
|
||||||
{
|
baud_value = divisor3 >> 3;
|
||||||
uint16_t baud_value, baud_index = 0;
|
divisor3 &= 0x7;
|
||||||
uint32_t divisor3;
|
|
||||||
|
if (divisor3 == 1) baud_value |= 0xc000;
|
||||||
divisor3 = 48000000 / 2 / baud; // divisor shifted 3 bits to the left
|
else // 0.125
|
||||||
|
if (divisor3 >= 4) baud_value |= 0x4000;
|
||||||
if (wFTDIType == FT232AM)
|
else // 0.5
|
||||||
{
|
if (divisor3 != 0) baud_value |= 0x8000; // 0.25
|
||||||
if ((divisor3 & 0x7) == 7)
|
if (baud_value == 1) baud_value = 0; /* special case for maximum baud rate */
|
||||||
divisor3 ++; // round x.7/8 up to x+1
|
} else {
|
||||||
|
static const unsigned char divfrac [8] = {0, 3, 2, 0, 1, 1, 2, 3};
|
||||||
baud_value = divisor3 >> 3;
|
static const unsigned char divindex[8] = {0, 0, 0, 1, 0, 1, 1, 1};
|
||||||
divisor3 &= 0x7;
|
|
||||||
|
baud_value = divisor3 >> 3;
|
||||||
if (divisor3 == 1) baud_value |= 0xc000; else // 0.125
|
baud_value |= divfrac [divisor3 & 0x7] << 14;
|
||||||
if (divisor3 >= 4) baud_value |= 0x4000; else // 0.5
|
baud_index = divindex[divisor3 & 0x7];
|
||||||
if (divisor3 != 0) baud_value |= 0x8000; // 0.25
|
|
||||||
if (baud_value == 1) baud_value = 0; /* special case for maximum baud rate */
|
/* Deal with special cases for highest baud rates. */
|
||||||
}
|
if (baud_value == 1) baud_value = 0;
|
||||||
else
|
else // 1.0
|
||||||
{
|
if (baud_value == 0x4001) baud_value = 1; // 1.5
|
||||||
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 };
|
USBTRACE2("baud_value:", baud_value);
|
||||||
|
USBTRACE2("baud_index:", baud_index);
|
||||||
baud_value = divisor3 >> 3;
|
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);
|
||||||
baud_value |= divfrac [divisor3 & 0x7] << 14;
|
}
|
||||||
baud_index = divindex[divisor3 & 0x7];
|
|
||||||
|
uint8_t FTDI::SetModemControl(uint16_t signal) {
|
||||||
/* Deal with special cases for highest baud rates. */
|
return pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_MODEM_CTRL, signal & 0xff, signal >> 8, 0, 0, 0, NULL, NULL);
|
||||||
if (baud_value == 1) baud_value = 0; else // 1.0
|
}
|
||||||
if (baud_value == 0x4001) baud_value = 1; // 1.5
|
|
||||||
}
|
uint8_t FTDI::SetFlowControl(uint8_t protocol, uint8_t xon, uint8_t xoff) {
|
||||||
USBTRACE2("baud_value:", baud_value);
|
return pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_SET_FLOW_CTRL, xon, xoff, protocol << 8, 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::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);
|
||||||
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);
|
uint8_t FTDI::RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr) {
|
||||||
}
|
return pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, dataptr);
|
||||||
|
}
|
||||||
uint8_t FTDI::SetFlowControl(uint8_t protocol, uint8_t xon, uint8_t xoff)
|
|
||||||
{
|
uint8_t FTDI::SndData(uint16_t nbytes, uint8_t *dataptr) {
|
||||||
return pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_SET_FLOW_CTRL, xon, xoff, protocol << 8, 0, 0, NULL, NULL);
|
return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, nbytes, dataptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t FTDI::SetData(uint16_t databm)
|
void FTDI::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr) {
|
||||||
{
|
Notify(PSTR("Endpoint descriptor:"), 0x80);
|
||||||
return pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_SET_DATA, databm & 0xff, databm >> 8, 0, 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);
|
||||||
uint8_t FTDI::RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr)
|
PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80);
|
||||||
{
|
Notify(PSTR("\r\nAddress:\t"), 0x80);
|
||||||
return pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, dataptr);
|
PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80);
|
||||||
}
|
Notify(PSTR("\r\nAttributes:\t"), 0x80);
|
||||||
|
PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80);
|
||||||
uint8_t FTDI::SndData(uint16_t nbytes, uint8_t *dataptr)
|
Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
|
||||||
{
|
PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80);
|
||||||
return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, nbytes, dataptr);
|
Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
|
||||||
}
|
PrintHex<uint8_t > (ep_ptr->bInterval, 0x80);
|
||||||
|
Notify(PSTR("\r\n"), 0x80);
|
||||||
void FTDI::PrintEndpointDescriptor( const USB_ENDPOINT_DESCRIPTOR* ep_ptr )
|
}
|
||||||
{
|
|
||||||
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);
|
|
||||||
Notify(PSTR("\r\n"));
|
|
||||||
}
|
|
||||||
|
|
299
cdcftdi.h
299
cdcftdi.h
|
@ -1,150 +1,151 @@
|
||||||
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||||
|
|
||||||
This software may be distributed and modified under the terms of the GNU
|
This software may be distributed and modified under the terms of the GNU
|
||||||
General Public License version 2 (GPL2) as published by the Free Software
|
General Public License version 2 (GPL2) as published by the Free Software
|
||||||
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
||||||
this file. Please note that GPL2 Section 2[b] requires that all works based
|
this file. Please note that GPL2 Section 2[b] requires that all works based
|
||||||
on this software must also be made publicly available under the terms of
|
on this software must also be made publicly available under the terms of
|
||||||
the GPL2 ("Copyleft").
|
the GPL2 ("Copyleft").
|
||||||
|
|
||||||
Contact information
|
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__
|
||||||
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <avr/pgmspace.h>
|
#include <avr/pgmspace.h>
|
||||||
#include "avrpins.h"
|
#include "avrpins.h"
|
||||||
#include "max3421e.h"
|
#include "max3421e.h"
|
||||||
#include "usbhost.h"
|
#include "usbhost.h"
|
||||||
#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
|
||||||
#include <WProgram.h>
|
#include <WProgram.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "printhex.h"
|
#include "printhex.h"
|
||||||
#include "hexdump.h"
|
#include "hexdump.h"
|
||||||
#include "message.h"
|
#include "message.h"
|
||||||
|
|
||||||
#include "confdescparser.h"
|
#include "confdescparser.h"
|
||||||
|
|
||||||
#define bmREQ_FTDI_OUT 0x40
|
#define bmREQ_FTDI_OUT 0x40
|
||||||
#define bmREQ_FTDI_IN 0xc0
|
#define bmREQ_FTDI_IN 0xc0
|
||||||
|
|
||||||
//#define bmREQ_FTDI_OUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
|
//#define bmREQ_FTDI_OUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
|
||||||
//#define bmREQ_FTDI_IN USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
|
//#define bmREQ_FTDI_IN USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
|
||||||
|
|
||||||
#define FTDI_VID 0x0403 // FTDI VID
|
#define FTDI_VID 0x0403 // FTDI VID
|
||||||
#define FTDI_PID 0x6001 // FTDI PID
|
#define FTDI_PID 0x6001 // FTDI PID
|
||||||
|
|
||||||
#define FT232AM 0x0200
|
#define FT232AM 0x0200
|
||||||
#define FT232BM 0x0400
|
#define FT232BM 0x0400
|
||||||
#define FT2232 0x0500
|
#define FT2232 0x0500
|
||||||
#define FT232R 0x0600
|
#define FT232R 0x0600
|
||||||
|
|
||||||
// Commands
|
// Commands
|
||||||
#define FTDI_SIO_RESET 0 /* Reset the port */
|
#define FTDI_SIO_RESET 0 /* Reset the port */
|
||||||
#define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */
|
#define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */
|
||||||
#define FTDI_SIO_SET_FLOW_CTRL 2 /* Set flow control register */
|
#define FTDI_SIO_SET_FLOW_CTRL 2 /* Set flow control register */
|
||||||
#define FTDI_SIO_SET_BAUD_RATE 3 /* Set baud rate */
|
#define FTDI_SIO_SET_BAUD_RATE 3 /* Set baud rate */
|
||||||
#define FTDI_SIO_SET_DATA 4 /* Set the data characteristics of the port */
|
#define FTDI_SIO_SET_DATA 4 /* Set the data characteristics of the port */
|
||||||
#define FTDI_SIO_GET_MODEM_STATUS 5 /* Retrieve current value of modem status register */
|
#define FTDI_SIO_GET_MODEM_STATUS 5 /* Retrieve current value of modem status register */
|
||||||
#define FTDI_SIO_SET_EVENT_CHAR 6 /* Set the event character */
|
#define FTDI_SIO_SET_EVENT_CHAR 6 /* Set the event character */
|
||||||
#define FTDI_SIO_SET_ERROR_CHAR 7 /* Set the error character */
|
#define FTDI_SIO_SET_ERROR_CHAR 7 /* Set the error character */
|
||||||
|
|
||||||
#define FTDI_SIO_RESET_SIO 0
|
#define FTDI_SIO_RESET_SIO 0
|
||||||
#define FTDI_SIO_RESET_PURGE_RX 1
|
#define FTDI_SIO_RESET_PURGE_RX 1
|
||||||
#define FTDI_SIO_RESET_PURGE_TX 2
|
#define FTDI_SIO_RESET_PURGE_TX 2
|
||||||
|
|
||||||
#define FTDI_SIO_SET_DATA_PARITY_NONE (0x0 << 8 )
|
#define FTDI_SIO_SET_DATA_PARITY_NONE (0x0 << 8 )
|
||||||
#define FTDI_SIO_SET_DATA_PARITY_ODD (0x1 << 8 )
|
#define FTDI_SIO_SET_DATA_PARITY_ODD (0x1 << 8 )
|
||||||
#define FTDI_SIO_SET_DATA_PARITY_EVEN (0x2 << 8 )
|
#define FTDI_SIO_SET_DATA_PARITY_EVEN (0x2 << 8 )
|
||||||
#define FTDI_SIO_SET_DATA_PARITY_MARK (0x3 << 8 )
|
#define FTDI_SIO_SET_DATA_PARITY_MARK (0x3 << 8 )
|
||||||
#define FTDI_SIO_SET_DATA_PARITY_SPACE (0x4 << 8 )
|
#define FTDI_SIO_SET_DATA_PARITY_SPACE (0x4 << 8 )
|
||||||
#define FTDI_SIO_SET_DATA_STOP_BITS_1 (0x0 << 11)
|
#define FTDI_SIO_SET_DATA_STOP_BITS_1 (0x0 << 11)
|
||||||
#define FTDI_SIO_SET_DATA_STOP_BITS_15 (0x1 << 11)
|
#define FTDI_SIO_SET_DATA_STOP_BITS_15 (0x1 << 11)
|
||||||
#define FTDI_SIO_SET_DATA_STOP_BITS_2 (0x2 << 11)
|
#define FTDI_SIO_SET_DATA_STOP_BITS_2 (0x2 << 11)
|
||||||
#define FTDI_SIO_SET_BREAK (0x1 << 14)
|
#define FTDI_SIO_SET_BREAK (0x1 << 14)
|
||||||
|
|
||||||
#define FTDI_SIO_SET_DTR_MASK 0x1
|
#define FTDI_SIO_SET_DTR_MASK 0x1
|
||||||
#define FTDI_SIO_SET_DTR_HIGH ( 1 | ( FTDI_SIO_SET_DTR_MASK << 8))
|
#define FTDI_SIO_SET_DTR_HIGH ( 1 | ( FTDI_SIO_SET_DTR_MASK << 8))
|
||||||
#define FTDI_SIO_SET_DTR_LOW ( 0 | ( FTDI_SIO_SET_DTR_MASK << 8))
|
#define FTDI_SIO_SET_DTR_LOW ( 0 | ( FTDI_SIO_SET_DTR_MASK << 8))
|
||||||
#define FTDI_SIO_SET_RTS_MASK 0x2
|
#define FTDI_SIO_SET_RTS_MASK 0x2
|
||||||
#define FTDI_SIO_SET_RTS_HIGH ( 2 | ( FTDI_SIO_SET_RTS_MASK << 8 ))
|
#define FTDI_SIO_SET_RTS_HIGH ( 2 | ( FTDI_SIO_SET_RTS_MASK << 8 ))
|
||||||
#define FTDI_SIO_SET_RTS_LOW ( 0 | ( FTDI_SIO_SET_RTS_MASK << 8 ))
|
#define FTDI_SIO_SET_RTS_LOW ( 0 | ( FTDI_SIO_SET_RTS_MASK << 8 ))
|
||||||
|
|
||||||
#define FTDI_SIO_DISABLE_FLOW_CTRL 0x0
|
#define FTDI_SIO_DISABLE_FLOW_CTRL 0x0
|
||||||
#define FTDI_SIO_RTS_CTS_HS (0x1 << 8)
|
#define FTDI_SIO_RTS_CTS_HS (0x1 << 8)
|
||||||
#define FTDI_SIO_DTR_DSR_HS (0x2 << 8)
|
#define FTDI_SIO_DTR_DSR_HS (0x2 << 8)
|
||||||
#define FTDI_SIO_XON_XOFF_HS (0x4 << 8)
|
#define FTDI_SIO_XON_XOFF_HS (0x4 << 8)
|
||||||
|
|
||||||
#define FTDI_SIO_CTS_MASK 0x10
|
#define FTDI_SIO_CTS_MASK 0x10
|
||||||
#define FTDI_SIO_DSR_MASK 0x20
|
#define FTDI_SIO_DSR_MASK 0x20
|
||||||
#define FTDI_SIO_RI_MASK 0x40
|
#define FTDI_SIO_RI_MASK 0x40
|
||||||
#define FTDI_SIO_RLSD_MASK 0x80
|
#define FTDI_SIO_RLSD_MASK 0x80
|
||||||
|
|
||||||
class FTDI;
|
class FTDI;
|
||||||
|
|
||||||
class FTDIAsyncOper
|
class FTDIAsyncOper {
|
||||||
{
|
public:
|
||||||
public:
|
virtual uint8_t OnInit(FTDI *pftdi) = 0;
|
||||||
virtual uint8_t OnInit(FTDI *pftdi) = 0;
|
};
|
||||||
};
|
|
||||||
|
|
||||||
|
// Only single port chips are currently supported by the library,
|
||||||
// Only single port chips are currently supported by the library,
|
// 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 epDataOutIndex; // DataOUT endpoint index
|
||||||
static const uint8_t epDataInIndex; // DataIn endpoint index
|
static const uint8_t epInterruptInIndex; // InterruptIN endpoint index
|
||||||
static const uint8_t epDataOutIndex; // DataOUT endpoint index
|
|
||||||
static const uint8_t epInterruptInIndex; // InterruptIN endpoint index
|
FTDIAsyncOper *pAsync;
|
||||||
|
USB *pUsb;
|
||||||
FTDIAsyncOper *pAsync;
|
uint8_t bAddress;
|
||||||
USB *pUsb;
|
uint8_t bConfNum; // configuration number
|
||||||
uint8_t bAddress;
|
uint8_t bNumIface; // number of interfaces in the configuration
|
||||||
uint8_t bConfNum; // configuration number
|
uint8_t bNumEP; // total number of EP in the configuration
|
||||||
uint8_t bNumIface; // number of interfaces in the configuration
|
uint32_t qNextPollTime; // next poll time
|
||||||
uint8_t bNumEP; // total number of EP in the configuration
|
bool bPollEnable; // poll enable flag
|
||||||
uint32_t qNextPollTime; // next poll time
|
uint16_t wFTDIType; // Type of FTDI chip
|
||||||
bool bPollEnable; // poll enable flag
|
|
||||||
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:
|
||||||
|
FTDI(USB *pusb, FTDIAsyncOper *pasync);
|
||||||
public:
|
|
||||||
FTDI(USB *pusb, FTDIAsyncOper *pasync);
|
uint8_t SetBaudRate(uint32_t baud);
|
||||||
|
uint8_t SetModemControl(uint16_t control);
|
||||||
uint8_t SetBaudRate(uint32_t baud);
|
uint8_t SetFlowControl(uint8_t protocol, uint8_t xon = 0x11, uint8_t xoff = 0x13);
|
||||||
uint8_t SetModemControl(uint16_t control);
|
uint8_t SetData(uint16_t databm);
|
||||||
uint8_t SetFlowControl(uint8_t protocol, uint8_t xon = 0x11, uint8_t xoff = 0x13);
|
|
||||||
uint8_t SetData(uint16_t databm);
|
// Methods for recieving and sending data
|
||||||
|
uint8_t RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr);
|
||||||
// Methods for recieving and sending data
|
uint8_t SndData(uint16_t nbytes, uint8_t *dataptr);
|
||||||
uint8_t RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr);
|
|
||||||
uint8_t SndData(uint16_t nbytes, uint8_t *dataptr);
|
// USBDeviceConfig implementation
|
||||||
|
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
|
||||||
// USBDeviceConfig implementation
|
virtual uint8_t Release();
|
||||||
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
|
virtual uint8_t Poll();
|
||||||
virtual uint8_t Release();
|
|
||||||
virtual uint8_t Poll();
|
virtual uint8_t GetAddress() {
|
||||||
virtual uint8_t GetAddress() { return bAddress; };
|
return bAddress;
|
||||||
|
};
|
||||||
// UsbConfigXtracter implementation
|
|
||||||
virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
|
// 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__
|
444
cdcprolific.cpp
444
cdcprolific.cpp
|
@ -1,243 +1,201 @@
|
||||||
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||||
|
|
||||||
This software may be distributed and modified under the terms of the GNU
|
This software may be distributed and modified under the terms of the GNU
|
||||||
General Public License version 2 (GPL2) as published by the Free Software
|
General Public License version 2 (GPL2) as published by the Free Software
|
||||||
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
||||||
this file. Please note that GPL2 Section 2[b] requires that all works based
|
this file. Please note that GPL2 Section 2[b] requires that all works based
|
||||||
on this software must also be made publicly available under the terms of
|
on this software must also be made publicly available under the terms of
|
||||||
the GPL2 ("Copyleft").
|
the GPL2 ("Copyleft").
|
||||||
|
|
||||||
Contact information
|
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 rcode;
|
||||||
uint8_t buf[constBufSize];
|
UsbDevice *p = NULL;
|
||||||
uint8_t rcode;
|
EpInfo *oldep_ptr = NULL;
|
||||||
UsbDevice *p = NULL;
|
uint8_t num_of_conf; // number of configurations
|
||||||
EpInfo *oldep_ptr = NULL;
|
|
||||||
uint8_t num_of_conf; // number of configurations
|
AddressPool &addrPool = pUsb->GetAddressPool();
|
||||||
enum pl2303_type pltype = unknown;
|
|
||||||
|
USBTRACE("PL Init\r\n");
|
||||||
AddressPool &addrPool = pUsb->GetAddressPool();
|
|
||||||
|
if (bAddress)
|
||||||
USBTRACE("PL Init\r\n");
|
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
|
||||||
|
|
||||||
if (bAddress)
|
// Get pointer to pseudo device with address 0 assigned
|
||||||
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
|
p = addrPool.GetUsbDevicePtr(0);
|
||||||
|
|
||||||
// Get pointer to pseudo device with address 0 assigned
|
if (!p)
|
||||||
p = addrPool.GetUsbDevicePtr(0);
|
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||||
|
|
||||||
if (!p)
|
if (!p->epinfo) {
|
||||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
USBTRACE("epinfo\r\n");
|
||||||
|
return USB_ERROR_EPINFO_IS_NULL;
|
||||||
if (!p->epinfo)
|
}
|
||||||
{
|
|
||||||
USBTRACE("epinfo\r\n");
|
// Save old pointer to EP_RECORD of address 0
|
||||||
return USB_ERROR_EPINFO_IS_NULL;
|
oldep_ptr = p->epinfo;
|
||||||
}
|
|
||||||
|
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
|
||||||
// Save old pointer to EP_RECORD of address 0
|
p->epinfo = epInfo;
|
||||||
oldep_ptr = p->epinfo;
|
|
||||||
|
p->lowspeed = lowspeed;
|
||||||
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
|
|
||||||
p->epinfo = epInfo;
|
// Get device descriptor
|
||||||
|
rcode = pUsb->getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), (uint8_t*) buf);
|
||||||
p->lowspeed = lowspeed;
|
|
||||||
|
// Restore p->epinfo
|
||||||
// Get device descriptor
|
p->epinfo = oldep_ptr;
|
||||||
rcode = pUsb->getDevDescr( 0, 0, sizeof(USB_DEVICE_DESCRIPTOR), (uint8_t*)buf );
|
|
||||||
|
if (rcode)
|
||||||
// Restore p->epinfo
|
goto FailGetDevDescr;
|
||||||
p->epinfo = oldep_ptr;
|
|
||||||
|
if (((USB_DEVICE_DESCRIPTOR*) buf)->idVendor != PL_VID && ((USB_DEVICE_DESCRIPTOR*) buf)->idProduct != PL_PID)
|
||||||
if( rcode )
|
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
|
||||||
goto FailGetDevDescr;
|
|
||||||
|
// Save type of PL chip
|
||||||
if (((USB_DEVICE_DESCRIPTOR*)buf)->idVendor != PL_VID && ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct != PL_PID ) {
|
wPLType = ((USB_DEVICE_DESCRIPTOR*) buf)->bcdDevice;
|
||||||
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
|
|
||||||
}
|
// Allocate new address according to device class
|
||||||
|
bAddress = addrPool.AllocAddress(parent, false, port);
|
||||||
/* determine chip variant */
|
|
||||||
|
if (!bAddress)
|
||||||
if (((USB_DEVICE_DESCRIPTOR*)buf)->bDeviceClass == 0x02 ) {
|
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
|
||||||
pltype = type_0;
|
|
||||||
}
|
// Extract Max Packet Size from the device descriptor
|
||||||
else if (((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0 == 0x40 ) {
|
epInfo[0].maxPktSize = (uint8_t) ((USB_DEVICE_DESCRIPTOR*) buf)->bMaxPacketSize0;
|
||||||
pltype = rev_HX;
|
|
||||||
}
|
// Assign new address to the device
|
||||||
else if (((USB_DEVICE_DESCRIPTOR*)buf)->bDeviceClass == 0x00) {
|
rcode = pUsb->setAddr(0, 0, bAddress);
|
||||||
pltype = type_1;
|
|
||||||
}
|
if (rcode) {
|
||||||
else if (((USB_DEVICE_DESCRIPTOR*)buf)->bDeviceClass == 0xff) {
|
p->lowspeed = false;
|
||||||
pltype = type_1;
|
addrPool.FreeAddress(bAddress);
|
||||||
}
|
bAddress = 0;
|
||||||
|
USBTRACE2("setAddr:", rcode);
|
||||||
// Allocate new address according to device class
|
return rcode;
|
||||||
bAddress = addrPool.AllocAddress(parent, false, port);
|
}
|
||||||
|
|
||||||
if (!bAddress)
|
USBTRACE2("Addr:", bAddress);
|
||||||
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
|
|
||||||
|
p->lowspeed = false;
|
||||||
// Extract Max Packet Size from the device descriptor
|
|
||||||
epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0;
|
p = addrPool.GetUsbDevicePtr(bAddress);
|
||||||
|
|
||||||
// Assign new address to the device
|
if (!p)
|
||||||
rcode = pUsb->setAddr( 0, 0, bAddress );
|
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||||
|
|
||||||
if (rcode)
|
p->lowspeed = lowspeed;
|
||||||
{
|
|
||||||
p->lowspeed = false;
|
num_of_conf = ((USB_DEVICE_DESCRIPTOR*) buf)->bNumConfigurations;
|
||||||
addrPool.FreeAddress(bAddress);
|
|
||||||
bAddress = 0;
|
// Assign epInfo to epinfo pointer
|
||||||
USBTRACE2("setAddr:",rcode);
|
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
|
||||||
return rcode;
|
|
||||||
}
|
if (rcode)
|
||||||
|
goto FailSetDevTblEntry;
|
||||||
USBTRACE2("Addr:", bAddress);
|
|
||||||
|
USBTRACE2("NC:", num_of_conf);
|
||||||
p->lowspeed = false;
|
|
||||||
|
for (uint8_t i = 0; i < num_of_conf; i++) {
|
||||||
p = addrPool.GetUsbDevicePtr(bAddress);
|
HexDumper<USBReadParser, uint16_t, uint16_t> HexDump;
|
||||||
|
ConfigDescParser < 0xFF, 0, 0, CP_MASK_COMPARE_CLASS> confDescrParser(this);
|
||||||
if (!p)
|
|
||||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump);
|
||||||
|
|
||||||
p->lowspeed = lowspeed;
|
if (rcode)
|
||||||
|
goto FailGetConfDescr;
|
||||||
num_of_conf = ((USB_DEVICE_DESCRIPTOR*)buf)->bNumConfigurations;
|
|
||||||
|
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
|
||||||
// Assign epInfo to epinfo pointer
|
|
||||||
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
|
if (rcode)
|
||||||
|
goto FailGetConfDescr;
|
||||||
if (rcode)
|
|
||||||
goto FailSetDevTblEntry;
|
if (bNumEP > 1)
|
||||||
|
break;
|
||||||
USBTRACE2("NC:", num_of_conf);
|
} // for
|
||||||
|
|
||||||
for( uint8_t i=0; i<num_of_conf; i++ )
|
if (bNumEP < 2)
|
||||||
{
|
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
|
||||||
//HexDumper<USBReadParser, uint16_t, uint16_t> HexDump;
|
|
||||||
ConfigDescParser<0xFF, 0, 0, CP_MASK_COMPARE_CLASS> confDescrParser(this);
|
// Assign epInfo to epinfo pointer
|
||||||
|
rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
|
||||||
//rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump);
|
|
||||||
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
|
USBTRACE2("Conf:", bConfNum);
|
||||||
|
|
||||||
if (bNumEP > 1)
|
// Set Configuration Value
|
||||||
break;
|
rcode = pUsb->setConf(bAddress, 0, bConfNum);
|
||||||
} // for
|
|
||||||
|
if (rcode)
|
||||||
if ( bNumEP < 2 )
|
goto FailSetConfDescr;
|
||||||
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
|
|
||||||
|
rcode = pAsync->OnInit(this);
|
||||||
// Assign epInfo to epinfo pointer
|
|
||||||
rcode = pUsb->setEpInfoEntry( bAddress, bNumEP, epInfo );
|
if (rcode)
|
||||||
|
goto FailOnInit;
|
||||||
USBTRACE2("Conf:", bConfNum);
|
|
||||||
|
USBTRACE("PL configured\r\n");
|
||||||
// Set Configuration Value
|
|
||||||
rcode = pUsb->setConf(bAddress, 0, bConfNum);
|
bPollEnable = true;
|
||||||
|
return 0;
|
||||||
if (rcode)
|
|
||||||
goto FailSetConfDescr;
|
FailGetDevDescr:
|
||||||
|
USBTRACE("getDevDescr:");
|
||||||
#if defined(PL2303_COMPAT)
|
goto Fail;
|
||||||
/* shamanic dance - sending Prolific init data as-is */
|
|
||||||
vendorRead( 0x84, 0x84, 0, buf );
|
FailSetDevTblEntry:
|
||||||
vendorWrite( 0x04, 0x04, 0 );
|
USBTRACE("setDevTblEn:");
|
||||||
vendorRead( 0x84, 0x84, 0, buf );
|
goto Fail;
|
||||||
vendorRead( 0x83, 0x83, 0, buf );
|
|
||||||
vendorRead( 0x84, 0x84, 0, buf );
|
FailGetConfDescr:
|
||||||
vendorWrite( 0x04, 0x04, 1 );
|
USBTRACE("getConf:");
|
||||||
vendorRead( 0x84, 0x84, 0, buf);
|
goto Fail;
|
||||||
vendorRead( 0x83, 0x83, 0, buf);
|
|
||||||
vendorWrite( 0, 0, 1 );
|
FailSetConfDescr:
|
||||||
vendorWrite( 1, 0, 0 );
|
USBTRACE("setConf:");
|
||||||
if ( pltype == rev_HX ) {
|
goto Fail;
|
||||||
vendorWrite( 2, 0, 0x44 );
|
|
||||||
vendorWrite( 0x06, 0x06, 0 ); //from W7 init
|
FailOnInit:
|
||||||
}
|
USBTRACE("OnInit:");
|
||||||
else {
|
goto Fail;
|
||||||
vendorWrite( 2, 0, 0x24 );
|
|
||||||
}
|
Fail:
|
||||||
/* shamanic dance end */
|
PrintHex<uint8_t > (rcode, 0x80);
|
||||||
#endif
|
Notify(PSTR("\r\n"), 0x80);
|
||||||
|
//Serial.println(rcode, HEX);
|
||||||
/* calling post-init callback */
|
Release();
|
||||||
rcode = pAsync->OnInit(this);
|
return rcode;
|
||||||
|
}
|
||||||
if (rcode)
|
|
||||||
goto FailOnInit;
|
//uint8_t PL::Poll()
|
||||||
|
//{
|
||||||
USBTRACE("PL configured\r\n");
|
// uint8_t rcode = 0;
|
||||||
|
//
|
||||||
//bPollEnable = true;
|
// //if (!bPollEnable)
|
||||||
ready = true;
|
// // return 0;
|
||||||
return 0;
|
//
|
||||||
|
// //if (qNextPollTime <= millis())
|
||||||
FailGetDevDescr:
|
// //{
|
||||||
USBTRACE("getDevDescr:");
|
// // Serial.println(bAddress, HEX);
|
||||||
goto Fail;
|
//
|
||||||
|
// // qNextPollTime = millis() + 100;
|
||||||
FailSetDevTblEntry:
|
// //}
|
||||||
USBTRACE("setDevTblEn:");
|
// return rcode;
|
||||||
goto Fail;
|
//}
|
||||||
|
|
||||||
FailGetConfDescr:
|
|
||||||
USBTRACE("getConf:");
|
|
||||||
goto Fail;
|
|
||||||
|
|
||||||
FailSetConfDescr:
|
|
||||||
USBTRACE("setConf:");
|
|
||||||
goto Fail;
|
|
||||||
|
|
||||||
FailSetControlLineState:
|
|
||||||
USBTRACE("SetControlLineState:");
|
|
||||||
goto Fail;
|
|
||||||
|
|
||||||
FailSetLineCoding:
|
|
||||||
USBTRACE("SetLineCoding:");
|
|
||||||
goto Fail;
|
|
||||||
|
|
||||||
FailOnInit:
|
|
||||||
USBTRACE("OnInit:");
|
|
||||||
goto Fail;
|
|
||||||
|
|
||||||
Fail:
|
|
||||||
Serial.println(rcode, HEX);
|
|
||||||
Release();
|
|
||||||
return rcode;
|
|
||||||
}
|
|
||||||
|
|
||||||
//uint8_t PL::Poll()
|
|
||||||
//{
|
|
||||||
// uint8_t rcode = 0;
|
|
||||||
//
|
|
||||||
// //if (!bPollEnable)
|
|
||||||
// // return 0;
|
|
||||||
//
|
|
||||||
// //if (qNextPollTime <= millis())
|
|
||||||
// //{
|
|
||||||
// // Serial.println(bAddress, HEX);
|
|
||||||
//
|
|
||||||
// // qNextPollTime = millis() + 100;
|
|
||||||
// //}
|
|
||||||
// return rcode;
|
|
||||||
//}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
330
cdcprolific.h
330
cdcprolific.h
|
@ -1,179 +1,153 @@
|
||||||
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||||
|
|
||||||
This software may be distributed and modified under the terms of the GNU
|
This software may be distributed and modified under the terms of the GNU
|
||||||
General Public License version 2 (GPL2) as published by the Free Software
|
General Public License version 2 (GPL2) as published by the Free Software
|
||||||
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
||||||
this file. Please note that GPL2 Section 2[b] requires that all works based
|
this file. Please note that GPL2 Section 2[b] requires that all works based
|
||||||
on this software must also be made publicly available under the terms of
|
on this software must also be made publicly available under the terms of
|
||||||
the GPL2 ("Copyleft").
|
the GPL2 ("Copyleft").
|
||||||
|
|
||||||
Contact information
|
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__
|
||||||
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <avr/pgmspace.h>
|
#include <avr/pgmspace.h>
|
||||||
#include "avrpins.h"
|
#include "avrpins.h"
|
||||||
#include "max3421e.h"
|
#include "max3421e.h"
|
||||||
#include "usbhost.h"
|
#include "usbhost.h"
|
||||||
#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
|
||||||
#include <WProgram.h>
|
#include <WProgram.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "printhex.h"
|
#include "printhex.h"
|
||||||
#include "hexdump.h"
|
#include "hexdump.h"
|
||||||
#include "message.h"
|
#include "message.h"
|
||||||
|
|
||||||
#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_PID ( 0x2303 || 0x0609 )
|
||||||
#define PL_VID 0x067B
|
|
||||||
#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
|
||||||
#define PROLIFIC_REV_1 0x0001
|
#define PROLIFIC_REV_1 0x0001
|
||||||
|
|
||||||
#define kXOnChar '\x11'
|
#define kXOnChar '\x11'
|
||||||
#define kXOffChar '\x13'
|
#define kXOffChar '\x13'
|
||||||
|
|
||||||
#define SPECIAL_SHIFT (5)
|
#define SPECIAL_SHIFT (5)
|
||||||
#define SPECIAL_MASK ((1<<SPECIAL_SHIFT) - 1)
|
#define SPECIAL_MASK ((1<<SPECIAL_SHIFT) - 1)
|
||||||
#define STATE_ALL ( PD_RS232_S_MASK | PD_S_MASK )
|
#define STATE_ALL ( PD_RS232_S_MASK | PD_S_MASK )
|
||||||
#define FLOW_RX_AUTO ( PD_RS232_A_RFR | PD_RS232_A_DTR | PD_RS232_A_RXO )
|
#define FLOW_RX_AUTO ( PD_RS232_A_RFR | PD_RS232_A_DTR | PD_RS232_A_RXO )
|
||||||
#define FLOW_TX_AUTO ( PD_RS232_A_CTS | PD_RS232_A_DSR | PD_RS232_A_TXO | PD_RS232_A_DCD )
|
#define FLOW_TX_AUTO ( PD_RS232_A_CTS | PD_RS232_A_DSR | PD_RS232_A_TXO | PD_RS232_A_DCD )
|
||||||
#define CAN_BE_AUTO ( FLOW_RX_AUTO | FLOW_TX_AUTO )
|
#define CAN_BE_AUTO ( FLOW_RX_AUTO | FLOW_TX_AUTO )
|
||||||
#define CAN_NOTIFY ( PD_RS232_N_MASK )
|
#define CAN_NOTIFY ( PD_RS232_N_MASK )
|
||||||
#define EXTERNAL_MASK ( PD_S_MASK | (PD_RS232_S_MASK & ~PD_RS232_S_LOOP) )
|
#define EXTERNAL_MASK ( PD_S_MASK | (PD_RS232_S_MASK & ~PD_RS232_S_LOOP) )
|
||||||
#define INTERNAL_DELAY ( PD_RS232_S_LOOP )
|
#define INTERNAL_DELAY ( PD_RS232_S_LOOP )
|
||||||
#define DEFAULT_AUTO ( PD_RS232_A_DTR | PD_RS232_A_RFR | PD_RS232_A_CTS | PD_RS232_A_DSR )
|
#define DEFAULT_AUTO ( PD_RS232_A_DTR | PD_RS232_A_RFR | PD_RS232_A_CTS | PD_RS232_A_DSR )
|
||||||
#define DEFAULT_NOTIFY 0x00
|
#define DEFAULT_NOTIFY 0x00
|
||||||
#define DEFAULT_STATE ( PD_S_TX_ENABLE | PD_S_RX_ENABLE | PD_RS232_A_TXO | PD_RS232_A_RXO )
|
#define DEFAULT_STATE ( PD_S_TX_ENABLE | PD_S_RX_ENABLE | PD_RS232_A_TXO | PD_RS232_A_RXO )
|
||||||
|
|
||||||
#define CONTINUE_SEND 1
|
#define CONTINUE_SEND 1
|
||||||
#define PAUSE_SEND 2
|
#define PAUSE_SEND 2
|
||||||
|
|
||||||
#define kRxAutoFlow ((UInt32)( PD_RS232_A_RFR | PD_RS232_A_DTR | PD_RS232_A_RXO ))
|
#define kRxAutoFlow ((UInt32)( PD_RS232_A_RFR | PD_RS232_A_DTR | PD_RS232_A_RXO ))
|
||||||
#define kTxAutoFlow ((UInt32)( PD_RS232_A_CTS | PD_RS232_A_DSR | PD_RS232_A_TXO | PD_RS232_A_DCD ))
|
#define kTxAutoFlow ((UInt32)( PD_RS232_A_CTS | PD_RS232_A_DSR | PD_RS232_A_TXO | PD_RS232_A_DCD ))
|
||||||
#define kControl_StateMask ((UInt32)( PD_RS232_S_CTS | PD_RS232_S_DSR | PD_RS232_S_CAR | PD_RS232_S_RI ))
|
#define kControl_StateMask ((UInt32)( PD_RS232_S_CTS | PD_RS232_S_DSR | PD_RS232_S_CAR | PD_RS232_S_RI ))
|
||||||
#define kRxQueueState ((UInt32)( PD_S_RXQ_EMPTY | PD_S_RXQ_LOW_WATER | PD_S_RXQ_HIGH_WATER | PD_S_RXQ_FULL ))
|
#define kRxQueueState ((UInt32)( PD_S_RXQ_EMPTY | PD_S_RXQ_LOW_WATER | PD_S_RXQ_HIGH_WATER | PD_S_RXQ_FULL ))
|
||||||
#define kTxQueueState ((UInt32)( PD_S_TXQ_EMPTY | PD_S_TXQ_LOW_WATER | PD_S_TXQ_HIGH_WATER | PD_S_TXQ_FULL ))
|
#define kTxQueueState ((UInt32)( PD_S_TXQ_EMPTY | PD_S_TXQ_LOW_WATER | PD_S_TXQ_HIGH_WATER | PD_S_TXQ_FULL ))
|
||||||
|
|
||||||
#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 kBreakError 0x04
|
||||||
#define kStateTransientMask 0x74
|
#define kFrameError 0x10
|
||||||
#define kBreakError 0x04
|
#define kParityError 0x20
|
||||||
#define kFrameError 0x10
|
#define kOverrunError 0x40
|
||||||
#define kParityError 0x20
|
|
||||||
#define kOverrunError 0x40
|
#define kCTS 0x80
|
||||||
|
#define kDSR 0x02
|
||||||
#define kCTS 0x80
|
#define kRI 0x08
|
||||||
#define kDSR 0x02
|
#define kDCD 0x01
|
||||||
#define kRI 0x08
|
#define kHandshakeInMask ((UInt32)( PD_RS232_S_CTS | PD_RS232_S_DSR | PD_RS232_S_CAR | PD_RS232_S_RI ))
|
||||||
#define kDCD 0x01
|
|
||||||
#define kHandshakeInMask ((UInt32)( PD_RS232_S_CTS | PD_RS232_S_DSR | PD_RS232_S_CAR | PD_RS232_S_RI ))
|
#define VENDOR_WRITE_REQUEST_TYPE 0x40
|
||||||
|
#define VENDOR_WRITE_REQUEST 0x01
|
||||||
#define VENDOR_WRITE_REQUEST_TYPE 0x40
|
|
||||||
#define VENDOR_WRITE_REQUEST 0x01
|
#define VENDOR_READ_REQUEST_TYPE 0xc0
|
||||||
|
#define VENDOR_READ_REQUEST 0x01
|
||||||
#define VENDOR_READ_REQUEST_TYPE 0xc0
|
|
||||||
#define VENDOR_READ_REQUEST 0x01
|
// Device Configuration Registers (DCR0, DCR1, DCR2)
|
||||||
|
#define SET_DCR0 0x00
|
||||||
// Device Configuration Registers (DCR0, DCR1, DCR2)
|
#define GET_DCR0 0x80
|
||||||
#define SET_DCR0 0x00
|
#define DCR0_INIT 0x01
|
||||||
#define GET_DCR0 0x80
|
#define DCR0_INIT_H 0x41
|
||||||
#define DCR0_INIT 0x01
|
#define DCR0_INIT_X 0x61
|
||||||
#define DCR0_INIT_H 0x41
|
|
||||||
#define DCR0_INIT_X 0x61
|
#define SET_DCR1 0x01
|
||||||
|
#define GET_DCR1 0x81
|
||||||
#define SET_DCR1 0x01
|
#define DCR1_INIT_H 0x80
|
||||||
#define GET_DCR1 0x81
|
#define DCR1_INIT_X 0x00
|
||||||
#define DCR1_INIT_H 0x80
|
|
||||||
#define DCR1_INIT_X 0x00
|
#define SET_DCR2 0x02
|
||||||
|
#define GET_DCR2 0x82
|
||||||
#define SET_DCR2 0x02
|
#define DCR2_INIT_H 0x24
|
||||||
#define GET_DCR2 0x82
|
#define DCR2_INIT_X 0x44
|
||||||
#define DCR2_INIT_H 0x24
|
|
||||||
#define DCR2_INIT_X 0x44
|
// On-chip Data Buffers:
|
||||||
|
#define RESET_DOWNSTREAM_DATA_PIPE 0x08
|
||||||
// On-chip Data Buffers:
|
#define RESET_UPSTREAM_DATA_PIPE 0x09
|
||||||
#define RESET_DOWNSTREAM_DATA_PIPE 0x08
|
|
||||||
#define RESET_UPSTREAM_DATA_PIPE 0x09
|
enum pl2303_type {
|
||||||
|
unknown,
|
||||||
enum pl2303_type
|
type_1, /* don't know the difference between type 0 and */
|
||||||
{
|
rev_X, /* type 1, until someone from prolific tells us... */
|
||||||
unknown,
|
rev_HX, /* HX version of the pl2303 chip */
|
||||||
type_0,
|
rev_H
|
||||||
type_1, /* don't know the difference between type 0 and */
|
};
|
||||||
rev_X, /* type 1, until someone from prolific tells us... */
|
|
||||||
rev_HX, /* HX version of the pl2303 chip */
|
|
||||||
rev_H
|
#define PL_MAX_ENDPOINTS 4
|
||||||
};
|
|
||||||
|
class PL2303 : public ACM {
|
||||||
|
uint16_t wPLType; // Type of chip
|
||||||
#define PL_MAX_ENDPOINTS 4
|
|
||||||
|
public:
|
||||||
//class PL2303;
|
PL2303(USB *pusb, CDCAsyncOper *pasync);
|
||||||
|
|
||||||
class PL2303 : public ACM
|
// USBDeviceConfig implementation
|
||||||
{
|
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
|
||||||
|
//virtual uint8_t Release();
|
||||||
//uint16_t wPLType; // Type of chip
|
//virtual uint8_t Poll();
|
||||||
|
//virtual uint8_t GetAddress() { return bAddress; };
|
||||||
|
|
||||||
public:
|
//// UsbConfigXtracter implementation
|
||||||
PL2303(USB *pusb, CDCAsyncOper *pasync);
|
//virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
|
||||||
|
};
|
||||||
// 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);
|
|
||||||
|
|
||||||
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__
|
432
confdescparser.h
432
confdescparser.h
|
@ -1,221 +1,213 @@
|
||||||
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||||
|
|
||||||
This software may be distributed and modified under the terms of the GNU
|
This software may be distributed and modified under the terms of the GNU
|
||||||
General Public License version 2 (GPL2) as published by the Free Software
|
General Public License version 2 (GPL2) as published by the Free Software
|
||||||
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
||||||
this file. Please note that GPL2 Section 2[b] requires that all works based
|
this file. Please note that GPL2 Section 2[b] requires that all works based
|
||||||
on this software must also be made publicly available under the terms of
|
on this software must also be made publicly available under the terms of
|
||||||
the GPL2 ("Copyleft").
|
the GPL2 ("Copyleft").
|
||||||
|
|
||||||
Contact information
|
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__
|
||||||
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
|
||||||
#include <avr/pgmspace.h>
|
#include <avr/pgmspace.h>
|
||||||
#include "printhex.h"
|
#include "printhex.h"
|
||||||
#include "hexdump.h"
|
#include "hexdump.h"
|
||||||
#include "message.h"
|
#include "message.h"
|
||||||
#include "parsetools.h"
|
#include "parsetools.h"
|
||||||
|
|
||||||
//#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
|
#define CP_MASK_COMPARE_SUBCLASS 2
|
||||||
#define CP_MASK_COMPARE_SUBCLASS 2
|
#define CP_MASK_COMPARE_PROTOCOL 4
|
||||||
#define CP_MASK_COMPARE_PROTOCOL 4
|
#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) :
|
theXtractor(xtractor),
|
||||||
stateParseDescr(0),
|
stateParseDescr(0),
|
||||||
dscrLen(0),
|
dscrLen(0),
|
||||||
dscrType(0),
|
dscrType(0) {
|
||||||
theXtractor(xtractor)
|
theBuffer.pValue = varBuffer;
|
||||||
{
|
valParser.Initialize(&theBuffer);
|
||||||
theBuffer.pValue = varBuffer;
|
theSkipper.Initialize(&theBuffer);
|
||||||
valParser.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>
|
||||||
|
void ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::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>
|
uint16_t cntdn = (uint16_t) len;
|
||||||
void ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset)
|
uint8_t *p = (uint8_t*) pbuf;
|
||||||
{
|
|
||||||
uint16_t cntdn = (uint16_t)len;
|
while (cntdn)
|
||||||
uint8_t *p = (uint8_t*)pbuf;
|
if (!ParseDescriptor(&p, &cntdn))
|
||||||
|
return;
|
||||||
while(cntdn)
|
}
|
||||||
if (!ParseDescriptor(&p, &cntdn))
|
|
||||||
return;
|
/* 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 */
|
||||||
/* Parser for the configuration descriptor. Takes values for class, subclass, protocol fields in interface descriptor and
|
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
|
||||||
compare masks for them. When the match is found, calls EndpointXtract passing buffer containing endpoint descriptor */
|
bool ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::ParseDescriptor(uint8_t **pp, uint16_t *pcntdn) {
|
||||||
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
|
switch (stateParseDescr) {
|
||||||
bool ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::ParseDescriptor(uint8_t **pp, uint16_t *pcntdn)
|
case 0:
|
||||||
{
|
theBuffer.valueSize = 2;
|
||||||
switch (stateParseDescr)
|
valParser.Initialize(&theBuffer);
|
||||||
{
|
stateParseDescr = 1;
|
||||||
case 0:
|
case 1:
|
||||||
theBuffer.valueSize = 2;
|
if (!valParser.Parse(pp, pcntdn))
|
||||||
valParser.Initialize(&theBuffer);
|
return false;
|
||||||
stateParseDescr = 1;
|
dscrLen = *((uint8_t*) theBuffer.pValue);
|
||||||
case 1:
|
dscrType = *((uint8_t*) theBuffer.pValue + 1);
|
||||||
if (!valParser.Parse(pp, pcntdn))
|
stateParseDescr = 2;
|
||||||
return false;
|
case 2:
|
||||||
dscrLen = *((uint8_t*)theBuffer.pValue);
|
// This is a sort of hack. Assuming that two bytes are allready in the buffer
|
||||||
dscrType = *((uint8_t*)theBuffer.pValue + 1);
|
// the pointer is positioned two bytes ahead in order for the rest of descriptor
|
||||||
stateParseDescr = 2;
|
// to be read right after the size and the type fields.
|
||||||
case 2:
|
// This should be used carefuly. varBuffer should be used directly to handle data
|
||||||
// This is a sort of hack. Assuming that two bytes are already in the buffer
|
// in the buffer.
|
||||||
// the pointer is positioned two bytes ahead in order for the rest of descriptor
|
theBuffer.pValue = varBuffer + 2;
|
||||||
// to be read right after the size and the type fields.
|
stateParseDescr = 3;
|
||||||
// This should be used carefuly. varBuffer should be used directly to handle data
|
case 3:
|
||||||
// in the buffer.
|
switch (dscrType) {
|
||||||
theBuffer.pValue = varBuffer + 2;
|
case USB_DESCRIPTOR_INTERFACE:
|
||||||
stateParseDescr = 3;
|
isGoodInterface = false;
|
||||||
case 3:
|
case USB_DESCRIPTOR_CONFIGURATION:
|
||||||
switch (dscrType)
|
theBuffer.valueSize = sizeof (USB_CONFIGURATION_DESCRIPTOR) - 2;
|
||||||
{
|
break;
|
||||||
case USB_DESCRIPTOR_INTERFACE:
|
case USB_DESCRIPTOR_ENDPOINT:
|
||||||
isGoodInterface = false;
|
theBuffer.valueSize = sizeof (USB_ENDPOINT_DESCRIPTOR) - 2;
|
||||||
case USB_DESCRIPTOR_CONFIGURATION:
|
break;
|
||||||
theBuffer.valueSize = sizeof(USB_CONFIGURATION_DESCRIPTOR) - 2;
|
case HID_DESCRIPTOR_HID:
|
||||||
break;
|
theBuffer.valueSize = dscrLen - 2;
|
||||||
case USB_DESCRIPTOR_ENDPOINT:
|
break;
|
||||||
theBuffer.valueSize = sizeof(USB_ENDPOINT_DESCRIPTOR) - 2;
|
}
|
||||||
break;
|
valParser.Initialize(&theBuffer);
|
||||||
case HID_DESCRIPTOR_HID:
|
stateParseDescr = 4;
|
||||||
theBuffer.valueSize = dscrLen - 2;
|
case 4:
|
||||||
break;
|
switch (dscrType) {
|
||||||
}
|
case USB_DESCRIPTOR_CONFIGURATION:
|
||||||
valParser.Initialize(&theBuffer);
|
if (!valParser.Parse(pp, pcntdn))
|
||||||
stateParseDescr = 4;
|
return false;
|
||||||
case 4:
|
confValue = ((USB_CONFIGURATION_DESCRIPTOR*) varBuffer)->bConfigurationValue;
|
||||||
switch (dscrType)
|
break;
|
||||||
{
|
case USB_DESCRIPTOR_INTERFACE:
|
||||||
case USB_DESCRIPTOR_CONFIGURATION:
|
if (!valParser.Parse(pp, pcntdn))
|
||||||
if (!valParser.Parse(pp, pcntdn))
|
return false;
|
||||||
return false;
|
if ((MASK & CP_MASK_COMPARE_CLASS) && ((USB_INTERFACE_DESCRIPTOR*) varBuffer)->bInterfaceClass != CLASS_ID)
|
||||||
confValue = ((USB_CONFIGURATION_DESCRIPTOR*)varBuffer)->bConfigurationValue;
|
break;
|
||||||
break;
|
if ((MASK & CP_MASK_COMPARE_SUBCLASS) && ((USB_INTERFACE_DESCRIPTOR*) varBuffer)->bInterfaceSubClass != SUBCLASS_ID)
|
||||||
case USB_DESCRIPTOR_INTERFACE:
|
break;
|
||||||
if (!valParser.Parse(pp, pcntdn))
|
if ((MASK & CP_MASK_COMPARE_PROTOCOL) && ((USB_INTERFACE_DESCRIPTOR*) varBuffer)->bInterfaceProtocol != PROTOCOL_ID)
|
||||||
return false;
|
break;
|
||||||
if ((MASK & CP_MASK_COMPARE_CLASS) && ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bInterfaceClass != CLASS_ID)
|
|
||||||
break;
|
isGoodInterface = true;
|
||||||
if ((MASK & CP_MASK_COMPARE_SUBCLASS) && ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bInterfaceSubClass != SUBCLASS_ID)
|
ifaceNumber = ((USB_INTERFACE_DESCRIPTOR*) varBuffer)->bInterfaceNumber;
|
||||||
break;
|
ifaceAltSet = ((USB_INTERFACE_DESCRIPTOR*) varBuffer)->bAlternateSetting;
|
||||||
if ((MASK & CP_MASK_COMPARE_PROTOCOL) && ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bInterfaceProtocol != PROTOCOL_ID)
|
protoValue = ((USB_INTERFACE_DESCRIPTOR*) varBuffer)->bInterfaceProtocol;
|
||||||
break;
|
break;
|
||||||
|
case USB_DESCRIPTOR_ENDPOINT:
|
||||||
isGoodInterface = true;
|
if (!valParser.Parse(pp, pcntdn))
|
||||||
ifaceNumber = ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bInterfaceNumber;
|
return false;
|
||||||
ifaceAltSet = ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bAlternateSetting;
|
if (isGoodInterface)
|
||||||
protoValue = ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bInterfaceProtocol;
|
if (theXtractor)
|
||||||
break;
|
theXtractor->EndpointXtract(confValue, ifaceNumber, ifaceAltSet, protoValue, (USB_ENDPOINT_DESCRIPTOR*) varBuffer);
|
||||||
case USB_DESCRIPTOR_ENDPOINT:
|
break;
|
||||||
if (!valParser.Parse(pp, pcntdn))
|
//case HID_DESCRIPTOR_HID:
|
||||||
return false;
|
// if (!valParser.Parse(pp, pcntdn))
|
||||||
if (isGoodInterface)
|
// return false;
|
||||||
if (theXtractor)
|
// PrintHidDescriptor((const USB_HID_DESCRIPTOR*)varBuffer);
|
||||||
theXtractor->EndpointXtract(confValue, ifaceNumber, ifaceAltSet, protoValue, (USB_ENDPOINT_DESCRIPTOR*)varBuffer);
|
// break;
|
||||||
break;
|
default:
|
||||||
//case HID_DESCRIPTOR_HID:
|
if (!theSkipper.Skip(pp, pcntdn, dscrLen - 2))
|
||||||
// if (!valParser.Parse(pp, pcntdn))
|
return false;
|
||||||
// return false;
|
}
|
||||||
// PrintHidDescriptor((const USB_HID_DESCRIPTOR*)varBuffer);
|
theBuffer.pValue = varBuffer;
|
||||||
// break;
|
stateParseDescr = 0;
|
||||||
default:
|
}
|
||||||
if (!theSkipper.Skip(pp, pcntdn, dscrLen-2))
|
return true;
|
||||||
return false;
|
}
|
||||||
}
|
|
||||||
theBuffer.pValue = varBuffer;
|
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
|
||||||
stateParseDescr = 0;
|
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);
|
||||||
return true;
|
Notify(PSTR("bDescLength:\t\t"), 0x80);
|
||||||
}
|
PrintHex<uint8_t > (pDesc->bLength, 0x80);
|
||||||
|
|
||||||
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
|
Notify(PSTR("\r\nbDescriptorType:\t"), 0x80);
|
||||||
void ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc)
|
PrintHex<uint8_t > (pDesc->bDescriptorType, 0x80);
|
||||||
{
|
|
||||||
Notify(PSTR("\r\n\r\nHID Descriptor:\r\n"));
|
Notify(PSTR("\r\nbcdHID:\t\t\t"), 0x80);
|
||||||
Notify(PSTR("bDescLength:\t\t"));
|
PrintHex<uint16_t > (pDesc->bcdHID, 0x80);
|
||||||
PrintHex<uint8_t>(pDesc->bLength);
|
|
||||||
|
Notify(PSTR("\r\nbCountryCode:\t\t"), 0x80);
|
||||||
Notify(PSTR("\r\nbDescriptorType:\t"));
|
PrintHex<uint8_t > (pDesc->bCountryCode, 0x80);
|
||||||
PrintHex<uint8_t>(pDesc->bDescriptorType);
|
|
||||||
|
Notify(PSTR("\r\nbNumDescriptors:\t"), 0x80);
|
||||||
Notify(PSTR("\r\nbcdHID:\t\t\t"));
|
PrintHex<uint8_t > (pDesc->bNumDescriptors, 0x80);
|
||||||
PrintHex<uint16_t>(pDesc->bcdHID);
|
|
||||||
|
//Notify(PSTR("\r\nbDescrType:\t\t"));
|
||||||
Notify(PSTR("\r\nbCountryCode:\t\t"));
|
//PrintHex<uint8_t>(pDesc->bDescrType);
|
||||||
PrintHex<uint8_t>(pDesc->bCountryCode);
|
//
|
||||||
|
//Notify(PSTR("\r\nwDescriptorLength:\t"));
|
||||||
Notify(PSTR("\r\nbNumDescriptors:\t"));
|
//PrintHex<uint16_t>(pDesc->wDescriptorLength);
|
||||||
PrintHex<uint8_t>(pDesc->bNumDescriptors);
|
|
||||||
|
for (uint8_t i = 0; i < pDesc->bNumDescriptors; i++) {
|
||||||
//Notify(PSTR("\r\nbDescrType:\t\t"));
|
HID_CLASS_DESCRIPTOR_LEN_AND_TYPE *pLT = (HID_CLASS_DESCRIPTOR_LEN_AND_TYPE*)&(pDesc->bDescrType);
|
||||||
//PrintHex<uint8_t>(pDesc->bDescrType);
|
|
||||||
//
|
Notify(PSTR("\r\nbDescrType:\t\t"), 0x80);
|
||||||
//Notify(PSTR("\r\nwDescriptorLength:\t"));
|
PrintHex<uint8_t > (pLT[i].bDescrType, 0x80);
|
||||||
//PrintHex<uint16_t>(pDesc->wDescriptorLength);
|
|
||||||
|
Notify(PSTR("\r\nwDescriptorLength:\t"), 0x80);
|
||||||
for (uint8_t i=0; i<pDesc->bNumDescriptors; i++)
|
PrintHex<uint16_t > (pLT[i].wDescriptorLength, 0x80);
|
||||||
{
|
}
|
||||||
HID_CLASS_DESCRIPTOR_LEN_AND_TYPE *pLT = (HID_CLASS_DESCRIPTOR_LEN_AND_TYPE*)&(pDesc->bDescrType);
|
Notify(PSTR("\r\n"), 0x80);
|
||||||
|
}
|
||||||
Notify(PSTR("\r\nbDescrType:\t\t"));
|
|
||||||
PrintHex<uint8_t>(pLT[i].bDescrType);
|
|
||||||
|
|
||||||
Notify(PSTR("\r\nwDescriptorLength:\t"));
|
|
||||||
PrintHex<uint16_t>(pLT[i].wDescriptorLength);
|
|
||||||
}
|
|
||||||
Notify(PSTR("\r\n"));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endif // __CONFDESCPARSER_H__
|
#endif // __CONFDESCPARSER_H__
|
680
gpl2.txt
680
gpl2.txt
|
@ -1,340 +1,340 @@
|
||||||
GNU GENERAL PUBLIC LICENSE
|
GNU GENERAL PUBLIC LICENSE
|
||||||
Version 2, June 1991
|
Version 2, June 1991
|
||||||
|
|
||||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
of this license document, but changing it is not allowed.
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
Preamble
|
Preamble
|
||||||
|
|
||||||
The licenses for most software are designed to take away your
|
The licenses for most software are designed to take away your
|
||||||
freedom to share and change it. By contrast, the GNU General Public
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
License is intended to guarantee your freedom to share and change free
|
License is intended to guarantee your freedom to share and change free
|
||||||
software--to make sure the software is free for all its users. This
|
software--to make sure the software is free for all its users. This
|
||||||
General Public License applies to most of the Free Software
|
General Public License applies to most of the Free Software
|
||||||
Foundation's software and to any other program whose authors commit to
|
Foundation's software and to any other program whose authors commit to
|
||||||
using it. (Some other Free Software Foundation software is covered by
|
using it. (Some other Free Software Foundation software is covered by
|
||||||
the GNU Library General Public License instead.) You can apply it to
|
the GNU Library General Public License instead.) You can apply it to
|
||||||
your programs, too.
|
your programs, too.
|
||||||
|
|
||||||
When we speak of free software, we are referring to freedom, not
|
When we speak of free software, we are referring to freedom, not
|
||||||
price. Our General Public Licenses are designed to make sure that you
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
have the freedom to distribute copies of free software (and charge for
|
have the freedom to distribute copies of free software (and charge for
|
||||||
this service if you wish), that you receive source code or can get it
|
this service if you wish), that you receive source code or can get it
|
||||||
if you want it, that you can change the software or use pieces of it
|
if you want it, that you can change the software or use pieces of it
|
||||||
in new free programs; and that you know you can do these things.
|
in new free programs; and that you know you can do these things.
|
||||||
|
|
||||||
To protect your rights, we need to make restrictions that forbid
|
To protect your rights, we need to make restrictions that forbid
|
||||||
anyone to deny you these rights or to ask you to surrender the rights.
|
anyone to deny you these rights or to ask you to surrender the rights.
|
||||||
These restrictions translate to certain responsibilities for you if you
|
These restrictions translate to certain responsibilities for you if you
|
||||||
distribute copies of the software, or if you modify it.
|
distribute copies of the software, or if you modify it.
|
||||||
|
|
||||||
For example, if you distribute copies of such a program, whether
|
For example, if you distribute copies of such a program, whether
|
||||||
gratis or for a fee, you must give the recipients all the rights that
|
gratis or for a fee, you must give the recipients all the rights that
|
||||||
you have. You must make sure that they, too, receive or can get the
|
you have. You must make sure that they, too, receive or can get the
|
||||||
source code. And you must show them these terms so they know their
|
source code. And you must show them these terms so they know their
|
||||||
rights.
|
rights.
|
||||||
|
|
||||||
We protect your rights with two steps: (1) copyright the software, and
|
We protect your rights with two steps: (1) copyright the software, and
|
||||||
(2) offer you this license which gives you legal permission to copy,
|
(2) offer you this license which gives you legal permission to copy,
|
||||||
distribute and/or modify the software.
|
distribute and/or modify the software.
|
||||||
|
|
||||||
Also, for each author's protection and ours, we want to make certain
|
Also, for each author's protection and ours, we want to make certain
|
||||||
that everyone understands that there is no warranty for this free
|
that everyone understands that there is no warranty for this free
|
||||||
software. If the software is modified by someone else and passed on, we
|
software. If the software is modified by someone else and passed on, we
|
||||||
want its recipients to know that what they have is not the original, so
|
want its recipients to know that what they have is not the original, so
|
||||||
that any problems introduced by others will not reflect on the original
|
that any problems introduced by others will not reflect on the original
|
||||||
authors' reputations.
|
authors' reputations.
|
||||||
|
|
||||||
Finally, any free program is threatened constantly by software
|
Finally, any free program is threatened constantly by software
|
||||||
patents. We wish to avoid the danger that redistributors of a free
|
patents. We wish to avoid the danger that redistributors of a free
|
||||||
program will individually obtain patent licenses, in effect making the
|
program will individually obtain patent licenses, in effect making the
|
||||||
program proprietary. To prevent this, we have made it clear that any
|
program proprietary. To prevent this, we have made it clear that any
|
||||||
patent must be licensed for everyone's free use or not licensed at all.
|
patent must be licensed for everyone's free use or not licensed at all.
|
||||||
|
|
||||||
The precise terms and conditions for copying, distribution and
|
The precise terms and conditions for copying, distribution and
|
||||||
modification follow.
|
modification follow.
|
||||||
|
|
||||||
GNU GENERAL PUBLIC LICENSE
|
GNU GENERAL PUBLIC LICENSE
|
||||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
0. This License applies to any program or other work which contains
|
0. This License applies to any program or other work which contains
|
||||||
a notice placed by the copyright holder saying it may be distributed
|
a notice placed by the copyright holder saying it may be distributed
|
||||||
under the terms of this General Public License. The "Program", below,
|
under the terms of this General Public License. The "Program", below,
|
||||||
refers to any such program or work, and a "work based on the Program"
|
refers to any such program or work, and a "work based on the Program"
|
||||||
means either the Program or any derivative work under copyright law:
|
means either the Program or any derivative work under copyright law:
|
||||||
that is to say, a work containing the Program or a portion of it,
|
that is to say, a work containing the Program or a portion of it,
|
||||||
either verbatim or with modifications and/or translated into another
|
either verbatim or with modifications and/or translated into another
|
||||||
language. (Hereinafter, translation is included without limitation in
|
language. (Hereinafter, translation is included without limitation in
|
||||||
the term "modification".) Each licensee is addressed as "you".
|
the term "modification".) Each licensee is addressed as "you".
|
||||||
|
|
||||||
Activities other than copying, distribution and modification are not
|
Activities other than copying, distribution and modification are not
|
||||||
covered by this License; they are outside its scope. The act of
|
covered by this License; they are outside its scope. The act of
|
||||||
running the Program is not restricted, and the output from the Program
|
running the Program is not restricted, and the output from the Program
|
||||||
is covered only if its contents constitute a work based on the
|
is covered only if its contents constitute a work based on the
|
||||||
Program (independent of having been made by running the Program).
|
Program (independent of having been made by running the Program).
|
||||||
Whether that is true depends on what the Program does.
|
Whether that is true depends on what the Program does.
|
||||||
|
|
||||||
1. You may copy and distribute verbatim copies of the Program's
|
1. You may copy and distribute verbatim copies of the Program's
|
||||||
source code as you receive it, in any medium, provided that you
|
source code as you receive it, in any medium, provided that you
|
||||||
conspicuously and appropriately publish on each copy an appropriate
|
conspicuously and appropriately publish on each copy an appropriate
|
||||||
copyright notice and disclaimer of warranty; keep intact all the
|
copyright notice and disclaimer of warranty; keep intact all the
|
||||||
notices that refer to this License and to the absence of any warranty;
|
notices that refer to this License and to the absence of any warranty;
|
||||||
and give any other recipients of the Program a copy of this License
|
and give any other recipients of the Program a copy of this License
|
||||||
along with the Program.
|
along with the Program.
|
||||||
|
|
||||||
You may charge a fee for the physical act of transferring a copy, and
|
You may charge a fee for the physical act of transferring a copy, and
|
||||||
you may at your option offer warranty protection in exchange for a fee.
|
you may at your option offer warranty protection in exchange for a fee.
|
||||||
|
|
||||||
2. You may modify your copy or copies of the Program or any portion
|
2. You may modify your copy or copies of the Program or any portion
|
||||||
of it, thus forming a work based on the Program, and copy and
|
of it, thus forming a work based on the Program, and copy and
|
||||||
distribute such modifications or work under the terms of Section 1
|
distribute such modifications or work under the terms of Section 1
|
||||||
above, provided that you also meet all of these conditions:
|
above, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
a) You must cause the modified files to carry prominent notices
|
a) You must cause the modified files to carry prominent notices
|
||||||
stating that you changed the files and the date of any change.
|
stating that you changed the files and the date of any change.
|
||||||
|
|
||||||
b) You must cause any work that you distribute or publish, that in
|
b) You must cause any work that you distribute or publish, that in
|
||||||
whole or in part contains or is derived from the Program or any
|
whole or in part contains or is derived from the Program or any
|
||||||
part thereof, to be licensed as a whole at no charge to all third
|
part thereof, to be licensed as a whole at no charge to all third
|
||||||
parties under the terms of this License.
|
parties under the terms of this License.
|
||||||
|
|
||||||
c) If the modified program normally reads commands interactively
|
c) If the modified program normally reads commands interactively
|
||||||
when run, you must cause it, when started running for such
|
when run, you must cause it, when started running for such
|
||||||
interactive use in the most ordinary way, to print or display an
|
interactive use in the most ordinary way, to print or display an
|
||||||
announcement including an appropriate copyright notice and a
|
announcement including an appropriate copyright notice and a
|
||||||
notice that there is no warranty (or else, saying that you provide
|
notice that there is no warranty (or else, saying that you provide
|
||||||
a warranty) and that users may redistribute the program under
|
a warranty) and that users may redistribute the program under
|
||||||
these conditions, and telling the user how to view a copy of this
|
these conditions, and telling the user how to view a copy of this
|
||||||
License. (Exception: if the Program itself is interactive but
|
License. (Exception: if the Program itself is interactive but
|
||||||
does not normally print such an announcement, your work based on
|
does not normally print such an announcement, your work based on
|
||||||
the Program is not required to print an announcement.)
|
the Program is not required to print an announcement.)
|
||||||
|
|
||||||
These requirements apply to the modified work as a whole. If
|
These requirements apply to the modified work as a whole. If
|
||||||
identifiable sections of that work are not derived from the Program,
|
identifiable sections of that work are not derived from the Program,
|
||||||
and can be reasonably considered independent and separate works in
|
and can be reasonably considered independent and separate works in
|
||||||
themselves, then this License, and its terms, do not apply to those
|
themselves, then this License, and its terms, do not apply to those
|
||||||
sections when you distribute them as separate works. But when you
|
sections when you distribute them as separate works. But when you
|
||||||
distribute the same sections as part of a whole which is a work based
|
distribute the same sections as part of a whole which is a work based
|
||||||
on the Program, the distribution of the whole must be on the terms of
|
on the Program, the distribution of the whole must be on the terms of
|
||||||
this License, whose permissions for other licensees extend to the
|
this License, whose permissions for other licensees extend to the
|
||||||
entire whole, and thus to each and every part regardless of who wrote it.
|
entire whole, and thus to each and every part regardless of who wrote it.
|
||||||
|
|
||||||
Thus, it is not the intent of this section to claim rights or contest
|
Thus, it is not the intent of this section to claim rights or contest
|
||||||
your rights to work written entirely by you; rather, the intent is to
|
your rights to work written entirely by you; rather, the intent is to
|
||||||
exercise the right to control the distribution of derivative or
|
exercise the right to control the distribution of derivative or
|
||||||
collective works based on the Program.
|
collective works based on the Program.
|
||||||
|
|
||||||
In addition, mere aggregation of another work not based on the Program
|
In addition, mere aggregation of another work not based on the Program
|
||||||
with the Program (or with a work based on the Program) on a volume of
|
with the Program (or with a work based on the Program) on a volume of
|
||||||
a storage or distribution medium does not bring the other work under
|
a storage or distribution medium does not bring the other work under
|
||||||
the scope of this License.
|
the scope of this License.
|
||||||
|
|
||||||
3. You may copy and distribute the Program (or a work based on it,
|
3. You may copy and distribute the Program (or a work based on it,
|
||||||
under Section 2) in object code or executable form under the terms of
|
under Section 2) in object code or executable form under the terms of
|
||||||
Sections 1 and 2 above provided that you also do one of the following:
|
Sections 1 and 2 above provided that you also do one of the following:
|
||||||
|
|
||||||
a) Accompany it with the complete corresponding machine-readable
|
a) Accompany it with the complete corresponding machine-readable
|
||||||
source code, which must be distributed under the terms of Sections
|
source code, which must be distributed under the terms of Sections
|
||||||
1 and 2 above on a medium customarily used for software interchange; or,
|
1 and 2 above on a medium customarily used for software interchange; or,
|
||||||
|
|
||||||
b) Accompany it with a written offer, valid for at least three
|
b) Accompany it with a written offer, valid for at least three
|
||||||
years, to give any third party, for a charge no more than your
|
years, to give any third party, for a charge no more than your
|
||||||
cost of physically performing source distribution, a complete
|
cost of physically performing source distribution, a complete
|
||||||
machine-readable copy of the corresponding source code, to be
|
machine-readable copy of the corresponding source code, to be
|
||||||
distributed under the terms of Sections 1 and 2 above on a medium
|
distributed under the terms of Sections 1 and 2 above on a medium
|
||||||
customarily used for software interchange; or,
|
customarily used for software interchange; or,
|
||||||
|
|
||||||
c) Accompany it with the information you received as to the offer
|
c) Accompany it with the information you received as to the offer
|
||||||
to distribute corresponding source code. (This alternative is
|
to distribute corresponding source code. (This alternative is
|
||||||
allowed only for noncommercial distribution and only if you
|
allowed only for noncommercial distribution and only if you
|
||||||
received the program in object code or executable form with such
|
received the program in object code or executable form with such
|
||||||
an offer, in accord with Subsection b above.)
|
an offer, in accord with Subsection b above.)
|
||||||
|
|
||||||
The source code for a work means the preferred form of the work for
|
The source code for a work means the preferred form of the work for
|
||||||
making modifications to it. For an executable work, complete source
|
making modifications to it. For an executable work, complete source
|
||||||
code means all the source code for all modules it contains, plus any
|
code means all the source code for all modules it contains, plus any
|
||||||
associated interface definition files, plus the scripts used to
|
associated interface definition files, plus the scripts used to
|
||||||
control compilation and installation of the executable. However, as a
|
control compilation and installation of the executable. However, as a
|
||||||
special exception, the source code distributed need not include
|
special exception, the source code distributed need not include
|
||||||
anything that is normally distributed (in either source or binary
|
anything that is normally distributed (in either source or binary
|
||||||
form) with the major components (compiler, kernel, and so on) of the
|
form) with the major components (compiler, kernel, and so on) of the
|
||||||
operating system on which the executable runs, unless that component
|
operating system on which the executable runs, unless that component
|
||||||
itself accompanies the executable.
|
itself accompanies the executable.
|
||||||
|
|
||||||
If distribution of executable or object code is made by offering
|
If distribution of executable or object code is made by offering
|
||||||
access to copy from a designated place, then offering equivalent
|
access to copy from a designated place, then offering equivalent
|
||||||
access to copy the source code from the same place counts as
|
access to copy the source code from the same place counts as
|
||||||
distribution of the source code, even though third parties are not
|
distribution of the source code, even though third parties are not
|
||||||
compelled to copy the source along with the object code.
|
compelled to copy the source along with the object code.
|
||||||
|
|
||||||
4. You may not copy, modify, sublicense, or distribute the Program
|
4. You may not copy, modify, sublicense, or distribute the Program
|
||||||
except as expressly provided under this License. Any attempt
|
except as expressly provided under this License. Any attempt
|
||||||
otherwise to copy, modify, sublicense or distribute the Program is
|
otherwise to copy, modify, sublicense or distribute the Program is
|
||||||
void, and will automatically terminate your rights under this License.
|
void, and will automatically terminate your rights under this License.
|
||||||
However, parties who have received copies, or rights, from you under
|
However, parties who have received copies, or rights, from you under
|
||||||
this License will not have their licenses terminated so long as such
|
this License will not have their licenses terminated so long as such
|
||||||
parties remain in full compliance.
|
parties remain in full compliance.
|
||||||
|
|
||||||
5. You are not required to accept this License, since you have not
|
5. You are not required to accept this License, since you have not
|
||||||
signed it. However, nothing else grants you permission to modify or
|
signed it. However, nothing else grants you permission to modify or
|
||||||
distribute the Program or its derivative works. These actions are
|
distribute the Program or its derivative works. These actions are
|
||||||
prohibited by law if you do not accept this License. Therefore, by
|
prohibited by law if you do not accept this License. Therefore, by
|
||||||
modifying or distributing the Program (or any work based on the
|
modifying or distributing the Program (or any work based on the
|
||||||
Program), you indicate your acceptance of this License to do so, and
|
Program), you indicate your acceptance of this License to do so, and
|
||||||
all its terms and conditions for copying, distributing or modifying
|
all its terms and conditions for copying, distributing or modifying
|
||||||
the Program or works based on it.
|
the Program or works based on it.
|
||||||
|
|
||||||
6. Each time you redistribute the Program (or any work based on the
|
6. Each time you redistribute the Program (or any work based on the
|
||||||
Program), the recipient automatically receives a license from the
|
Program), the recipient automatically receives a license from the
|
||||||
original licensor to copy, distribute or modify the Program subject to
|
original licensor to copy, distribute or modify the Program subject to
|
||||||
these terms and conditions. You may not impose any further
|
these terms and conditions. You may not impose any further
|
||||||
restrictions on the recipients' exercise of the rights granted herein.
|
restrictions on the recipients' exercise of the rights granted herein.
|
||||||
You are not responsible for enforcing compliance by third parties to
|
You are not responsible for enforcing compliance by third parties to
|
||||||
this License.
|
this License.
|
||||||
|
|
||||||
7. If, as a consequence of a court judgment or allegation of patent
|
7. If, as a consequence of a court judgment or allegation of patent
|
||||||
infringement or for any other reason (not limited to patent issues),
|
infringement or for any other reason (not limited to patent issues),
|
||||||
conditions are imposed on you (whether by court order, agreement or
|
conditions are imposed on you (whether by court order, agreement or
|
||||||
otherwise) that contradict the conditions of this License, they do not
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
excuse you from the conditions of this License. If you cannot
|
excuse you from the conditions of this License. If you cannot
|
||||||
distribute so as to satisfy simultaneously your obligations under this
|
distribute so as to satisfy simultaneously your obligations under this
|
||||||
License and any other pertinent obligations, then as a consequence you
|
License and any other pertinent obligations, then as a consequence you
|
||||||
may not distribute the Program at all. For example, if a patent
|
may not distribute the Program at all. For example, if a patent
|
||||||
license would not permit royalty-free redistribution of the Program by
|
license would not permit royalty-free redistribution of the Program by
|
||||||
all those who receive copies directly or indirectly through you, then
|
all those who receive copies directly or indirectly through you, then
|
||||||
the only way you could satisfy both it and this License would be to
|
the only way you could satisfy both it and this License would be to
|
||||||
refrain entirely from distribution of the Program.
|
refrain entirely from distribution of the Program.
|
||||||
|
|
||||||
If any portion of this section is held invalid or unenforceable under
|
If any portion of this section is held invalid or unenforceable under
|
||||||
any particular circumstance, the balance of the section is intended to
|
any particular circumstance, the balance of the section is intended to
|
||||||
apply and the section as a whole is intended to apply in other
|
apply and the section as a whole is intended to apply in other
|
||||||
circumstances.
|
circumstances.
|
||||||
|
|
||||||
It is not the purpose of this section to induce you to infringe any
|
It is not the purpose of this section to induce you to infringe any
|
||||||
patents or other property right claims or to contest validity of any
|
patents or other property right claims or to contest validity of any
|
||||||
such claims; this section has the sole purpose of protecting the
|
such claims; this section has the sole purpose of protecting the
|
||||||
integrity of the free software distribution system, which is
|
integrity of the free software distribution system, which is
|
||||||
implemented by public license practices. Many people have made
|
implemented by public license practices. Many people have made
|
||||||
generous contributions to the wide range of software distributed
|
generous contributions to the wide range of software distributed
|
||||||
through that system in reliance on consistent application of that
|
through that system in reliance on consistent application of that
|
||||||
system; it is up to the author/donor to decide if he or she is willing
|
system; it is up to the author/donor to decide if he or she is willing
|
||||||
to distribute software through any other system and a licensee cannot
|
to distribute software through any other system and a licensee cannot
|
||||||
impose that choice.
|
impose that choice.
|
||||||
|
|
||||||
This section is intended to make thoroughly clear what is believed to
|
This section is intended to make thoroughly clear what is believed to
|
||||||
be a consequence of the rest of this License.
|
be a consequence of the rest of this License.
|
||||||
|
|
||||||
8. If the distribution and/or use of the Program is restricted in
|
8. If the distribution and/or use of the Program is restricted in
|
||||||
certain countries either by patents or by copyrighted interfaces, the
|
certain countries either by patents or by copyrighted interfaces, the
|
||||||
original copyright holder who places the Program under this License
|
original copyright holder who places the Program under this License
|
||||||
may add an explicit geographical distribution limitation excluding
|
may add an explicit geographical distribution limitation excluding
|
||||||
those countries, so that distribution is permitted only in or among
|
those countries, so that distribution is permitted only in or among
|
||||||
countries not thus excluded. In such case, this License incorporates
|
countries not thus excluded. In such case, this License incorporates
|
||||||
the limitation as if written in the body of this License.
|
the limitation as if written in the body of this License.
|
||||||
|
|
||||||
9. The Free Software Foundation may publish revised and/or new versions
|
9. The Free Software Foundation may publish revised and/or new versions
|
||||||
of the General Public License from time to time. Such new versions will
|
of the General Public License from time to time. Such new versions will
|
||||||
be similar in spirit to the present version, but may differ in detail to
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
address new problems or concerns.
|
address new problems or concerns.
|
||||||
|
|
||||||
Each version is given a distinguishing version number. If the Program
|
Each version is given a distinguishing version number. If the Program
|
||||||
specifies a version number of this License which applies to it and "any
|
specifies a version number of this License which applies to it and "any
|
||||||
later version", you have the option of following the terms and conditions
|
later version", you have the option of following the terms and conditions
|
||||||
either of that version or of any later version published by the Free
|
either of that version or of any later version published by the Free
|
||||||
Software Foundation. If the Program does not specify a version number of
|
Software Foundation. If the Program does not specify a version number of
|
||||||
this License, you may choose any version ever published by the Free Software
|
this License, you may choose any version ever published by the Free Software
|
||||||
Foundation.
|
Foundation.
|
||||||
|
|
||||||
10. If you wish to incorporate parts of the Program into other free
|
10. If you wish to incorporate parts of the Program into other free
|
||||||
programs whose distribution conditions are different, write to the author
|
programs whose distribution conditions are different, write to the author
|
||||||
to ask for permission. For software which is copyrighted by the Free
|
to ask for permission. For software which is copyrighted by the Free
|
||||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||||
make exceptions for this. Our decision will be guided by the two goals
|
make exceptions for this. Our decision will be guided by the two goals
|
||||||
of preserving the free status of all derivatives of our free software and
|
of preserving the free status of all derivatives of our free software and
|
||||||
of promoting the sharing and reuse of software generally.
|
of promoting the sharing and reuse of software generally.
|
||||||
|
|
||||||
NO WARRANTY
|
NO WARRANTY
|
||||||
|
|
||||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||||
REPAIR OR CORRECTION.
|
REPAIR OR CORRECTION.
|
||||||
|
|
||||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||||
POSSIBILITY OF SUCH DAMAGES.
|
POSSIBILITY OF SUCH DAMAGES.
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
How to Apply These Terms to Your New Programs
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
If you develop a new program, and you want it to be of the greatest
|
If you develop a new program, and you want it to be of the greatest
|
||||||
possible use to the public, the best way to achieve this is to make it
|
possible use to the public, the best way to achieve this is to make it
|
||||||
free software which everyone can redistribute and change under these terms.
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
To do so, attach the following notices to the program. It is safest
|
To do so, attach the following notices to the program. It is safest
|
||||||
to attach them to the start of each source file to most effectively
|
to attach them to the start of each source file to most effectively
|
||||||
convey the exclusion of warranty; and each file should have at least
|
convey the exclusion of warranty; and each file should have at least
|
||||||
the "copyright" line and a pointer to where the full notice is found.
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
<one line to give the program's name and a brief idea of what it does.>
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
Copyright (C) <year> <name of author>
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
the Free Software Foundation; either version 2 of the License, or
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
(at your option) any later version.
|
(at your option) any later version.
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
This program is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
GNU General Public License for more details.
|
GNU General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program; if not, write to the Free Software
|
along with this program; if not, write to the Free Software
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
|
||||||
Also add information on how to contact you by electronic and paper mail.
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
If the program is interactive, make it output a short notice like this
|
If the program is interactive, make it output a short notice like this
|
||||||
when it starts in an interactive mode:
|
when it starts in an interactive mode:
|
||||||
|
|
||||||
Gnomovision version 69, Copyright (C) year name of author
|
Gnomovision version 69, Copyright (C) year name of author
|
||||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
This is free software, and you are welcome to redistribute it
|
This is free software, and you are welcome to redistribute it
|
||||||
under certain conditions; type `show c' for details.
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
parts of the General Public License. Of course, the commands you use may
|
parts of the General Public License. Of course, the commands you use may
|
||||||
be called something other than `show w' and `show c'; they could even be
|
be called something other than `show w' and `show c'; they could even be
|
||||||
mouse-clicks or menu items--whatever suits your program.
|
mouse-clicks or menu items--whatever suits your program.
|
||||||
|
|
||||||
You should also get your employer (if you work as a programmer) or your
|
You should also get your employer (if you work as a programmer) or your
|
||||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||||
necessary. Here is a sample; alter the names:
|
necessary. Here is a sample; alter the names:
|
||||||
|
|
||||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||||
|
|
||||||
<signature of Ty Coon>, 1 April 1989
|
<signature of Ty Coon>, 1 April 1989
|
||||||
Ty Coon, President of Vice
|
Ty Coon, President of Vice
|
||||||
|
|
||||||
This General Public License does not permit incorporating your program into
|
This General Public License does not permit incorporating your program into
|
||||||
proprietary programs. If your program is a subroutine library, you may
|
proprietary programs. If your program is a subroutine library, you may
|
||||||
consider it more useful to permit linking proprietary applications with the
|
consider it more useful to permit linking proprietary applications with the
|
||||||
library. If this is what you want to do, use the GNU Library General
|
library. If this is what you want to do, use the GNU Library General
|
||||||
Public License instead of this License.
|
Public License instead of this License.
|
||||||
|
|
115
hexdump.h
115
hexdump.h
|
@ -1,58 +1,59 @@
|
||||||
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||||
|
|
||||||
This software may be distributed and modified under the terms of the GNU
|
This software may be distributed and modified under the terms of the GNU
|
||||||
General Public License version 2 (GPL2) as published by the Free Software
|
General Public License version 2 (GPL2) as published by the Free Software
|
||||||
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
||||||
this file. Please note that GPL2 Section 2[b] requires that all works based
|
this file. Please note that GPL2 Section 2[b] requires that all works based
|
||||||
on this software must also be made publicly available under the terms of
|
on this software must also be made publicly available under the terms of
|
||||||
the GPL2 ("Copyleft").
|
the GPL2 ("Copyleft").
|
||||||
|
|
||||||
Contact information
|
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__
|
||||||
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <avr/pgmspace.h>
|
#include <avr/pgmspace.h>
|
||||||
#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) {};
|
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);
|
void Initialize() {
|
||||||
};
|
byteCount = 0;
|
||||||
|
byteTotal = 0;
|
||||||
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)
|
|
||||||
{
|
virtual void Parse(const LEN_TYPE len, const uint8_t *pbuf, const OFFSET_TYPE &offset);
|
||||||
for (LEN_TYPE j=0; j<len; j++, byteCount++, byteTotal++)
|
};
|
||||||
{
|
|
||||||
if (!byteCount)
|
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) {
|
||||||
PrintHex<OFFSET_TYPE>(byteTotal);
|
for (LEN_TYPE j = 0; j < len; j++, byteCount++, byteTotal++) {
|
||||||
Serial.print(": ");
|
if (!byteCount) {
|
||||||
}
|
SerialPrintHex<OFFSET_TYPE > (byteTotal);
|
||||||
PrintHex<uint8_t>(pbuf[j]);
|
Serial.print(": ");
|
||||||
Serial.print(" ");
|
}
|
||||||
|
SerialPrintHex<uint8_t > (pbuf[j]);
|
||||||
if (byteCount == 15)
|
Serial.print(" ");
|
||||||
{
|
|
||||||
Serial.println("");
|
if (byteCount == 15) {
|
||||||
byteCount = 0xFF;
|
Serial.println("");
|
||||||
}
|
byteCount = 0xFF;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endif // __HEXDUMP_H__
|
#endif // __HEXDUMP_H__
|
166
hid.cpp
166
hid.cpp
|
@ -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 )
|
|
||||||
{
|
uint8_t HID::GetReportDescr(uint8_t ep, USBReadParser *parser) {
|
||||||
const uint8_t constBufLen = 64;
|
const uint8_t constBufLen = 64;
|
||||||
uint8_t buf[constBufLen];
|
uint8_t buf[constBufLen];
|
||||||
|
|
||||||
uint8_t rcode = pUsb->ctrlReq( bAddress, ep, bmREQ_HIDREPORT, USB_REQUEST_GET_DESCRIPTOR, 0x00,
|
uint8_t rcode = pUsb->ctrlReq(bAddress, ep, bmREQ_HIDREPORT, USB_REQUEST_GET_DESCRIPTOR, 0x00,
|
||||||
HID_DESCRIPTOR_REPORT, 0x0000, 128, constBufLen, buf, (USBReadParser*)parser );
|
HID_DESCRIPTOR_REPORT, 0x0000, 128, constBufLen, buf, (USBReadParser*) parser);
|
||||||
|
|
||||||
//return ((rcode != hrSTALL) ? rcode : 0);
|
//return ((rcode != hrSTALL) ? rcode : 0);
|
||||||
return rcode;
|
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 )
|
|
||||||
{
|
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 ));
|
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 )
|
|
||||||
{
|
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 ));
|
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 )
|
|
||||||
{
|
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 ));
|
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 )
|
|
||||||
{
|
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 ));
|
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 )
|
|
||||||
{
|
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 ));
|
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 )
|
void HID::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);
|
}
|
||||||
}
|
|
||||||
|
void HID::PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc) {
|
||||||
void HID::PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc)
|
Notify(PSTR("\r\n\r\nHID Descriptor:\r\n"), 0x80);
|
||||||
{
|
Notify(PSTR("bDescLength:\t\t"), 0x80);
|
||||||
Notify(PSTR("\r\n\r\nHID Descriptor:\r\n"));
|
PrintHex<uint8_t > (pDesc->bLength, 0x80);
|
||||||
Notify(PSTR("bDescLength:\t\t"));
|
|
||||||
PrintHex<uint8_t>(pDesc->bLength);
|
Notify(PSTR("\r\nbDescriptorType:\t"), 0x80);
|
||||||
|
PrintHex<uint8_t > (pDesc->bDescriptorType, 0x80);
|
||||||
Notify(PSTR("\r\nbDescriptorType:\t"));
|
|
||||||
PrintHex<uint8_t>(pDesc->bDescriptorType);
|
Notify(PSTR("\r\nbcdHID:\t\t\t"), 0x80);
|
||||||
|
PrintHex<uint16_t > (pDesc->bcdHID, 0x80);
|
||||||
Notify(PSTR("\r\nbcdHID:\t\t\t"));
|
|
||||||
PrintHex<uint16_t>(pDesc->bcdHID);
|
Notify(PSTR("\r\nbCountryCode:\t\t"), 0x80);
|
||||||
|
PrintHex<uint8_t > (pDesc->bCountryCode, 0x80);
|
||||||
Notify(PSTR("\r\nbCountryCode:\t\t"));
|
|
||||||
PrintHex<uint8_t>(pDesc->bCountryCode);
|
Notify(PSTR("\r\nbNumDescriptors:\t"), 0x80);
|
||||||
|
PrintHex<uint8_t > (pDesc->bNumDescriptors, 0x80);
|
||||||
Notify(PSTR("\r\nbNumDescriptors:\t"));
|
|
||||||
PrintHex<uint8_t>(pDesc->bNumDescriptors);
|
Notify(PSTR("\r\nbDescrType:\t\t"), 0x80);
|
||||||
|
PrintHex<uint8_t > (pDesc->bDescrType, 0x80);
|
||||||
Notify(PSTR("\r\nbDescrType:\t\t"));
|
|
||||||
PrintHex<uint8_t>(pDesc->bDescrType);
|
Notify(PSTR("\r\nwDescriptorLength:\t"), 0x80);
|
||||||
|
PrintHex<uint16_t > (pDesc->wDescriptorLength, 0x80);
|
||||||
Notify(PSTR("\r\nwDescriptorLength:\t"));
|
}
|
||||||
PrintHex<uint16_t>(pDesc->wDescriptorLength);
|
|
||||||
}
|
|
||||||
|
|
400
hid.h
400
hid.h
|
@ -1,201 +1,201 @@
|
||||||
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||||
|
|
||||||
This software may be distributed and modified under the terms of the GNU
|
This software may be distributed and modified under the terms of the GNU
|
||||||
General Public License version 2 (GPL2) as published by the Free Software
|
General Public License version 2 (GPL2) as published by the Free Software
|
||||||
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
||||||
this file. Please note that GPL2 Section 2[b] requires that all works based
|
this file. Please note that GPL2 Section 2[b] requires that all works based
|
||||||
on this software must also be made publicly available under the terms of
|
on this software must also be made publicly available under the terms of
|
||||||
the GPL2 ("Copyleft").
|
the GPL2 ("Copyleft").
|
||||||
|
|
||||||
Contact information
|
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__
|
||||||
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <avr/pgmspace.h>
|
#include <avr/pgmspace.h>
|
||||||
#include "avrpins.h"
|
#include "avrpins.h"
|
||||||
#include "max3421e.h"
|
#include "max3421e.h"
|
||||||
#include "usbhost.h"
|
#include "usbhost.h"
|
||||||
#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
|
||||||
#include <WProgram.h>
|
#include <WProgram.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "printhex.h"
|
#include "printhex.h"
|
||||||
#include "hexdump.h"
|
#include "hexdump.h"
|
||||||
#include "message.h"
|
#include "message.h"
|
||||||
|
|
||||||
#include "confdescparser.h"
|
#include "confdescparser.h"
|
||||||
#include "hidusagestr.h"
|
#include "hidusagestr.h"
|
||||||
|
|
||||||
#define DATA_SIZE_MASK 0x03
|
#define DATA_SIZE_MASK 0x03
|
||||||
#define TYPE_MASK 0x0C
|
#define TYPE_MASK 0x0C
|
||||||
#define TAG_MASK 0xF0
|
#define TAG_MASK 0xF0
|
||||||
|
|
||||||
#define DATA_SIZE_0 0x00
|
#define DATA_SIZE_0 0x00
|
||||||
#define DATA_SIZE_1 0x01
|
#define DATA_SIZE_1 0x01
|
||||||
#define DATA_SIZE_2 0x02
|
#define DATA_SIZE_2 0x02
|
||||||
#define DATA_SIZE_4 0x03
|
#define DATA_SIZE_4 0x03
|
||||||
|
|
||||||
#define TYPE_MAIN 0x00
|
#define TYPE_MAIN 0x00
|
||||||
#define TYPE_GLOBAL 0x04
|
#define TYPE_GLOBAL 0x04
|
||||||
#define TYPE_LOCAL 0x08
|
#define TYPE_LOCAL 0x08
|
||||||
|
|
||||||
#define TAG_MAIN_INPUT 0x80
|
#define TAG_MAIN_INPUT 0x80
|
||||||
#define TAG_MAIN_OUTPUT 0x90
|
#define TAG_MAIN_OUTPUT 0x90
|
||||||
#define TAG_MAIN_COLLECTION 0xA0
|
#define TAG_MAIN_COLLECTION 0xA0
|
||||||
#define TAG_MAIN_FEATURE 0xB0
|
#define TAG_MAIN_FEATURE 0xB0
|
||||||
#define TAG_MAIN_ENDCOLLECTION 0xC0
|
#define TAG_MAIN_ENDCOLLECTION 0xC0
|
||||||
|
|
||||||
#define TAG_GLOBAL_USAGEPAGE 0x00
|
#define TAG_GLOBAL_USAGEPAGE 0x00
|
||||||
#define TAG_GLOBAL_LOGICALMIN 0x10
|
#define TAG_GLOBAL_LOGICALMIN 0x10
|
||||||
#define TAG_GLOBAL_LOGICALMAX 0x20
|
#define TAG_GLOBAL_LOGICALMAX 0x20
|
||||||
#define TAG_GLOBAL_PHYSMIN 0x30
|
#define TAG_GLOBAL_PHYSMIN 0x30
|
||||||
#define TAG_GLOBAL_PHYSMAX 0x40
|
#define TAG_GLOBAL_PHYSMAX 0x40
|
||||||
#define TAG_GLOBAL_UNITEXP 0x50
|
#define TAG_GLOBAL_UNITEXP 0x50
|
||||||
#define TAG_GLOBAL_UNIT 0x60
|
#define TAG_GLOBAL_UNIT 0x60
|
||||||
#define TAG_GLOBAL_REPORTSIZE 0x70
|
#define TAG_GLOBAL_REPORTSIZE 0x70
|
||||||
#define TAG_GLOBAL_REPORTID 0x80
|
#define TAG_GLOBAL_REPORTID 0x80
|
||||||
#define TAG_GLOBAL_REPORTCOUNT 0x90
|
#define TAG_GLOBAL_REPORTCOUNT 0x90
|
||||||
#define TAG_GLOBAL_PUSH 0xA0
|
#define TAG_GLOBAL_PUSH 0xA0
|
||||||
#define TAG_GLOBAL_POP 0xB0
|
#define TAG_GLOBAL_POP 0xB0
|
||||||
|
|
||||||
#define TAG_LOCAL_USAGE 0x00
|
#define TAG_LOCAL_USAGE 0x00
|
||||||
#define TAG_LOCAL_USAGEMIN 0x10
|
#define TAG_LOCAL_USAGEMIN 0x10
|
||||||
#define TAG_LOCAL_USAGEMAX 0x20
|
#define TAG_LOCAL_USAGEMAX 0x20
|
||||||
|
|
||||||
/* HID requests */
|
/* HID requests */
|
||||||
#define bmREQ_HIDOUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
|
#define bmREQ_HIDOUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
|
||||||
#define bmREQ_HIDIN USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
|
#define bmREQ_HIDIN USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
|
||||||
#define bmREQ_HIDREPORT USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_INTERFACE
|
#define bmREQ_HIDREPORT USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_INTERFACE
|
||||||
|
|
||||||
/* HID constants. Not part of chapter 9 */
|
/* HID constants. Not part of chapter 9 */
|
||||||
/* Class-Specific Requests */
|
/* Class-Specific Requests */
|
||||||
#define HID_REQUEST_GET_REPORT 0x01
|
#define HID_REQUEST_GET_REPORT 0x01
|
||||||
#define HID_REQUEST_GET_IDLE 0x02
|
#define HID_REQUEST_GET_IDLE 0x02
|
||||||
#define HID_REQUEST_GET_PROTOCOL 0x03
|
#define HID_REQUEST_GET_PROTOCOL 0x03
|
||||||
#define HID_REQUEST_SET_REPORT 0x09
|
#define HID_REQUEST_SET_REPORT 0x09
|
||||||
#define HID_REQUEST_SET_IDLE 0x0A
|
#define HID_REQUEST_SET_IDLE 0x0A
|
||||||
#define HID_REQUEST_SET_PROTOCOL 0x0B
|
#define HID_REQUEST_SET_PROTOCOL 0x0B
|
||||||
|
|
||||||
/* Class Descriptor Types */
|
/* Class Descriptor Types */
|
||||||
#define HID_DESCRIPTOR_HID 0x21
|
#define HID_DESCRIPTOR_HID 0x21
|
||||||
#define HID_DESCRIPTOR_REPORT 0x22
|
#define HID_DESCRIPTOR_REPORT 0x22
|
||||||
#define HID_DESRIPTOR_PHY 0x23
|
#define HID_DESRIPTOR_PHY 0x23
|
||||||
|
|
||||||
/* Protocol Selection */
|
/* Protocol Selection */
|
||||||
#define HID_BOOT_PROTOCOL 0x00
|
#define HID_BOOT_PROTOCOL 0x00
|
||||||
#define HID_RPT_PROTOCOL 0x01
|
#define HID_RPT_PROTOCOL 0x01
|
||||||
|
|
||||||
/* HID Interface Class Code */
|
/* HID Interface Class Code */
|
||||||
#define HID_INTF 0x03
|
#define HID_INTF 0x03
|
||||||
|
|
||||||
/* HID Interface Class SubClass Codes */
|
/* HID Interface Class SubClass Codes */
|
||||||
#define HID_BOOT_INTF_SUBCLASS 0x01
|
#define HID_BOOT_INTF_SUBCLASS 0x01
|
||||||
|
|
||||||
/* HID Interface Class Protocol Codes */
|
/* HID Interface Class Protocol Codes */
|
||||||
#define HID_PROTOCOL_NONE 0x00
|
#define HID_PROTOCOL_NONE 0x00
|
||||||
#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
|
#define HID_ITEM_TYPE_GLOBAL 1
|
||||||
#define HID_ITEM_TYPE_GLOBAL 1
|
#define HID_ITEM_TYPE_LOCAL 2
|
||||||
#define HID_ITEM_TYPE_LOCAL 2
|
#define HID_ITEM_TYPE_RESERVED 3
|
||||||
#define HID_ITEM_TYPE_RESERVED 3
|
|
||||||
|
#define HID_LONG_ITEM_PREFIX 0xfe // Long item prefix value
|
||||||
#define HID_LONG_ITEM_PREFIX 0xfe // Long item prefix value
|
|
||||||
|
#define bmHID_MAIN_ITEM_TAG 0xfc // Main item tag mask
|
||||||
#define bmHID_MAIN_ITEM_TAG 0xfc // Main item tag mask
|
|
||||||
|
#define bmHID_MAIN_ITEM_INPUT 0x80 // Main item Input tag value
|
||||||
#define bmHID_MAIN_ITEM_INPUT 0x80 // Main item Input tag value
|
#define bmHID_MAIN_ITEM_OUTPUT 0x90 // Main item Output tag value
|
||||||
#define bmHID_MAIN_ITEM_OUTPUT 0x90 // Main item Output tag value
|
#define bmHID_MAIN_ITEM_FEATURE 0xb0 // Main item Feature tag value
|
||||||
#define bmHID_MAIN_ITEM_FEATURE 0xb0 // Main item Feature tag value
|
#define bmHID_MAIN_ITEM_COLLECTION 0xa0 // Main item Collection tag value
|
||||||
#define bmHID_MAIN_ITEM_COLLECTION 0xa0 // Main item Collection tag value
|
#define bmHID_MAIN_ITEM_END_COLLECTION 0xce // Main item End Collection tag value
|
||||||
#define bmHID_MAIN_ITEM_END_COLLECTION 0xce // Main item End Collection tag value
|
|
||||||
|
#define HID_MAIN_ITEM_COLLECTION_PHYSICAL 0
|
||||||
#define HID_MAIN_ITEM_COLLECTION_PHYSICAL 0
|
#define HID_MAIN_ITEM_COLLECTION_APPLICATION 1
|
||||||
#define HID_MAIN_ITEM_COLLECTION_APPLICATION 1
|
#define HID_MAIN_ITEM_COLLECTION_LOGICAL 2
|
||||||
#define HID_MAIN_ITEM_COLLECTION_LOGICAL 2
|
#define HID_MAIN_ITEM_COLLECTION_REPORT 3
|
||||||
#define HID_MAIN_ITEM_COLLECTION_REPORT 3
|
#define HID_MAIN_ITEM_COLLECTION_NAMED_ARRAY 4
|
||||||
#define HID_MAIN_ITEM_COLLECTION_NAMED_ARRAY 4
|
#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 bmIsArrayOrVariable : 1;
|
||||||
uint8_t bmIsConstantOrData : 1;
|
uint8_t bmIsRelativeOrAbsolute : 1;
|
||||||
uint8_t bmIsArrayOrVariable : 1;
|
uint8_t bmIsWrapOrNoWrap : 1;
|
||||||
uint8_t bmIsRelativeOrAbsolute : 1;
|
uint8_t bmIsNonLonearOrLinear : 1;
|
||||||
uint8_t bmIsWrapOrNoWrap : 1;
|
uint8_t bmIsNoPreferedOrPrefered : 1;
|
||||||
uint8_t bmIsNonLonearOrLinear : 1;
|
uint8_t bmIsNullOrNoNull : 1;
|
||||||
uint8_t bmIsNoPreferedOrPrefered : 1;
|
uint8_t bmIsVolatileOrNonVolatile : 1;
|
||||||
uint8_t bmIsNullOrNoNull : 1;
|
};
|
||||||
uint8_t bmIsVolatileOrNonVolatile : 1;
|
|
||||||
};
|
class HID;
|
||||||
|
|
||||||
class HID;
|
class HIDReportParser {
|
||||||
|
public:
|
||||||
class HIDReportParser
|
virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) = 0;
|
||||||
{
|
};
|
||||||
public:
|
|
||||||
virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) = 0;
|
#define MAX_REPORT_PARSERS 2
|
||||||
};
|
#define HID_MAX_HID_CLASS_DESCRIPTORS 5
|
||||||
|
|
||||||
#define MAX_REPORT_PARSERS 2
|
class HID : public USBDeviceConfig, public UsbConfigXtracter {
|
||||||
#define HID_MAX_HID_CLASS_DESCRIPTORS 5
|
protected:
|
||||||
|
USB *pUsb; // USB class instance pointer
|
||||||
class HID : public USBDeviceConfig, public UsbConfigXtracter
|
uint8_t bAddress; // address
|
||||||
{
|
|
||||||
protected:
|
protected:
|
||||||
USB *pUsb; // USB class instance pointer
|
static const uint8_t epInterruptInIndex = 1; // InterruptIN endpoint index
|
||||||
uint8_t bAddress; // address
|
static const uint8_t epInterruptOutIndex = 2; // InterruptOUT endpoint index
|
||||||
|
|
||||||
protected:
|
static const uint8_t maxHidInterfaces = 3;
|
||||||
static const uint8_t epInterruptInIndex = 1; // InterruptIN endpoint index
|
static const uint8_t maxEpPerInterface = 2;
|
||||||
static const uint8_t epInterruptOutIndex = 2; // InterruptOUT endpoint index
|
static const uint8_t totalEndpoints = (maxHidInterfaces * maxEpPerInterface + 1);
|
||||||
|
|
||||||
static const uint8_t maxHidInterfaces = 3;
|
void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr);
|
||||||
static const uint8_t maxEpPerInterface = 2;
|
void PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc);
|
||||||
static const uint8_t totalEndpoints = (maxHidInterfaces * maxEpPerInterface + 1);
|
|
||||||
|
virtual HIDReportParser* GetReportParser(uint8_t id);
|
||||||
void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr);
|
|
||||||
void PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc);
|
public:
|
||||||
|
|
||||||
virtual HIDReportParser* GetReportParser(uint8_t id);
|
HID(USB *pusb) : pUsb(pusb) {
|
||||||
|
};
|
||||||
public:
|
|
||||||
HID(USB *pusb) : pUsb(pusb) {};
|
const USB* GetUsb() {
|
||||||
|
return pUsb;
|
||||||
const USB* GetUsb() { return pUsb; };
|
};
|
||||||
virtual bool SetReportParser(uint8_t id, HIDReportParser *prs);
|
virtual bool SetReportParser(uint8_t id, HIDReportParser *prs);
|
||||||
|
|
||||||
uint8_t SetProtocol( uint8_t iface, uint8_t protocol );
|
uint8_t SetProtocol(uint8_t iface, uint8_t protocol);
|
||||||
uint8_t GetProtocol( uint8_t iface, uint8_t* dataptr );
|
uint8_t GetProtocol(uint8_t iface, uint8_t* dataptr);
|
||||||
uint8_t GetIdle( uint8_t iface, uint8_t reportID, 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 SetIdle(uint8_t iface, uint8_t reportID, uint8_t duration);
|
||||||
|
|
||||||
uint8_t GetReportDescr( uint8_t ep, USBReadParser *parser = NULL);
|
uint8_t GetReportDescr(uint8_t ep, USBReadParser *parser = NULL);
|
||||||
|
|
||||||
uint8_t GetHidDescr( uint8_t ep, 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 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 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__
|
293
hidboot.cpp
293
hidboot.cpp
|
@ -1,154 +1,139 @@
|
||||||
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||||
|
|
||||||
This software may be distributed and modified under the terms of the GNU
|
This software may be distributed and modified under the terms of the GNU
|
||||||
General Public License version 2 (GPL2) as published by the Free Software
|
General Public License version 2 (GPL2) as published by the Free Software
|
||||||
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
||||||
this file. Please note that GPL2 Section 2[b] requires that all works based
|
this file. Please note that GPL2 Section 2[b] requires that all works based
|
||||||
on this software must also be made publicly available under the terms of
|
on this software must also be made publicly available under the terms of
|
||||||
the GPL2 ("Copyleft").
|
the GPL2 ("Copyleft").
|
||||||
|
|
||||||
Contact information
|
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);
|
|
||||||
|
if (len > sizeof (MOUSEINFO))
|
||||||
for (uint8_t i=0; i<3; i++)
|
for (uint8_t i = 0; i<sizeof (MOUSEINFO); i++)
|
||||||
prevState.bInfo[i] = buf[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 up = false;
|
||||||
bool down = false;
|
|
||||||
bool up = false;
|
for (uint8_t j = 2; j < 8; j++) {
|
||||||
|
if (buf[i] == prevState.bInfo[j] && buf[i] != 1)
|
||||||
for (uint8_t j=2; j<8; j++)
|
down = true;
|
||||||
{
|
if (buf[j] == prevState.bInfo[i] && prevState.bInfo[i] != 1)
|
||||||
if (buf[i] == prevState.bInfo[j] && buf[i] != 1)
|
up = true;
|
||||||
down = true;
|
}
|
||||||
if (buf[j] == prevState.bInfo[i] && prevState.bInfo[i] != 1)
|
if (!down) {
|
||||||
up = true;
|
HandleLockingKeys(hid, buf[i]);
|
||||||
}
|
OnKeyDown(*buf, buf[i]);
|
||||||
if (!down)
|
}
|
||||||
{
|
if (!up)
|
||||||
HandleLockingKeys(hid, buf[i]);
|
OnKeyUp(prevState.bInfo[0], prevState.bInfo[i]);
|
||||||
OnKeyDown(*buf, buf[i]);
|
}
|
||||||
}
|
for (uint8_t i = 0; i < 8; i++)
|
||||||
if (!up)
|
prevState.bInfo[i] = buf[i];
|
||||||
OnKeyUp(prevState.bInfo[0], prevState.bInfo[i]);
|
};
|
||||||
}
|
|
||||||
for (uint8_t i=0; i<8; i++)
|
uint8_t KeyboardReportParser::HandleLockingKeys(HID *hid, uint8_t key) {
|
||||||
prevState.bInfo[i] = buf[i];
|
uint8_t old_keys = kbdLockingKeys.bLeds;
|
||||||
};
|
|
||||||
|
switch (key) {
|
||||||
uint8_t KeyboardReportParser::HandleLockingKeys(HID *hid, uint8_t key)
|
case KEY_NUM_LOCK:
|
||||||
{
|
kbdLockingKeys.kbdLeds.bmNumLock = ~kbdLockingKeys.kbdLeds.bmNumLock;
|
||||||
uint8_t old_keys = kbdLockingKeys.bLeds;
|
break;
|
||||||
|
case KEY_CAPS_LOCK:
|
||||||
switch (key)
|
kbdLockingKeys.kbdLeds.bmCapsLock = ~kbdLockingKeys.kbdLeds.bmCapsLock;
|
||||||
{
|
break;
|
||||||
case KEY_NUM_LOCK:
|
case KEY_SCROLL_LOCK:
|
||||||
kbdLockingKeys.kbdLeds.bmNumLock = ~kbdLockingKeys.kbdLeds.bmNumLock;
|
kbdLockingKeys.kbdLeds.bmScrollLock = ~kbdLockingKeys.kbdLeds.bmScrollLock;
|
||||||
break;
|
break;
|
||||||
case KEY_CAPS_LOCK:
|
}
|
||||||
kbdLockingKeys.kbdLeds.bmCapsLock = ~kbdLockingKeys.kbdLeds.bmCapsLock;
|
|
||||||
break;
|
if (old_keys != kbdLockingKeys.bLeds && hid)
|
||||||
case KEY_SCROLL_LOCK:
|
return (hid->SetReport(0, 0/*hid->GetIface()*/, 2, 0, 1, &kbdLockingKeys.bLeds));
|
||||||
kbdLockingKeys.kbdLeds.bmScrollLock = ~kbdLockingKeys.kbdLeds.bmScrollLock;
|
|
||||||
break;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (old_keys != kbdLockingKeys.bLeds && hid)
|
const uint8_t KeyboardReportParser::numKeys[] PROGMEM = {'!', '@', '#', '$', '%', '^', '&', '*', '(', ')'};
|
||||||
return (hid->SetReport(0, 0/*hid->GetIface()*/, 2, 0, 1, &kbdLockingKeys.bLeds));
|
const uint8_t KeyboardReportParser::symKeysUp[] PROGMEM = {'_', '+', '{', '}', '|', '~', ':', '"', '~', '<', '>', '?'};
|
||||||
|
const uint8_t KeyboardReportParser::symKeysLo[] PROGMEM = {'-', '=', '[', ']', '\\', ' ', ';', '\'', '`', ',', '.', '/'};
|
||||||
return 0;
|
const uint8_t KeyboardReportParser::padKeys[] PROGMEM = {'/', '*', '-', '+', 0x13};
|
||||||
}
|
|
||||||
|
uint8_t KeyboardReportParser::OemToAscii(uint8_t mod, uint8_t key) {
|
||||||
const uint8_t KeyboardReportParser::numKeys[] PROGMEM = { '!', '@', '#', '$', '%', '^', '&', '*', '(', ')' };
|
uint8_t shift = (mod & 0x22);
|
||||||
const uint8_t KeyboardReportParser::symKeysUp[] PROGMEM = { '_', '+', '{', '}', '|', '~', ':', '"', '~', '<', '>', '?' };
|
|
||||||
const uint8_t KeyboardReportParser::symKeysLo[] PROGMEM = { '-', '=', '[', ']', '\\', ' ', ';', '\'', '`', ',', '.', '/' };
|
// [a-z]
|
||||||
const uint8_t KeyboardReportParser::padKeys[] PROGMEM = { '/', '*', '-', '+', 0x13 };
|
if (key > 0x03 && key < 0x1e) {
|
||||||
|
// Upper case letters
|
||||||
uint8_t KeyboardReportParser::OemToAscii(uint8_t mod, uint8_t key)
|
if ((kbdLockingKeys.kbdLeds.bmCapsLock == 0 && (mod & 2)) ||
|
||||||
{
|
(kbdLockingKeys.kbdLeds.bmCapsLock == 1 && (mod & 2) == 0))
|
||||||
uint8_t shift = (mod & 0x22);
|
return (key - 4 + 'A');
|
||||||
|
|
||||||
// [a-z]
|
// Lower case letters
|
||||||
if (key > 0x03 && key < 0x1e)
|
else
|
||||||
{
|
return (key - 4 + 'a');
|
||||||
// Upper case letters
|
} // Numbers
|
||||||
if ( (kbdLockingKeys.kbdLeds.bmCapsLock == 0 && (mod & 2)) ||
|
else if (key > 0x1d && key < 0x27) {
|
||||||
(kbdLockingKeys.kbdLeds.bmCapsLock == 1 && (mod & 2) == 0) )
|
if (shift)
|
||||||
return (key - 4 + 'A');
|
return ((uint8_t) pgm_read_byte(&numKeys[key - 0x1e]));
|
||||||
|
else
|
||||||
// Lower case letters
|
return (key - 0x1e + '1');
|
||||||
else
|
} // Keypad Numbers
|
||||||
return (key - 4 + 'a');
|
else if (key > 0x58 && key < 0x62) {
|
||||||
}
|
if (kbdLockingKeys.kbdLeds.bmNumLock == 1)
|
||||||
// Numbers
|
return (key - 0x59 + '1');
|
||||||
else if (key > 0x1d && key < 0x27)
|
} 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 (shift)
|
else if (key > 0x53 && key < 0x59)
|
||||||
return ((uint8_t)pgm_read_byte(&numKeys[key - 0x1e]));
|
return (uint8_t) pgm_read_byte(&padKeys[key - 0x54]);
|
||||||
else
|
else {
|
||||||
return (key - 0x1e + '1');
|
switch (key) {
|
||||||
}
|
case KEY_SPACE: return (0x20);
|
||||||
// Keypad Numbers
|
case KEY_ENTER: return (0x13);
|
||||||
else if (key > 0x58 && key < 0x62)
|
case KEY_ZERO: return ((shift) ? ')': '0');
|
||||||
{
|
case KEY_ZERO2: return ((kbdLockingKeys.kbdLeds.bmNumLock == 1) ? '0': 0);
|
||||||
if (kbdLockingKeys.kbdLeds.bmNumLock == 1)
|
case KEY_PERIOD: return ((kbdLockingKeys.kbdLeds.bmNumLock == 1) ? '.': 0);
|
||||||
return (key - 0x59 + '1');
|
}
|
||||||
}
|
}
|
||||||
else if (key > 0x2c && key < 0x39)
|
return ( 0);
|
||||||
return ((shift) ? (uint8_t)pgm_read_byte(&symKeysUp[key-0x2d]) : (uint8_t)pgm_read_byte(&symKeysLo[key-0x2d]));
|
}
|
||||||
else if (key > 0x53 && key < 0x59)
|
|
||||||
return (uint8_t)pgm_read_byte(&padKeys[key - 0x54]);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
switch (key)
|
|
||||||
{
|
|
||||||
case KEY_SPACE: return(0x20);
|
|
||||||
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 );
|
|
||||||
}
|
|
||||||
|
|
987
hidboot.h
987
hidboot.h
|
@ -1,495 +1,494 @@
|
||||||
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||||
|
|
||||||
This software may be distributed and modified under the terms of the GNU
|
This software may be distributed and modified under the terms of the GNU
|
||||||
General Public License version 2 (GPL2) as published by the Free Software
|
General Public License version 2 (GPL2) as published by the Free Software
|
||||||
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
||||||
this file. Please note that GPL2 Section 2[b] requires that all works based
|
this file. Please note that GPL2 Section 2[b] requires that all works based
|
||||||
on this software must also be made publicly available under the terms of
|
on this software must also be made publicly available under the terms of
|
||||||
the GPL2 ("Copyleft").
|
the GPL2 ("Copyleft").
|
||||||
|
|
||||||
Contact information
|
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__
|
||||||
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <avr/pgmspace.h>
|
#include <avr/pgmspace.h>
|
||||||
#include "avrpins.h"
|
#include "avrpins.h"
|
||||||
#include "max3421e.h"
|
#include "max3421e.h"
|
||||||
#include "usbhost.h"
|
#include "usbhost.h"
|
||||||
#include "usb_ch9.h"
|
#include "usb_ch9.h"
|
||||||
#include "Usb.h"
|
#include "Usb.h"
|
||||||
#include "hid.h"
|
#include "hid.h"
|
||||||
|
|
||||||
#if defined(ARDUINO) && ARDUINO >=100
|
#if defined(ARDUINO) && ARDUINO >=100
|
||||||
#include "Arduino.h"
|
#include "Arduino.h"
|
||||||
#else
|
#else
|
||||||
#include <WProgram.h>
|
#include <WProgram.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "printhex.h"
|
#include "printhex.h"
|
||||||
#include "hexdump.h"
|
#include "hexdump.h"
|
||||||
#include "message.h"
|
#include "message.h"
|
||||||
|
|
||||||
#include "confdescparser.h"
|
#include "confdescparser.h"
|
||||||
|
|
||||||
#define KEY_SPACE 0x2c
|
#define KEY_SPACE 0x2c
|
||||||
#define KEY_ZERO 0x27
|
#define KEY_ZERO 0x27
|
||||||
#define KEY_ZERO2 0x62
|
#define KEY_ZERO2 0x62
|
||||||
#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;
|
||||||
{
|
uint8_t bInfo[sizeof (MOUSEINFO)];
|
||||||
MOUSEINFO mouseInfo;
|
} prevState;
|
||||||
uint8_t bInfo[3];
|
|
||||||
} prevState;
|
public:
|
||||||
|
virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf);
|
||||||
public:
|
|
||||||
virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf);
|
protected:
|
||||||
|
|
||||||
protected:
|
virtual void OnMouseMove(MOUSEINFO *mi) {
|
||||||
virtual void OnMouseMove (MOUSEINFO *mi) {};
|
};
|
||||||
virtual void OnLeftButtonUp (MOUSEINFO *mi) {};
|
|
||||||
virtual void OnLeftButtonDown (MOUSEINFO *mi) {};
|
virtual void OnLeftButtonUp(MOUSEINFO *mi) {
|
||||||
virtual void OnRightButtonUp (MOUSEINFO *mi) {};
|
};
|
||||||
virtual void OnRightButtonDown (MOUSEINFO *mi) {};
|
|
||||||
virtual void OnMiddleButtonUp (MOUSEINFO *mi) {};
|
virtual void OnLeftButtonDown(MOUSEINFO *mi) {
|
||||||
virtual void OnMiddleButtonDown (MOUSEINFO *mi) {};
|
};
|
||||||
};
|
|
||||||
|
virtual void OnRightButtonUp(MOUSEINFO *mi) {
|
||||||
struct MODIFIERKEYS
|
};
|
||||||
{
|
|
||||||
uint8_t bmLeftCtrl : 1;
|
virtual void OnRightButtonDown(MOUSEINFO *mi) {
|
||||||
uint8_t bmLeftShift : 1;
|
};
|
||||||
uint8_t bmLeftAlt : 1;
|
|
||||||
uint8_t bmLeftGUI : 1;
|
virtual void OnMiddleButtonUp(MOUSEINFO *mi) {
|
||||||
uint8_t bmRightCtrl : 1;
|
};
|
||||||
uint8_t bmRightShift : 1;
|
|
||||||
uint8_t bmRightAlt : 1;
|
virtual void OnMiddleButtonDown(MOUSEINFO *mi) {
|
||||||
uint8_t bmRightGUI : 1;
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct KBDINFO
|
struct MODIFIERKEYS {
|
||||||
{
|
uint8_t bmLeftCtrl : 1;
|
||||||
struct
|
uint8_t bmLeftShift : 1;
|
||||||
{
|
uint8_t bmLeftAlt : 1;
|
||||||
uint8_t bmLeftCtrl : 1;
|
uint8_t bmLeftGUI : 1;
|
||||||
uint8_t bmLeftShift : 1;
|
uint8_t bmRightCtrl : 1;
|
||||||
uint8_t bmLeftAlt : 1;
|
uint8_t bmRightShift : 1;
|
||||||
uint8_t bmLeftGUI : 1;
|
uint8_t bmRightAlt : 1;
|
||||||
uint8_t bmRightCtrl : 1;
|
uint8_t bmRightGUI : 1;
|
||||||
uint8_t bmRightShift : 1;
|
};
|
||||||
uint8_t bmRightAlt : 1;
|
|
||||||
uint8_t bmRightGUI : 1;
|
struct KBDINFO {
|
||||||
};
|
|
||||||
uint8_t bReserved;
|
struct {
|
||||||
uint8_t Keys[6];
|
uint8_t bmLeftCtrl : 1;
|
||||||
};
|
uint8_t bmLeftShift : 1;
|
||||||
|
uint8_t bmLeftAlt : 1;
|
||||||
struct KBDLEDS
|
uint8_t bmLeftGUI : 1;
|
||||||
{
|
uint8_t bmRightCtrl : 1;
|
||||||
uint8_t bmNumLock : 1;
|
uint8_t bmRightShift : 1;
|
||||||
uint8_t bmCapsLock : 1;
|
uint8_t bmRightAlt : 1;
|
||||||
uint8_t bmScrollLock : 1;
|
uint8_t bmRightGUI : 1;
|
||||||
uint8_t bmCompose : 1;
|
};
|
||||||
uint8_t bmKana : 1;
|
uint8_t bReserved;
|
||||||
uint8_t bmReserved : 3;
|
uint8_t Keys[6];
|
||||||
};
|
};
|
||||||
|
|
||||||
#define KEY_NUM_LOCK 0x53
|
struct KBDLEDS {
|
||||||
#define KEY_CAPS_LOCK 0x39
|
uint8_t bmNumLock : 1;
|
||||||
#define KEY_SCROLL_LOCK 0x47
|
uint8_t bmCapsLock : 1;
|
||||||
|
uint8_t bmScrollLock : 1;
|
||||||
class KeyboardReportParser : public HIDReportParser
|
uint8_t bmCompose : 1;
|
||||||
{
|
uint8_t bmKana : 1;
|
||||||
static const uint8_t numKeys[];
|
uint8_t bmReserved : 3;
|
||||||
static const uint8_t symKeysUp[];
|
};
|
||||||
static const uint8_t symKeysLo[];
|
|
||||||
static const uint8_t padKeys[];
|
#define KEY_NUM_LOCK 0x53
|
||||||
|
#define KEY_CAPS_LOCK 0x39
|
||||||
protected:
|
#define KEY_SCROLL_LOCK 0x47
|
||||||
union
|
|
||||||
{
|
class KeyboardReportParser : public HIDReportParser {
|
||||||
KBDINFO kbdInfo;
|
static const uint8_t numKeys[];
|
||||||
uint8_t bInfo[sizeof(KBDINFO)];
|
static const uint8_t symKeysUp[];
|
||||||
} prevState;
|
static const uint8_t symKeysLo[];
|
||||||
|
static const uint8_t padKeys[];
|
||||||
union
|
|
||||||
{
|
protected:
|
||||||
KBDLEDS kbdLeds;
|
|
||||||
uint8_t bLeds;
|
union {
|
||||||
} kbdLockingKeys;
|
KBDINFO kbdInfo;
|
||||||
|
uint8_t bInfo[sizeof (KBDINFO)];
|
||||||
uint8_t OemToAscii(uint8_t mod, uint8_t key);
|
} prevState;
|
||||||
|
|
||||||
public:
|
union {
|
||||||
KeyboardReportParser() { kbdLockingKeys.bLeds = 0; };
|
KBDLEDS kbdLeds;
|
||||||
|
uint8_t bLeds;
|
||||||
virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf);
|
} kbdLockingKeys;
|
||||||
|
|
||||||
protected:
|
uint8_t OemToAscii(uint8_t mod, uint8_t key);
|
||||||
uint8_t HandleLockingKeys(HID* hid, uint8_t key);
|
|
||||||
|
public:
|
||||||
virtual void OnKeyDown (uint8_t mod, uint8_t key) {};
|
|
||||||
virtual void OnKeyUp (uint8_t mod, uint8_t key) {};
|
KeyboardReportParser() {
|
||||||
};
|
kbdLockingKeys.bLeds = 0;
|
||||||
|
};
|
||||||
#define totalEndpoints 2
|
|
||||||
|
virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf);
|
||||||
#define HID_MAX_HID_CLASS_DESCRIPTORS 5
|
|
||||||
|
protected:
|
||||||
template <const uint8_t BOOT_PROTOCOL>
|
uint8_t HandleLockingKeys(HID* hid, uint8_t key);
|
||||||
class HIDBoot : public HID //public USBDeviceConfig, public UsbConfigXtracter
|
|
||||||
{
|
virtual void OnKeyDown(uint8_t mod, uint8_t key) {
|
||||||
EpInfo epInfo[totalEndpoints];
|
};
|
||||||
|
|
||||||
HIDReportParser *pRptParser;
|
virtual void OnKeyUp(uint8_t mod, uint8_t key) {
|
||||||
|
};
|
||||||
uint8_t bConfNum; // configuration number
|
};
|
||||||
uint8_t bIfaceNum; // Interface Number
|
|
||||||
uint8_t bNumIface; // number of interfaces in the configuration
|
#define totalEndpoints 2
|
||||||
uint8_t bNumEP; // total number of EP in the configuration
|
|
||||||
uint32_t qNextPollTime; // next poll time
|
#define HID_MAX_HID_CLASS_DESCRIPTORS 5
|
||||||
bool bPollEnable; // poll enable flag
|
|
||||||
|
template <const uint8_t BOOT_PROTOCOL>
|
||||||
void Initialize();
|
class HIDBoot : public HID //public USBDeviceConfig, public UsbConfigXtracter
|
||||||
|
{
|
||||||
virtual HIDReportParser* GetReportParser(uint8_t id) { return pRptParser; };
|
EpInfo epInfo[totalEndpoints];
|
||||||
|
|
||||||
public:
|
HIDReportParser *pRptParser;
|
||||||
HIDBoot(USB *p);
|
|
||||||
|
uint8_t bConfNum; // configuration number
|
||||||
virtual bool SetReportParser(uint8_t id, HIDReportParser *prs) { pRptParser = prs; };
|
uint8_t bIfaceNum; // Interface Number
|
||||||
|
uint8_t bNumIface; // number of interfaces in the configuration
|
||||||
// USBDeviceConfig implementation
|
uint8_t bNumEP; // total number of EP in the configuration
|
||||||
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
|
uint32_t qNextPollTime; // next poll time
|
||||||
virtual uint8_t Release();
|
bool bPollEnable; // poll enable flag
|
||||||
virtual uint8_t Poll();
|
|
||||||
virtual uint8_t GetAddress() { return bAddress; };
|
void Initialize();
|
||||||
|
|
||||||
// UsbConfigXtracter implementation
|
virtual HIDReportParser* GetReportParser(uint8_t id) {
|
||||||
virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
|
return pRptParser;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <const uint8_t BOOT_PROTOCOL>
|
public:
|
||||||
HIDBoot<BOOT_PROTOCOL>::HIDBoot(USB *p) :
|
HIDBoot(USB *p);
|
||||||
HID(p),
|
|
||||||
qNextPollTime(0),
|
virtual bool SetReportParser(uint8_t id, HIDReportParser *prs) {
|
||||||
bPollEnable(false),
|
pRptParser = prs;
|
||||||
pRptParser(NULL)
|
return true;
|
||||||
{
|
};
|
||||||
Initialize();
|
|
||||||
|
// USBDeviceConfig implementation
|
||||||
if (pUsb)
|
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
|
||||||
pUsb->RegisterDeviceClass(this);
|
virtual uint8_t Release();
|
||||||
}
|
virtual uint8_t Poll();
|
||||||
|
|
||||||
template <const uint8_t BOOT_PROTOCOL>
|
virtual uint8_t GetAddress() {
|
||||||
void HIDBoot<BOOT_PROTOCOL>::Initialize()
|
return bAddress;
|
||||||
{
|
};
|
||||||
for(uint8_t i=0; i<totalEndpoints; i++)
|
|
||||||
{
|
// UsbConfigXtracter implementation
|
||||||
epInfo[i].epAddr = 0;
|
virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
|
||||||
epInfo[i].maxPktSize = (i) ? 0 : 8;
|
};
|
||||||
epInfo[i].epAttribs = 0;
|
|
||||||
epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER;
|
template <const uint8_t BOOT_PROTOCOL>
|
||||||
}
|
HIDBoot<BOOT_PROTOCOL>::HIDBoot(USB *p) :
|
||||||
bNumEP = 1;
|
HID(p),
|
||||||
bNumIface = 0;
|
qNextPollTime(0),
|
||||||
bConfNum = 0;
|
bPollEnable(false),
|
||||||
}
|
pRptParser(NULL) {
|
||||||
|
Initialize();
|
||||||
template <const uint8_t BOOT_PROTOCOL>
|
|
||||||
uint8_t HIDBoot<BOOT_PROTOCOL>::Init(uint8_t parent, uint8_t port, bool lowspeed)
|
if (pUsb)
|
||||||
{
|
pUsb->RegisterDeviceClass(this);
|
||||||
const uint8_t constBufSize = sizeof(USB_DEVICE_DESCRIPTOR);
|
}
|
||||||
|
|
||||||
uint8_t buf[constBufSize];
|
template <const uint8_t BOOT_PROTOCOL>
|
||||||
uint8_t rcode;
|
void HIDBoot<BOOT_PROTOCOL>::Initialize() {
|
||||||
UsbDevice *p = NULL;
|
for (uint8_t i = 0; i < totalEndpoints; i++) {
|
||||||
EpInfo *oldep_ptr = NULL;
|
epInfo[i].epAddr = 0;
|
||||||
uint8_t len = 0;
|
epInfo[i].maxPktSize = (i) ? 0 : 8;
|
||||||
uint16_t cd_len = 0;
|
epInfo[i].epAttribs = 0;
|
||||||
|
epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER;
|
||||||
uint8_t num_of_conf; // number of configurations
|
}
|
||||||
uint8_t num_of_intf; // number of interfaces
|
bNumEP = 1;
|
||||||
|
bNumIface = 0;
|
||||||
AddressPool &addrPool = pUsb->GetAddressPool();
|
bConfNum = 0;
|
||||||
|
}
|
||||||
USBTRACE("BM Init\r\n");
|
|
||||||
|
template <const uint8_t BOOT_PROTOCOL>
|
||||||
if (bAddress)
|
uint8_t HIDBoot<BOOT_PROTOCOL>::Init(uint8_t parent, uint8_t port, bool lowspeed) {
|
||||||
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
|
const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR);
|
||||||
|
|
||||||
// Get pointer to pseudo device with address 0 assigned
|
uint8_t buf[constBufSize];
|
||||||
p = addrPool.GetUsbDevicePtr(0);
|
uint8_t rcode;
|
||||||
|
UsbDevice *p = NULL;
|
||||||
if (!p)
|
EpInfo *oldep_ptr = NULL;
|
||||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
uint8_t len = 0;
|
||||||
|
uint16_t cd_len = 0;
|
||||||
if (!p->epinfo)
|
|
||||||
{
|
uint8_t num_of_conf; // number of configurations
|
||||||
USBTRACE("epinfo\r\n");
|
uint8_t num_of_intf; // number of interfaces
|
||||||
return USB_ERROR_EPINFO_IS_NULL;
|
|
||||||
}
|
AddressPool &addrPool = pUsb->GetAddressPool();
|
||||||
|
|
||||||
// Save old pointer to EP_RECORD of address 0
|
USBTRACE("BM Init\r\n");
|
||||||
oldep_ptr = p->epinfo;
|
|
||||||
|
if (bAddress)
|
||||||
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
|
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
|
||||||
p->epinfo = epInfo;
|
|
||||||
|
// Get pointer to pseudo device with address 0 assigned
|
||||||
p->lowspeed = lowspeed;
|
p = addrPool.GetUsbDevicePtr(0);
|
||||||
|
|
||||||
// Get device descriptor
|
if (!p)
|
||||||
rcode = pUsb->getDevDescr( 0, 0, 8, (uint8_t*)buf );
|
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||||
|
|
||||||
if (!rcode)
|
if (!p->epinfo) {
|
||||||
len = (buf[0] > constBufSize) ? constBufSize : buf[0];
|
USBTRACE("epinfo\r\n");
|
||||||
|
return USB_ERROR_EPINFO_IS_NULL;
|
||||||
if( rcode )
|
}
|
||||||
{
|
|
||||||
// Restore p->epinfo
|
// Save old pointer to EP_RECORD of address 0
|
||||||
p->epinfo = oldep_ptr;
|
oldep_ptr = p->epinfo;
|
||||||
|
|
||||||
goto FailGetDevDescr;
|
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
|
||||||
}
|
p->epinfo = epInfo;
|
||||||
|
|
||||||
// Restore p->epinfo
|
p->lowspeed = lowspeed;
|
||||||
p->epinfo = oldep_ptr;
|
|
||||||
|
// Get device descriptor
|
||||||
// Allocate new address according to device class
|
rcode = pUsb->getDevDescr(0, 0, 8, (uint8_t*) buf);
|
||||||
bAddress = addrPool.AllocAddress(parent, false, port);
|
|
||||||
|
if (!rcode)
|
||||||
if (!bAddress)
|
len = (buf[0] > constBufSize) ? constBufSize : buf[0];
|
||||||
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
|
|
||||||
|
if (rcode) {
|
||||||
// Extract Max Packet Size from the device descriptor
|
// Restore p->epinfo
|
||||||
epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0;
|
p->epinfo = oldep_ptr;
|
||||||
|
|
||||||
// Assign new address to the device
|
goto FailGetDevDescr;
|
||||||
rcode = pUsb->setAddr( 0, 0, bAddress );
|
}
|
||||||
|
|
||||||
if (rcode)
|
// Restore p->epinfo
|
||||||
{
|
p->epinfo = oldep_ptr;
|
||||||
p->lowspeed = false;
|
|
||||||
addrPool.FreeAddress(bAddress);
|
// Allocate new address according to device class
|
||||||
bAddress = 0;
|
bAddress = addrPool.AllocAddress(parent, false, port);
|
||||||
USBTRACE2("setAddr:",rcode);
|
|
||||||
return rcode;
|
if (!bAddress)
|
||||||
}
|
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
|
||||||
|
|
||||||
USBTRACE2("Addr:", bAddress);
|
// Extract Max Packet Size from the device descriptor
|
||||||
|
epInfo[0].maxPktSize = (uint8_t) ((USB_DEVICE_DESCRIPTOR*) buf)->bMaxPacketSize0;
|
||||||
p->lowspeed = false;
|
|
||||||
|
// Assign new address to the device
|
||||||
p = addrPool.GetUsbDevicePtr(bAddress);
|
rcode = pUsb->setAddr(0, 0, bAddress);
|
||||||
|
|
||||||
if (!p)
|
if (rcode) {
|
||||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
p->lowspeed = false;
|
||||||
|
addrPool.FreeAddress(bAddress);
|
||||||
p->lowspeed = lowspeed;
|
bAddress = 0;
|
||||||
|
USBTRACE2("setAddr:", rcode);
|
||||||
if (len)
|
return rcode;
|
||||||
rcode = pUsb->getDevDescr( bAddress, 0, len, (uint8_t*)buf );
|
}
|
||||||
|
|
||||||
if(rcode)
|
USBTRACE2("Addr:", bAddress);
|
||||||
goto FailGetDevDescr;
|
|
||||||
|
p->lowspeed = false;
|
||||||
num_of_conf = ((USB_DEVICE_DESCRIPTOR*)buf)->bNumConfigurations;
|
|
||||||
|
p = addrPool.GetUsbDevicePtr(bAddress);
|
||||||
// Assign epInfo to epinfo pointer
|
|
||||||
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
|
if (!p)
|
||||||
|
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||||
if (rcode)
|
|
||||||
goto FailSetDevTblEntry;
|
p->lowspeed = lowspeed;
|
||||||
|
|
||||||
//USBTRACE2("NC:", num_of_conf);
|
if (len)
|
||||||
|
rcode = pUsb->getDevDescr(bAddress, 0, len, (uint8_t*) buf);
|
||||||
for (uint8_t i=0; i<num_of_conf; i++)
|
|
||||||
{
|
if (rcode)
|
||||||
//HexDumper<USBReadParser, uint16_t, uint16_t> HexDump;
|
goto FailGetDevDescr;
|
||||||
ConfigDescParser<
|
|
||||||
USB_CLASS_HID,
|
num_of_conf = ((USB_DEVICE_DESCRIPTOR*) buf)->bNumConfigurations;
|
||||||
HID_BOOT_INTF_SUBCLASS,
|
|
||||||
BOOT_PROTOCOL,
|
// Assign epInfo to epinfo pointer
|
||||||
CP_MASK_COMPARE_ALL> confDescrParser(this);
|
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
|
||||||
|
|
||||||
//rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump);
|
if (rcode)
|
||||||
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
|
goto FailSetDevTblEntry;
|
||||||
|
|
||||||
if (bNumEP > 1)
|
//USBTRACE2("NC:", num_of_conf);
|
||||||
break;
|
|
||||||
} // for
|
for (uint8_t i = 0; i < num_of_conf; i++) {
|
||||||
|
ConfigDescParser<
|
||||||
if (bNumEP < 2)
|
USB_CLASS_HID,
|
||||||
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
|
HID_BOOT_INTF_SUBCLASS,
|
||||||
|
BOOT_PROTOCOL,
|
||||||
//USBTRACE2("\r\nbAddr:", bAddress);
|
CP_MASK_COMPARE_ALL> confDescrParser(this);
|
||||||
//USBTRACE2("\r\nbNumEP:", bNumEP);
|
|
||||||
|
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
|
||||||
// Assign epInfo to epinfo pointer
|
|
||||||
rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
|
if (bNumEP > 1)
|
||||||
|
break;
|
||||||
//USBTRACE2("\r\nCnf:", bConfNum);
|
} // for
|
||||||
|
|
||||||
// Set Configuration Value
|
if (bNumEP < 2)
|
||||||
rcode = pUsb->setConf(bAddress, 0, bConfNum);
|
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
|
||||||
|
|
||||||
if (rcode)
|
//USBTRACE2("\r\nbAddr:", bAddress);
|
||||||
goto FailSetConfDescr;
|
//USBTRACE2("\r\nbNumEP:", bNumEP);
|
||||||
|
|
||||||
//USBTRACE2("\r\nIf:", bIfaceNum);
|
// Assign epInfo to epinfo pointer
|
||||||
|
rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
|
||||||
rcode = SetProtocol(bIfaceNum, HID_BOOT_PROTOCOL);
|
|
||||||
|
//USBTRACE2("\r\nCnf:", bConfNum);
|
||||||
if (rcode)
|
|
||||||
goto FailSetProtocol;
|
// Set Configuration Value
|
||||||
|
rcode = pUsb->setConf(bAddress, 0, bConfNum);
|
||||||
if (BOOT_PROTOCOL == 1)
|
|
||||||
{
|
if (rcode)
|
||||||
rcode = SetIdle(bIfaceNum, 0, 0);
|
goto FailSetConfDescr;
|
||||||
|
|
||||||
if (rcode)
|
//USBTRACE2("\r\nIf:", bIfaceNum);
|
||||||
goto FailSetIdle;
|
|
||||||
}
|
rcode = SetProtocol(bIfaceNum, HID_BOOT_PROTOCOL);
|
||||||
USBTRACE("BM configured\r\n");
|
|
||||||
|
if (rcode)
|
||||||
bPollEnable = true;
|
goto FailSetProtocol;
|
||||||
return 0;
|
|
||||||
|
if (BOOT_PROTOCOL == 1) {
|
||||||
FailGetDevDescr:
|
rcode = SetIdle(bIfaceNum, 0, 0);
|
||||||
USBTRACE("getDevDescr:");
|
|
||||||
goto Fail;
|
if (rcode)
|
||||||
|
goto FailSetIdle;
|
||||||
FailSetDevTblEntry:
|
}
|
||||||
USBTRACE("setDevTblEn:");
|
USBTRACE("BM configured\r\n");
|
||||||
goto Fail;
|
|
||||||
|
bPollEnable = true;
|
||||||
FailGetConfDescr:
|
return 0;
|
||||||
USBTRACE("getConf:");
|
|
||||||
goto Fail;
|
FailGetDevDescr:
|
||||||
|
USBTRACE("getDevDescr:");
|
||||||
FailSetProtocol:
|
goto Fail;
|
||||||
USBTRACE("SetProto:");
|
|
||||||
goto Fail;
|
FailSetDevTblEntry:
|
||||||
|
USBTRACE("setDevTblEn:");
|
||||||
FailSetIdle:
|
goto Fail;
|
||||||
USBTRACE("SetIdle:");
|
|
||||||
goto Fail;
|
FailGetConfDescr:
|
||||||
|
USBTRACE("getConf:");
|
||||||
FailSetConfDescr:
|
goto Fail;
|
||||||
USBTRACE("setConf:");
|
|
||||||
goto Fail;
|
FailSetProtocol:
|
||||||
|
USBTRACE("SetProto:");
|
||||||
Fail:
|
goto Fail;
|
||||||
Serial.println(rcode, HEX);
|
|
||||||
Release();
|
FailSetIdle:
|
||||||
return rcode;
|
USBTRACE("SetIdle:");
|
||||||
}
|
goto Fail;
|
||||||
|
|
||||||
template <const uint8_t BOOT_PROTOCOL>
|
FailSetConfDescr:
|
||||||
void HIDBoot<BOOT_PROTOCOL>::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep)
|
USBTRACE("setConf:");
|
||||||
{
|
goto Fail;
|
||||||
// If the first configuration satisfies, the others are not concidered.
|
|
||||||
if (bNumEP > 1 && conf != bConfNum)
|
Fail:
|
||||||
return;
|
PrintHex<uint8_t > (rcode, 0x80);
|
||||||
|
Notify(PSTR("\n"), 0x80);
|
||||||
//ErrorMessage<uint8_t>(PSTR("\r\nConf.Val"), conf);
|
// Serial.println(rcode, HEX);
|
||||||
//ErrorMessage<uint8_t>(PSTR("Iface Num"), iface);
|
Release();
|
||||||
//ErrorMessage<uint8_t>(PSTR("Alt.Set"), alt);
|
return rcode;
|
||||||
|
}
|
||||||
bConfNum = conf;
|
|
||||||
bIfaceNum = iface;
|
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) {
|
||||||
uint8_t index;
|
// If the first configuration satisfies, the others are not concidered.
|
||||||
|
if (bNumEP > 1 && conf != bConfNum)
|
||||||
if ((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80)
|
return;
|
||||||
{
|
|
||||||
index = epInterruptInIndex;
|
bConfNum = conf;
|
||||||
|
bIfaceNum = iface;
|
||||||
// Fill in the endpoint info structure
|
|
||||||
epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
|
uint8_t index;
|
||||||
epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
|
|
||||||
epInfo[index].epAttribs = 0;
|
if ((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80) {
|
||||||
|
index = epInterruptInIndex;
|
||||||
bNumEP ++;
|
|
||||||
|
// Fill in the endpoint info structure
|
||||||
//PrintEndpointDescriptor(pep);
|
epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
|
||||||
}
|
epInfo[index].maxPktSize = (uint8_t) pep->wMaxPacketSize;
|
||||||
}
|
epInfo[index].epAttribs = 0;
|
||||||
|
|
||||||
|
bNumEP++;
|
||||||
template <const uint8_t BOOT_PROTOCOL>
|
}
|
||||||
uint8_t HIDBoot<BOOT_PROTOCOL>::Release()
|
}
|
||||||
{
|
|
||||||
pUsb->GetAddressPool().FreeAddress(bAddress);
|
template <const uint8_t BOOT_PROTOCOL>
|
||||||
|
uint8_t HIDBoot<BOOT_PROTOCOL>::Release() {
|
||||||
bConfNum = 0;
|
pUsb->GetAddressPool().FreeAddress(bAddress);
|
||||||
bIfaceNum = 0;
|
|
||||||
bNumEP = 1;
|
bConfNum = 0;
|
||||||
bAddress = 0;
|
bIfaceNum = 0;
|
||||||
qNextPollTime = 0;
|
bNumEP = 1;
|
||||||
bPollEnable = false;
|
bAddress = 0;
|
||||||
return 0;
|
qNextPollTime = 0;
|
||||||
}
|
bPollEnable = false;
|
||||||
|
return 0;
|
||||||
template <const uint8_t BOOT_PROTOCOL>
|
}
|
||||||
uint8_t HIDBoot<BOOT_PROTOCOL>::Poll()
|
|
||||||
{
|
template <const uint8_t BOOT_PROTOCOL>
|
||||||
uint8_t rcode = 0;
|
uint8_t HIDBoot<BOOT_PROTOCOL>::Poll() {
|
||||||
|
uint8_t rcode = 0;
|
||||||
if (!bPollEnable)
|
|
||||||
return 0;
|
if (!bPollEnable)
|
||||||
|
return 0;
|
||||||
if (qNextPollTime <= millis())
|
|
||||||
{
|
if (qNextPollTime <= millis()) {
|
||||||
qNextPollTime = millis() + 10;
|
qNextPollTime = millis() + 10;
|
||||||
|
|
||||||
const uint8_t const_buff_len = 16;
|
const uint8_t const_buff_len = 16;
|
||||||
uint8_t buf[const_buff_len];
|
uint8_t buf[const_buff_len];
|
||||||
|
|
||||||
uint16_t read = (uint16_t)epInfo[epInterruptInIndex].maxPktSize;
|
uint16_t read = (uint16_t) epInfo[epInterruptInIndex].maxPktSize;
|
||||||
|
|
||||||
uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[epInterruptInIndex].epAddr, &read, buf);
|
uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[epInterruptInIndex].epAddr, &read, buf);
|
||||||
|
|
||||||
if (rcode)
|
if (rcode) {
|
||||||
{
|
if (rcode != hrNAK)
|
||||||
if (rcode != hrNAK)
|
USBTRACE2("Poll:", rcode);
|
||||||
USBTRACE2("Poll:", 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]);
|
//if (read)
|
||||||
//if (read)
|
// Serial.println("");
|
||||||
// Serial.println("");
|
|
||||||
|
if (pRptParser)
|
||||||
if (pRptParser)
|
pRptParser->Parse((HID*)this, 0, (uint8_t) read, buf);
|
||||||
pRptParser->Parse((HID*)this, 0, (uint8_t)read, buf);
|
}
|
||||||
}
|
return rcode;
|
||||||
return rcode;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endif // __HIDBOOTMOUSE_H__
|
#endif // __HIDBOOTMOUSE_H__
|
File diff suppressed because it is too large
Load diff
|
@ -1,195 +1,191 @@
|
||||||
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||||
|
|
||||||
This software may be distributed and modified under the terms of the GNU
|
This software may be distributed and modified under the terms of the GNU
|
||||||
General Public License version 2 (GPL2) as published by the Free Software
|
General Public License version 2 (GPL2) as published by the Free Software
|
||||||
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
||||||
this file. Please note that GPL2 Section 2[b] requires that all works based
|
this file. Please note that GPL2 Section 2[b] requires that all works based
|
||||||
on this software must also be made publicly available under the terms of
|
on this software must also be made publicly available under the terms of
|
||||||
the GPL2 ("Copyleft").
|
the GPL2 ("Copyleft").
|
||||||
|
|
||||||
Contact information
|
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__
|
||||||
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <avr/pgmspace.h>
|
#include <avr/pgmspace.h>
|
||||||
#include "avrpins.h"
|
#include "avrpins.h"
|
||||||
#include "max3421e.h"
|
#include "max3421e.h"
|
||||||
#include "usbhost.h"
|
#include "usbhost.h"
|
||||||
#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
|
||||||
#include <WProgram.h>
|
#include <WProgram.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "printhex.h"
|
#include "printhex.h"
|
||||||
#include "hexdump.h"
|
#include "hexdump.h"
|
||||||
#include "message.h"
|
#include "message.h"
|
||||||
#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 * const usagePageTitles0[];
|
||||||
static const char *usagePageTitles0[];
|
static const char * const usagePageTitles1[];
|
||||||
static const char *usagePageTitles1[];
|
static const char * const genDesktopTitles0[];
|
||||||
static const char *genDesktopTitles0[];
|
static const char * const genDesktopTitles1[];
|
||||||
static const char *genDesktopTitles1[];
|
static const char * const genDesktopTitles2[];
|
||||||
static const char *genDesktopTitles2[];
|
static const char * const genDesktopTitles3[];
|
||||||
static const char *genDesktopTitles3[];
|
static const char * const genDesktopTitles4[];
|
||||||
static const char *genDesktopTitles4[];
|
static const char * const simuTitles0[];
|
||||||
static const char *simuTitles0[];
|
static const char * const simuTitles1[];
|
||||||
static const char *simuTitles1[];
|
static const char * const simuTitles2[];
|
||||||
static const char *simuTitles2[];
|
static const char * const vrTitles0[];
|
||||||
static const char *vrTitles0[];
|
static const char * const vrTitles1[];
|
||||||
static const char *vrTitles1[];
|
static const char * const sportsCtrlTitles0[];
|
||||||
static const char *sportsCtrlTitles0[];
|
static const char * const sportsCtrlTitles1[];
|
||||||
static const char *sportsCtrlTitles1[];
|
static const char * const sportsCtrlTitles2[];
|
||||||
static const char *sportsCtrlTitles2[];
|
static const char * const gameTitles0[];
|
||||||
static const char *gameTitles0[];
|
static const char * const gameTitles1[];
|
||||||
static const char *gameTitles1[];
|
static const char * const genDevCtrlTitles[];
|
||||||
static const char *genDevCtrlTitles[];
|
static const char * const ledTitles[];
|
||||||
static const char *ledTitles[];
|
static const char * const telTitles0[];
|
||||||
static const char *telTitles0[];
|
static const char * const telTitles1[];
|
||||||
static const char *telTitles1[];
|
static const char * const telTitles2[];
|
||||||
static const char *telTitles2[];
|
static const char * const telTitles3[];
|
||||||
static const char *telTitles3[];
|
static const char * const telTitles4[];
|
||||||
static const char *telTitles4[];
|
static const char * const telTitles5[];
|
||||||
static const char *telTitles5[];
|
static const char * const consTitles0[];
|
||||||
static const char *consTitles0[];
|
static const char * const consTitles1[];
|
||||||
static const char *consTitles1[];
|
static const char * const consTitles2[];
|
||||||
static const char *consTitles2[];
|
static const char * const consTitles3[];
|
||||||
static const char *consTitles3[];
|
static const char * const consTitles4[];
|
||||||
static const char *consTitles4[];
|
static const char * const consTitles5[];
|
||||||
static const char *consTitles5[];
|
static const char * const consTitles6[];
|
||||||
static const char *consTitles6[];
|
static const char * const consTitles7[];
|
||||||
static const char *consTitles7[];
|
static const char * const consTitles8[];
|
||||||
static const char *consTitles8[];
|
static const char * const consTitles9[];
|
||||||
static const char *consTitles9[];
|
static const char * const consTitlesA[];
|
||||||
static const char *consTitlesA[];
|
static const char * const consTitlesB[];
|
||||||
static const char *consTitlesB[];
|
static const char * const consTitlesC[];
|
||||||
static const char *consTitlesC[];
|
static const char * const consTitlesD[];
|
||||||
static const char *consTitlesD[];
|
static const char * const consTitlesE[];
|
||||||
static const char *consTitlesE[];
|
static const char * const digitTitles0[];
|
||||||
static const char *digitTitles0[];
|
static const char * const digitTitles1[];
|
||||||
static const char *digitTitles1[];
|
static const char * const digitTitles2[];
|
||||||
static const char *digitTitles2[];
|
static const char * const aplphanumTitles0[];
|
||||||
static const char *aplphanumTitles0[];
|
static const char * const aplphanumTitles1[];
|
||||||
static const char *aplphanumTitles1[];
|
static const char * const aplphanumTitles2[];
|
||||||
static const char *aplphanumTitles2[];
|
static const char * const medInstrTitles0[];
|
||||||
static const char *medInstrTitles0[];
|
static const char * const medInstrTitles1[];
|
||||||
static const char *medInstrTitles1[];
|
static const char * const medInstrTitles2[];
|
||||||
static const char *medInstrTitles2[];
|
static const char * const medInstrTitles3[];
|
||||||
static const char *medInstrTitles3[];
|
static const char * const medInstrTitles4[];
|
||||||
static const char *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() :
|
ReportDescParserBase() :
|
||||||
itemParseState(0),
|
itemParseState(0),
|
||||||
itemSize(0),
|
itemSize(0),
|
||||||
itemPrefix(0),
|
itemPrefix(0),
|
||||||
rptSize(0),
|
rptSize(0),
|
||||||
rptCount(0),
|
rptCount(0),
|
||||||
pfUsage(NULL)
|
pfUsage(NULL) {
|
||||||
{
|
theBuffer.pValue = varBuffer;
|
||||||
theBuffer.pValue = varBuffer;
|
valParser.Initialize(&theBuffer);
|
||||||
valParser.Initialize(&theBuffer);
|
theSkipper.Initialize(&theBuffer);
|
||||||
theSkipper.Initialize(&theBuffer);
|
};
|
||||||
};
|
|
||||||
|
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);
|
|
||||||
|
enum {
|
||||||
enum
|
enErrorSuccess = 0
|
||||||
{
|
, 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 {
|
||||||
};
|
uint8_t rptId; // Report ID
|
||||||
|
uint8_t useMin; // Usage Minimum
|
||||||
class ReportDescParser2 : public ReportDescParserBase
|
uint8_t useMax; // Usage Maximum
|
||||||
{
|
uint8_t fieldCount; // Number of field being currently processed
|
||||||
uint8_t rptId; // Report ID
|
|
||||||
uint8_t useMin; // Usage Minimum
|
void OnInputItem(uint8_t itm); // Method which is called every time Input item is found
|
||||||
uint8_t useMax; // Usage Maximum
|
|
||||||
uint8_t fieldCount; // Number of field being currently processed
|
uint8_t *pBuf; // Report buffer pointer
|
||||||
|
uint8_t bLen; // Report length
|
||||||
void OnInputItem(uint8_t itm); // Method which is called every time Input item is found
|
|
||||||
|
protected:
|
||||||
uint8_t *pBuf; // Report buffer pointer
|
virtual uint8_t ParseItem(uint8_t **pp, uint16_t *pcntdn);
|
||||||
uint8_t bLen; // Report length
|
|
||||||
|
public:
|
||||||
protected:
|
|
||||||
virtual uint8_t ParseItem(uint8_t **pp, uint16_t *pcntdn);
|
ReportDescParser2(uint16_t len, uint8_t *pbuf) :
|
||||||
|
ReportDescParserBase(), rptId(0), useMin(0), useMax(0), fieldCount(0), pBuf(pbuf), bLen(len) {
|
||||||
public:
|
};
|
||||||
ReportDescParser2(uint16_t len, uint8_t *pbuf) :
|
};
|
||||||
ReportDescParserBase(), bLen(len), pBuf(pbuf), rptId(0), useMin(0), useMax(0), fieldCount(0)
|
|
||||||
{};
|
class UniversalReportParser : public HIDReportParser {
|
||||||
};
|
public:
|
||||||
|
virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf);
|
||||||
class UniversalReportParser : public HIDReportParser
|
};
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // __HIDDESCRIPTORPARSER_H__
|
#endif // __HIDDESCRIPTORPARSER_H__
|
796
hiduniversal.cpp
796
hiduniversal.cpp
|
@ -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++) {
|
||||||
{
|
if (descrInfo[i].bDescrType == type) {
|
||||||
for (uint8_t i=0, n=0; i<HID_MAX_HID_CLASS_DESCRIPTORS; i++)
|
if (n == num)
|
||||||
{
|
return descrInfo[i].wDescriptorLength;
|
||||||
if (descrInfo[i].bDescrType == type)
|
n++;
|
||||||
{
|
}
|
||||||
if (n == num)
|
}
|
||||||
return descrInfo[i].wDescriptorLength;
|
return 0;
|
||||||
n ++;
|
}
|
||||||
}
|
|
||||||
}
|
void HIDUniversal::Initialize() {
|
||||||
return 0;
|
for (uint8_t i = 0; i < MAX_REPORT_PARSERS; i++) {
|
||||||
}
|
rptParsers[i].rptId = 0;
|
||||||
|
rptParsers[i].rptParser = NULL;
|
||||||
void HIDUniversal::Initialize()
|
}
|
||||||
{
|
for (uint8_t i = 0; i < HID_MAX_HID_CLASS_DESCRIPTORS; i++) {
|
||||||
for (uint8_t i=0; i<MAX_REPORT_PARSERS; i++)
|
descrInfo[i].bDescrType = 0;
|
||||||
{
|
descrInfo[i].wDescriptorLength = 0;
|
||||||
rptParsers[i].rptId = 0;
|
}
|
||||||
rptParsers[i].rptParser = NULL;
|
for (uint8_t i = 0; i < maxHidInterfaces; i++) {
|
||||||
}
|
hidInterfaces[i].bmInterface = 0;
|
||||||
for (uint8_t i=0; i<HID_MAX_HID_CLASS_DESCRIPTORS; i++)
|
hidInterfaces[i].bmProtocol = 0;
|
||||||
{
|
|
||||||
descrInfo[i].bDescrType = 0;
|
for (uint8_t j = 0; j < maxEpPerInterface; j++)
|
||||||
descrInfo[i].wDescriptorLength = 0;
|
hidInterfaces[i].epIndex[j] = 0;
|
||||||
}
|
}
|
||||||
for (uint8_t i=0; i<maxHidInterfaces; i++)
|
for (uint8_t i = 0; i < totalEndpoints; i++) {
|
||||||
{
|
epInfo[i].epAddr = 0;
|
||||||
hidInterfaces[i].bmInterface = 0;
|
epInfo[i].maxPktSize = (i) ? 0 : 8;
|
||||||
hidInterfaces[i].bmProtocol = 0;
|
epInfo[i].epAttribs = 0;
|
||||||
|
epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER;
|
||||||
for (uint8_t j=0; j<maxEpPerInterface; j++)
|
}
|
||||||
hidInterfaces[i].epIndex[j] = 0;
|
bNumEP = 1;
|
||||||
}
|
bNumIface = 0;
|
||||||
for(uint8_t i=0; i<totalEndpoints; i++)
|
bConfNum = 0;
|
||||||
{
|
|
||||||
epInfo[i].epAddr = 0;
|
ZeroMemory(constBuffLen, prevBuf);
|
||||||
epInfo[i].maxPktSize = (i) ? 0 : 8;
|
}
|
||||||
epInfo[i].epAttribs = 0;
|
|
||||||
epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER;
|
bool HIDUniversal::SetReportParser(uint8_t id, HIDReportParser *prs) {
|
||||||
}
|
for (uint8_t i = 0; i < MAX_REPORT_PARSERS; i++) {
|
||||||
bNumEP = 1;
|
if (rptParsers[i].rptId == 0 && rptParsers[i].rptParser == NULL) {
|
||||||
bNumIface = 0;
|
rptParsers[i].rptId = id;
|
||||||
bConfNum = 0;
|
rptParsers[i].rptParser = prs;
|
||||||
|
return true;
|
||||||
ZeroMemory(constBuffLen, prevBuf);
|
}
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
bool HIDUniversal::SetReportParser(uint8_t id, HIDReportParser *prs)
|
}
|
||||||
{
|
|
||||||
for (uint8_t i=0; i<MAX_REPORT_PARSERS; i++)
|
HIDReportParser* HIDUniversal::GetReportParser(uint8_t id) {
|
||||||
{
|
if (!bHasReportId)
|
||||||
if (rptParsers[i].rptId == 0 && rptParsers[i].rptParser == NULL)
|
return ((rptParsers[0].rptParser) ? rptParsers[0].rptParser : NULL);
|
||||||
{
|
|
||||||
rptParsers[i].rptId = id;
|
for (uint8_t i = 0; i < MAX_REPORT_PARSERS; i++) {
|
||||||
rptParsers[i].rptParser = prs;
|
if (rptParsers[i].rptId == id)
|
||||||
return true;
|
return rptParsers[i].rptParser;
|
||||||
}
|
}
|
||||||
}
|
return NULL;
|
||||||
return false;
|
}
|
||||||
}
|
|
||||||
|
uint8_t HIDUniversal::Init(uint8_t parent, uint8_t port, bool lowspeed) {
|
||||||
HIDReportParser* HIDUniversal::GetReportParser(uint8_t id)
|
const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR);
|
||||||
{
|
|
||||||
if (!bHasReportId)
|
uint8_t buf[constBufSize];
|
||||||
return ((rptParsers[0].rptParser) ? rptParsers[0].rptParser : NULL);
|
uint8_t rcode;
|
||||||
|
UsbDevice *p = NULL;
|
||||||
for (uint8_t i=0; i<MAX_REPORT_PARSERS; i++)
|
EpInfo *oldep_ptr = NULL;
|
||||||
{
|
uint8_t len = 0;
|
||||||
if (rptParsers[i].rptId == id)
|
|
||||||
return rptParsers[i].rptParser;
|
uint8_t num_of_conf; // number of configurations
|
||||||
}
|
//uint8_t num_of_intf; // number of interfaces
|
||||||
return NULL;
|
|
||||||
}
|
AddressPool &addrPool = pUsb->GetAddressPool();
|
||||||
|
|
||||||
uint8_t HIDUniversal::Init(uint8_t parent, uint8_t port, bool lowspeed)
|
USBTRACE("HU Init\r\n");
|
||||||
{
|
|
||||||
const uint8_t constBufSize = sizeof(USB_DEVICE_DESCRIPTOR);
|
if (bAddress)
|
||||||
|
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
|
||||||
uint8_t buf[constBufSize];
|
|
||||||
uint8_t rcode;
|
// Get pointer to pseudo device with address 0 assigned
|
||||||
UsbDevice *p = NULL;
|
p = addrPool.GetUsbDevicePtr(0);
|
||||||
EpInfo *oldep_ptr = NULL;
|
|
||||||
uint8_t len = 0;
|
if (!p)
|
||||||
|
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||||
uint8_t num_of_conf; // number of configurations
|
|
||||||
uint8_t num_of_intf; // number of interfaces
|
if (!p->epinfo) {
|
||||||
|
USBTRACE("epinfo\r\n");
|
||||||
AddressPool &addrPool = pUsb->GetAddressPool();
|
return USB_ERROR_EPINFO_IS_NULL;
|
||||||
|
}
|
||||||
USBTRACE("HU Init\r\n");
|
|
||||||
|
// Save old pointer to EP_RECORD of address 0
|
||||||
if (bAddress)
|
oldep_ptr = p->epinfo;
|
||||||
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
|
|
||||||
|
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
|
||||||
// Get pointer to pseudo device with address 0 assigned
|
p->epinfo = epInfo;
|
||||||
p = addrPool.GetUsbDevicePtr(0);
|
|
||||||
|
p->lowspeed = lowspeed;
|
||||||
if (!p)
|
|
||||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
// Get device descriptor
|
||||||
|
rcode = pUsb->getDevDescr(0, 0, 8, (uint8_t*) buf);
|
||||||
if (!p->epinfo)
|
|
||||||
{
|
if (!rcode)
|
||||||
USBTRACE("epinfo\r\n");
|
len = (buf[0] > constBufSize) ? constBufSize : buf[0];
|
||||||
return USB_ERROR_EPINFO_IS_NULL;
|
|
||||||
}
|
if (rcode) {
|
||||||
|
// Restore p->epinfo
|
||||||
// Save old pointer to EP_RECORD of address 0
|
p->epinfo = oldep_ptr;
|
||||||
oldep_ptr = p->epinfo;
|
|
||||||
|
goto FailGetDevDescr;
|
||||||
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
|
}
|
||||||
p->epinfo = epInfo;
|
|
||||||
|
// Restore p->epinfo
|
||||||
p->lowspeed = lowspeed;
|
p->epinfo = oldep_ptr;
|
||||||
|
|
||||||
//delay(200);
|
// Allocate new address according to device class
|
||||||
|
bAddress = addrPool.AllocAddress(parent, false, port);
|
||||||
// Get device descriptor
|
|
||||||
rcode = pUsb->getDevDescr( 0, 0, 8, (uint8_t*)buf );
|
if (!bAddress)
|
||||||
|
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
|
||||||
if (!rcode)
|
|
||||||
len = (buf[0] > constBufSize) ? constBufSize : buf[0];
|
// Extract Max Packet Size from the device descriptor
|
||||||
|
epInfo[0].maxPktSize = (uint8_t) ((USB_DEVICE_DESCRIPTOR*) buf)->bMaxPacketSize0;
|
||||||
if( rcode )
|
|
||||||
{
|
// Assign new address to the device
|
||||||
// Restore p->epinfo
|
rcode = pUsb->setAddr(0, 0, bAddress);
|
||||||
p->epinfo = oldep_ptr;
|
|
||||||
|
if (rcode) {
|
||||||
goto FailGetDevDescr;
|
p->lowspeed = false;
|
||||||
}
|
addrPool.FreeAddress(bAddress);
|
||||||
|
bAddress = 0;
|
||||||
// Restore p->epinfo
|
USBTRACE2("setAddr:", rcode);
|
||||||
p->epinfo = oldep_ptr;
|
return rcode;
|
||||||
|
}
|
||||||
// Allocate new address according to device class
|
|
||||||
bAddress = addrPool.AllocAddress(parent, false, port);
|
USBTRACE2("Addr:", bAddress);
|
||||||
|
|
||||||
if (!bAddress)
|
p->lowspeed = false;
|
||||||
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
|
|
||||||
|
p = addrPool.GetUsbDevicePtr(bAddress);
|
||||||
// Extract Max Packet Size from the device descriptor
|
|
||||||
epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0;
|
if (!p)
|
||||||
|
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||||
// Assign new address to the device
|
|
||||||
rcode = pUsb->setAddr( 0, 0, bAddress );
|
p->lowspeed = lowspeed;
|
||||||
|
|
||||||
if (rcode)
|
if (len)
|
||||||
{
|
rcode = pUsb->getDevDescr(bAddress, 0, len, (uint8_t*) buf);
|
||||||
p->lowspeed = false;
|
|
||||||
addrPool.FreeAddress(bAddress);
|
if (rcode)
|
||||||
bAddress = 0;
|
goto FailGetDevDescr;
|
||||||
USBTRACE2("setAddr:",rcode);
|
|
||||||
return rcode;
|
num_of_conf = ((USB_DEVICE_DESCRIPTOR*) buf)->bNumConfigurations;
|
||||||
}
|
|
||||||
|
// Assign epInfo to epinfo pointer
|
||||||
USBTRACE2("Addr:", bAddress);
|
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
|
||||||
|
|
||||||
p->lowspeed = false;
|
if (rcode)
|
||||||
|
goto FailSetDevTblEntry;
|
||||||
p = addrPool.GetUsbDevicePtr(bAddress);
|
|
||||||
|
USBTRACE2("NC:", num_of_conf);
|
||||||
if (!p)
|
|
||||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
for (uint8_t i = 0; i < num_of_conf; i++) {
|
||||||
|
//HexDumper<USBReadParser, uint16_t, uint16_t> HexDump;
|
||||||
p->lowspeed = lowspeed;
|
ConfigDescParser<USB_CLASS_HID, 0, 0,
|
||||||
|
CP_MASK_COMPARE_CLASS> confDescrParser(this);
|
||||||
delay(500);
|
|
||||||
|
//rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump);
|
||||||
if (len)
|
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
|
||||||
rcode = pUsb->getDevDescr( bAddress, 0, len, (uint8_t*)buf );
|
|
||||||
|
if (rcode)
|
||||||
if(rcode)
|
goto FailGetConfDescr;
|
||||||
goto FailGetDevDescr;
|
|
||||||
|
if (bNumEP > 1)
|
||||||
num_of_conf = ((USB_DEVICE_DESCRIPTOR*)buf)->bNumConfigurations;
|
break;
|
||||||
|
} // for
|
||||||
// Assign epInfo to epinfo pointer
|
|
||||||
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
|
if (bNumEP < 2)
|
||||||
|
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
|
||||||
if (rcode)
|
|
||||||
goto FailSetDevTblEntry;
|
// Assign epInfo to epinfo pointer
|
||||||
|
rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
|
||||||
USBTRACE2("NC:", num_of_conf);
|
|
||||||
|
USBTRACE2("\r\nCnf:", bConfNum);
|
||||||
for (uint8_t i=0; i<num_of_conf; i++)
|
|
||||||
{
|
// Set Configuration Value
|
||||||
//delay(1000);
|
rcode = pUsb->setConf(bAddress, 0, bConfNum);
|
||||||
//HexDumper<USBReadParser, uint16_t, uint16_t> HexDump;
|
|
||||||
ConfigDescParser<USB_CLASS_HID, 0, 0,
|
if (rcode)
|
||||||
CP_MASK_COMPARE_CLASS> confDescrParser(this);
|
goto FailSetConfDescr;
|
||||||
|
|
||||||
//rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump);
|
for (uint8_t i = 0; i < bNumIface; i++) {
|
||||||
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
|
if (hidInterfaces[i].epIndex[epInterruptInIndex] == 0)
|
||||||
|
continue;
|
||||||
if (bNumEP > 1)
|
|
||||||
break;
|
rcode = SetIdle(hidInterfaces[i].bmInterface, 0, 0);
|
||||||
} // for
|
|
||||||
|
if (rcode && rcode != hrSTALL)
|
||||||
if (bNumEP < 2)
|
goto FailSetIdle;
|
||||||
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
|
}
|
||||||
|
|
||||||
// Assign epInfo to epinfo pointer
|
USBTRACE("HU configured\r\n");
|
||||||
rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
|
|
||||||
|
OnInitSuccessful();
|
||||||
USBTRACE2("\r\nCnf:", bConfNum);
|
|
||||||
|
bPollEnable = true;
|
||||||
// Set Configuration Value
|
return 0;
|
||||||
rcode = pUsb->setConf(bAddress, 0, bConfNum);
|
|
||||||
|
FailGetDevDescr:
|
||||||
if (rcode)
|
USBTRACE("getDevDescr:");
|
||||||
goto FailSetConfDescr;
|
goto Fail;
|
||||||
|
|
||||||
for (uint8_t i=0; i<bNumIface; i++)
|
FailSetDevTblEntry:
|
||||||
{
|
USBTRACE("setDevTblEn:");
|
||||||
if (hidInterfaces[i].epIndex[epInterruptInIndex] == 0)
|
goto Fail;
|
||||||
continue;
|
|
||||||
|
FailGetConfDescr:
|
||||||
rcode = SetIdle(hidInterfaces[i].bmInterface, 0, 0);
|
USBTRACE("getConf:");
|
||||||
|
goto Fail;
|
||||||
if (rcode && rcode != hrSTALL)
|
|
||||||
goto FailSetIdle;
|
FailSetConfDescr:
|
||||||
}
|
USBTRACE("setConf:");
|
||||||
|
goto Fail;
|
||||||
USBTRACE("HU configured\r\n");
|
|
||||||
|
FailSetIdle:
|
||||||
OnInitSuccessful();
|
USBTRACE("SetIdle:");
|
||||||
|
goto Fail;
|
||||||
bPollEnable = true;
|
|
||||||
return 0;
|
Fail:
|
||||||
|
PrintHex<uint8_t > (rcode, 0x80);
|
||||||
FailGetDevDescr:
|
Notify(PSTR("\r\n"), 0x80);
|
||||||
USBTRACE("getDevDescr:");
|
//Serial.println(rcode, HEX);
|
||||||
goto Fail;
|
Release();
|
||||||
|
return rcode;
|
||||||
FailSetDevTblEntry:
|
}
|
||||||
USBTRACE("setDevTblEn:");
|
|
||||||
goto Fail;
|
HIDUniversal::HIDInterface* HIDUniversal::FindInterface(uint8_t iface, uint8_t alt, uint8_t proto) {
|
||||||
|
for (uint8_t i = 0; i < bNumIface && i < maxHidInterfaces; i++)
|
||||||
FailGetConfDescr:
|
if (hidInterfaces[i].bmInterface == iface && hidInterfaces[i].bmAltSet == alt
|
||||||
USBTRACE("getConf:");
|
&& hidInterfaces[i].bmProtocol == proto)
|
||||||
goto Fail;
|
return hidInterfaces + i;
|
||||||
|
return NULL;
|
||||||
FailSetConfDescr:
|
}
|
||||||
USBTRACE("setConf:");
|
|
||||||
goto Fail;
|
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.
|
||||||
FailSetProtocol:
|
if (bNumEP > 1 && conf != bConfNum)
|
||||||
USBTRACE("SetProto:");
|
return;
|
||||||
goto Fail;
|
|
||||||
|
//ErrorMessage<uint8_t>(PSTR("\r\nConf.Val"), conf);
|
||||||
FailSetIdle:
|
//ErrorMessage<uint8_t>(PSTR("Iface Num"), iface);
|
||||||
USBTRACE("SetIdle:");
|
//ErrorMessage<uint8_t>(PSTR("Alt.Set"), alt);
|
||||||
goto Fail;
|
|
||||||
|
bConfNum = conf;
|
||||||
FailGetReportDescr:
|
|
||||||
USBTRACE("GetReportDescr:");
|
uint8_t index = 0;
|
||||||
goto Fail;
|
HIDInterface *piface = FindInterface(iface, alt, proto);
|
||||||
|
|
||||||
Fail:
|
// Fill in interface structure in case of new interface
|
||||||
Serial.println(rcode, HEX);
|
if (!piface) {
|
||||||
Release();
|
piface = hidInterfaces + bNumIface;
|
||||||
return rcode;
|
piface->bmInterface = iface;
|
||||||
}
|
piface->bmAltSet = alt;
|
||||||
|
piface->bmProtocol = proto;
|
||||||
HIDUniversal::HIDInterface* HIDUniversal::FindInterface(uint8_t iface, uint8_t alt, uint8_t proto)
|
bNumIface++;
|
||||||
{
|
}
|
||||||
for (uint8_t i=0; i<bNumIface && i<maxHidInterfaces; i++)
|
|
||||||
if (hidInterfaces[i].bmInterface == iface && hidInterfaces[i].bmAltSet == alt
|
if ((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80)
|
||||||
&& hidInterfaces[i].bmProtocol == proto)
|
index = epInterruptInIndex;
|
||||||
return hidInterfaces + i;
|
else
|
||||||
return NULL;
|
index = epInterruptOutIndex;
|
||||||
}
|
|
||||||
|
if (index) {
|
||||||
void HIDUniversal::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep)
|
// Fill in the endpoint info structure
|
||||||
{
|
epInfo[bNumEP].epAddr = (pep->bEndpointAddress & 0x0F);
|
||||||
// If the first configuration satisfies, the others are not concidered.
|
epInfo[bNumEP].maxPktSize = (uint8_t) pep->wMaxPacketSize;
|
||||||
if (bNumEP > 1 && conf != bConfNum)
|
epInfo[bNumEP].epAttribs = 0;
|
||||||
return;
|
epInfo[bNumEP].bmNakPower = USB_NAK_NOWAIT;
|
||||||
|
|
||||||
//ErrorMessage<uint8_t>(PSTR("\r\nConf.Val"), conf);
|
// Fill in the endpoint index list
|
||||||
//ErrorMessage<uint8_t>(PSTR("Iface Num"), iface);
|
piface->epIndex[index] = bNumEP; //(pep->bEndpointAddress & 0x0F);
|
||||||
//ErrorMessage<uint8_t>(PSTR("Alt.Set"), alt);
|
|
||||||
|
bNumEP++;
|
||||||
bConfNum = conf;
|
}
|
||||||
|
//PrintEndpointDescriptor(pep);
|
||||||
uint8_t index = 0;
|
}
|
||||||
HIDInterface *piface = FindInterface(iface, alt, proto);
|
|
||||||
|
uint8_t HIDUniversal::Release() {
|
||||||
// Fill in interface structure in case of new interface
|
pUsb->GetAddressPool().FreeAddress(bAddress);
|
||||||
if (!piface)
|
|
||||||
{
|
bNumEP = 1;
|
||||||
piface = hidInterfaces + bNumIface;
|
bAddress = 0;
|
||||||
piface->bmInterface = iface;
|
qNextPollTime = 0;
|
||||||
piface->bmAltSet = alt;
|
bPollEnable = false;
|
||||||
piface->bmProtocol = proto;
|
return 0;
|
||||||
bNumIface ++;
|
}
|
||||||
}
|
|
||||||
|
bool HIDUniversal::BuffersIdentical(uint8_t len, uint8_t *buf1, uint8_t *buf2) {
|
||||||
if ((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80)
|
for (uint8_t i = 0; i < len; i++)
|
||||||
index = epInterruptInIndex;
|
if (buf1[i] != buf2[i])
|
||||||
else
|
return false;
|
||||||
index = epInterruptOutIndex;
|
return true;
|
||||||
|
}
|
||||||
if (index)
|
|
||||||
{
|
void HIDUniversal::ZeroMemory(uint8_t len, uint8_t *buf) {
|
||||||
// Fill in the endpoint info structure
|
for (uint8_t i = 0; i < len; i++)
|
||||||
epInfo[bNumEP].epAddr = (pep->bEndpointAddress & 0x0F);
|
buf[i] = 0;
|
||||||
epInfo[bNumEP].maxPktSize = (uint8_t)pep->wMaxPacketSize;
|
}
|
||||||
epInfo[bNumEP].epAttribs = 0;
|
|
||||||
epInfo[bNumEP].bmNakPower = USB_NAK_NOWAIT;
|
void HIDUniversal::SaveBuffer(uint8_t len, uint8_t *src, uint8_t *dest) {
|
||||||
|
for (uint8_t i = 0; i < len; i++)
|
||||||
// Fill in the endpoint index list
|
dest[i] = src[i];
|
||||||
piface->epIndex[index] = bNumEP; //(pep->bEndpointAddress & 0x0F);
|
}
|
||||||
|
|
||||||
bNumEP ++;
|
uint8_t HIDUniversal::Poll() {
|
||||||
}
|
uint8_t rcode = 0;
|
||||||
//PrintEndpointDescriptor(pep);
|
|
||||||
}
|
if (!bPollEnable)
|
||||||
|
return 0;
|
||||||
|
|
||||||
uint8_t HIDUniversal::Release()
|
if (qNextPollTime <= millis()) {
|
||||||
{
|
qNextPollTime = millis() + 50;
|
||||||
pUsb->GetAddressPool().FreeAddress(bAddress);
|
|
||||||
|
uint8_t buf[constBuffLen];
|
||||||
bNumEP = 1;
|
|
||||||
bAddress = 0;
|
for (uint8_t i = 0; i < bNumIface; i++) {
|
||||||
qNextPollTime = 0;
|
uint8_t index = hidInterfaces[i].epIndex[epInterruptInIndex];
|
||||||
bPollEnable = false;
|
uint16_t read = (uint16_t) epInfo[index].maxPktSize;
|
||||||
return 0;
|
|
||||||
}
|
ZeroMemory(constBuffLen, buf);
|
||||||
|
|
||||||
bool HIDUniversal::BuffersIdentical(uint8_t len, uint8_t *buf1, uint8_t *buf2)
|
uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[index].epAddr, &read, buf);
|
||||||
{
|
|
||||||
for (uint8_t i=0; i<len; i++)
|
if (rcode) {
|
||||||
if (buf1[i] != buf2[i])
|
if (rcode != hrNAK)
|
||||||
return false;
|
USBTRACE2("Poll:", rcode);
|
||||||
return true;
|
return rcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HIDUniversal::ZeroMemory(uint8_t len, uint8_t *buf)
|
if (read > constBuffLen)
|
||||||
{
|
read = constBuffLen;
|
||||||
for (uint8_t i=0; i<len; i++)
|
|
||||||
buf[i] = 0;
|
bool identical = BuffersIdentical(read, buf, prevBuf);
|
||||||
}
|
|
||||||
void HIDUniversal::SaveBuffer(uint8_t len, uint8_t *src, uint8_t *dest)
|
SaveBuffer(read, buf, prevBuf);
|
||||||
{
|
|
||||||
for (uint8_t i=0; i<len; i++)
|
if (identical)
|
||||||
dest[i] = src[i];
|
return 0;
|
||||||
}
|
|
||||||
|
Notify(PSTR("\r\nBuf: "), 0x80);
|
||||||
uint8_t HIDUniversal::Poll()
|
|
||||||
{
|
for (uint8_t i = 0; i < read; i++)
|
||||||
uint8_t rcode = 0;
|
PrintHex<uint8_t > (buf[i], 0x80);
|
||||||
|
|
||||||
if (!bPollEnable)
|
Notify(PSTR("\r\n"), 0x80);
|
||||||
return 0;
|
|
||||||
|
HIDReportParser *prs = GetReportParser(((bHasReportId) ? *buf : 0));
|
||||||
if (qNextPollTime <= millis())
|
|
||||||
{
|
if (prs)
|
||||||
qNextPollTime = millis() + 50;
|
prs->Parse(this, bHasReportId, (uint8_t) read, buf);
|
||||||
|
}
|
||||||
uint8_t buf[constBuffLen];
|
}
|
||||||
|
return rcode;
|
||||||
for (uint8_t i=0; i<bNumIface; i++)
|
}
|
||||||
{
|
|
||||||
uint8_t index = hidInterfaces[i].epIndex[epInterruptInIndex];
|
|
||||||
uint16_t read = (uint16_t)epInfo[index].maxPktSize;
|
|
||||||
|
|
||||||
ZeroMemory(constBuffLen, buf);
|
|
||||||
|
|
||||||
uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[index].epAddr, &read, buf);
|
|
||||||
|
|
||||||
if (rcode)
|
|
||||||
{
|
|
||||||
if (rcode != hrNAK)
|
|
||||||
USBTRACE2("Poll:", rcode);
|
|
||||||
return rcode;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (read > constBuffLen)
|
|
||||||
read = constBuffLen;
|
|
||||||
|
|
||||||
bool identical = BuffersIdentical(read, buf, prevBuf);
|
|
||||||
|
|
||||||
SaveBuffer(read, buf, prevBuf);
|
|
||||||
|
|
||||||
if (identical)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
Serial.print("\r\nBuf: ");
|
|
||||||
|
|
||||||
for (uint8_t i=0; i<read; i++)
|
|
||||||
PrintHex<uint8_t>(buf[i]);
|
|
||||||
|
|
||||||
Serial.println("");
|
|
||||||
|
|
||||||
HIDReportParser *prs = GetReportParser( ((bHasReportId) ? *buf : 0) );
|
|
||||||
|
|
||||||
if (prs)
|
|
||||||
prs->Parse(this, bHasReportId, (uint8_t)read, buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return rcode;
|
|
||||||
}
|
|
||||||
|
|
152
hiduniversal.h
152
hiduniversal.h
|
@ -1,75 +1,79 @@
|
||||||
#if !defined(__HIDUNIVERSAL_H__)
|
#if !defined(__HIDUNIVERSAL_H__)
|
||||||
#define __HIDUNIVERSAL_H__
|
#define __HIDUNIVERSAL_H__
|
||||||
|
|
||||||
#include "hid.h"
|
#include "hid.h"
|
||||||
//#include "hidescriptorparser.h"
|
//#include "hidescriptorparser.h"
|
||||||
|
|
||||||
class HIDUniversal : public HID
|
class HIDUniversal : public HID {
|
||||||
{
|
|
||||||
struct ReportParser
|
struct ReportParser {
|
||||||
{
|
uint8_t rptId;
|
||||||
uint8_t rptId;
|
HIDReportParser *rptParser;
|
||||||
HIDReportParser *rptParser;
|
} rptParsers[MAX_REPORT_PARSERS];
|
||||||
} rptParsers[MAX_REPORT_PARSERS];
|
|
||||||
|
// HID class specific descriptor type and length info obtained from HID descriptor
|
||||||
// HID class specific descriptor type and length info obtained from HID descriptor
|
HID_CLASS_DESCRIPTOR_LEN_AND_TYPE descrInfo[HID_MAX_HID_CLASS_DESCRIPTORS];
|
||||||
HID_CLASS_DESCRIPTOR_LEN_AND_TYPE descrInfo[HID_MAX_HID_CLASS_DESCRIPTORS];
|
|
||||||
|
// Returns HID class specific descriptor length by its type and order number
|
||||||
// Returns HID class specific descriptor length by its type and order number
|
uint16_t GetHidClassDescrLen(uint8_t type, uint8_t num);
|
||||||
uint16_t GetHidClassDescrLen(uint8_t type, uint8_t num);
|
|
||||||
|
EpInfo epInfo[totalEndpoints];
|
||||||
EpInfo epInfo[totalEndpoints];
|
|
||||||
|
struct HIDInterface {
|
||||||
struct HIDInterface
|
|
||||||
{
|
struct {
|
||||||
struct
|
uint8_t bmInterface : 3;
|
||||||
{
|
uint8_t bmAltSet : 3;
|
||||||
uint8_t bmInterface : 3;
|
uint8_t bmProtocol : 2;
|
||||||
uint8_t bmAltSet : 3;
|
};
|
||||||
uint8_t bmProtocol : 2;
|
uint8_t epIndex[maxEpPerInterface];
|
||||||
};
|
};
|
||||||
uint8_t epIndex[maxEpPerInterface];
|
|
||||||
};
|
HIDInterface hidInterfaces[maxHidInterfaces];
|
||||||
|
|
||||||
HIDInterface hidInterfaces[maxHidInterfaces];
|
uint8_t bConfNum; // configuration number
|
||||||
|
uint8_t bNumIface; // number of interfaces in the configuration
|
||||||
uint8_t bConfNum; // configuration number
|
uint8_t bNumEP; // total number of EP in the configuration
|
||||||
uint8_t bNumIface; // number of interfaces in the configuration
|
uint32_t qNextPollTime; // next poll time
|
||||||
uint8_t bNumEP; // total number of EP in the configuration
|
bool bPollEnable; // poll enable flag
|
||||||
uint32_t qNextPollTime; // next poll time
|
|
||||||
bool bPollEnable; // poll enable flag
|
static const uint16_t constBuffLen = 64; // event buffer length
|
||||||
|
uint8_t prevBuf[constBuffLen]; // previous event buffer
|
||||||
static const uint16_t constBuffLen = 64; // event buffer length
|
|
||||||
uint8_t prevBuf[constBuffLen]; // previous event buffer
|
void Initialize();
|
||||||
|
HIDInterface* FindInterface(uint8_t iface, uint8_t alt, uint8_t proto);
|
||||||
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 ZeroMemory(uint8_t len, uint8_t *buf);
|
void SaveBuffer(uint8_t len, uint8_t *src, uint8_t *dest);
|
||||||
bool BuffersIdentical(uint8_t len, uint8_t *buf1, uint8_t *buf2);
|
|
||||||
void SaveBuffer(uint8_t len, uint8_t *src, uint8_t *dest);
|
protected:
|
||||||
|
bool bHasReportId;
|
||||||
protected:
|
|
||||||
bool bHasReportId;
|
// HID implementation
|
||||||
|
virtual HIDReportParser* GetReportParser(uint8_t id);
|
||||||
// HID implementation
|
|
||||||
virtual HIDReportParser* GetReportParser(uint8_t id);
|
virtual uint8_t OnInitSuccessful() {
|
||||||
virtual uint8_t OnInitSuccessful() { return 0; };
|
return 0;
|
||||||
|
};
|
||||||
public:
|
|
||||||
HIDUniversal(USB *p);
|
public:
|
||||||
|
HIDUniversal(USB *p);
|
||||||
// HID implementation
|
|
||||||
virtual bool SetReportParser(uint8_t id, HIDReportParser *prs);
|
// HID implementation
|
||||||
|
virtual bool SetReportParser(uint8_t id, HIDReportParser *prs);
|
||||||
// USBDeviceConfig implementation
|
|
||||||
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
|
// USBDeviceConfig implementation
|
||||||
virtual uint8_t Release();
|
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
|
||||||
virtual uint8_t Poll();
|
virtual uint8_t Release();
|
||||||
virtual uint8_t GetAddress() { return bAddress; };
|
virtual uint8_t Poll();
|
||||||
|
|
||||||
// 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__
|
1952
hidusagestr.h
1952
hidusagestr.h
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
1507
masstorage.cpp
1507
masstorage.cpp
File diff suppressed because it is too large
Load diff
528
masstorage.h
528
masstorage.h
|
@ -1,252 +1,276 @@
|
||||||
#if !defined(__MASSTORAGE_H__)
|
#if !defined(__MASSTORAGE_H__)
|
||||||
#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"
|
||||||
#include "Usb.h"
|
#include "Usb.h"
|
||||||
|
|
||||||
#if defined(ARDUINO) && ARDUINO >=100
|
#if defined(ARDUINO) && ARDUINO >=100
|
||||||
#include "Arduino.h"
|
#include "Arduino.h"
|
||||||
#else
|
#else
|
||||||
#include <WProgram.h>
|
#include <WProgram.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "printhex.h"
|
#include "printhex.h"
|
||||||
#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)))
|
||||||
|
|
||||||
#define bmREQ_MASSOUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
|
#define bmREQ_MASSOUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
|
||||||
#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 MASS_ERR_PHASE_ERROR 0x01
|
#define SCSI_S_NOT_READY 0x02
|
||||||
#define MASS_ERR_DEVICE_DISCONNECTED 0x11
|
#define SCSI_S_MEDIUM_ERROR 0x03
|
||||||
#define MASS_ERR_UNABLE_TO_RECOVER 0x12 // Reset recovery error
|
#define SCSI_S_ILLEGAL_REQUEST 0x05
|
||||||
#define MASS_ERR_GENERAL_USB_ERROR 0xFF
|
#define SCSI_S_UNIT_ATTENTION 0x06
|
||||||
|
|
||||||
#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
|
|
||||||
|
|
||||||
|
#define MASS_ERR_SUCCESS 0x00
|
||||||
struct Capacity
|
#define MASS_ERR_PHASE_ERROR 0x02
|
||||||
{
|
#define MASS_ERR_UNIT_NOT_READY 0x03
|
||||||
uint8_t data[8];
|
#define MASS_ERR_UNIT_BUSY 0x04
|
||||||
//uint32_t dwBlockAddress;
|
#define MASS_ERR_STALL 0x05
|
||||||
//uint32_t dwBlockLength;
|
#define MASS_ERR_CMD_NOT_SUPPORTED 0x06
|
||||||
};
|
#define MASS_ERR_INVALID_CSW 0x07
|
||||||
|
#define MASS_ERR_NO_MEDIA 0x08
|
||||||
struct InquiryResponse
|
#define MASS_ERR_BAD_LBA 0x09
|
||||||
{
|
#define MASS_ERR_DEVICE_DISCONNECTED 0x11
|
||||||
uint8_t DeviceType : 5;
|
#define MASS_ERR_UNABLE_TO_RECOVER 0x12 // Reset recovery error
|
||||||
uint8_t PeripheralQualifier : 3;
|
#define MASS_ERR_INVALID_LUN 0x13
|
||||||
|
#define MASS_ERR_GENERAL_SCSI_ERROR 0xFE
|
||||||
unsigned Reserved : 7;
|
#define MASS_ERR_GENERAL_USB_ERROR 0xFF
|
||||||
unsigned Removable : 1;
|
#define MASS_ERR_USER 0xA0 // For subclasses to define their own error codes
|
||||||
|
|
||||||
uint8_t Version;
|
#define MASS_TRANS_FLG_CALLBACK 0x01 // Callback is involved
|
||||||
|
#define MASS_TRANS_FLG_NO_STALL_CHECK 0x02 // STALL condition is not checked
|
||||||
unsigned ResponseDataFormat : 4;
|
#define MASS_TRANS_FLG_NO_PHASE_CHECK 0x04 // PHASE_ERROR is not checked
|
||||||
unsigned Reserved2 : 1;
|
|
||||||
unsigned NormACA : 1;
|
struct Capacity {
|
||||||
unsigned TrmTsk : 1;
|
uint8_t data[8];
|
||||||
unsigned AERC : 1;
|
//uint32_t dwBlockAddress;
|
||||||
|
//uint32_t dwBlockLength;
|
||||||
uint8_t AdditionalLength;
|
}__attribute__((packed));
|
||||||
uint8_t Reserved3[2];
|
|
||||||
|
struct InquiryResponse {
|
||||||
unsigned SoftReset : 1;
|
uint8_t DeviceType : 5;
|
||||||
unsigned CmdQue : 1;
|
uint8_t PeripheralQualifier : 3;
|
||||||
unsigned Reserved4 : 1;
|
|
||||||
unsigned Linked : 1;
|
unsigned Reserved : 7;
|
||||||
unsigned Sync : 1;
|
unsigned Removable : 1;
|
||||||
unsigned WideBus16Bit : 1;
|
|
||||||
unsigned WideBus32Bit : 1;
|
uint8_t Version;
|
||||||
unsigned RelAddr : 1;
|
|
||||||
|
unsigned ResponseDataFormat : 4;
|
||||||
uint8_t VendorID[8];
|
unsigned Reserved2 : 1;
|
||||||
uint8_t ProductID[16];
|
unsigned NormACA : 1;
|
||||||
uint8_t RevisionID[4];
|
unsigned TrmTsk : 1;
|
||||||
};
|
unsigned AERC : 1;
|
||||||
|
|
||||||
struct CommandBlockWrapper
|
uint8_t AdditionalLength;
|
||||||
{
|
uint8_t Reserved3[2];
|
||||||
uint32_t dCBWSignature;
|
|
||||||
uint32_t dCBWTag;
|
unsigned SoftReset : 1;
|
||||||
uint32_t dCBWDataTransferLength;
|
unsigned CmdQue : 1;
|
||||||
uint8_t bmCBWFlags;
|
unsigned Reserved4 : 1;
|
||||||
|
unsigned Linked : 1;
|
||||||
struct
|
unsigned Sync : 1;
|
||||||
{
|
unsigned WideBus16Bit : 1;
|
||||||
uint8_t bmCBWLUN : 4;
|
unsigned WideBus32Bit : 1;
|
||||||
uint8_t bmReserved1 : 4;
|
unsigned RelAddr : 1;
|
||||||
};
|
|
||||||
struct
|
uint8_t VendorID[8];
|
||||||
{
|
uint8_t ProductID[16];
|
||||||
uint8_t bmCBWCBLength : 4;
|
uint8_t RevisionID[4];
|
||||||
uint8_t bmReserved2 : 4;
|
}__attribute__((packed));
|
||||||
};
|
|
||||||
|
struct CommandBlockWrapperBase {
|
||||||
uint8_t CBWCB[16];
|
uint32_t dCBWSignature;
|
||||||
} ;
|
uint32_t dCBWTag;
|
||||||
|
uint32_t dCBWDataTransferLength;
|
||||||
struct CommandStatusWrapper
|
uint8_t bmCBWFlags;
|
||||||
{
|
}__attribute__((packed));
|
||||||
uint32_t dCSWSignature;
|
|
||||||
uint32_t dCSWTag;
|
struct CommandBlockWrapper : public CommandBlockWrapperBase {
|
||||||
uint32_t dCSWDataResidue;
|
|
||||||
uint8_t bCSWStatus;
|
struct {
|
||||||
};
|
uint8_t bmCBWLUN : 4;
|
||||||
|
uint8_t bmReserved1 : 4;
|
||||||
struct RequestSenseResponce
|
};
|
||||||
{
|
|
||||||
uint8_t bResponseCode;
|
struct {
|
||||||
uint8_t bSegmentNumber;
|
uint8_t bmCBWCBLength : 4;
|
||||||
|
uint8_t bmReserved2 : 4;
|
||||||
uint8_t bmSenseKey : 4;
|
};
|
||||||
uint8_t bmReserved : 1;
|
|
||||||
uint8_t bmILI : 1;
|
uint8_t CBWCB[16];
|
||||||
uint8_t bmEOM : 1;
|
}__attribute__((packed));
|
||||||
uint8_t bmFileMark : 1;
|
|
||||||
|
struct CommandStatusWrapper {
|
||||||
uint8_t Information[4];
|
uint32_t dCSWSignature;
|
||||||
uint8_t bAdditionalLength;
|
uint32_t dCSWTag;
|
||||||
uint8_t CmdSpecificInformation[4];
|
uint32_t dCSWDataResidue;
|
||||||
uint8_t bAdditionalSenseCode;
|
uint8_t bCSWStatus;
|
||||||
uint8_t bAdditionalSenseQualifier;
|
}__attribute__((packed));
|
||||||
uint8_t bFieldReplaceableUnitCode;
|
|
||||||
uint8_t SenseKeySpecific[3];
|
struct RequestSenseResponce {
|
||||||
};
|
uint8_t bResponseCode;
|
||||||
|
uint8_t bSegmentNumber;
|
||||||
//class BulkReadParser : public USBReadParser
|
|
||||||
//{
|
uint8_t bmSenseKey : 4;
|
||||||
//protected:
|
uint8_t bmReserved : 1;
|
||||||
// bool IsValidCSW(uint8_t size, uint8_t *pcsw);
|
uint8_t bmILI : 1;
|
||||||
// bool IsMeaningfulCSW(uint8_t size, uint8_t *pcsw);
|
uint8_t bmEOM : 1;
|
||||||
//
|
uint8_t bmFileMark : 1;
|
||||||
//public:
|
|
||||||
// virtual void Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset) = 0;
|
uint8_t Information[4];
|
||||||
//};
|
uint8_t bAdditionalLength;
|
||||||
|
uint8_t CmdSpecificInformation[4];
|
||||||
#define MASS_MAX_ENDPOINTS 3
|
uint8_t bAdditionalSenseCode;
|
||||||
|
uint8_t bAdditionalSenseQualifier;
|
||||||
class BulkOnly : public USBDeviceConfig, public UsbConfigXtracter
|
uint8_t bFieldReplaceableUnitCode;
|
||||||
{
|
uint8_t SenseKeySpecific[3];
|
||||||
protected:
|
}__attribute__((packed));
|
||||||
static const uint8_t epDataInIndex; // DataIn endpoint index
|
|
||||||
static const uint8_t epDataOutIndex; // DataOUT endpoint index
|
#define MASS_MAX_ENDPOINTS 3
|
||||||
static const uint8_t epInterruptInIndex; // InterruptIN endpoint index
|
|
||||||
|
class BulkOnly : public USBDeviceConfig, public UsbConfigXtracter {
|
||||||
USB *pUsb;
|
protected:
|
||||||
uint8_t bAddress;
|
static const uint8_t epDataInIndex; // DataIn endpoint index
|
||||||
uint8_t bConfNum; // configuration number
|
static const uint8_t epDataOutIndex; // DataOUT endpoint index
|
||||||
uint8_t bIface; // interface value
|
static const uint8_t epInterruptInIndex; // InterruptIN endpoint index
|
||||||
uint8_t bNumEP; // total number of EP in the configuration
|
|
||||||
uint32_t qNextPollTime; // next poll time
|
USB *pUsb;
|
||||||
bool bPollEnable; // poll enable flag
|
uint8_t bAddress;
|
||||||
|
uint8_t bConfNum; // configuration number
|
||||||
EpInfo epInfo[MASS_MAX_ENDPOINTS];
|
uint8_t bIface; // interface value
|
||||||
|
uint8_t bNumEP; // total number of EP in the configuration
|
||||||
uint32_t dCBWTag; // Tag
|
uint32_t qNextPollTime; // next poll time
|
||||||
uint32_t dCBWDataTransferLength; // Data Transfer Length
|
bool bPollEnable; // poll enable flag
|
||||||
uint8_t bMaxLUN; // Max LUN
|
|
||||||
uint8_t bLastUsbError; // Last USB error
|
EpInfo epInfo[MASS_MAX_ENDPOINTS];
|
||||||
|
|
||||||
protected:
|
uint32_t dCBWTag; // Tag
|
||||||
//union TransFlags
|
uint32_t dCBWDataTransferLength; // Data Transfer Length
|
||||||
//{
|
uint8_t bLastUsbError; // Last USB error
|
||||||
// uint8_t nValue;
|
uint8_t bMaxLUN; // Max LUN
|
||||||
|
uint8_t bTheLUN; // Active LUN
|
||||||
// struct {
|
|
||||||
// uint8_t bmCallback : 1;
|
protected:
|
||||||
// uint8_t bmCheckPhaseErr : 1;
|
void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr);
|
||||||
// uint8_t bmDummy : 6;
|
|
||||||
// };
|
bool IsValidCBW(uint8_t size, uint8_t *pcbw);
|
||||||
//};
|
bool IsMeaningfulCBW(uint8_t size, uint8_t *pcbw);
|
||||||
void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr);
|
|
||||||
|
bool IsValidCSW(CommandStatusWrapper *pcsw, CommandBlockWrapperBase *pcbw);
|
||||||
bool IsValidCBW(uint8_t size, uint8_t *pcbw);
|
|
||||||
bool IsMeaningfulCBW(uint8_t size, uint8_t *pcbw);
|
uint8_t ClearEpHalt(uint8_t index);
|
||||||
|
uint8_t Transaction(CommandBlockWrapper *cbw, uint16_t bsize, void *buf, uint8_t flags);
|
||||||
uint8_t ClearEpHalt(uint8_t index);
|
uint8_t HandleUsbError(uint8_t error, uint8_t index);
|
||||||
uint8_t Transaction(CommandBlockWrapper *cbw, uint16_t bsize, void *buf, uint8_t flags);
|
uint8_t HandleSCSIError(uint8_t status);
|
||||||
uint8_t HandleUsbError(uint8_t index);
|
|
||||||
|
public:
|
||||||
public:
|
BulkOnly(USB *p);
|
||||||
BulkOnly(USB *p);
|
|
||||||
uint8_t GetLastUsbError() { return bLastUsbError; };
|
uint8_t GetLastUsbError() {
|
||||||
|
return bLastUsbError;
|
||||||
uint8_t Reset();
|
};
|
||||||
uint8_t GetMaxLUN(uint8_t *max_lun);
|
|
||||||
|
uint8_t GetbMaxLUN() {
|
||||||
uint8_t ResetRecovery();
|
return bMaxLUN; // Max LUN
|
||||||
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 GetbTheLUN() {
|
||||||
uint8_t RequestSense(uint8_t lun, uint16_t size, uint8_t *buf);
|
return bTheLUN; // Active LUN
|
||||||
//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);
|
|
||||||
|
uint8_t Reset();
|
||||||
// USBDeviceConfig implementation
|
uint8_t GetMaxLUN(uint8_t *max_lun);
|
||||||
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
|
uint8_t SetCurLUN(uint8_t lun);
|
||||||
virtual uint8_t Release();
|
|
||||||
virtual uint8_t Poll();
|
uint8_t ResetRecovery();
|
||||||
virtual uint8_t GetAddress() { return bAddress; };
|
uint8_t Inquiry(uint8_t lun, uint16_t size, uint8_t *buf);
|
||||||
|
uint8_t TestUnitReady(uint8_t lun);
|
||||||
// UsbConfigXtracter implementation
|
uint8_t ReadCapacity(uint8_t lun, uint16_t size, uint8_t *buf);
|
||||||
virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
|
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);
|
||||||
#endif // __MASSTORAGE_H__
|
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__
|
||||||
|
|
10
max3421e.h
10
max3421e.h
|
@ -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_
|
||||||
|
@ -37,7 +37,7 @@ e-mail : support@circuitsathome.com
|
||||||
|
|
||||||
/* MAX3421E command byte format: rrrrr0wa where 'r' is register number */
|
/* MAX3421E command byte format: rrrrr0wa where 'r' is register number */
|
||||||
//
|
//
|
||||||
// MAX3421E Registers in HOST mode.
|
// MAX3421E Registers in HOST mode.
|
||||||
//
|
//
|
||||||
#define rRCVFIFO 0x08 //1<<3
|
#define rRCVFIFO 0x08 //1<<3
|
||||||
#define rSNDFIFO 0x10 //2<<3
|
#define rSNDFIFO 0x10 //2<<3
|
||||||
|
@ -141,7 +141,7 @@ e-mail : support@circuitsathome.com
|
||||||
|
|
||||||
#define rHIRQ 0xc8 //25<<3
|
#define rHIRQ 0xc8 //25<<3
|
||||||
/* HIRQ Bits */
|
/* HIRQ Bits */
|
||||||
#define bmBUSEVENTIRQ 0x01 // indicates BUS Reset Done or BUS Resume
|
#define bmBUSEVENTIRQ 0x01 // indicates BUS Reset Done or BUS Resume
|
||||||
#define bmRWUIRQ 0x02
|
#define bmRWUIRQ 0x02
|
||||||
#define bmRCVDAVIRQ 0x04
|
#define bmRCVDAVIRQ 0x04
|
||||||
#define bmSNDBAVIRQ 0x08
|
#define bmSNDBAVIRQ 0x08
|
||||||
|
@ -194,7 +194,7 @@ e-mail : support@circuitsathome.com
|
||||||
#define tokIN 0x00 // HS=0, ISO=0, OUTNIN=0, SETUP=0
|
#define tokIN 0x00 // HS=0, ISO=0, OUTNIN=0, SETUP=0
|
||||||
#define tokOUT 0x20 // HS=0, ISO=0, OUTNIN=1, SETUP=0
|
#define tokOUT 0x20 // HS=0, ISO=0, OUTNIN=1, SETUP=0
|
||||||
#define tokINHS 0x80 // HS=1, ISO=0, OUTNIN=0, SETUP=0
|
#define tokINHS 0x80 // HS=1, ISO=0, OUTNIN=0, SETUP=0
|
||||||
#define tokOUTHS 0xA0 // HS=1, ISO=0, OUTNIN=1, SETUP=0
|
#define tokOUTHS 0xA0 // HS=1, ISO=0, OUTNIN=1, SETUP=0
|
||||||
#define tokISOIN 0x40 // HS=0, ISO=1, OUTNIN=0, SETUP=0
|
#define tokISOIN 0x40 // HS=0, ISO=1, OUTNIN=0, SETUP=0
|
||||||
#define tokISOOUT 0x60 // HS=0, ISO=1, OUTNIN=1, SETUP=0
|
#define tokISOOUT 0x60 // HS=0, ISO=1, OUTNIN=1, SETUP=0
|
||||||
|
|
||||||
|
@ -206,7 +206,7 @@ e-mail : support@circuitsathome.com
|
||||||
#define bmKSTATUS 0x40
|
#define bmKSTATUS 0x40
|
||||||
#define bmJSTATUS 0x80
|
#define bmJSTATUS 0x80
|
||||||
#define bmSE0 0x00 //SE0 - disconnect state
|
#define bmSE0 0x00 //SE0 - disconnect state
|
||||||
#define bmSE1 0xc0 //SE1 - illegal state
|
#define bmSE1 0xc0 //SE1 - illegal state
|
||||||
|
|
||||||
/* Host error result codes, the 4 LSB's in the HRSL register */
|
/* Host error result codes, the 4 LSB's in the HRSL register */
|
||||||
#define hrSUCCESS 0x00
|
#define hrSUCCESS 0x00
|
||||||
|
|
506
max_LCD.cpp
506
max_LCD.cpp
|
@ -1,250 +1,256 @@
|
||||||
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||||
|
|
||||||
This software may be distributed and modified under the terms of the GNU
|
This software may be distributed and modified under the terms of the GNU
|
||||||
General Public License version 2 (GPL2) as published by the Free Software
|
General Public License version 2 (GPL2) as published by the Free Software
|
||||||
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
||||||
this file. Please note that GPL2 Section 2[b] requires that all works based
|
this file. Please note that GPL2 Section 2[b] requires that all works based
|
||||||
on this software must also be made publicly available under the terms of
|
on this software must also be made publicly available under the terms of
|
||||||
the GPL2 ("Copyleft").
|
the GPL2 ("Copyleft").
|
||||||
|
|
||||||
Contact information
|
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"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
|
||||||
#if defined(ARDUINO) && ARDUINO >=100
|
#if defined(ARDUINO) && ARDUINO >=100
|
||||||
#include "Arduino.h"
|
#include "Arduino.h"
|
||||||
#else
|
#else
|
||||||
#include <WProgram.h>
|
#include <WProgram.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// pin definition and set/clear
|
// pin definition and set/clear
|
||||||
|
|
||||||
#define RS 0x04 // RS pin
|
#define RS 0x04 // RS pin
|
||||||
#define E 0x08 // E pin
|
#define E 0x08 // E pin
|
||||||
|
|
||||||
#define SET_RS lcdPins |= RS
|
#define SET_RS lcdPins |= RS
|
||||||
#define CLR_RS lcdPins &= ~RS
|
#define CLR_RS lcdPins &= ~RS
|
||||||
#define SET_E lcdPins |= E
|
#define SET_E lcdPins |= E
|
||||||
#define CLR_E lcdPins &= ~E
|
#define CLR_E lcdPins &= ~E
|
||||||
|
|
||||||
#define SENDlcdPins() pUsb->gpioWr( lcdPins )
|
#define SENDlcdPins() pUsb->gpioWr( lcdPins )
|
||||||
|
|
||||||
#define LCD_sendcmd(a) { CLR_RS; \
|
#define LCD_sendcmd(a) { CLR_RS; \
|
||||||
sendbyte(a); \
|
sendbyte(a); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define LCD_sendchar(a) { SET_RS; \
|
#define LCD_sendchar(a) { SET_RS; \
|
||||||
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;
|
|
||||||
|
begin(16, 1);
|
||||||
// MAX3421E::gpioWr(0x55);
|
}
|
||||||
|
|
||||||
begin(16, 1);
|
void Max_LCD::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) {
|
||||||
}
|
if (lines > 1) {
|
||||||
|
_displayfunction |= LCD_2LINE;
|
||||||
void Max_LCD::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) {
|
}
|
||||||
if (lines > 1) {
|
_numlines = lines;
|
||||||
_displayfunction |= LCD_2LINE;
|
_currline = 0;
|
||||||
}
|
|
||||||
_numlines = lines;
|
// for some 1 line displays you can select a 10 pixel high font
|
||||||
_currline = 0;
|
if ((dotsize != 0) && (lines == 1)) {
|
||||||
|
_displayfunction |= LCD_5x10DOTS;
|
||||||
// for some 1 line displays you can select a 10 pixel high font
|
}
|
||||||
if ((dotsize != 0) && (lines == 1)) {
|
|
||||||
_displayfunction |= LCD_5x10DOTS;
|
// SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION!
|
||||||
}
|
// according to datasheet, we need at least 40ms after power rises above 2.7V
|
||||||
|
// before sending commands. Arduino can turn on way befer 4.5V so we'll wait 50
|
||||||
// SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION!
|
delayMicroseconds(50000);
|
||||||
// according to datasheet, we need at least 40ms after power rises above 2.7V
|
lcdPins = 0x30;
|
||||||
// before sending commands. Arduino can turn on way befer 4.5V so we'll wait 50
|
SET_E;
|
||||||
delayMicroseconds(50000);
|
SENDlcdPins();
|
||||||
lcdPins = 0x30;
|
CLR_E;
|
||||||
SET_E;
|
SENDlcdPins();
|
||||||
SENDlcdPins();
|
delayMicroseconds(10000); // wait min 4.1ms
|
||||||
CLR_E;
|
//second try
|
||||||
SENDlcdPins();
|
SET_E;
|
||||||
delayMicroseconds(10000); // wait min 4.1ms
|
SENDlcdPins();
|
||||||
//second try
|
CLR_E;
|
||||||
SET_E;
|
SENDlcdPins();
|
||||||
SENDlcdPins();
|
delayMicroseconds(10000); // wait min 4.1ms
|
||||||
CLR_E;
|
// third go!
|
||||||
SENDlcdPins();
|
SET_E;
|
||||||
delayMicroseconds(10000); // wait min 4.1ms
|
SENDlcdPins();
|
||||||
// third go!
|
CLR_E;
|
||||||
SET_E;
|
SENDlcdPins();
|
||||||
SENDlcdPins();
|
delayMicroseconds(10000);
|
||||||
CLR_E;
|
// finally, set to 4-bit interface
|
||||||
SENDlcdPins();
|
lcdPins = 0x20;
|
||||||
delayMicroseconds(10000);
|
//SET_RS;
|
||||||
// finally, set to 4-bit interface
|
SET_E;
|
||||||
lcdPins = 0x20;
|
SENDlcdPins();
|
||||||
//SET_RS;
|
//CLR_RS;
|
||||||
SET_E;
|
CLR_E;
|
||||||
SENDlcdPins();
|
SENDlcdPins();
|
||||||
//CLR_RS;
|
delayMicroseconds(10000);
|
||||||
CLR_E;
|
// finally, set # lines, font size, etc.
|
||||||
SENDlcdPins();
|
command(LCD_FUNCTIONSET | _displayfunction);
|
||||||
delayMicroseconds(10000);
|
|
||||||
// finally, set # lines, font size, etc.
|
// turn the display on with no cursor or blinking default
|
||||||
command(LCD_FUNCTIONSET | _displayfunction);
|
_displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
|
||||||
|
display();
|
||||||
// turn the display on with no cursor or blinking default
|
|
||||||
_displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
|
// clear it off
|
||||||
display();
|
clear();
|
||||||
|
|
||||||
// clear it off
|
// Initialize to default text direction (for romance languages)
|
||||||
clear();
|
_displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
|
||||||
|
// set the entry mode
|
||||||
// Initialize to default text direction (for romance languages)
|
command(LCD_ENTRYMODESET | _displaymode);
|
||||||
_displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
|
}
|
||||||
// set the entry mode
|
|
||||||
command(LCD_ENTRYMODESET | _displaymode);
|
/********** high level commands, for the user! */
|
||||||
}
|
void Max_LCD::clear() {
|
||||||
|
command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero
|
||||||
/********** high level commands, for the user! */
|
delayMicroseconds(2000); // this command takes a long time!
|
||||||
void Max_LCD::clear()
|
}
|
||||||
{
|
|
||||||
command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero
|
void Max_LCD::home() {
|
||||||
delayMicroseconds(2000); // this command takes a long time!
|
command(LCD_RETURNHOME); // set cursor position to zero
|
||||||
}
|
delayMicroseconds(2000); // this command takes a long time!
|
||||||
|
}
|
||||||
void Max_LCD::home()
|
|
||||||
{
|
void Max_LCD::setCursor(uint8_t col, uint8_t row) {
|
||||||
command(LCD_RETURNHOME); // set cursor position to zero
|
int row_offsets[] = {0x00, 0x40, 0x14, 0x54};
|
||||||
delayMicroseconds(2000); // this command takes a long time!
|
if (row > _numlines) {
|
||||||
}
|
row = _numlines - 1; // we count rows starting w/0
|
||||||
|
}
|
||||||
void Max_LCD::setCursor(uint8_t col, uint8_t row)
|
|
||||||
{
|
command(LCD_SETDDRAMADDR | (col + row_offsets[row]));
|
||||||
int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 };
|
}
|
||||||
if ( row > _numlines ) {
|
|
||||||
row = _numlines-1; // we count rows starting w/0
|
// Turn the display on/off (quickly)
|
||||||
}
|
|
||||||
|
void Max_LCD::noDisplay() {
|
||||||
command(LCD_SETDDRAMADDR | (col + row_offsets[row]));
|
_displaycontrol &= ~LCD_DISPLAYON;
|
||||||
}
|
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||||
|
}
|
||||||
// Turn the display on/off (quickly)
|
|
||||||
void Max_LCD::noDisplay() {
|
void Max_LCD::display() {
|
||||||
_displaycontrol &= ~LCD_DISPLAYON;
|
_displaycontrol |= LCD_DISPLAYON;
|
||||||
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||||
}
|
}
|
||||||
void Max_LCD::display() {
|
|
||||||
_displaycontrol |= LCD_DISPLAYON;
|
// Turns the underline cursor on/off
|
||||||
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
|
||||||
}
|
void Max_LCD::noCursor() {
|
||||||
|
_displaycontrol &= ~LCD_CURSORON;
|
||||||
// Turns the underline cursor on/off
|
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||||
void Max_LCD::noCursor() {
|
}
|
||||||
_displaycontrol &= ~LCD_CURSORON;
|
|
||||||
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
void Max_LCD::cursor() {
|
||||||
}
|
_displaycontrol |= LCD_CURSORON;
|
||||||
void Max_LCD::cursor() {
|
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||||
_displaycontrol |= LCD_CURSORON;
|
}
|
||||||
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) {
|
|
||||||
command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);
|
void Max_LCD::scrollDisplayLeft(void) {
|
||||||
}
|
command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);
|
||||||
void Max_LCD::scrollDisplayRight(void) {
|
}
|
||||||
command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);
|
|
||||||
}
|
void Max_LCD::scrollDisplayRight(void) {
|
||||||
|
command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);
|
||||||
// This is for text that flows Left to Right
|
}
|
||||||
void Max_LCD::leftToRight(void) {
|
|
||||||
_displaymode |= LCD_ENTRYLEFT;
|
// This is for text that flows Left to Right
|
||||||
command(LCD_ENTRYMODESET | _displaymode);
|
|
||||||
}
|
void Max_LCD::leftToRight(void) {
|
||||||
|
_displaymode |= LCD_ENTRYLEFT;
|
||||||
// This is for text that flows Right to Left
|
command(LCD_ENTRYMODESET | _displaymode);
|
||||||
void Max_LCD::rightToLeft(void) {
|
}
|
||||||
_displaymode &= ~LCD_ENTRYLEFT;
|
|
||||||
command(LCD_ENTRYMODESET | _displaymode);
|
// This is for text that flows Right to Left
|
||||||
}
|
|
||||||
|
void Max_LCD::rightToLeft(void) {
|
||||||
// This will 'right justify' text from the cursor
|
_displaymode &= ~LCD_ENTRYLEFT;
|
||||||
void Max_LCD::autoscroll(void) {
|
command(LCD_ENTRYMODESET | _displaymode);
|
||||||
_displaymode |= LCD_ENTRYSHIFTINCREMENT;
|
}
|
||||||
command(LCD_ENTRYMODESET | _displaymode);
|
|
||||||
}
|
// This will 'right justify' text from the cursor
|
||||||
|
|
||||||
// This will 'left justify' text from the cursor
|
void Max_LCD::autoscroll(void) {
|
||||||
void Max_LCD::noAutoscroll(void) {
|
_displaymode |= LCD_ENTRYSHIFTINCREMENT;
|
||||||
_displaymode &= ~LCD_ENTRYSHIFTINCREMENT;
|
command(LCD_ENTRYMODESET | _displaymode);
|
||||||
command(LCD_ENTRYMODESET | _displaymode);
|
}
|
||||||
}
|
|
||||||
|
// This will 'left justify' text from the cursor
|
||||||
// Allows us to fill the first 8 CGRAM locations
|
|
||||||
// with custom characters
|
void Max_LCD::noAutoscroll(void) {
|
||||||
void Max_LCD::createChar(uint8_t location, uint8_t charmap[]) {
|
_displaymode &= ~LCD_ENTRYSHIFTINCREMENT;
|
||||||
location &= 0x7; // we only have 8 locations 0-7
|
command(LCD_ENTRYMODESET | _displaymode);
|
||||||
command(LCD_SETCGRAMADDR | (location << 3));
|
}
|
||||||
for (int i=0; i<8; i++) {
|
|
||||||
write(charmap[i]);
|
// Allows us to fill the first 8 CGRAM locations
|
||||||
}
|
// with custom characters
|
||||||
}
|
|
||||||
|
void Max_LCD::createChar(uint8_t location, uint8_t charmap[]) {
|
||||||
/*********** mid level commands, for sending data/cmds */
|
location &= 0x7; // we only have 8 locations 0-7
|
||||||
|
command(LCD_SETCGRAMADDR | (location << 3));
|
||||||
inline void Max_LCD::command(uint8_t value) {
|
for (int i = 0; i < 8; i++) {
|
||||||
LCD_sendcmd(value);
|
write(charmap[i]);
|
||||||
delayMicroseconds(100);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void Max_LCD::write(uint8_t value) {
|
/*********** mid level commands, for sending data/cmds */
|
||||||
LCD_sendchar(value);
|
|
||||||
}
|
inline void Max_LCD::command(uint8_t value) {
|
||||||
|
LCD_sendcmd(value);
|
||||||
void Max_LCD::sendbyte( uint8_t val )
|
delayMicroseconds(100);
|
||||||
{
|
}
|
||||||
lcdPins &= 0x0f; //prepare place for the upper nibble
|
|
||||||
lcdPins |= ( val & 0xf0 ); //copy upper nibble to LCD variable
|
inline void Max_LCD::write(uint8_t value) {
|
||||||
SET_E; //send
|
LCD_sendchar(value);
|
||||||
SENDlcdPins();
|
}
|
||||||
delayMicroseconds(2);
|
|
||||||
CLR_E;
|
void Max_LCD::sendbyte(uint8_t val) {
|
||||||
delayMicroseconds(2);
|
lcdPins &= 0x0f; //prepare place for the upper nibble
|
||||||
SENDlcdPins();
|
lcdPins |= (val & 0xf0); //copy upper nibble to LCD variable
|
||||||
lcdPins &= 0x0f; //prepare place for the lower nibble
|
SET_E; //send
|
||||||
lcdPins |= ( val << 4 ) & 0xf0; //copy lower nibble to LCD variable
|
SENDlcdPins();
|
||||||
SET_E; //send
|
delayMicroseconds(2);
|
||||||
SENDlcdPins();
|
CLR_E;
|
||||||
CLR_E;
|
delayMicroseconds(2);
|
||||||
SENDlcdPins();
|
SENDlcdPins();
|
||||||
delayMicroseconds(100);
|
lcdPins &= 0x0f; //prepare place for the lower nibble
|
||||||
}
|
lcdPins |= (val << 4) & 0xf0; //copy lower nibble to LCD variable
|
||||||
|
SET_E; //send
|
||||||
|
SENDlcdPins();
|
||||||
|
CLR_E;
|
||||||
|
SENDlcdPins();
|
||||||
|
delayMicroseconds(100);
|
||||||
|
}
|
||||||
|
|
202
max_LCD.h
202
max_LCD.h
|
@ -1,102 +1,102 @@
|
||||||
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||||
|
|
||||||
This software may be distributed and modified under the terms of the GNU
|
This software may be distributed and modified under the terms of the GNU
|
||||||
General Public License version 2 (GPL2) as published by the Free Software
|
General Public License version 2 (GPL2) as published by the Free Software
|
||||||
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
||||||
this file. Please note that GPL2 Section 2[b] requires that all works based
|
this file. Please note that GPL2 Section 2[b] requires that all works based
|
||||||
on this software must also be made publicly available under the terms of
|
on this software must also be made publicly available under the terms of
|
||||||
the GPL2 ("Copyleft").
|
the GPL2 ("Copyleft").
|
||||||
|
|
||||||
Contact information
|
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]
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef _Max_LCD_h_
|
#ifndef _Max_LCD_h_
|
||||||
#define _Max_LCD_h_
|
#define _Max_LCD_h_
|
||||||
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include "Print.h"
|
#include "Print.h"
|
||||||
#include "Usb.h"
|
#include "Usb.h"
|
||||||
|
|
||||||
// commands
|
// commands
|
||||||
#define LCD_CLEARDISPLAY 0x01
|
#define LCD_CLEARDISPLAY 0x01
|
||||||
#define LCD_RETURNHOME 0x02
|
#define LCD_RETURNHOME 0x02
|
||||||
#define LCD_ENTRYMODESET 0x04
|
#define LCD_ENTRYMODESET 0x04
|
||||||
#define LCD_DISPLAYCONTROL 0x08
|
#define LCD_DISPLAYCONTROL 0x08
|
||||||
#define LCD_CURSORSHIFT 0x10
|
#define LCD_CURSORSHIFT 0x10
|
||||||
#define LCD_FUNCTIONSET 0x20
|
#define LCD_FUNCTIONSET 0x20
|
||||||
#define LCD_SETCGRAMADDR 0x40
|
#define LCD_SETCGRAMADDR 0x40
|
||||||
#define LCD_SETDDRAMADDR 0x80
|
#define LCD_SETDDRAMADDR 0x80
|
||||||
|
|
||||||
// flags for display entry mode
|
// flags for display entry mode
|
||||||
#define LCD_ENTRYRIGHT 0x00
|
#define LCD_ENTRYRIGHT 0x00
|
||||||
#define LCD_ENTRYLEFT 0x02
|
#define LCD_ENTRYLEFT 0x02
|
||||||
#define LCD_ENTRYSHIFTINCREMENT 0x01
|
#define LCD_ENTRYSHIFTINCREMENT 0x01
|
||||||
#define LCD_ENTRYSHIFTDECREMENT 0x00
|
#define LCD_ENTRYSHIFTDECREMENT 0x00
|
||||||
|
|
||||||
// flags for display on/off control
|
// flags for display on/off control
|
||||||
#define LCD_DISPLAYON 0x04
|
#define LCD_DISPLAYON 0x04
|
||||||
#define LCD_DISPLAYOFF 0x00
|
#define LCD_DISPLAYOFF 0x00
|
||||||
#define LCD_CURSORON 0x02
|
#define LCD_CURSORON 0x02
|
||||||
#define LCD_CURSOROFF 0x00
|
#define LCD_CURSOROFF 0x00
|
||||||
#define LCD_BLINKON 0x01
|
#define LCD_BLINKON 0x01
|
||||||
#define LCD_BLINKOFF 0x00
|
#define LCD_BLINKOFF 0x00
|
||||||
|
|
||||||
// flags for display/cursor shift
|
// flags for display/cursor shift
|
||||||
#define LCD_DISPLAYMOVE 0x08
|
#define LCD_DISPLAYMOVE 0x08
|
||||||
#define LCD_CURSORMOVE 0x00
|
#define LCD_CURSORMOVE 0x00
|
||||||
#define LCD_MOVERIGHT 0x04
|
#define LCD_MOVERIGHT 0x04
|
||||||
#define LCD_MOVELEFT 0x00
|
#define LCD_MOVELEFT 0x00
|
||||||
|
|
||||||
// flags for function set
|
// flags for function set
|
||||||
#define LCD_8BITMODE 0x10
|
#define LCD_8BITMODE 0x10
|
||||||
#define LCD_4BITMODE 0x00
|
#define LCD_4BITMODE 0x00
|
||||||
#define LCD_2LINE 0x08
|
#define LCD_2LINE 0x08
|
||||||
#define LCD_1LINE 0x00
|
#define LCD_1LINE 0x00
|
||||||
#define LCD_5x10DOTS 0x04
|
#define LCD_5x10DOTS 0x04
|
||||||
#define LCD_5x8DOTS 0x00
|
#define LCD_5x8DOTS 0x00
|
||||||
|
|
||||||
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
|
78
message.cpp
78
message.cpp
|
@ -1,31 +1,47 @@
|
||||||
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||||
|
|
||||||
This software may be distributed and modified under the terms of the GNU
|
This software may be distributed and modified under the terms of the GNU
|
||||||
General Public License version 2 (GPL2) as published by the Free Software
|
General Public License version 2 (GPL2) as published by the Free Software
|
||||||
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
||||||
this file. Please note that GPL2 Section 2[b] requires that all works based
|
this file. Please note that GPL2 Section 2[b] requires that all works based
|
||||||
on this software must also be made publicly available under the terms of
|
on this software must also be made publicly available under the terms of
|
||||||
the GPL2 ("Copyleft").
|
the GPL2 ("Copyleft").
|
||||||
|
|
||||||
Contact information
|
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.
|
||||||
void Notify(char const * msg)
|
// this allows for 126 other debugging levels.
|
||||||
//void Notify(const char* msg)
|
// TO-DO: Allow assignment to a different serial port
|
||||||
{
|
int UsbDEBUGlvl = 0x80;
|
||||||
if(!msg) return;
|
|
||||||
char c;
|
void Notifyc(char c, int lvl) {
|
||||||
|
if (UsbDEBUGlvl < lvl) return;
|
||||||
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);
|
||||||
|
}
|
||||||
|
|
76
message.h
76
message.h
|
@ -1,37 +1,39 @@
|
||||||
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||||
|
|
||||||
This software may be distributed and modified under the terms of the GNU
|
This software may be distributed and modified under the terms of the GNU
|
||||||
General Public License version 2 (GPL2) as published by the Free Software
|
General Public License version 2 (GPL2) as published by the Free Software
|
||||||
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
||||||
this file. Please note that GPL2 Section 2[b] requires that all works based
|
this file. Please note that GPL2 Section 2[b] requires that all works based
|
||||||
on this software must also be made publicly available under the terms of
|
on this software must also be made publicly available under the terms of
|
||||||
the GPL2 ("Copyleft").
|
the GPL2 ("Copyleft").
|
||||||
|
|
||||||
Contact information
|
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>
|
||||||
#include "printhex.h"
|
|
||||||
|
void Notify(char const * msg, int lvl);
|
||||||
void Notify(char const * msg);
|
void NotifyStr(char const * msg, int lvl);
|
||||||
//void Notify(const char* msg);
|
|
||||||
|
#include "printhex.h"
|
||||||
template <class ERROR_TYPE>
|
|
||||||
void ErrorMessage(char const * msg, ERROR_TYPE rcode = 0)
|
//void Notify(const char* msg);
|
||||||
{
|
|
||||||
Notify(msg);
|
template <class ERROR_TYPE>
|
||||||
Notify(PSTR(": "));
|
void ErrorMessage(char const * msg, ERROR_TYPE rcode = 0) {
|
||||||
PrintHex<ERROR_TYPE>(rcode);
|
Notify(msg, 0x80);
|
||||||
Notify(PSTR("\r\n"));
|
Notify(PSTR(": "), 0x80);
|
||||||
}
|
PrintHex<ERROR_TYPE > (rcode, 0x80);
|
||||||
|
Notify(PSTR("\r\n"), 0x80);
|
||||||
|
}
|
||||||
#endif // __MESSAGE_H__
|
|
||||||
|
|
||||||
|
#endif // __MESSAGE_H__
|
||||||
|
|
139
parsetools.cpp
139
parsetools.cpp
|
@ -1,72 +1,67 @@
|
||||||
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||||
|
|
||||||
This software may be distributed and modified under the terms of the GNU
|
This software may be distributed and modified under the terms of the GNU
|
||||||
General Public License version 2 (GPL2) as published by the Free Software
|
General Public License version 2 (GPL2) as published by the Free Software
|
||||||
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
||||||
this file. Please note that GPL2 Section 2[b] requires that all works based
|
this file. Please note that GPL2 Section 2[b] requires that all works based
|
||||||
on this software must also be made publicly available under the terms of
|
on this software must also be made publicly available under the terms of
|
||||||
the GPL2 ("Copyleft").
|
the GPL2 ("Copyleft").
|
||||||
|
|
||||||
Contact information
|
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)
|
||||||
|
return false;
|
||||||
if (countDown)
|
|
||||||
return false;
|
countDown = valueSize;
|
||||||
|
return true;
|
||||||
countDown = valueSize;
|
}
|
||||||
return true;
|
|
||||||
}
|
bool PTPListParser::Parse(uint8_t **pp, uint16_t *pcntdn, PTP_ARRAY_EL_FUNC pf, const void *me) {
|
||||||
|
switch (nStage) {
|
||||||
bool PTPListParser::Parse(uint8_t **pp, uint16_t *pcntdn, PTP_ARRAY_EL_FUNC pf, const void *me)
|
case 0:
|
||||||
{
|
pBuf->valueSize = lenSize;
|
||||||
switch (nStage)
|
theParser.Initialize(pBuf);
|
||||||
{
|
nStage = 1;
|
||||||
case 0:
|
|
||||||
pBuf->valueSize = lenSize;
|
case 1:
|
||||||
theParser.Initialize(pBuf);
|
if (!theParser.Parse(pp, pcntdn))
|
||||||
nStage = 1;
|
return false;
|
||||||
|
|
||||||
case 1:
|
arLen = 0;
|
||||||
if (!theParser.Parse(pp, pcntdn))
|
arLen = (pBuf->valueSize >= 4) ? *((uint32_t*) pBuf->pValue) : (uint32_t) (*((uint16_t*) pBuf->pValue));
|
||||||
return false;
|
arLenCntdn = arLen;
|
||||||
|
nStage = 2;
|
||||||
arLen = 0;
|
|
||||||
arLen = (pBuf->valueSize >= 4) ? *((uint32_t*)pBuf->pValue) : (uint32_t)(*((uint16_t*)pBuf->pValue));
|
case 2:
|
||||||
arLenCntdn = arLen;
|
pBuf->valueSize = valSize;
|
||||||
nStage = 2;
|
theParser.Initialize(pBuf);
|
||||||
|
nStage = 3;
|
||||||
case 2:
|
|
||||||
pBuf->valueSize = valSize;
|
case 3:
|
||||||
theParser.Initialize(pBuf);
|
for (; arLenCntdn; arLenCntdn--) {
|
||||||
nStage = 3;
|
if (!theParser.Parse(pp, pcntdn))
|
||||||
|
return false;
|
||||||
case 3:
|
|
||||||
for (; arLenCntdn; arLenCntdn--)
|
if (pf)
|
||||||
{
|
pf(pBuf, (arLen - arLenCntdn), me);
|
||||||
if (!theParser.Parse(pp, pcntdn))
|
}
|
||||||
return false;
|
|
||||||
|
nStage = 0;
|
||||||
if (pf)
|
}
|
||||||
pf(pBuf, (arLen - arLenCntdn), me);
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
nStage = 0;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
300
parsetools.h
300
parsetools.h
|
@ -1,151 +1,149 @@
|
||||||
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||||
|
|
||||||
This software may be distributed and modified under the terms of the GNU
|
This software may be distributed and modified under the terms of the GNU
|
||||||
General Public License version 2 (GPL2) as published by the Free Software
|
General Public License version 2 (GPL2) as published by the Free Software
|
||||||
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
||||||
this file. Please note that GPL2 Section 2[b] requires that all works based
|
this file. Please note that GPL2 Section 2[b] requires that all works based
|
||||||
on this software must also be made publicly available under the terms of
|
on this software must also be made publicly available under the terms of
|
||||||
the GPL2 ("Copyleft").
|
the GPL2 ("Copyleft").
|
||||||
|
|
||||||
Contact information
|
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__
|
||||||
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <avr/pgmspace.h>
|
#include <avr/pgmspace.h>
|
||||||
#include "printhex.h"
|
#include "printhex.h"
|
||||||
#include "hexdump.h"
|
#include "hexdump.h"
|
||||||
#include "message.h"
|
#include "message.h"
|
||||||
|
|
||||||
#if defined(ARDUINO) && ARDUINO >=100
|
#if defined(ARDUINO) && ARDUINO >=100
|
||||||
#include "Arduino.h"
|
#include "Arduino.h"
|
||||||
#else
|
#else
|
||||||
#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 countDown;
|
||||||
uint8_t * pBuf;
|
uint8_t valueSize;
|
||||||
uint8_t countDown;
|
|
||||||
uint8_t valueSize;
|
public:
|
||||||
|
|
||||||
public:
|
MultiByteValueParser() : pBuf(NULL), countDown(0), valueSize(0) {
|
||||||
MultiByteValueParser() : pBuf(NULL), countDown(0), valueSize(0) {};
|
};
|
||||||
|
|
||||||
const uint8_t* GetBuffer() { return pBuf; };
|
const uint8_t* GetBuffer() {
|
||||||
|
return pBuf;
|
||||||
void Initialize(MultiValueBuffer * const pbuf)
|
};
|
||||||
{
|
|
||||||
pBuf = (uint8_t*)pbuf->pValue;
|
void Initialize(MultiValueBuffer * const pbuf) {
|
||||||
countDown = valueSize = pbuf->valueSize;
|
pBuf = (uint8_t*) pbuf->pValue;
|
||||||
};
|
countDown = valueSize = pbuf->valueSize;
|
||||||
|
};
|
||||||
bool Parse(uint8_t **pp, uint16_t *pcntdn);
|
|
||||||
};
|
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) {};
|
|
||||||
|
ByteSkipper() : pBuf(NULL), nStage(0), countDown(0) {
|
||||||
void Initialize(MultiValueBuffer *pbuf)
|
};
|
||||||
{
|
|
||||||
pBuf = (uint8_t*)pbuf->pValue;
|
void Initialize(MultiValueBuffer *pbuf) {
|
||||||
countDown = 0;
|
pBuf = (uint8_t*) pbuf->pValue;
|
||||||
};
|
countDown = 0;
|
||||||
|
};
|
||||||
bool Skip(uint8_t **pp, uint16_t *pcntdn, uint16_t bytes_to_skip)
|
|
||||||
{
|
bool Skip(uint8_t **pp, uint16_t *pcntdn, uint16_t bytes_to_skip) {
|
||||||
switch (nStage)
|
switch (nStage) {
|
||||||
{
|
case 0:
|
||||||
case 0:
|
countDown = bytes_to_skip;
|
||||||
countDown = bytes_to_skip;
|
nStage++;
|
||||||
nStage ++;
|
case 1:
|
||||||
case 1:
|
for (; countDown && (*pcntdn); countDown--, (*pp)++, (*pcntdn)--);
|
||||||
for (; countDown && (*pcntdn); countDown--, (*pp)++, (*pcntdn)--);
|
|
||||||
|
if (!countDown)
|
||||||
if (!countDown)
|
nStage = 0;
|
||||||
nStage = 0;
|
};
|
||||||
};
|
return (!countDown);
|
||||||
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 {
|
||||||
enum ParseMode { modeArray, modeRange/*, modeEnum*/ };
|
modeArray, modeRange/*, modeEnum*/
|
||||||
|
};
|
||||||
private:
|
|
||||||
uint8_t nStage;
|
private:
|
||||||
uint8_t enStage;
|
uint8_t nStage;
|
||||||
|
uint8_t enStage;
|
||||||
uint32_t arLen;
|
|
||||||
uint32_t arLenCntdn;
|
uint32_t arLen;
|
||||||
|
uint32_t arLenCntdn;
|
||||||
uint8_t lenSize; // size of the array length field in bytes
|
|
||||||
uint8_t valSize; // size of the array element in bytes
|
uint8_t lenSize; // size of the array length field 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
|
|
||||||
MultiByteValueParser theParser;
|
// The only parser for both size and array element parsing
|
||||||
|
MultiByteValueParser theParser;
|
||||||
uint8_t /*ParseMode*/ prsMode;
|
|
||||||
|
uint8_t /*ParseMode*/ prsMode;
|
||||||
public:
|
|
||||||
PTPListParser() :
|
public:
|
||||||
pBuf(NULL),
|
|
||||||
nStage(0),
|
PTPListParser() :
|
||||||
enStage(0),
|
nStage(0),
|
||||||
arLenCntdn(0),
|
enStage(0),
|
||||||
arLen(0),
|
arLen(0),
|
||||||
lenSize(0),
|
arLenCntdn(0),
|
||||||
valSize(0),
|
lenSize(0),
|
||||||
prsMode(modeArray)
|
valSize(0),
|
||||||
{};
|
pBuf(NULL),
|
||||||
|
prsMode(modeArray) {
|
||||||
void Initialize(const uint8_t len_size, const uint8_t val_size, MultiValueBuffer * const p, const uint8_t mode = modeArray)
|
};
|
||||||
{
|
|
||||||
pBuf = p;
|
void Initialize(const uint8_t len_size, const uint8_t val_size, MultiValueBuffer * const p, const uint8_t mode = modeArray) {
|
||||||
lenSize = len_size;
|
pBuf = p;
|
||||||
valSize = val_size;
|
lenSize = len_size;
|
||||||
prsMode = mode;
|
valSize = val_size;
|
||||||
|
prsMode = mode;
|
||||||
if (prsMode == modeRange)
|
|
||||||
{
|
if (prsMode == modeRange) {
|
||||||
arLenCntdn = arLen = 3;
|
arLenCntdn = arLen = 3;
|
||||||
nStage = 2;
|
nStage = 2;
|
||||||
}
|
} else {
|
||||||
else
|
arLenCntdn = arLen = 0;
|
||||||
{
|
nStage = 0;
|
||||||
arLenCntdn = arLen = 0;
|
}
|
||||||
nStage = 0;
|
enStage = 0;
|
||||||
}
|
theParser.Initialize(p);
|
||||||
enStage = 0;
|
};
|
||||||
theParser.Initialize(p);
|
|
||||||
};
|
bool Parse(uint8_t **pp, uint16_t *pcntdn, PTP_ARRAY_EL_FUNC pf, const void *me = NULL);
|
||||||
|
};
|
||||||
bool Parse(uint8_t **pp, uint16_t *pcntdn, PTP_ARRAY_EL_FUNC pf, const void *me = NULL);
|
|
||||||
};
|
#endif // __PARSETOOLS_H__
|
||||||
|
|
||||||
#endif // __PARSETOOLS_H__
|
|
||||||
|
|
137
printhex.h
137
printhex.h
|
@ -1,66 +1,71 @@
|
||||||
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||||
|
|
||||||
This software may be distributed and modified under the terms of the GNU
|
This software may be distributed and modified under the terms of the GNU
|
||||||
General Public License version 2 (GPL2) as published by the Free Software
|
General Public License version 2 (GPL2) as published by the Free Software
|
||||||
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
||||||
this file. Please note that GPL2 Section 2[b] requires that all works based
|
this file. Please note that GPL2 Section 2[b] requires that all works based
|
||||||
on this software must also be made publicly available under the terms of
|
on this software must also be made publicly available under the terms of
|
||||||
the GPL2 ("Copyleft").
|
the GPL2 ("Copyleft").
|
||||||
|
|
||||||
Contact information
|
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__
|
||||||
|
|
||||||
#if defined(ARDUINO) && ARDUINO >=100
|
#if defined(ARDUINO) && ARDUINO >=100
|
||||||
#include "Arduino.h"
|
#include "Arduino.h"
|
||||||
#else
|
#else
|
||||||
#include <WProgram.h>
|
#include <WProgram.h>
|
||||||
#endif
|
#endif
|
||||||
|
void Notifyc(char c, int lvl);
|
||||||
template <class T>
|
|
||||||
void PrintHex(T val)
|
template <class T>
|
||||||
{
|
void PrintHex(T val, int lvl) {
|
||||||
T mask = (((T)1) << (((sizeof(T) << 1) - 1) << 2));
|
int num_nibbles = sizeof (T) * 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>
|
||||||
}
|
void PrintBin(T val, int lvl) {
|
||||||
|
for (T mask = (((T) 1) << ((sizeof (T) << 3) - 1)); mask; mask >>= 1)
|
||||||
template <class T>
|
if (val & mask)
|
||||||
void PrintHex2(Print *prn, T val)
|
Notifyc('1', lvl);
|
||||||
{
|
else
|
||||||
T mask = (((T)1) << (((sizeof(T) << 1) - 1) << 2));
|
Notifyc('0', lvl);
|
||||||
|
}
|
||||||
while (mask > 1)
|
|
||||||
{
|
template <class T>
|
||||||
if (val < mask)
|
void SerialPrintHex(T val) {
|
||||||
prn->print("0");
|
int num_nibbles = sizeof (T) * 2;
|
||||||
|
|
||||||
mask >>= 4;
|
do {
|
||||||
}
|
char v = 48 + (((val >> (num_nibbles - 1) * 4)) & 0x0f);
|
||||||
prn->print((T)val, HEX);
|
if (v > 57) v += 7;
|
||||||
}
|
Serial.print(v);
|
||||||
|
} while (--num_nibbles);
|
||||||
template <class T>
|
}
|
||||||
void PrintBin(T val)
|
|
||||||
{
|
template <class T>
|
||||||
for (T mask = (((T)1) << (sizeof(T) << 3)-1); mask; mask>>=1)
|
void PrintHex2(Print *prn, T val) {
|
||||||
if (val & mask)
|
T mask = (((T) 1) << (((sizeof (T) << 1) - 1) << 2));
|
||||||
Serial.print("1");
|
|
||||||
else
|
while (mask > 1) {
|
||||||
Serial.print("0");
|
if (val < mask)
|
||||||
}
|
prn->print("0");
|
||||||
|
|
||||||
#endif // __PRINTHEX_H__
|
mask >>= 4;
|
||||||
|
}
|
||||||
|
prn->print((T) val, HEX);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __PRINTHEX_H__
|
||||||
|
|
122
usb_ch9.h
122
usb_ch9.h
|
@ -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_
|
||||||
|
|
402
usbhost.h
402
usbhost.h
|
@ -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,25 +22,24 @@ 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 */
|
||||||
#if defined(__AVR_ATmega1280__) || (__AVR_ATmega2560__) || defined(__AVR_ATmega32U4__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
|
#if defined(__AVR_ATmega1280__) || (__AVR_ATmega2560__) || defined(__AVR_ATmega32U4__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
|
||||||
|
@ -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 >
|
||||||
|
@ -199,105 +193,101 @@ uint16_t MAX3421e< SS, INTR >::reset()
|
||||||
// return ( -1 );
|
// return ( -1 );
|
||||||
// }
|
// }
|
||||||
// regWr( rMODE, bmDPPULLDN|bmDMPULLDN|bmHOST ); // set pull-downs, Host
|
// regWr( rMODE, bmDPPULLDN|bmDMPULLDN|bmHOST ); // set pull-downs, Host
|
||||||
//
|
//
|
||||||
// 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
|
|
||||||
|
|
||||||
/* check if device is connected */
|
regWr(rHIEN, bmCONDETIE | bmFRAMEIE); //connection detection
|
||||||
regWr( rHCTL,bmSAMPLEBUS ); // sample USB bus
|
|
||||||
while(!(regRd( rHCTL ) & bmSAMPLEBUS )); //wait for sample operation to finish
|
|
||||||
|
|
||||||
busprobe(); //check if anything is connected
|
/* check if device is connected */
|
||||||
|
regWr(rHCTL, bmSAMPLEBUS); // sample USB bus
|
||||||
|
while (!(regRd(rHCTL) & bmSAMPLEBUS)); //wait for sample operation to finish
|
||||||
|
|
||||||
regWr( rHIRQ, bmCONDETIRQ ); //clear connection detect interrupt
|
busprobe(); //check if anything is connected
|
||||||
regWr( rCPUCTL, 0x01 ); //enable interrupt pin
|
|
||||||
return( 0 );
|
regWr(rHIRQ, bmCONDETIRQ); //clear connection detect interrupt
|
||||||
|
regWr(rCPUCTL, 0x01); //enable interrupt pin
|
||||||
|
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()
|
||||||
|
@ -308,7 +298,7 @@ uint8_t MAX3421e< SS, INTR >::IntHandler()
|
||||||
//// delay( 1000 );
|
//// delay( 1000 );
|
||||||
//// vbusPwr( ON );
|
//// vbusPwr( ON );
|
||||||
//// regWr( rGPINIRQ, bmGPINIRQ7 );
|
//// regWr( rGPINIRQ, bmGPINIRQ7 );
|
||||||
//// }
|
//// }
|
||||||
// return( GPINIRQ );
|
// return( GPINIRQ );
|
||||||
//}
|
//}
|
||||||
|
|
||||||
|
|
578
usbhub.cpp
578
usbhub.cpp
|
@ -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");
|
|
||||||
|
|
||||||
AddressPool &addrPool = pUsb->GetAddressPool();
|
//USBTRACE("\r\nHub Init Start");
|
||||||
|
|
||||||
switch (bInitState)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
if (bAddress)
|
|
||||||
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
|
|
||||||
|
|
||||||
// Get pointer to pseudo device with address 0 assigned
|
AddressPool &addrPool = pUsb->GetAddressPool();
|
||||||
p = addrPool.GetUsbDevicePtr(0);
|
|
||||||
|
|
||||||
if (!p)
|
switch (bInitState) {
|
||||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
case 0:
|
||||||
|
if (bAddress)
|
||||||
|
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
|
||||||
|
|
||||||
if (!p->epinfo)
|
// Get pointer to pseudo device with address 0 assigned
|
||||||
return USB_ERROR_EPINFO_IS_NULL;
|
p = addrPool.GetUsbDevicePtr(0);
|
||||||
|
|
||||||
// Save old pointer to EP_RECORD of address 0
|
if (!p)
|
||||||
oldep_ptr = p->epinfo;
|
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;
|
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, 8, (uint8_t*)buf );
|
p->epinfo = epInfo;
|
||||||
|
|
||||||
p->lowspeed = false;
|
p->lowspeed = lowspeed;
|
||||||
|
|
||||||
if (!rcode)
|
// Get device descriptor
|
||||||
len = (buf[0] > 32) ? 32 : buf[0];
|
rcode = pUsb->getDevDescr(0, 0, 8, (uint8_t*) buf);
|
||||||
|
|
||||||
if( rcode )
|
p->lowspeed = false;
|
||||||
{
|
|
||||||
// Restore p->epinfo
|
|
||||||
p->epinfo = oldep_ptr;
|
|
||||||
return rcode;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extract device class from device descriptor
|
if (!rcode)
|
||||||
// If device class is not a hub return
|
len = (buf[0] > 32) ? 32 : buf[0];
|
||||||
if (((USB_DEVICE_DESCRIPTOR*)buf)->bDeviceClass != 0x09)
|
|
||||||
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
|
|
||||||
|
|
||||||
// Allocate new address according to device class
|
if (rcode) {
|
||||||
bAddress = addrPool.AllocAddress(parent, (((USB_DEVICE_DESCRIPTOR*)buf)->bDeviceClass == 0x09) ? true : false, port);
|
// Restore p->epinfo
|
||||||
|
p->epinfo = oldep_ptr;
|
||||||
|
return rcode;
|
||||||
|
}
|
||||||
|
|
||||||
if (!bAddress)
|
// Extract device class from device descriptor
|
||||||
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
|
// If device class is not a hub return
|
||||||
|
if (((USB_DEVICE_DESCRIPTOR*) buf)->bDeviceClass != 0x09)
|
||||||
|
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
|
||||||
|
|
||||||
// Extract Max Packet Size from the device descriptor
|
// Allocate new address according to device class
|
||||||
epInfo[0].maxPktSize = ((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0;
|
bAddress = addrPool.AllocAddress(parent, (((USB_DEVICE_DESCRIPTOR*) buf)->bDeviceClass == 0x09) ? true : false, port);
|
||||||
|
|
||||||
// Assign new address to the device
|
if (!bAddress)
|
||||||
rcode = pUsb->setAddr( 0, 0, bAddress );
|
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
|
||||||
|
|
||||||
if (rcode)
|
// Extract Max Packet Size from the device descriptor
|
||||||
{
|
epInfo[0].maxPktSize = ((USB_DEVICE_DESCRIPTOR*) buf)->bMaxPacketSize0;
|
||||||
// Restore p->epinfo
|
|
||||||
p->epinfo = oldep_ptr;
|
|
||||||
addrPool.FreeAddress(bAddress);
|
|
||||||
bAddress = 0;
|
|
||||||
return rcode;
|
|
||||||
}
|
|
||||||
|
|
||||||
//USBTRACE2("\r\nHub address: ", bAddress );
|
|
||||||
|
|
||||||
// Restore p->epinfo
|
|
||||||
p->epinfo = oldep_ptr;
|
|
||||||
|
|
||||||
if (len)
|
// Assign new address to the device
|
||||||
rcode = pUsb->getDevDescr( bAddress, 0, len, (uint8_t*)buf );
|
rcode = pUsb->setAddr(0, 0, bAddress);
|
||||||
|
|
||||||
if(rcode)
|
if (rcode) {
|
||||||
goto FailGetDevDescr;
|
// Restore p->epinfo
|
||||||
|
p->epinfo = oldep_ptr;
|
||||||
|
addrPool.FreeAddress(bAddress);
|
||||||
|
bAddress = 0;
|
||||||
|
return rcode;
|
||||||
|
}
|
||||||
|
|
||||||
// Assign epInfo to epinfo pointer
|
//USBTRACE2("\r\nHub address: ", bAddress );
|
||||||
rcode = pUsb->setEpInfoEntry(bAddress, 2, epInfo);
|
|
||||||
|
|
||||||
if (rcode)
|
// Restore p->epinfo
|
||||||
goto FailSetDevTblEntry;
|
p->epinfo = oldep_ptr;
|
||||||
|
|
||||||
bInitState = 1;
|
if (len)
|
||||||
|
rcode = pUsb->getDevDescr(bAddress, 0, len, (uint8_t*) buf);
|
||||||
|
|
||||||
case 1:
|
if (rcode)
|
||||||
// Get hub descriptor
|
goto FailGetDevDescr;
|
||||||
rcode = GetHubDescriptor(0, 8, buf);
|
|
||||||
|
|
||||||
if (rcode)
|
// Assign epInfo to epinfo pointer
|
||||||
goto FailGetHubDescr;
|
rcode = pUsb->setEpInfoEntry(bAddress, 2, epInfo);
|
||||||
|
|
||||||
// Save number of ports for future use
|
if (rcode)
|
||||||
bNbrPorts = ((HubDescriptor*)buf)->bNbrPorts;
|
goto FailSetDevTblEntry;
|
||||||
|
|
||||||
bInitState = 2;
|
bInitState = 1;
|
||||||
|
|
||||||
case 2:
|
case 1:
|
||||||
// Read configuration Descriptor in Order To Obtain Proper Configuration Value
|
// Get hub descriptor
|
||||||
rcode = pUsb->getConfDescr(bAddress, 0, 8, 0, buf);
|
rcode = GetHubDescriptor(0, 8, buf);
|
||||||
|
|
||||||
if (!rcode)
|
if (rcode)
|
||||||
{
|
goto FailGetHubDescr;
|
||||||
cd_len = ((USB_CONFIGURATION_DESCRIPTOR*)buf)->wTotalLength;
|
|
||||||
rcode = pUsb->getConfDescr(bAddress, 0, cd_len, 0, buf);
|
|
||||||
}
|
|
||||||
if (rcode)
|
|
||||||
goto FailGetConfDescr;
|
|
||||||
|
|
||||||
// The following code is of no practical use in real life applications.
|
// Save number of ports for future use
|
||||||
// It only intended for the usb protocol sniffer to properly parse hub-class requests.
|
bNbrPorts = ((HubDescriptor*) buf)->bNbrPorts;
|
||||||
{
|
|
||||||
uint8_t buf2[24];
|
|
||||||
|
|
||||||
rcode = pUsb->getConfDescr(bAddress, 0, buf[0], 0, buf2);
|
bInitState = 2;
|
||||||
|
|
||||||
if (rcode)
|
case 2:
|
||||||
goto FailGetConfDescr;
|
// Read configuration Descriptor in Order To Obtain Proper Configuration Value
|
||||||
}
|
rcode = pUsb->getConfDescr(bAddress, 0, 8, 0, buf);
|
||||||
|
|
||||||
// Set Configuration Value
|
if (!rcode) {
|
||||||
rcode = pUsb->setConf(bAddress, 0, buf[5]);
|
cd_len = ((USB_CONFIGURATION_DESCRIPTOR*) buf)->wTotalLength;
|
||||||
|
rcode = pUsb->getConfDescr(bAddress, 0, cd_len, 0, buf);
|
||||||
|
}
|
||||||
|
if (rcode)
|
||||||
|
goto FailGetConfDescr;
|
||||||
|
|
||||||
if (rcode)
|
// The following code is of no practical use in real life applications.
|
||||||
goto FailSetConfDescr;
|
// It only intended for the usb protocol sniffer to properly parse hub-class requests.
|
||||||
|
{
|
||||||
|
uint8_t buf2[24];
|
||||||
|
|
||||||
bInitState = 3;
|
rcode = pUsb->getConfDescr(bAddress, 0, buf[0], 0, buf2);
|
||||||
|
|
||||||
case 3:
|
if (rcode)
|
||||||
// Power on all ports
|
goto FailGetConfDescr;
|
||||||
for (uint8_t j=1; j<=bNbrPorts; j++)
|
}
|
||||||
SetPortFeature(HUB_FEATURE_PORT_POWER, j, 0); //HubPortPowerOn(j);
|
|
||||||
|
|
||||||
pUsb->SetHubPreMask();
|
// Set Configuration Value
|
||||||
bPollEnable = true;
|
rcode = pUsb->setConf(bAddress, 0, buf[5]);
|
||||||
bInitState = 0;
|
|
||||||
}
|
if (rcode)
|
||||||
bInitState = 0;
|
goto FailSetConfDescr;
|
||||||
return 0;
|
|
||||||
|
bInitState = 3;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
// Power on all ports
|
||||||
|
for (uint8_t j = 1; j <= bNbrPorts; j++)
|
||||||
|
SetPortFeature(HUB_FEATURE_PORT_POWER, j, 0); //HubPortPowerOn(j);
|
||||||
|
|
||||||
|
pUsb->SetHubPreMask();
|
||||||
|
bPollEnable = true;
|
||||||
|
bInitState = 0;
|
||||||
|
}
|
||||||
|
bInitState = 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);
|
||||||
}
|
}
|
||||||
|
|
172
usbhub.h
172
usbhub.h
|
@ -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
|
||||||
|
@ -76,7 +77,7 @@ e-mail : support@circuitsathome.com
|
||||||
#define HUB_PORT_TEST_MODE_K 2
|
#define HUB_PORT_TEST_MODE_K 2
|
||||||
#define HUB_PORT_TEST_MODE_SE0_NAK 3
|
#define HUB_PORT_TEST_MODE_SE0_NAK 3
|
||||||
#define HUB_PORT_TEST_MODE_PACKET 4
|
#define HUB_PORT_TEST_MODE_PACKET 4
|
||||||
#define HUB_PORT_TEST_MODE_FORCE_ENABLE 5
|
#define HUB_PORT_TEST_MODE_FORCE_ENABLE 5
|
||||||
|
|
||||||
// Hub Port Indicator Color
|
// Hub Port Indicator Color
|
||||||
#define HUB_PORT_INDICATOR_AUTO 0
|
#define HUB_PORT_INDICATOR_AUTO 0
|
||||||
|
@ -84,7 +85,7 @@ e-mail : support@circuitsathome.com
|
||||||
#define HUB_PORT_INDICATOR_GREEN 2
|
#define HUB_PORT_INDICATOR_GREEN 2
|
||||||
#define HUB_PORT_INDICATOR_OFF 3
|
#define HUB_PORT_INDICATOR_OFF 3
|
||||||
|
|
||||||
// Hub Port Status Bitmasks
|
// Hub Port Status Bitmasks
|
||||||
#define bmHUB_PORT_STATUS_PORT_CONNECTION 0x0001
|
#define bmHUB_PORT_STATUS_PORT_CONNECTION 0x0001
|
||||||
#define bmHUB_PORT_STATUS_PORT_ENABLE 0x0002
|
#define bmHUB_PORT_STATUS_PORT_ENABLE 0x0002
|
||||||
#define bmHUB_PORT_STATUS_PORT_SUSPEND 0x0004
|
#define bmHUB_PORT_STATUS_PORT_SUSPEND 0x0004
|
||||||
|
@ -127,7 +128,7 @@ e-mail : support@circuitsathome.com
|
||||||
// The bit mask to check for all necessary state bits
|
// The bit mask to check for all necessary state bits
|
||||||
#define bmHUB_PORT_STATUS_ALL_MAIN ((0UL | bmHUB_PORT_STATUS_C_PORT_CONNECTION | bmHUB_PORT_STATUS_C_PORT_ENABLE | bmHUB_PORT_STATUS_C_PORT_SUSPEND | 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_SUSPEND)
|
#define bmHUB_PORT_STATUS_ALL_MAIN ((0UL | bmHUB_PORT_STATUS_C_PORT_CONNECTION | bmHUB_PORT_STATUS_C_PORT_ENABLE | bmHUB_PORT_STATUS_C_PORT_SUSPEND | 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_SUSPEND)
|
||||||
|
|
||||||
// Bit mask to check for DISABLED state in HubEvent::bmStatus field
|
// Bit mask to check for DISABLED state in HubEvent::bmStatus field
|
||||||
#define bmHUB_PORT_STATE_CHECK_DISABLED (0x0000 | bmHUB_PORT_STATUS_PORT_POWER | bmHUB_PORT_STATUS_PORT_ENABLE | bmHUB_PORT_STATUS_PORT_CONNECTION | bmHUB_PORT_STATUS_PORT_SUSPEND)
|
#define bmHUB_PORT_STATE_CHECK_DISABLED (0x0000 | bmHUB_PORT_STATUS_PORT_POWER | bmHUB_PORT_STATUS_PORT_ENABLE | bmHUB_PORT_STATUS_PORT_CONNECTION | bmHUB_PORT_STATUS_PORT_SUSPEND)
|
||||||
|
|
||||||
// Hub Port States
|
// Hub Port States
|
||||||
|
@ -142,118 +143,117 @@ 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
|
|
||||||
{
|
|
||||||
uint16_t LogPwrSwitchMode : 2;
|
|
||||||
uint16_t CompoundDevice : 1;
|
|
||||||
uint16_t OverCurrentProtectMode : 2;
|
|
||||||
uint16_t TTThinkTime : 2;
|
|
||||||
uint16_t PortIndicatorsSupported : 1;
|
|
||||||
uint16_t Reserved : 8;
|
|
||||||
};
|
|
||||||
|
|
||||||
uint8_t bPwrOn2PwrGood;
|
struct {
|
||||||
uint8_t bHubContrCurrent;
|
uint16_t LogPwrSwitchMode : 2;
|
||||||
};
|
uint16_t CompoundDevice : 1;
|
||||||
|
uint16_t OverCurrentProtectMode : 2;
|
||||||
|
uint16_t TTThinkTime : 2;
|
||||||
|
uint16_t PortIndicatorsSupported : 1;
|
||||||
|
uint16_t Reserved : 8;
|
||||||
|
}__attribute__((packed));
|
||||||
|
|
||||||
struct HubEvent
|
uint8_t bPwrOn2PwrGood;
|
||||||
{
|
uint8_t bHubContrCurrent;
|
||||||
union
|
}__attribute__((packed));
|
||||||
{
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
uint16_t bmStatus; // port status bits
|
|
||||||
uint16_t bmChange; // port status change bits
|
|
||||||
};
|
|
||||||
uint32_t bmEvent;
|
|
||||||
uint8_t evtBuff[4];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
class USBHub : USBDeviceConfig
|
struct HubEvent {
|
||||||
{
|
|
||||||
static bool bResetInitiated; // True when reset is triggered
|
|
||||||
|
|
||||||
USB *pUsb; // USB class instance pointer
|
union {
|
||||||
|
|
||||||
EpInfo epInfo[2]; // interrupt endpoint info structure
|
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));
|
||||||
|
|
||||||
uint8_t bAddress; // address
|
class USBHub : USBDeviceConfig {
|
||||||
uint8_t bNbrPorts; // number of ports
|
static bool bResetInitiated; // True when reset is triggered
|
||||||
uint8_t bInitState; // initialization state variable
|
|
||||||
uint32_t qNextPollTime; // next poll time
|
|
||||||
bool bPollEnable; // poll enable flag
|
|
||||||
|
|
||||||
uint8_t CheckHubStatus();
|
USB *pUsb; // USB class instance pointer
|
||||||
uint8_t PortStatusChange(uint8_t port, HubEvent &evt);
|
|
||||||
|
EpInfo epInfo[2]; // interrupt endpoint info structure
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
#endif // __USBHUB_H__
|
#endif // __USBHUB_H__
|
||||||
|
|
Loading…
Reference in a new issue