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