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 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  uint8_t rcode;
66  uint8_t num_of_conf; // number of configurations
67  UsbDevice *p = NULL;
68  EpInfo *oldep_ptr = NULL;
69 
70  // get memory address of USB device address pool
71  AddressPool &addrPool = pUsb->GetAddressPool();
72 
73  USBTRACE("\r\nADK Init");
74 
75  // check if address has already been assigned to an instance
76  if (bAddress) {
77  USBTRACE("\r\nAddress in use");
79  }
80 
81  // Get pointer to pseudo device with address 0 assigned
82  p = addrPool.GetUsbDevicePtr(0);
83 
84  if (!p) {
85  USBTRACE("\r\nAddress not found");
87  }
88 
89  if (!p->epinfo) {
90  USBTRACE("epinfo is null\r\n");
92  }
93 
94  // Save old pointer to EP_RECORD of address 0
95  oldep_ptr = p->epinfo;
96 
97  // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
98  p->epinfo = epInfo;
99 
100  p->lowspeed = lowspeed;
101 
102  // Get device descriptor
103  rcode = pUsb->getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), (uint8_t*)buf);
104 
105  // Restore p->epinfo
106  p->epinfo = oldep_ptr;
107 
108  if (rcode) {
109  goto FailGetDevDescr;
110  }
111 
112  // Allocate new address according to device class
113  bAddress = addrPool.AllocAddress(parent, false, port);
114 
115  // Extract Max Packet Size from device descriptor
116  epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0;
117 
118  // Assign new address to the device
119  rcode = pUsb->setAddr(0, 0, bAddress);
120  if (rcode) {
121  p->lowspeed = false;
122  addrPool.FreeAddress(bAddress);
123  bAddress = 0;
124  //USBTRACE2("setAddr:",rcode);
125  return rcode;
126  }//if (rcode...
127 
128  //USBTRACE2("\r\nAddr:", bAddress);
129  // Spec says you should wait at least 200ms.
130  delay(300);
131 
132  p->lowspeed = false;
133 
134  //get pointer to assigned address record
135  p = addrPool.GetUsbDevicePtr(bAddress);
136  if (!p) {
138  }
139 
140  p->lowspeed = lowspeed;
141 
142  // Assign epInfo to epinfo pointer - only EP0 is known
143  rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
144  if (rcode) {
145  goto FailSetDevTblEntry;
146  }
147 
148  //check if ADK device is already in accessory mode; if yes, configure and exit
149  if (((USB_DEVICE_DESCRIPTOR*)buf)->idVendor == ADK_VID &&
150  (((USB_DEVICE_DESCRIPTOR*)buf)->idProduct == ADK_PID || ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct == ADB_PID)) {
151  USBTRACE("\r\nAcc.mode device detected");
152  /* go through configurations, find first bulk-IN, bulk-OUT EP, fill epInfo and quit */
153  num_of_conf = ((USB_DEVICE_DESCRIPTOR*)buf)->bNumConfigurations;
154 
155  //USBTRACE2("\r\nNC:",num_of_conf);
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  // Set Configuration Value
185  rcode = pUsb->setConf(bAddress, 0, bConfNum);
186  if (rcode) {
187  goto FailSetConfDescr;
188  }
189  /* print endpoint structure */
190  /*
191  USBTRACE("\r\nEndpoint Structure:");
192  USBTRACE("\r\nEP0:");
193  USBTRACE2("\r\nAddr: ", epInfo[0].epAddr);
194  USBTRACE2("\r\nMax.pkt.size: ", epInfo[0].maxPktSize);
195  USBTRACE2("\r\nAttr: ", epInfo[0].epAttribs);
196  USBTRACE("\r\nEpout:");
197  USBTRACE2("\r\nAddr: ", epInfo[epDataOutIndex].epAddr);
198  USBTRACE2("\r\nMax.pkt.size: ", epInfo[epDataOutIndex].maxPktSize);
199  USBTRACE2("\r\nAttr: ", epInfo[epDataOutIndex].epAttribs);
200  USBTRACE("\r\nEpin:");
201  USBTRACE2("\r\nAddr: ", epInfo[epDataInIndex].epAddr);
202  USBTRACE2("\r\nMax.pkt.size: ", epInfo[epDataInIndex].maxPktSize);
203  USBTRACE2("\r\nAttr: ", epInfo[epDataInIndex].epAttribs);
204  */
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  }
245  delay(1000); // Give Android a chance to do its reset. This is a guess, and possibly could be lower.
246  goto SwAttempt; //switch to accessory mode attempted
247 
248  /* diagnostic messages */
249 FailGetDevDescr:
250 #ifdef DEBUG_USB_HOST
251  NotifyFailGetDevDescr(rcode);
252  goto Fail;
253 #endif
254 
255 FailSetDevTblEntry:
256 #ifdef DEBUG_USB_HOST
258  goto Fail;
259 #endif
260 
261 FailGetConfDescr:
262 #ifdef DEBUG_USB_HOST
263  NotifyFailGetConfDescr(rcode);
264  goto Fail;
265 #endif
266 
267 FailSetConfDescr:
268 #ifdef DEBUG_USB_HOST
269  NotifyFailSetConfDescr(rcode);
270  goto Fail;
271 #endif
272 
273 FailGetProto:
274 #ifdef DEBUG_USB_HOST
275  USBTRACE("\r\ngetProto:");
276  goto Fail;
277 #endif
278 
279 FailSwAcc:
280 #ifdef DEBUG_USB_HOST
281  USBTRACE("\r\nswAcc:");
282  goto Fail;
283 #endif
284 
285 SwAttempt:
286 #ifdef DEBUG_USB_HOST
287  USBTRACE("\r\nAccessory mode switch attempt");
288 #endif
289 //FailOnInit:
290 // USBTRACE("OnInit:");
291 // goto Fail;
292 Fail:
293  //USBTRACE2("\r\nADK Init Failed, error code: ", rcode);
294  //NotifyFail(rcode);
295  Release();
296  return rcode;
297 }
298 
299 /* Extracts bulk-IN and bulk-OUT endpoint information from config descriptor */
300 void ADK::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) {
301  //ErrorMessage<uint8_t>(PSTR("Conf.Val"), conf);
302  //ErrorMessage<uint8_t>(PSTR("Iface Num"), iface);
303  //ErrorMessage<uint8_t>(PSTR("Alt.Set"), alt);
304 
305  //added by Yuuichi Akagawa
306  if (bNumEP == 3) {
307  return;
308  }
309 
310  bConfNum = conf;
311 
312  if ((pep->bmAttributes & 0x02) == 2) {
313  uint8_t index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex;
314  // Fill in the endpoint info structure
315  epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
316  epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
317 
318  bNumEP++;
319 
320  //PrintEndpointDescriptor(pep);
321  }
322 }
323 
324 /* Performs a cleanup after failed Init() attempt */
325 uint8_t ADK::Release() {
327 
328  bNumEP = 1; //must have to be reset to 1
329 
330  bAddress = 0;
331  ready = false;
332  return 0;
333 }
334 
335 uint8_t ADK::RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr) {
336  //USBTRACE2("\r\nAddr: ", bAddress );
337  //USBTRACE2("\r\nEP: ",epInfo[epDataInIndex].epAddr);
338  return pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, dataptr);
339 }
340 
341 uint8_t ADK::SndData(uint16_t nbytes, uint8_t *dataptr) {
342  return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, nbytes, dataptr);
343 }
344 
346  Notify(PSTR("Endpoint descriptor:"), 0x80);
347  Notify(PSTR("\r\nLength:\t\t"), 0x80);
348  PrintHex<uint8_t > (ep_ptr->bLength, 0x80);
349  Notify(PSTR("\r\nType:\t\t"), 0x80);
350  PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80);
351  Notify(PSTR("\r\nAddress:\t"), 0x80);
352  PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80);
353  Notify(PSTR("\r\nAttributes:\t"), 0x80);
354  PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80);
355  Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
356  PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80);
357  Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
358  PrintHex<uint8_t > (ep_ptr->bInterval, 0x80);
359  Notify(PSTR("\r\n"), 0x80);
360 }
uint8_t getConfDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t *dataptr)
Definition: Usb.cpp:764
#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:335
EpInfo * epinfo
Definition: address.h:76
bool lowspeed
Definition: address.h:79
#define USB_ERROR_EPINFO_IS_NULL
Definition: UsbCore.h:67
uint8_t bmNakPower
Definition: address.h:42
virtual uint8_t Release()
Definition: adk.cpp:325
uint8_t SndData(uint16_t nbytes, uint8_t *dataptr)
Definition: adk.cpp:341
#define ACCESSORY_STRING_URI
Definition: adk.h:46
#define ACCESSORY_STRING_MANUFACTURER
Definition: adk.h:42
virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep)
Definition: adk.cpp:300
USB * pUsb
Definition: adk.h:73
uint8_t setConf(uint8_t addr, uint8_t ep, uint8_t conf_value)
Definition: Usb.cpp:798
virtual 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:61
uint8_t setAddr(uint8_t oldaddr, uint8_t ep, uint8_t newaddr)
Definition: Usb.cpp:793
#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:290
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:69
#define ADK_MAX_ENDPOINTS
Definition: adk.h:49
void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR *ep_ptr)
Definition: adk.cpp:345
#define USB_NAK_NOWAIT
Definition: address.h:29
#define USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL
Definition: UsbCore.h:66
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:168
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed)
Definition: adk.cpp:63
Definition: UsbCore.h:152
#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:172
#define NotifyFailSetConfDescr(...)
Definition: message.h:53
uint8_t bConfNum
Definition: adk.h:75
#define USBTRACE(s)
Definition: macros.h:60
uint8_t getDevDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t *dataptr)
defined(USB_METHODS_INLINE)
Definition: Usb.cpp:759
#define NotifyFailSetDevTblEntry(...)
Definition: message.h:51
uint8_t bAddress
Definition: adk.h:74
#define USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET
Definition: UsbCore.h:72