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