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