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