USB Host Shield 2.0
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
cdcacm.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 #include "cdcacm.h"
18 
19 const uint8_t ACM::epDataInIndex = 1;
20 const uint8_t ACM::epDataOutIndex = 2;
21 const uint8_t ACM::epInterruptInIndex = 3;
22 
23 ACM::ACM(USB *p, CDCAsyncOper *pasync) :
24 pUsb(p),
25 pAsync(pasync),
26 bAddress(0),
27 bControlIface(0),
28 bDataIface(0),
29 bNumEP(1),
30 qNextPollTime(0),
31 ready(false),
32 bPollEnable(false) {
33  for (uint8_t i = 0; i < ACM_MAX_ENDPOINTS; i++) {
34  epInfo[i].epAddr = 0;
35  epInfo[i].maxPktSize = (i) ? 0 : 8;
36  epInfo[i].epAttribs = 0;
37  //epInfo[i].bmNakPower = USB_NAK_NOWAIT;
39 
40  //if (!i)
42  }
43  if (pUsb)
45 }
46 
47 uint8_t ACM::Init(uint8_t parent, uint8_t port, bool lowspeed) {
48  const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR);
49 
50  uint8_t buf[constBufSize];
51  uint8_t rcode;
52  UsbDevice *p = NULL;
53  EpInfo *oldep_ptr = NULL;
54  uint8_t num_of_conf; // number of configurations
55 
56  AddressPool &addrPool = pUsb->GetAddressPool();
57 
58  USBTRACE("ACM Init\r\n");
59 
60  if (bAddress)
62 
63  // Get pointer to pseudo device with address 0 assigned
64  p = addrPool.GetUsbDevicePtr(0);
65 
66  if (!p)
68 
69  if (!p->epinfo) {
70  USBTRACE("epinfo\r\n");
72  }
73 
74  // Save old pointer to EP_RECORD of address 0
75  oldep_ptr = p->epinfo;
76 
77  // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
78  p->epinfo = epInfo;
79 
80  p->lowspeed = lowspeed;
81 
82  // Get device descriptor
83  rcode = pUsb->getDevDescr(0, 0, constBufSize, (uint8_t*)buf);
84 
85  // Restore p->epinfo
86  p->epinfo = oldep_ptr;
87 
88  if (rcode)
89  goto FailGetDevDescr;
90 
91  // Allocate new address according to device class
92  bAddress = addrPool.AllocAddress(parent, false, port);
93 
94  if (!bAddress)
96 
97  // Extract Max Packet Size from the device descriptor
98  epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0;
99 
100  // Assign new address to the device
101  rcode = pUsb->setAddr(0, 0, bAddress);
102 
103  if (rcode) {
104  p->lowspeed = false;
105  addrPool.FreeAddress(bAddress);
106  bAddress = 0;
107  USBTRACE2("setAddr:", rcode);
108  return rcode;
109  }
110 
111  USBTRACE2("Addr:", bAddress);
112 
113  p->lowspeed = false;
114 
115  p = addrPool.GetUsbDevicePtr(bAddress);
116 
117  if (!p)
119 
120  p->lowspeed = lowspeed;
121 
122  num_of_conf = ((USB_DEVICE_DESCRIPTOR*)buf)->bNumConfigurations;
123 
124  // Assign epInfo to epinfo pointer
125  rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
126 
127  if (rcode)
128  goto FailSetDevTblEntry;
129 
130  USBTRACE2("NC:", num_of_conf);
131 
132  for (uint8_t i = 0; i < num_of_conf; i++) {
138  CP_MASK_COMPARE_PROTOCOL > CdcControlParser(this);
139 
141  CP_MASK_COMPARE_CLASS> CdcDataParser(this);
142 
143  rcode = pUsb->getConfDescr(bAddress, 0, i, &CdcControlParser);
144 
145  if (rcode)
146  goto FailGetConfDescr;
147 
148  rcode = pUsb->getConfDescr(bAddress, 0, i, &CdcDataParser);
149 
150  if (rcode)
151  goto FailGetConfDescr;
152 
153  if (bNumEP > 1)
154  break;
155  } // for
156 
157  if (bNumEP < 4)
159 
160  // Assign epInfo to epinfo pointer
162 
163  USBTRACE2("Conf:", bConfNum);
164 
165  // Set Configuration Value
166  rcode = pUsb->setConf(bAddress, 0, bConfNum);
167 
168  if (rcode)
169  goto FailSetConfDescr;
170 
171  rcode = pAsync->OnInit(this);
172 
173  if (rcode)
174  goto FailOnInit;
175 
176  USBTRACE("ACM configured\r\n");
177 
178  ready = true;
179 
180  //bPollEnable = true;
181 
182  //USBTRACE("Poll enabled\r\n");
183  return 0;
184 
185 FailGetDevDescr:
186 #ifdef DEBUG_USB_HOST
188  goto Fail;
189 #endif
190 
191 FailSetDevTblEntry:
192 #ifdef DEBUG_USB_HOST
194  goto Fail;
195 #endif
196 
197 FailGetConfDescr:
198 #ifdef DEBUG_USB_HOST
200  goto Fail;
201 #endif
202 
203 FailSetConfDescr:
204 #ifdef DEBUG_USB_HOST
206  goto Fail;
207 #endif
208 
209 FailOnInit:
210 #ifdef DEBUG_USB_HOST
211  USBTRACE("OnInit:");
212 #endif
213 
214 Fail:
215 #ifdef DEBUG_USB_HOST
216  NotifyFail(rcode);
217 #endif
218  Release();
219  return rcode;
220 }
221 
222 void ACM::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) {
223  ErrorMessage<uint8_t > (PSTR("Conf.Val"), conf);
224  ErrorMessage<uint8_t > (PSTR("Iface Num"), iface);
225  ErrorMessage<uint8_t > (PSTR("Alt.Set"), alt);
226 
227  bConfNum = conf;
228 
229  uint8_t index;
230 
231  if ((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80)
232  index = epInterruptInIndex;
233  else
234  if ((pep->bmAttributes & 0x02) == 2)
235  index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex;
236  else
237  return;
238 
239  // Fill in the endpoint info structure
240  epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
241  epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
242  epInfo[index].epAttribs = 0;
243 
244  bNumEP++;
245 
247 }
248 
249 uint8_t ACM::Release() {
251 
252  bControlIface = 0;
253  bDataIface = 0;
254  bNumEP = 1;
255 
256  bAddress = 0;
257  qNextPollTime = 0;
258  bPollEnable = false;
259  return 0;
260 }
261 
262 uint8_t ACM::Poll() {
263  uint8_t rcode = 0;
264 
265  if (!bPollEnable)
266  return 0;
267 
268  //uint32_t time_now = millis();
269 
270  //if (qNextPollTime <= time_now)
271  //{
272  // qNextPollTime = time_now + 100;
273 
274  // uint8_t rcode;
275  // const uint8_t constBufSize = 16;
276  // uint8_t buf[constBufSize];
277 
278  // for (uint8_t i=0; i<constBufSize; i++)
279  // buf[i] = 0;
280 
281  // uint16_t read = (constBufSize > epInfo[epInterruptInIndex].maxPktSize)
282  // ? epInfo[epInterruptInIndex].maxPktSize : constBufSize;
283  // rcode = pUsb->inTransfer(bAddress, epInfo[epInterruptInIndex].epAddr, &read, buf);
284 
285  // if (rcode)
286  // return rcode;
287 
288  // for (uint8_t i=0; i<read; i++)
289  // {
290  // PrintHex<uint8_t>(buf[i]);
291  // USB_HOST_SERIAL.print(" ");
292  // }
293  // USBTRACE("\r\n");
294  //}
295  return rcode;
296 }
297 
298 uint8_t ACM::RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr) {
299  return pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, dataptr);
300 }
301 
302 uint8_t ACM::SndData(uint16_t nbytes, uint8_t *dataptr) {
303  return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, nbytes, dataptr);
304 }
305 
306 uint8_t ACM::SetCommFeature(uint16_t fid, uint8_t nbytes, uint8_t *dataptr) {
307  return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCOUT, CDC_SET_COMM_FEATURE, (fid & 0xff), (fid >> 8), bControlIface, nbytes, nbytes, dataptr, NULL));
308 }
309 
310 uint8_t ACM::GetCommFeature(uint16_t fid, uint8_t nbytes, uint8_t *dataptr) {
311  return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCIN, CDC_GET_COMM_FEATURE, (fid & 0xff), (fid >> 8), bControlIface, nbytes, nbytes, dataptr, NULL));
312 }
313 
314 uint8_t ACM::ClearCommFeature(uint16_t fid) {
315  return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCOUT, CDC_CLEAR_COMM_FEATURE, (fid & 0xff), (fid >> 8), bControlIface, 0, 0, NULL, NULL));
316 }
317 
318 uint8_t ACM::SetLineCoding(const LINE_CODING *dataptr) {
319  return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCOUT, CDC_SET_LINE_CODING, 0x00, 0x00, bControlIface, sizeof (LINE_CODING), sizeof (LINE_CODING), (uint8_t*)dataptr, NULL));
320 }
321 
322 uint8_t ACM::GetLineCoding(LINE_CODING *dataptr) {
323  return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCIN, CDC_GET_LINE_CODING, 0x00, 0x00, bControlIface, sizeof (LINE_CODING), sizeof (LINE_CODING), (uint8_t*)dataptr, NULL));
324 }
325 
326 uint8_t ACM::SetControlLineState(uint8_t state) {
327  return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCOUT, CDC_SET_CONTROL_LINE_STATE, state, 0, bControlIface, 0, 0, NULL, NULL));
328 }
329 
330 uint8_t ACM::SendBreak(uint16_t duration) {
331  return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCOUT, CDC_SEND_BREAK, (duration & 0xff), (duration >> 8), bControlIface, 0, 0, NULL, NULL));
332 }
333 
335  Notify(PSTR("Endpoint descriptor:"), 0x80);
336  Notify(PSTR("\r\nLength:\t\t"), 0x80);
337  D_PrintHex<uint8_t > (ep_ptr->bLength, 0x80);
338  Notify(PSTR("\r\nType:\t\t"), 0x80);
339  D_PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80);
340  Notify(PSTR("\r\nAddress:\t"), 0x80);
341  D_PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80);
342  Notify(PSTR("\r\nAttributes:\t"), 0x80);
343  D_PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80);
344  Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
345  D_PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80);
346  Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
347  D_PrintHex<uint8_t > (ep_ptr->bInterval, 0x80);
348  Notify(PSTR("\r\n"), 0x80);
349 }