diff --git a/Usb.cpp b/Usb.cpp index 992f57e1..7a5a6477 100644 --- a/Usb.cpp +++ b/Usb.cpp @@ -225,7 +225,7 @@ uint8_t USB::InTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t *nbytesptr, ui while( 1 ) // use a 'return' to exit this loop { rcode = dispatchPkt( tokIN, pep->epAddr, nak_limit ); //IN packet to EP-'endpoint'. Function takes care of NAKS. - + if( rcode ) return( rcode ); //should be 0, indicating ACK. Else return error code. @@ -234,7 +234,9 @@ uint8_t USB::InTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t *nbytesptr, ui if(( regRd( rHIRQ ) & bmRCVDAVIRQ ) == 0 ) return ( 0xf0 ); //receive error - pktsize = regRd( rRCVBC ); //number of received bytes */ + pktsize = regRd( rRCVBC ); //number of received bytes + + assert(pktsize <= nbytes); int16_t mem_left = (int16_t)nbytes - *((int16_t*)nbytesptr); @@ -249,10 +251,10 @@ uint8_t USB::InTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t *nbytesptr, ui /* The transfer is complete under two conditions: */ /* 1. The device sent a short packet (L.T. maxPacketSize) */ /* 2. 'nbytes' have been transferred. */ - if (/*pktsize == 6 ||*/ ( pktsize < maxpktsize ) || (*nbytesptr >= nbytes )) // have we transferred 'nbytes' bytes? + if (( pktsize < maxpktsize ) || (*nbytesptr >= nbytes )) // have we transferred 'nbytes' bytes? { // Save toggle value - pep->bmRcvToggle = ( regRd( rHRSL ) & bmRCVTOGRD ) ? 1 : 0; + pep->bmRcvToggle = (( regRd( rHRSL ) & bmRCVTOGRD )) ? 1 : 0; return( 0 ); } // if @@ -603,7 +605,7 @@ uint8_t USB::getConfDescr( uint8_t addr, uint8_t ep, uint8_t conf, USBReadParser uint16_t total = ((USB_CONFIGURATION_DESCRIPTOR*)buf)->wTotalLength; - USBTRACE2("total:", total); + //USBTRACE2("\r\ntotal conf.size:", total); return( ctrlReq( addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, total, bufSize, buf, p )); } diff --git a/Usb.h b/Usb.h index d331a09b..8676589f 100644 --- a/Usb.h +++ b/Usb.h @@ -21,6 +21,9 @@ e-mail : support@circuitsathome.com #define USB_METHODS_INLINE #include + +#include + #include "avrpins.h" #include "max3421e.h" #include "usbhost.h" @@ -97,7 +100,7 @@ public: #define USB_NAK_LIMIT 32000 //NAK limit for a transfer. o meand NAKs are not counted #define USB_RETRY_LIMIT 3 //retry limit for a transfer #define USB_SETTLE_DELAY 200 //settle delay in milliseconds -#define USB_NAK_NOWAIT 1 //used in Richard's PS2/Wiimote code +#define USB_NAK_NOWAIT 1 //quit after receiving a single NAK #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 @@ -120,9 +123,6 @@ public: #define USB_STATE_RUNNING 0x90 #define USB_STATE_ERROR 0xa0 - -// byte usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE - /* USB Setup Packet Structure */ typedef struct { union { // offset description diff --git a/adk.cpp b/adk.cpp new file mode 100644 index 00000000..ce49e350 --- /dev/null +++ b/adk.cpp @@ -0,0 +1,321 @@ +/* Google ADK interface */ + +#include "adk.h" + +const uint8_t ADK::epDataInIndex = 1; +const uint8_t ADK::epDataOutIndex = 2; + +ADK::ADK(USB *p, const char* manufacturer, + const char* model, + const char* description, + const char* version, + const char* uri, + const char* serial) : + + pUsb(p), //pointer to USB class instance - mandatory + bAddress(0), //device address - mandatory + bNumEP(1), //if config descriptor needs to be parsed + ready(false), + + /* ADK ID Strings */ + + manufacturer(manufacturer), + model(model), + description(description), + version(version), + uri(uri), + serial(serial) + +{ + // initialize endpoint data structures + for(uint8_t i=0; iRegisterDeviceClass(this); //set devConfig[] entry + } +} + +/* Connection initialization of an Android phone */ +uint8_t ADK::Init(uint8_t parent, uint8_t port, bool lowspeed) +{ + + uint8_t buf[sizeof(USB_DEVICE_DESCRIPTOR)]; + uint8_t rcode; + UsbDevice *p = NULL; + EpInfo *oldep_ptr = NULL; + uint8_t num_of_conf; // number of configurations + + // get memory address of USB device address pool + AddressPool &addrPool = pUsb->GetAddressPool(); + + USBTRACE("\r\nADK Init"); + + // check if address has already been assigned to an instance + if (bAddress) { + USBTRACE("\r\nAddress in use"); + return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE; + } + + // Get pointer to pseudo device with address 0 assigned + p = addrPool.GetUsbDevicePtr(0); + + if (!p) { + USBTRACE("\r\nAddress not found"); + return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; + } + + if (!p->epinfo) { + USBTRACE("epinfo is null\r\n"); + return USB_ERROR_EPINFO_IS_NULL; + } + + // Save old pointer to EP_RECORD of address 0 + oldep_ptr = p->epinfo; + + // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence + p->epinfo = epInfo; + + p->lowspeed = lowspeed; + + // Get device descriptor + rcode = pUsb->getDevDescr( 0, 0, sizeof(USB_DEVICE_DESCRIPTOR), (uint8_t*)buf ); + + // Restore p->epinfo + p->epinfo = oldep_ptr; + + if( rcode ){ + goto FailGetDevDescr; + } + + // Allocate new address according to device class + bAddress = addrPool.AllocAddress(parent, false, port); + + // Extract Max Packet Size from device descriptor + epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0; + + // Assign new address to the device + rcode = pUsb->setAddr( 0, 0, bAddress ); + if (rcode) { + p->lowspeed = false; + addrPool.FreeAddress(bAddress); + bAddress = 0; + //USBTRACE2("setAddr:",rcode); + return rcode; + }//if (rcode... + + //USBTRACE2("\r\nAddr:", bAddress); + + p->lowspeed = false; + + //get pointer to assigned address record + p = addrPool.GetUsbDevicePtr(bAddress); + if (!p) { + return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; + } + + p->lowspeed = lowspeed; + + // Assign epInfo to epinfo pointer - only EP0 is known + rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo); + if (rcode) { + goto FailSetDevTblEntry; + } + + //check if ADK device is already in accessory mode; if yes, configure and exit + if(((USB_DEVICE_DESCRIPTOR*)buf)->idVendor == ADK_VID && + (((USB_DEVICE_DESCRIPTOR*)buf)->idProduct == ADK_PID || ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct == ADB_PID)) { + USBTRACE("\r\nAcc.mode device detected"); + /* go through configurations, find first bulk-IN, bulk-OUT EP, fill epInfo and quit */ + num_of_conf = ((USB_DEVICE_DESCRIPTOR*)buf)->bNumConfigurations; + + //USBTRACE2("\r\nNC:",num_of_conf); + + for (uint8_t i=0; i confDescrParser(this); + rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser); + if( rcode ) { + goto FailGetConfDescr; + } + if( bNumEP > 2 ) { + break; + } + } // for (uint8_t i=0; isetEpInfoEntry(bAddress, 3, epInfo); + if (rcode) { + goto FailSetDevTblEntry; + } + } + + + + // Set Configuration Value + rcode = pUsb->setConf(bAddress, 0, bConfNum); + if( rcode ){ + goto FailSetConf; + } + /* print endpoint structure */ +// USBTRACE("\r\nEndpoint Structure:"); +// USBTRACE("\r\nEP0:"); +// USBTRACE2("\r\nAddr: ", epInfo[0].epAddr ); +// USBTRACE2("\r\nMax.pkt.size: ", epInfo[0].maxPktSize ); +// USBTRACE2("\r\nAttr: ", epInfo[0].epAttribs ); +// USBTRACE("\r\nEpout:"); +// USBTRACE2("\r\nAddr: ", epInfo[epDataOutIndex].epAddr ); +// USBTRACE2("\r\nMax.pkt.size: ", epInfo[epDataOutIndex].maxPktSize ); +// USBTRACE2("\r\nAttr: ", epInfo[epDataOutIndex].epAttribs ); +// USBTRACE("\r\nEpin:"); +// USBTRACE2("\r\nAddr: ", epInfo[epDataInIndex].epAddr ); +// USBTRACE2("\r\nMax.pkt.size: ", epInfo[epDataInIndex].maxPktSize ); +// USBTRACE2("\r\nAttr: ", epInfo[epDataInIndex].epAttribs ); + + USBTRACE("\r\nConfiguration successful"); + ready = true; + return 0; //successful configuration + }//if( buf->idVendor == ADK_VID... + + //probe device - get accessory protocol revision + { + uint16_t adkproto = -1; + rcode = getProto((uint8_t*)&adkproto ); + if( rcode ){ + goto FailGetProto; //init fails + } + USBTRACE2("\r\nADK protocol rev. ", adkproto ); + } + + //sending ID strings + sendStr( ACCESSORY_STRING_MANUFACTURER, manufacturer); + sendStr( ACCESSORY_STRING_MODEL, model); + sendStr( ACCESSORY_STRING_DESCRIPTION, description); + sendStr( ACCESSORY_STRING_VERSION, version); + sendStr( ACCESSORY_STRING_URI, uri); + sendStr( ACCESSORY_STRING_SERIAL, serial); + + //switch to accessory mode + //the Android phone will reset + rcode = switchAcc(); + if( rcode ) { + goto FailSwAcc; //init fails + } + rcode = -1; + goto SwAttempt; //switch to accessory mode attempted + + /* diagnostic messages */ +FailGetDevDescr: + USBTRACE("\r\ngetDevDescr:"); + goto Fail; + +FailSetDevTblEntry: + USBTRACE("\r\nsetDevTblEn:"); + goto Fail; + +FailGetProto: + USBTRACE("\r\ngetProto:"); + goto Fail; + +FailSwAcc: + USBTRACE("\r\nswAcc:"); + goto Fail; + +SwAttempt: + USBTRACE("\r\nAccessory mode switch attempt"); + goto Fail; + +//FailSetDevTblEntry: +// USBTRACE("setDevTblEn:"); +// goto Fail; +// +FailGetConfDescr: +// USBTRACE("getConf:"); + goto Fail; +// +FailSetConf: +// USBTRACE("setConf:"); + goto Fail; +// +//FailOnInit: +// USBTRACE("OnInit:"); +// goto Fail; +// +Fail: + //USBTRACE2("\r\nADK Init Failed, error code: ", rcode); + Release(); + return rcode; +} + +/* 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) +{ + //ErrorMessage(PSTR("Conf.Val"), conf); + //ErrorMessage(PSTR("Iface Num"),iface); + //ErrorMessage(PSTR("Alt.Set"), alt); + + bConfNum = conf; + + uint8_t index; + + if ((pep->bmAttributes & 0x02) == 2) { + index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex; + } + + // 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 ) +{ + Notify(PSTR("Endpoint descriptor:")); + Notify(PSTR("\r\nLength:\t\t")); + PrintHex(ep_ptr->bLength); + Notify(PSTR("\r\nType:\t\t")); + PrintHex(ep_ptr->bDescriptorType); + Notify(PSTR("\r\nAddress:\t")); + PrintHex(ep_ptr->bEndpointAddress); + Notify(PSTR("\r\nAttributes:\t")); + PrintHex(ep_ptr->bmAttributes); + Notify(PSTR("\r\nMaxPktSize:\t")); + PrintHex(ep_ptr->wMaxPacketSize); + Notify(PSTR("\r\nPoll Intrv:\t")); + PrintHex(ep_ptr->bInterval); + Notify(PSTR("\r\n")); +} diff --git a/adk.h b/adk.h new file mode 100644 index 00000000..2d41f9da --- /dev/null +++ b/adk.h @@ -0,0 +1,119 @@ +/* Google ADK interface support header */ + +#if !defined(_ADK_H_) +#define _ADK_H_ + +#include +#include +#include "avrpins.h" +#include "max3421e.h" +#include "usbhost.h" +#include "usb_ch9.h" +#include "Usb.h" +#include + +#include "printhex.h" +#include "hexdump.h" +#include "message.h" + +#include "confdescparser.h" + +#define ADK_VID 0x18D1 +#define ADK_PID 0x2D00 +#define ADB_PID 0x2D01 + +/* requests */ + +#define ADK_GETPROTO 51 //check USB accessory protocol version +#define ADK_SENDSTR 52 //send identifying string +#define ADK_ACCSTART 53 //start device in accessory mode + +#define bmREQ_ADK_GET USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_VENDOR|USB_SETUP_RECIPIENT_DEVICE +#define bmREQ_ADK_SEND USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_VENDOR|USB_SETUP_RECIPIENT_DEVICE + +#define ACCESSORY_STRING_MANUFACTURER 0 +#define ACCESSORY_STRING_MODEL 1 +#define ACCESSORY_STRING_DESCRIPTION 2 +#define ACCESSORY_STRING_VERSION 3 +#define ACCESSORY_STRING_URI 4 +#define ACCESSORY_STRING_SERIAL 5 + +#define ADK_MAX_ENDPOINTS 3 //endpoint 0, bulk_IN, bulk_OUT + +class ADK; + +class ADK : public USBDeviceConfig, public UsbConfigXtracter +{ +private: + /* ID strings */ + const char* manufacturer; + const char* model; + const char* description; + const char* version; + const char* uri; + const char* serial; + + /* ADK proprietary requests */ + uint8_t getProto( uint8_t* adkproto ); + uint8_t sendStr( uint8_t index, const char* str ); + uint8_t switchAcc( void ); + +protected: + static const uint8_t epDataInIndex; // DataIn endpoint index + static const uint8_t epDataOutIndex; // DataOUT endpoint index + + /* mandatory members */ + USB *pUsb; + uint8_t bAddress; + uint8_t bConfNum; // configuration number + + uint8_t bNumEP; // total number of EP in the configuration + bool ready; + + /* Endpoint data structure */ + EpInfo epInfo[ADK_MAX_ENDPOINTS]; + + void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr); + +public: + ADK(USB *pUsb, const char* manufacturer, + const char* model, + const char* description, + const char* version, + const char* uri, + const char* serial); + + // 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(){}; //not implemented + virtual uint8_t GetAddress() { return bAddress; }; + virtual bool isReady() { return ready; }; + + //UsbConfigXtracter implementation + virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep); +}; //class ADK : public USBDeviceConfig ... + +/* get ADK protocol version */ +/* returns 2 bytes in *adkproto */ +inline uint8_t ADK::getProto( uint8_t* adkproto ) +{ + return( pUsb->ctrlReq(bAddress, 0, bmREQ_ADK_GET, ADK_GETPROTO, 0, 0, 0, 2, 2, adkproto, NULL )); +} +/* send ADK string */ +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)); +} +/* 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_ \ No newline at end of file diff --git a/confdescparser.h b/confdescparser.h index 27ea57e5..295a1203 100644 --- a/confdescparser.h +++ b/confdescparser.h @@ -92,7 +92,8 @@ void ConfigDescParser::Parse(const uin 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 */ template bool ConfigDescParser::ParseDescriptor(uint8_t **pp, uint16_t *pcntdn) { diff --git a/examples/adk/demokit_20/demokit_20.pde b/examples/adk/demokit_20/demokit_20.pde new file mode 100644 index 00000000..b1f47294 --- /dev/null +++ b/examples/adk/demokit_20/demokit_20.pde @@ -0,0 +1,110 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +USB Usb; +USBHub hub0(&Usb); +USBHub hub1(&Usb); +ADK adk(&Usb,"Google, Inc.", + "DemoKit", + "DemoKit Arduino Board", + "1.0", + "http://www.android.com", + "0000000012345678"); +uint8_t b, b1; + + +#define LED1_RED 3 +#define BUTTON1 2 + +void setup(); +void loop(); + +void init_buttons() +{ + pinMode(BUTTON1, INPUT); + + // enable the internal pullups + digitalWrite(BUTTON1, HIGH); +} + +void init_leds() +{ + digitalWrite(LED1_RED, 0); + + pinMode(LED1_RED, OUTPUT); +} + +void setup() +{ + Serial.begin(115200); + Serial.println("\r\nADK demo start"); + + if (Usb.Init() == -1) { + Serial.println("OSCOKIRQ failed to assert"); + while(1); //halt + }//if (Usb.Init() == -1... + + + init_leds(); + init_buttons(); + b1 = digitalRead(BUTTON1); +} + +void loop() +{ + uint8_t rcode; + uint8_t msg[3] = { 0x00 }; + Usb.Task(); + + if( adk.isReady() == false ) { + analogWrite(LED1_RED, 255); + return; + } + uint16_t len = sizeof(msg); + + rcode = adk.RcvData(&len, msg); + if( rcode ) { + USBTRACE2("Data rcv. :", rcode ); + } + if(len > 0) { + USBTRACE("\r\nData Packet."); + // assumes only one command per packet + if (msg[0] == 0x2) { + switch( msg[1] ) { + case 0: + analogWrite(LED1_RED, 255 - msg[2]); + break; + }//switch( msg[1]... + }//if (msg[0] == 0x2... + }//if( len > 0... + + msg[0] = 0x1; + + b = digitalRead(BUTTON1); + if (b != b1) { + USBTRACE("\r\nButton state changed"); + msg[1] = 0; + msg[2] = b ? 0 : 1; + rcode = adk.SndData( 3, msg ); + if( rcode ) { + USBTRACE2("Button send: ", rcode ); + } + b1 = b; + }//if (b != b1... + + + delay( 10 ); +} diff --git a/hid.cpp b/hid.cpp index 3c53bbc9..225ac7d3 100644 --- a/hid.cpp +++ b/hid.cpp @@ -1,19 +1,3 @@ -/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. - -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 -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 -on this software must also be made publicly available under the terms of -the GPL2 ("Copyleft"). - -Contact information -------------------- - -Circuits At Home, LTD -Web : http://www.circuitsathome.com -e-mail : support@circuitsathome.com -*/ #include "hid.h" //const uint16_t HID::maxHidInterfaces = 3; @@ -316,13 +300,13 @@ uint8_t HID::Poll() if (qNextPollTime <= millis()) { - qNextPollTime = millis() + 100; + qNextPollTime = millis() + 500; const uint8_t const_buff_len = 16; uint8_t buf[const_buff_len]; HexDumper Hex; - uint16_t read = (uint16_t)const_buff_len; + uint16_t read = (uint16_t)epInfo[epInterruptInIndex].maxPktSize; uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[epInterruptInIndex].epAddr, &read, buf); @@ -395,6 +379,22 @@ void ReportDescParser::Parse(const uint16_t len, const uint8_t *pbuf, const uint //if (ParseItem(&p, &cntdn)) // return; } + USBTRACE2("Total:", totalSize); +} + +void ReportDescParser::PrintValue(uint8_t *p, uint8_t len) +{ + Notify(PSTR("(")); + for (; len; p++, len--) + PrintHex(*p); + Notify(PSTR(")")); +} + +void ReportDescParser::PrintByteValue(uint8_t data) +{ + Notify(PSTR("(")); + PrintHex(data); + Notify(PSTR(")")); } uint8_t ReportDescParser::ParseItem(uint8_t **pp, uint16_t *pcntdn) @@ -404,6 +404,11 @@ uint8_t ReportDescParser::ParseItem(uint8_t **pp, uint16_t *pcntdn) switch (itemParseState) { case 0: + if (**pp == HID_LONG_ITEM_PREFIX) + USBTRACE("\r\nLONG\r\n"); + //totalSize = 0; + //rptSize = 0; + //rptCount = 0; //if (**pp == HID_LONG_ITEM_PREFIX) //{ // *pp ++; @@ -417,12 +422,19 @@ uint8_t ReportDescParser::ParseItem(uint8_t **pp, uint16_t *pcntdn) //else { uint8_t size = ((**pp) & DATA_SIZE_MASK); + + USBTRACE2("\r\nSZ:", size); + itemPrefix = (**pp); itemSize = 1 + ((size == DATA_SIZE_4) ? 4 : size); - //USBTRACE2("Sz1:", size); - //Serial.print("\r\nSz:"); - //Serial.println(itemSize,DEC); + Serial.print("\r\nSz:"); + Serial.println(itemSize,DEC); + + PrintHex(*pcntdn); + Serial.print(":"); + PrintHex((itemPrefix & (TYPE_MASK | TAG_MASK))); + Serial.println(""); switch (itemPrefix & (TYPE_MASK | TAG_MASK)) { @@ -518,21 +530,29 @@ uint8_t ReportDescParser::ParseItem(uint8_t **pp, uint16_t *pcntdn) pfUsage(*((uint16_t*)varBuffer)); else pfUsage(data); + case (TYPE_GLOBAL | TAG_GLOBAL_REPORTSIZE): + rptSize = data; + PrintByteValue(data); + break; + case (TYPE_GLOBAL | TAG_GLOBAL_REPORTCOUNT): + rptCount = data; + PrintByteValue(data); + break; case (TYPE_GLOBAL | TAG_GLOBAL_LOGICALMIN): case (TYPE_GLOBAL | TAG_GLOBAL_LOGICALMAX): case (TYPE_GLOBAL | TAG_GLOBAL_PHYSMIN): case (TYPE_GLOBAL | TAG_GLOBAL_PHYSMAX): - case (TYPE_GLOBAL | TAG_GLOBAL_REPORTSIZE): - case (TYPE_GLOBAL | TAG_GLOBAL_REPORTCOUNT): case (TYPE_GLOBAL | TAG_GLOBAL_REPORTID): case (TYPE_LOCAL | TAG_LOCAL_USAGEMIN): case (TYPE_LOCAL | TAG_LOCAL_USAGEMAX): case (TYPE_GLOBAL | TAG_GLOBAL_UNITEXP): case (TYPE_GLOBAL | TAG_GLOBAL_UNIT): - Notify(PSTR("(")); - for (uint8_t i=0; i(data); - Notify(PSTR(")")); + PrintValue(varBuffer, theBuffer.valueSize); + //Notify(PSTR("(")); + //for (uint8_t i=0; i(varBuffer[i]); + // //PrintHex(data); + //Notify(PSTR(")")); break; case (TYPE_GLOBAL | TAG_GLOBAL_PUSH): case (TYPE_GLOBAL | TAG_GLOBAL_POP): @@ -540,11 +560,7 @@ uint8_t ReportDescParser::ParseItem(uint8_t **pp, uint16_t *pcntdn) case (TYPE_GLOBAL | TAG_GLOBAL_USAGEPAGE): SetUsagePage(data); PrintUsagePage(data); - - Notify(PSTR("(")); - for (uint8_t i=0; i(data); - Notify(PSTR(")")); + PrintByteValue(data); break; case (TYPE_MAIN | TAG_MAIN_COLLECTION): case (TYPE_MAIN | TAG_MAIN_ENDCOLLECTION): @@ -580,6 +596,9 @@ uint8_t ReportDescParser::ParseItem(uint8_t **pp, uint16_t *pcntdn) case (TYPE_MAIN | TAG_MAIN_INPUT): case (TYPE_MAIN | TAG_MAIN_OUTPUT): case (TYPE_MAIN | TAG_MAIN_FEATURE): + totalSize += (uint16_t)rptSize * (uint16_t)rptCount; + rptSize = 0; + rptCount = 0; Notify(PSTR("(")); PrintBin(data); Notify(PSTR(")")); @@ -588,6 +607,13 @@ uint8_t ReportDescParser::ParseItem(uint8_t **pp, uint16_t *pcntdn) } itemParseState = 4; case 4: + USBTRACE2("iSz:", itemSize); + + PrintHex(*pcntdn); + Serial.print(":"); + PrintHex((itemPrefix & (TYPE_MASK | TAG_MASK))); + Serial.println(""); + if (itemSize > 1 && !theSkipper.Skip(pp, pcntdn, itemSize)) return enErrorIncomplete; } // switch (itemParseState) diff --git a/hid.h b/hid.h index 0f41e7e5..7ca81b20 100644 --- a/hid.h +++ b/hid.h @@ -1,19 +1,3 @@ -/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. - -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 -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 -on this software must also be made publicly available under the terms of -the GPL2 ("Copyleft"). - -Contact information -------------------- - -Circuits At Home, LTD -Web : http://www.circuitsathome.com -e-mail : support@circuitsathome.com -*/ #if !defined(__HID_H__) #define __HID_H__ @@ -180,6 +164,9 @@ public: static void PrintAlphanumDisplayPageUsage(uint16_t usage); static void PrintMedicalInstrumentPageUsage(uint16_t usage); + static void PrintValue(uint8_t *p, uint8_t len); + static void PrintByteValue(uint8_t data); + private: static UsagePageFunc usagePageFunctions[]; @@ -191,6 +178,10 @@ private: uint8_t itemParseState; // Item parser state variable uint8_t itemSize; // Item size uint8_t itemPrefix; // Item prefix (first byte) + uint8_t rptSize; // Report Size + uint8_t rptCount; // Report Count + + uint8_t totalSize; // Report size in bytes uint8_t ParseItem(uint8_t **pp, uint16_t *pcntdn); @@ -204,6 +195,8 @@ public: itemParseState(0), itemSize(0), itemPrefix(0), + rptSize(0), + rptCount(0), pfUsage(NULL) { theBuffer.pValue = varBuffer; diff --git a/masstorage.cpp b/masstorage.cpp new file mode 100644 index 00000000..21c25202 --- /dev/null +++ b/masstorage.cpp @@ -0,0 +1,328 @@ +#include "masstorage.h" + +const uint8_t BulkOnly::epDataInIndex = 1; +const uint8_t BulkOnly::epDataOutIndex = 2; +const uint8_t BulkOnly::epInterruptInIndex = 3; + +BulkOnly::BulkOnly(USB *p /*, CDCAsyncOper *pasync*/) : + pUsb(p), + //pAsync(pasync), + bAddress(0), + qNextPollTime(0), + bPollEnable(false), + bIface(0), + bNumEP(1) +{ + for(uint8_t i=0; iRegisterDeviceClass(this); +} + +uint8_t BulkOnly::Init(uint8_t parent, uint8_t port, bool lowspeed) +{ + const uint8_t constBufSize = sizeof(USB_DEVICE_DESCRIPTOR); + + uint8_t buf[constBufSize]; + uint8_t rcode; + UsbDevice *p = NULL; + EpInfo *oldep_ptr = NULL; + uint8_t num_of_conf; // number of configurations + + AddressPool &addrPool = pUsb->GetAddressPool(); + + USBTRACE("MS Init\r\n"); + + if (bAddress) + return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE; + + // Get pointer to pseudo device with address 0 assigned + p = addrPool.GetUsbDevicePtr(0); + + if (!p) + return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; + + if (!p->epinfo) + { + USBTRACE("epinfo\r\n"); + return USB_ERROR_EPINFO_IS_NULL; + } + + // Save old pointer to EP_RECORD of address 0 + oldep_ptr = p->epinfo; + + // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence + p->epinfo = epInfo; + + p->lowspeed = lowspeed; + + // Get device descriptor + rcode = pUsb->getDevDescr( 0, 0, constBufSize, (uint8_t*)buf ); + + // Restore p->epinfo + p->epinfo = oldep_ptr; + + if( rcode ) + goto FailGetDevDescr; + + // Allocate new address according to device class + bAddress = addrPool.AllocAddress(parent, false, port); + + if (!bAddress) + return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL; + + // Extract Max Packet Size from the device descriptor + epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0; + + // Assign new address to the device + rcode = pUsb->setAddr( 0, 0, bAddress ); + + if (rcode) + { + p->lowspeed = false; + addrPool.FreeAddress(bAddress); + bAddress = 0; + USBTRACE2("setAddr:",rcode); + return rcode; + } + + USBTRACE2("Addr:", bAddress); + + p->lowspeed = false; + + p = addrPool.GetUsbDevicePtr(bAddress); + + if (!p) + return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; + + p->lowspeed = lowspeed; + + num_of_conf = ((USB_DEVICE_DESCRIPTOR*)buf)->bNumConfigurations; + + // Assign epInfo to epinfo pointer + rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo); + + if (rcode) + goto FailSetDevTblEntry; + + USBTRACE2("NC:", num_of_conf); + + for (uint8_t i=0; i HexDump; + ConfigDescParser< USB_CLASS_MASS_STORAGE, + MASS_SUBCLASS_SCSI, + MASS_PROTO_BBB, + CP_MASK_COMPARE_CLASS | + CP_MASK_COMPARE_SUBCLASS | + CP_MASK_COMPARE_PROTOCOL> BulkOnlyParser(this); + + rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump); + rcode = pUsb->getConfDescr(bAddress, 0, i, &BulkOnlyParser); + + + if (bNumEP > 1) + break; + } // for + + if (bNumEP < 4) + return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; + + // Assign epInfo to epinfo pointer + rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo); + + USBTRACE2("Conf:", bConfNum); + + // Set Configuration Value + rcode = pUsb->setConf(bAddress, 0, bConfNum); + + if (rcode) + goto FailSetConf; + + //rcode = pAsync->OnInit(this); + + if (rcode) + goto FailOnInit; + + USBTRACE("MS configured\r\n"); + + //bPollEnable = true; + + //USBTRACE("Poll enabled\r\n"); + return 0; + +FailGetDevDescr: + USBTRACE("getDevDescr:"); + goto Fail; + +FailSetDevTblEntry: + USBTRACE("setDevTblEn:"); + goto Fail; + +FailGetConfDescr: + USBTRACE("getConf:"); + goto Fail; + +FailSetConf: + USBTRACE("setConf:"); + goto Fail; + +FailOnInit: + USBTRACE("OnInit:"); + goto Fail; + +Fail: + Serial.println(rcode, HEX); + Release(); + return rcode; +} + + +void BulkOnly::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) +{ + ErrorMessage(PSTR("Conf.Val"), conf); + ErrorMessage(PSTR("Iface Num"),iface); + ErrorMessage(PSTR("Alt.Set"), alt); + + bConfNum = conf; + + uint8_t index; + + if ((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80) + index = epInterruptInIndex; + else + if ((pep->bmAttributes & 0x02) == 2) + index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex; + else + return; + + // Fill in the endpoint info structure + epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F); + epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize; + epInfo[index].epAttribs = 0; + + bNumEP ++; + + PrintEndpointDescriptor(pep); +} + +uint8_t BulkOnly::Release() +{ + pUsb->GetAddressPool().FreeAddress(bAddress); + + bIface = 0; + bNumEP = 1; + + bAddress = 0; + qNextPollTime = 0; + bPollEnable = false; + return 0; +} + +uint8_t BulkOnly::Poll() +{ + uint8_t rcode = 0; + + if (!bPollEnable) + return 0; + + uint32_t time_now = millis(); + + //if (qNextPollTime <= time_now) + //{ + // qNextPollTime = time_now + 100; + + // uint8_t rcode; + // const uint8_t constBufSize = 16; + // uint8_t buf[constBufSize]; + + // for (uint8_t i=0; i epInfo[epInterruptInIndex].maxPktSize) + // ? epInfo[epInterruptInIndex].maxPktSize : constBufSize; + // rcode = pUsb->inTransfer(bAddress, epInfo[epInterruptInIndex].epAddr, &read, buf); + + // if (rcode) + // return rcode; + + // for (uint8_t i=0; i(buf[i]); + // Serial.print(" "); + // } + // USBTRACE("\r\n"); + //} + return rcode; +} + +//uint8_t ACM::RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr) +//{ +// return pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, dataptr); +//} +// +//uint8_t ACM::SndData(uint16_t nbytes, uint8_t *dataptr) +//{ +// return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, nbytes, 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::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::ClearCommFeature(uint16_t fid) +//{ +// return( pUsb->ctrlReq( bAddress, 0, bmREQ_CDCOUT, CDC_CLEAR_COMM_FEATURE, (fid & 0xff), (fid >> 8), bControlIface, 0, 0, NULL, NULL )); +//} +// +//uint8_t ACM::SetLineCoding(const LINE_CODING *dataptr) +//{ +// return( pUsb->ctrlReq( bAddress, 0, bmREQ_CDCOUT, CDC_SET_LINE_CODING, 0x00, 0x00, bControlIface, sizeof(LINE_CODING), sizeof(LINE_CODING), (uint8_t*)dataptr, NULL )); +//} +// +//uint8_t ACM::GetLineCoding(LINE_CODING *dataptr) +//{ +// return( pUsb->ctrlReq( bAddress, 0, bmREQ_CDCIN, CDC_GET_LINE_CODING, 0x00, 0x00, bControlIface, sizeof(LINE_CODING), sizeof(LINE_CODING), (uint8_t*)dataptr, NULL )); +//} +// +//uint8_t ACM::SetControlLineState(uint8_t state) +//{ +// return( pUsb->ctrlReq( bAddress, 0, bmREQ_CDCOUT, CDC_SET_CONTROL_LINE_STATE, state, 0, bControlIface, 0, 0, NULL, NULL )); +//} +// +//uint8_t ACM::SendBreak(uint16_t duration) +//{ +// return( pUsb->ctrlReq( bAddress, 0, bmREQ_CDCOUT, CDC_SEND_BREAK, (duration & 0xff), (duration >> 8), bControlIface, 0, 0, NULL, NULL )); +//} + + +void BulkOnly::PrintEndpointDescriptor( const USB_ENDPOINT_DESCRIPTOR* ep_ptr ) +{ + Notify(PSTR("Endpoint descriptor:")); + Notify(PSTR("\r\nLength:\t\t")); + PrintHex(ep_ptr->bLength); + Notify(PSTR("\r\nType:\t\t")); + PrintHex(ep_ptr->bDescriptorType); + Notify(PSTR("\r\nAddress:\t")); + PrintHex(ep_ptr->bEndpointAddress); + Notify(PSTR("\r\nAttributes:\t")); + PrintHex(ep_ptr->bmAttributes); + Notify(PSTR("\r\nMaxPktSize:\t")); + PrintHex(ep_ptr->wMaxPacketSize); + Notify(PSTR("\r\nPoll Intrv:\t")); + PrintHex(ep_ptr->bInterval); + Notify(PSTR("\r\n")); +} diff --git a/masstorage.h b/masstorage.h index 2d667ad9..ac92e737 100644 --- a/masstorage.h +++ b/masstorage.h @@ -1,19 +1,3 @@ -/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. - -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 -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 -on this software must also be made publicly available under the terms of -the GPL2 ("Copyleft"). - -Contact information -------------------- - -Circuits At Home, LTD -Web : http://www.circuitsathome.com -e-mail : support@circuitsathome.com -*/ #if !defined(__MASSTORAGE_H__) #define __MASSTORAGE_H__ @@ -73,7 +57,7 @@ struct CommandBlockWrapper struct { uint8_t bCBWLUN : 4; - uint8_r bReserved1 : 4; + uint8_t bReserved1 : 4; }; struct { @@ -92,9 +76,31 @@ struct CommandStatusWrapper uint8_t bCSWStatus; }; +#define MASS_MAX_ENDPOINTS 3 + class BulkOnly : public USBDeviceConfig, public UsbConfigXtracter { +protected: + static const uint8_t epDataInIndex; // DataIn endpoint index + static const uint8_t epDataOutIndex; // DataOUT endpoint index + static const uint8_t epInterruptInIndex; // InterruptIN endpoint index + + USB *pUsb; +// CDCAsyncOper *pAsync; + uint8_t bAddress; + uint8_t bConfNum; // configuration number + uint8_t bIface; // interface value + uint8_t bNumEP; // total number of EP in the configuration + uint32_t qNextPollTime; // next poll time + bool bPollEnable; // poll enable flag + + EpInfo epInfo[MASS_MAX_ENDPOINTS]; + + void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr); + public: + BulkOnly(USB *p); + uint8_t Reset(); uint8_t GetMaxLun(uint8_t *max_lun); diff --git a/usbhub.cpp b/usbhub.cpp index 2ec1f754..4fe427be 100644 --- a/usbhub.cpp +++ b/usbhub.cpp @@ -47,9 +47,11 @@ uint8_t USBHub::Init(uint8_t parent, uint8_t port, bool lowspeed) EpInfo *oldep_ptr = NULL; uint8_t len = 0; uint16_t cd_len = 0; + + //USBTRACE("\r\nHub Init Start"); AddressPool &addrPool = pUsb->GetAddressPool(); - + switch (bInitState) { case 0: @@ -113,7 +115,9 @@ uint8_t USBHub::Init(uint8_t parent, uint8_t port, bool lowspeed) bAddress = 0; return rcode; } - + + //USBTRACE2("\r\nHub address: ", bAddress ); + // Restore p->epinfo p->epinfo = oldep_ptr;