USB Host Shield 2.0
adk.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
2 
3 This software may be distributed and modified under the terms of the GNU
4 General Public License version 2 (GPL2) as published by the Free Software
5 Foundation and appearing in the file GPL2.TXT included in the packaging of
6 this file. Please note that GPL2 Section 2[b] requires that all works based
7 on this software must also be made publicly available under the terms of
8 the GPL2 ("Copyleft").
9 
10 Contact information
11 -------------------
12 
13 Circuits At Home, LTD
14 Web : http://www.circuitsathome.com
15 e-mail : support@circuitsathome.com
16  */
17 
18 /* Google ADK interface */
19 
20 #include "adk.h"
21 
22 const uint8_t ADK::epDataInIndex = 1;
23 const uint8_t ADK::epDataOutIndex = 2;
24 
25 ADK::ADK(USB *p, const char* manufacturer,
26  const char* model,
27  const char* description,
28  const char* version,
29  const char* uri,
30  const char* serial) :
31 
32 /* ADK ID Strings */
33 manufacturer(manufacturer),
34 model(model),
35 description(description),
36 version(version),
37 uri(uri),
38 serial(serial),
39 pUsb(p), //pointer to USB class instance - mandatory
40 bAddress(0), //device address - mandatory
41 bConfNum(0), //configuration number
42 bNumEP(1), //if config descriptor needs to be parsed
43 ready(false) {
44  // initialize endpoint data structures
45  for(uint8_t i = 0; i < ADK_MAX_ENDPOINTS; i++) {
46  epInfo[i].epAddr = 0;
47  epInfo[i].maxPktSize = (i) ? 0 : 8;
48  epInfo[i].bmSndToggle = 0;
49  epInfo[i].bmRcvToggle = 0;
51  }//for(uint8_t i=0; i<ADK_MAX_ENDPOINTS; i++...
52 
53  // register in USB subsystem
54  if(pUsb) {
55  pUsb->RegisterDeviceClass(this); //set devConfig[] entry
56  }
57 }
58 
59 uint8_t ADK::ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed) {
60  return Init(parent, port, lowspeed); // Just call Init. Yes, really!
61 }
62 
63 /* Connection initialization of an Android phone */
64 uint8_t ADK::Init(uint8_t parent, uint8_t port, bool lowspeed) {
65  uint8_t buf[sizeof (USB_DEVICE_DESCRIPTOR)];
66  USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf);
67  uint8_t rcode;
68  uint8_t num_of_conf; // number of configurations
69  UsbDevice *p = NULL;
70  EpInfo *oldep_ptr = NULL;
71 
72  // get memory address of USB device address pool
73  AddressPool &addrPool = pUsb->GetAddressPool();
74 
75  USBTRACE("\r\nADK Init");
76 
77  // check if address has already been assigned to an instance
78  if(bAddress) {
79  USBTRACE("\r\nAddress in use");
81  }
82 
83  // Get pointer to pseudo device with address 0 assigned
84  p = addrPool.GetUsbDevicePtr(0);
85 
86  if(!p) {
87  USBTRACE("\r\nAddress not found");
89  }
90 
91  if(!p->epinfo) {
92  USBTRACE("epinfo is null\r\n");
94  }
95 
96  // Save old pointer to EP_RECORD of address 0
97  oldep_ptr = p->epinfo;
98 
99  // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
100  p->epinfo = epInfo;
101 
102  p->lowspeed = lowspeed;
103 
104  // Get device descriptor
105  rcode = pUsb->getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), (uint8_t*)buf);
106 
107  // Restore p->epinfo
108  p->epinfo = oldep_ptr;
109 
110  if(rcode) {
111  goto FailGetDevDescr;
112  }
113 
114  // Allocate new address according to device class
115  bAddress = addrPool.AllocAddress(parent, false, port);
116 
117  // Extract Max Packet Size from device descriptor
118  epInfo[0].maxPktSize = udd->bMaxPacketSize0;
119 
120  // Assign new address to the device
121  rcode = pUsb->setAddr(0, 0, bAddress);
122  if(rcode) {
123  p->lowspeed = false;
124  addrPool.FreeAddress(bAddress);
125  bAddress = 0;
126  //USBTRACE2("setAddr:",rcode);
127  return rcode;
128  }//if (rcode...
129 
130  //USBTRACE2("\r\nAddr:", bAddress);
131  // Spec says you should wait at least 200ms.
132  //delay(300);
133 
134  p->lowspeed = false;
135 
136  //get pointer to assigned address record
137  p = addrPool.GetUsbDevicePtr(bAddress);
138  if(!p) {
140  }
141 
142  p->lowspeed = lowspeed;
143 
144  // Assign epInfo to epinfo pointer - only EP0 is known
145  rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
146  if(rcode) {
147  goto FailSetDevTblEntry;
148  }
149 
150  //check if ADK device is already in accessory mode; if yes, configure and exit
151  if(udd->idVendor == ADK_VID &&
152  (udd->idProduct == ADK_PID || udd->idProduct == ADB_PID)) {
153  USBTRACE("\r\nAcc.mode device detected");
154  /* go through configurations, find first bulk-IN, bulk-OUT EP, fill epInfo and quit */
155  num_of_conf = udd->bNumConfigurations;
156 
157  //USBTRACE2("\r\nNC:",num_of_conf);
158  for(uint8_t i = 0; i < num_of_conf; i++) {
159  ConfigDescParser < 0, 0, 0, 0 > confDescrParser(this);
160  delay(1);
161  rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
162 #if defined(XOOM)
163  //added by Jaylen Scott Vanorden
164  if(rcode) {
165  USBTRACE2("\r\nGot 1st bad code for config: ", rcode);
166  // Try once more
167  rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
168  }
169 #endif
170  if(rcode) {
171  goto FailGetConfDescr;
172  }
173  if(bNumEP > 2) {
174  break;
175  }
176  } // for (uint8_t i=0; i<num_of_conf; i++...
177 
178  if(bNumEP == 3) {
179  // Assign epInfo to epinfo pointer - this time all 3 endpoins
180  rcode = pUsb->setEpInfoEntry(bAddress, 3, epInfo);
181  if(rcode) {
182  goto FailSetDevTblEntry;
183  }
184  }
185 
186  // Set Configuration Value
187  rcode = pUsb->setConf(bAddress, 0, bConfNum);
188  if(rcode) {
189  goto FailSetConfDescr;
190  }
191  /* print endpoint structure */
192  /*
193  USBTRACE("\r\nEndpoint Structure:");
194  USBTRACE("\r\nEP0:");
195  USBTRACE2("\r\nAddr: ", epInfo[0].epAddr);
196  USBTRACE2("\r\nMax.pkt.size: ", epInfo[0].maxPktSize);
197  USBTRACE2("\r\nAttr: ", epInfo[0].epAttribs);
198  USBTRACE("\r\nEpout:");
199  USBTRACE2("\r\nAddr: ", epInfo[epDataOutIndex].epAddr);
200  USBTRACE2("\r\nMax.pkt.size: ", epInfo[epDataOutIndex].maxPktSize);
201  USBTRACE2("\r\nAttr: ", epInfo[epDataOutIndex].epAttribs);
202  USBTRACE("\r\nEpin:");
203  USBTRACE2("\r\nAddr: ", epInfo[epDataInIndex].epAddr);
204  USBTRACE2("\r\nMax.pkt.size: ", epInfo[epDataInIndex].maxPktSize);
205  USBTRACE2("\r\nAttr: ", epInfo[epDataInIndex].epAttribs);
206  */
207 
208  USBTRACE("\r\nConfiguration successful");
209  ready = true;
210  return 0; //successful configuration
211  }//if( buf->idVendor == ADK_VID...
212 
213  //probe device - get accessory protocol revision
214  {
215  uint16_t adkproto = -1;
216  delay(1);
217  rcode = getProto((uint8_t*) & adkproto);
218 #if defined(XOOM)
219  //added by Jaylen Scott Vanorden
220  if(rcode) {
221  USBTRACE2("\r\nGot 1st bad code for proto: ", rcode);
222  // Try once more
223  rcode = getProto((uint8_t*) & adkproto);
224  }
225 #endif
226  if(rcode) {
227  goto FailGetProto; //init fails
228  }
229  USBTRACE2("\r\nADK protocol rev. ", adkproto);
230  }
231 
232  delay(100);
233 
234  //sending ID strings
235  sendStr(ACCESSORY_STRING_MANUFACTURER, manufacturer);
236  delay(10);
237  sendStr(ACCESSORY_STRING_MODEL, model);
238  delay(10);
239  sendStr(ACCESSORY_STRING_DESCRIPTION, description);
240  delay(10);
241  sendStr(ACCESSORY_STRING_VERSION, version);
242  delay(10);
243  sendStr(ACCESSORY_STRING_URI, uri);
244  delay(10);
245  sendStr(ACCESSORY_STRING_SERIAL, serial);
246 
247  delay(100);
248 
249  //switch to accessory mode
250  //the Android phone will reset
251  rcode = switchAcc();
252  if(rcode) {
253  goto FailSwAcc; //init fails
254  }
256  delay(100); // Give Android a chance to do its reset. This is a guess, and possibly could be lower.
257  goto SwAttempt; //switch to accessory mode attempted
258 
259  /* diagnostic messages */
260 FailGetDevDescr:
261 #ifdef DEBUG_USB_HOST
262  NotifyFailGetDevDescr(rcode);
263  goto Fail;
264 #endif
265 
266 FailSetDevTblEntry:
267 #ifdef DEBUG_USB_HOST
269  goto Fail;
270 #endif
271 
272 FailGetConfDescr:
273 #ifdef DEBUG_USB_HOST
274  NotifyFailGetConfDescr(rcode);
275  goto Fail;
276 #endif
277 
278 FailSetConfDescr:
279 #ifdef DEBUG_USB_HOST
280  NotifyFailSetConfDescr(rcode);
281  goto Fail;
282 #endif
283 
284 FailGetProto:
285 #ifdef DEBUG_USB_HOST
286  USBTRACE("\r\ngetProto:");
287  goto Fail;
288 #endif
289 
290 FailSwAcc:
291 #ifdef DEBUG_USB_HOST
292  USBTRACE("\r\nswAcc:");
293  goto Fail;
294 #endif
295 
296  //FailOnInit:
297  // USBTRACE("OnInit:");
298  // goto Fail;
299  //
300 SwAttempt:
301 #ifdef DEBUG_USB_HOST
302  USBTRACE("\r\nAccessory mode switch attempt");
303 Fail:
304 #endif
305  //USBTRACE2("\r\nADK Init Failed, error code: ", rcode);
306  //NotifyFail(rcode);
307  Release();
308  return rcode;
309 }
310 
311 /* Extracts bulk-IN and bulk-OUT endpoint information from config descriptor */
312 void ADK::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) {
313  //ErrorMessage<uint8_t>(PSTR("Conf.Val"), conf);
314  //ErrorMessage<uint8_t>(PSTR("Iface Num"), iface);
315  //ErrorMessage<uint8_t>(PSTR("Alt.Set"), alt);
316 
317  //added by Yuuichi Akagawa
318  if(bNumEP == 3) {
319  return;
320  }
321 
322  bConfNum = conf;
323 
324  if((pep->bmAttributes & 0x02) == 2) {
325  uint8_t index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex;
326  // Fill in the endpoint info structure
327  epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
328  epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
329 
330  bNumEP++;
331 
332  //PrintEndpointDescriptor(pep);
333  }
334 }
335 
336 /* Performs a cleanup after failed Init() attempt */
337 uint8_t ADK::Release() {
339 
340  bNumEP = 1; //must have to be reset to 1
341 
342  bAddress = 0;
343  ready = false;
344  return 0;
345 }
346 
347 uint8_t ADK::RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr) {
348  //USBTRACE2("\r\nAddr: ", bAddress );
349  //USBTRACE2("\r\nEP: ",epInfo[epDataInIndex].epAddr);
350  return pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, dataptr);
351 }
352 
353 uint8_t ADK::SndData(uint16_t nbytes, uint8_t *dataptr) {
354  return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, nbytes, dataptr);
355 }
356 
358  Notify(PSTR("Endpoint descriptor:"), 0x80);
359  Notify(PSTR("\r\nLength:\t\t"), 0x80);
360  D_PrintHex<uint8_t > (ep_ptr->bLength, 0x80);
361  Notify(PSTR("\r\nType:\t\t"), 0x80);
362  D_PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80);
363  Notify(PSTR("\r\nAddress:\t"), 0x80);
364  D_PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80);
365  Notify(PSTR("\r\nAttributes:\t"), 0x80);
366  D_PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80);
367  Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
368  D_PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80);
369  Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
370  D_PrintHex<uint8_t > (ep_ptr->bInterval, 0x80);
371  Notify(PSTR("\r\n"), 0x80);
372 }
uint8_t getConfDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t *dataptr)
Definition: Usb.cpp:771
uint8_t bmRcvToggle
Definition: address.h:41
#define ADB_PID
Definition: adk.h:27
#define ACCESSORY_STRING_MODEL
Definition: adk.h:43
static const uint8_t epDataInIndex
Definition: adk.h:69
uint8_t RcvData(uint16_t *nbytesptr, uint8_t *dataptr)
Definition: adk.cpp:347
EpInfo * epinfo
Definition: address.h:76
bool lowspeed
Definition: address.h:79
#define USB_ERROR_EPINFO_IS_NULL
Definition: UsbCore.h:83
uint8_t bmNakPower
Definition: address.h:42
uint8_t Release()
Definition: adk.cpp:337
uint8_t SndData(uint16_t nbytes, uint8_t *dataptr)
Definition: adk.cpp:353
#define ACCESSORY_STRING_URI
Definition: adk.h:46
#define ACCESSORY_STRING_MANUFACTURER
Definition: adk.h:42
void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep)
Definition: adk.cpp:312
USB * pUsb
Definition: adk.h:73
uint8_t setConf(uint8_t addr, uint8_t ep, uint8_t conf_value)
Definition: Usb.cpp:810
uint8_t ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed)
Definition: adk.cpp:59
#define NotifyFailGetDevDescr(...)
Definition: message.h:50
static const uint8_t epDataOutIndex
Definition: adk.h:70
uint8_t setEpInfoEntry(uint8_t addr, uint8_t epcount, EpInfo *eprecord_ptr)
Definition: Usb.cpp:64
#define ADK_PID
Definition: adk.h:26
virtual void FreeAddress(uint8_t addr)=0
virtual UsbDevice * GetUsbDevicePtr(uint8_t addr)=0
#define Notify(...)
Definition: message.h:44
#define USBTRACE2(s, r)
Definition: macros.h:77
uint8_t setAddr(uint8_t oldaddr, uint8_t ep, uint8_t newaddr)
Definition: Usb.cpp:801
#define NotifyFailGetConfDescr(...)
Definition: message.h:52
uint8_t epAddr
Definition: address.h:33
#define USB_NAK_MAX_POWER
Definition: address.h:27
bool ready
Definition: adk.h:78
#define ACCESSORY_STRING_SERIAL
Definition: adk.h:47
Definition: address.h:32
uint8_t outTransfer(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t *data)
Definition: Usb.cpp:293
uint16_t wMaxPacketSize
Definition: usb_ch9.h:146
#define ACCESSORY_STRING_VERSION
Definition: adk.h:45
ADK(USB *pUsb, const char *manufacturer, const char *model, const char *description, const char *version, const char *uri, const char *serial)
Definition: adk.cpp:25
EpInfo epInfo[ADK_MAX_ENDPOINTS]
Definition: adk.h:81
virtual uint8_t AllocAddress(uint8_t parent, bool is_hub=false, uint8_t port=0)=0
uint8_t bEndpointAddress
Definition: usb_ch9.h:144
uint8_t bmSndToggle
Definition: address.h:40
#define USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE
Definition: UsbCore.h:85
#define PSTR(str)
#define ADK_MAX_ENDPOINTS
Definition: adk.h:49
void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR *ep_ptr)
Definition: adk.cpp:357
#define USB_NAK_NOWAIT
Definition: address.h:29
#define USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL
Definition: UsbCore.h:82
uint8_t inTransfer(uint8_t addr, uint8_t ep, uint16_t *nbytesptr, uint8_t *data, uint8_t bInterval=0)
Definition: Usb.cpp:206
uint8_t maxPktSize
Definition: address.h:34
AddressPool & GetAddressPool()
Definition: UsbCore.h:213
uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed)
Definition: adk.cpp:64
Definition: UsbCore.h:197
#define ACCESSORY_STRING_DESCRIPTION
Definition: adk.h:44
uint8_t bNumEP
Definition: adk.h:77
#define ADK_VID
Definition: adk.h:25
uint8_t RegisterDeviceClass(USBDeviceConfig *pdev)
Definition: UsbCore.h:217
#define NotifyFailSetConfDescr(...)
Definition: message.h:53
uint8_t bConfNum
Definition: adk.h:75
#define USBTRACE(s)
Definition: macros.h:75
uint8_t getDevDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t *dataptr)
defined(USB_METHODS_INLINE)
Definition: Usb.cpp:766
#define NotifyFailSetDevTblEntry(...)
Definition: message.h:51
uint8_t bAddress
Definition: adk.h:74
#define USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET
Definition: UsbCore.h:88