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  pUsb(p), //pointer to USB class instance - mandatory
33  bAddress(0), //device address - mandatory
34  bNumEP(1), //if config descriptor needs to be parsed
35  ready(false),
36 
37  /* ADK ID Strings */
38 
39  manufacturer(manufacturer),
40  model(model),
41  description(description),
42  version(version),
43  uri(uri),
44  serial(serial)
45 
46 {
47  // initialize endpoint data structures
48  for(uint8_t i=0; i<ADK_MAX_ENDPOINTS; i++) {
49  epInfo[i].epAddr = 0;
50  epInfo[i].maxPktSize = (i) ? 0 : 8;
51  epInfo[i].epAttribs = 0;
53  }//for(uint8_t i=0; i<ADK_MAX_ENDPOINTS; i++...
54 
55  // register in USB subsystem
56  if (pUsb) {
57  pUsb->RegisterDeviceClass(this); //set devConfig[] entry
58  }
59 }
60 
61 /* Connection initialization of an Android phone */
62 uint8_t ADK::Init(uint8_t parent, uint8_t port, bool lowspeed)
63 {
64 
65  uint8_t buf[sizeof(USB_DEVICE_DESCRIPTOR)];
66  uint8_t rcode;
67  UsbDevice *p = NULL;
68  EpInfo *oldep_ptr = NULL;
69  uint8_t num_of_conf; // number of configurations
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 = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->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 
131  p->lowspeed = false;
132 
133  //get pointer to assigned address record
134  p = addrPool.GetUsbDevicePtr(bAddress);
135  if (!p) {
137  }
138 
139  p->lowspeed = lowspeed;
140 
141  // Assign epInfo to epinfo pointer - only EP0 is known
142  rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
143  if (rcode) {
144  goto FailSetDevTblEntry;
145  }
146 
147  //check if ADK device is already in accessory mode; if yes, configure and exit
148  if(((USB_DEVICE_DESCRIPTOR*)buf)->idVendor == ADK_VID &&
149  (((USB_DEVICE_DESCRIPTOR*)buf)->idProduct == ADK_PID || ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct == ADB_PID)) {
150  USBTRACE("\r\nAcc.mode device detected");
151  /* go through configurations, find first bulk-IN, bulk-OUT EP, fill epInfo and quit */
152  num_of_conf = ((USB_DEVICE_DESCRIPTOR*)buf)->bNumConfigurations;
153 
154  //USBTRACE2("\r\nNC:",num_of_conf);
155 
156  for (uint8_t i=0; i<num_of_conf; i++) {
157  ConfigDescParser<0, 0, 0, 0> confDescrParser(this);
158  delay(1);
159  rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
160 #if defined(XOOM)
161  //added by Jaylen Scott Vanorden
162  if( rcode ) {
163  USBTRACE2("\r\nGot 1st bad code for config: ", rcode);
164  // Try once more
165  rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
166  }
167 #endif
168  if( rcode ) {
169  goto FailGetConfDescr;
170  }
171  if( bNumEP > 2 ) {
172  break;
173  }
174  } // for (uint8_t i=0; i<num_of_conf; i++...
175 
176  if( bNumEP == 3 ) {
177  // Assign epInfo to epinfo pointer - this time all 3 endpoins
178  rcode = pUsb->setEpInfoEntry(bAddress, 3, epInfo);
179  if (rcode) {
180  goto FailSetDevTblEntry;
181  }
182  }
183 
184 
185 
186  // Set Configuration Value
187  rcode = pUsb->setConf(bAddress, 0, bConfNum);
188  if( rcode ){
189  goto FailSetConf;
190  }
191  /* print endpoint structure */
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  USBTRACE("\r\nConfiguration successful");
207  ready = true;
208  return 0; //successful configuration
209  }//if( buf->idVendor == ADK_VID...
210 
211  //probe device - get accessory protocol revision
212  {
213  uint16_t adkproto = -1;
214  delay(1);
215  rcode = getProto((uint8_t*)&adkproto );
216 #if defined(XOOM)
217  //added by Jaylen Scott Vanorden
218  if( rcode ) {
219  USBTRACE2("\r\nGot 1st bad code for proto: ", rcode);
220  // Try once more
221  rcode = getProto((uint8_t*)&adkproto );
222  }
223 #endif
224  if( rcode ){
225  goto FailGetProto; //init fails
226  }
227  USBTRACE2("\r\nADK protocol rev. ", adkproto );
228  }
229 
230  //sending ID strings
231  sendStr( ACCESSORY_STRING_MANUFACTURER, manufacturer);
232  sendStr( ACCESSORY_STRING_MODEL, model);
233  sendStr( ACCESSORY_STRING_DESCRIPTION, description);
234  sendStr( ACCESSORY_STRING_VERSION, version);
235  sendStr( ACCESSORY_STRING_URI, uri);
236  sendStr( ACCESSORY_STRING_SERIAL, serial);
237 
238  //switch to accessory mode
239  //the Android phone will reset
240  rcode = switchAcc();
241  if( rcode ) {
242  goto FailSwAcc; //init fails
243  }
244  rcode = -1;
245  goto SwAttempt; //switch to accessory mode attempted
246 
247  /* diagnostic messages */
248 FailGetDevDescr:
249  USBTRACE("\r\ngetDevDescr:");
250  goto Fail;
251 
252 FailSetDevTblEntry:
253  USBTRACE("\r\nsetDevTblEn:");
254  goto Fail;
255 
256 FailGetProto:
257  USBTRACE("\r\ngetProto:");
258  goto Fail;
259 
260 FailSwAcc:
261  USBTRACE("\r\nswAcc:");
262  goto Fail;
263 
264 SwAttempt:
265  USBTRACE("\r\nAccessory mode switch attempt");
266  goto Fail;
267 
268 FailGetConfDescr:
269 // USBTRACE("getConf:");
270  goto Fail;
271 //
272 FailSetConf:
273 // USBTRACE("setConf:");
274  goto Fail;
275 //
276 //FailOnInit:
277 // USBTRACE("OnInit:");
278 // goto Fail;
279 //
280 Fail:
281  //USBTRACE2("\r\nADK Init Failed, error code: ", 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 {
289  //ErrorMessage<uint8_t>(PSTR("Conf.Val"), conf);
290  //ErrorMessage<uint8_t>(PSTR("Iface Num"),iface);
291  //ErrorMessage<uint8_t>(PSTR("Alt.Set"), alt);
292 
293  //added by Yuuichi Akagawa
294  if( bNumEP == 3 ) {
295  return;
296  }
297 
298  bConfNum = conf;
299 
300  uint8_t index;
301 
302  if ((pep->bmAttributes & 0x02) == 2) {
303  index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex;
304  }
305 
306  // Fill in the endpoint info structure
307  epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
308  epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
309 
310  bNumEP ++;
311 
312  //PrintEndpointDescriptor(pep);
313 }
314 
315 /* Performs a cleanup after failed Init() attempt */
316 uint8_t ADK::Release()
317 {
319 
320  bNumEP = 1; //must have to be reset to 1
321 
322  bAddress = 0;
323  ready = false;
324  return 0;
325 }
326 
327 uint8_t ADK::RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr)
328 {
329  //USBTRACE2("\r\nAddr: ", bAddress );
330  //USBTRACE2("\r\nEP: ",epInfo[epDataInIndex].epAddr);
331  return pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, dataptr);
332 }
333 
334 uint8_t ADK::SndData(uint16_t nbytes, uint8_t *dataptr)
335 {
336  return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, nbytes, dataptr);
337 }
338 
340 {
341  Notify(PSTR("Endpoint descriptor:"));
342  Notify(PSTR("\r\nLength:\t\t"));
343  PrintHex<uint8_t>(ep_ptr->bLength);
344  Notify(PSTR("\r\nType:\t\t"));
345  PrintHex<uint8_t>(ep_ptr->bDescriptorType);
346  Notify(PSTR("\r\nAddress:\t"));
347  PrintHex<uint8_t>(ep_ptr->bEndpointAddress);
348  Notify(PSTR("\r\nAttributes:\t"));
349  PrintHex<uint8_t>(ep_ptr->bmAttributes);
350  Notify(PSTR("\r\nMaxPktSize:\t"));
351  PrintHex<uint16_t>(ep_ptr->wMaxPacketSize);
352  Notify(PSTR("\r\nPoll Intrv:\t"));
353  PrintHex<uint8_t>(ep_ptr->bInterval);
354  Notify(PSTR("\r\n"));
355 }