USB Host Shield 2.0
cdcftdi.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 "cdcftdi.h"
18 
19 const uint8_t FTDI::epDataInIndex = 1;
20 const uint8_t FTDI::epDataOutIndex = 2;
21 const uint8_t FTDI::epInterruptInIndex = 3;
22 
23 FTDI::FTDI(USB *p, FTDIAsyncOper *pasync, uint16_t idProduct) :
24 pAsync(pasync),
25 pUsb(p),
26 bAddress(0),
27 bNumEP(1),
28 wFTDIType(0),
29 wIdProduct(idProduct) {
30  for(uint8_t i = 0; i < FTDI_MAX_ENDPOINTS; i++) {
31  epInfo[i].epAddr = 0;
32  epInfo[i].maxPktSize = (i) ? 0 : 8;
33  epInfo[i].bmSndToggle = 0;
34  epInfo[i].bmRcvToggle = 0;
35  epInfo[i].bmNakPower = (i==epDataInIndex) ? USB_NAK_NOWAIT: USB_NAK_MAX_POWER;
36  }
37  if(pUsb)
38  pUsb->RegisterDeviceClass(this);
39 }
40 
41 uint8_t FTDI::Init(uint8_t parent, uint8_t port, bool lowspeed) {
42  const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR);
43 
44  uint8_t buf[constBufSize];
45  USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf);
46  uint8_t rcode;
47  UsbDevice *p = NULL;
48  EpInfo *oldep_ptr = NULL;
49 
50  uint8_t num_of_conf; // number of configurations
51 
52  AddressPool &addrPool = pUsb->GetAddressPool();
53 
54  USBTRACE("FTDI Init\r\n");
55 
56  if(bAddress) {
57  USBTRACE("FTDI CLASS IN USE??\r\n");
59  }
60  // Get pointer to pseudo device with address 0 assigned
61  p = addrPool.GetUsbDevicePtr(0);
62 
63  if(!p) {
64  USBTRACE("FTDI NO ADDRESS??\r\n");
66  }
67  if(!p->epinfo) {
68  USBTRACE("epinfo\r\n");
70  }
71 
72  // Save old pointer to EP_RECORD of address 0
73  oldep_ptr = p->epinfo;
74 
75  // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
76  p->epinfo = epInfo;
77 
78  p->lowspeed = lowspeed;
79 
80  // Get device descriptor
81  rcode = pUsb->getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), buf);
82 
83  // Restore p->epinfo
84  p->epinfo = oldep_ptr;
85 
86  if(rcode) {
87  goto FailGetDevDescr;
88  }
89  if(udd->idVendor != FTDI_VID || udd->idProduct != wIdProduct)
90  {
91  USBTRACE("FTDI Init: Product not supported\r\n");
92  USBTRACE2("Expected VID:", FTDI_VID);
93  USBTRACE2("Found VID:", udd->idVendor);
94 
95  USBTRACE2("Expected PID:", wIdProduct);
96  USBTRACE2("Found PID:", udd->idProduct);
98  }
99 
100  // Save type of FTDI chip
101  wFTDIType = udd->bcdDevice;
102 
103  // Allocate new address according to device class
104  bAddress = addrPool.AllocAddress(parent, false, port);
105 
106  if(!bAddress)
108 
109  // Extract Max Packet Size from the device descriptor
110  epInfo[0].maxPktSize = udd->bMaxPacketSize0;
111 
112  // Assign new address to the device
113  rcode = pUsb->setAddr(0, 0, bAddress);
114 
115  if(rcode) {
116  p->lowspeed = false;
117  addrPool.FreeAddress(bAddress);
118  bAddress = 0;
119  USBTRACE2("setAddr:", rcode);
120  return rcode;
121  }
122 
123  USBTRACE2("Addr:", bAddress);
124 
125  p->lowspeed = false;
126 
127  p = addrPool.GetUsbDevicePtr(bAddress);
128 
129  if(!p)
131 
132  p->lowspeed = lowspeed;
133 
134  num_of_conf = udd->bNumConfigurations;
135 
136  // Assign epInfo to epinfo pointer
137  rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
138 
139  if(rcode)
140  goto FailSetDevTblEntry;
141 
142  USBTRACE2("NC:", num_of_conf);
143 
144  for(uint8_t i = 0; i < num_of_conf; i++) {
146 
147  // This interferes with serial output, and should be opt-in for debugging.
148  //HexDumper<USBReadParser, uint16_t, uint16_t> HexDump;
149  //rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump);
150  //if(rcode)
151  // goto FailGetConfDescr;
152 
153  rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
154 
155  if(rcode)
156  goto FailGetConfDescr;
157 
158  if(bNumEP > 1)
159  break;
160  } // for
161 
162  if(bNumEP < 2)
164 
165  USBTRACE2("NumEP:", bNumEP);
166 
167  // Assign epInfo to epinfo pointer
168  rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
169 
170  USBTRACE2("Conf:", bConfNum);
171 
172  // Set Configuration Value
173  rcode = pUsb->setConf(bAddress, 0, bConfNum);
174 
175  if(rcode)
176  goto FailSetConfDescr;
177 
178  rcode = pAsync->OnInit(this);
179 
180  if(rcode)
181  goto FailOnInit;
182 
183  USBTRACE("FTDI configured\r\n");
184 
185  ready = true;
186  return 0;
187 
188 FailGetDevDescr:
189 #ifdef DEBUG_USB_HOST
191  goto Fail;
192 #endif
193 
194 FailSetDevTblEntry:
195 #ifdef DEBUG_USB_HOST
197  goto Fail;
198 #endif
199 
200 FailGetConfDescr:
201 #ifdef DEBUG_USB_HOST
203  goto Fail;
204 #endif
205 
206 FailSetConfDescr:
207 #ifdef DEBUG_USB_HOST
209  goto Fail;
210 #endif
211 
212 FailOnInit:
213 #ifdef DEBUG_USB_HOST
214  USBTRACE("OnInit:");
215 
216 Fail:
217  NotifyFail(rcode);
218 #endif
219  Release();
220  return rcode;
221 }
222 
223 void FTDI::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto __attribute__((unused)), const USB_ENDPOINT_DESCRIPTOR *pep) {
224  ErrorMessage<uint8_t > (PSTR("Conf.Val"), conf);
225  ErrorMessage<uint8_t > (PSTR("Iface Num"), iface);
226  ErrorMessage<uint8_t > (PSTR("Alt.Set"), alt);
227 
228  bConfNum = conf;
229 
230  uint8_t index;
231 
232  if((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_INTERRUPT && (pep->bEndpointAddress & 0x80) == 0x80)
233  index = epInterruptInIndex;
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].bmSndToggle = 0;
243  epInfo[index].bmRcvToggle = 0;
244 
245  bNumEP++;
246 
247  PrintEndpointDescriptor(pep);
248 }
249 
250 uint8_t FTDI::Release() {
251  pUsb->GetAddressPool().FreeAddress(bAddress);
252 
253  bAddress = 0;
254  bNumEP = 1;
255  qNextPollTime = 0;
256  bPollEnable = false;
257  ready = false;
258  return pAsync->OnRelease(this);
259 }
260 
261 uint8_t FTDI::Poll() {
262  uint8_t rcode = 0;
263 
264  //if (!bPollEnable)
265  // return 0;
266 
267  //if (qNextPollTime <= (uint32_t)millis())
268  //{
269  // USB_HOST_SERIAL.println(bAddress, HEX);
270 
271  // qNextPollTime = (uint32_t)millis() + 100;
272  //}
273  return rcode;
274 }
275 
276 uint8_t FTDI::SetBaudRate(uint32_t baud) {
277  uint16_t baud_value, baud_index = 0;
278  uint32_t divisor3;
279  divisor3 = 48000000 / 2 / baud; // divisor shifted 3 bits to the left
280 
281  if(wFTDIType == FT232AM) {
282  if((divisor3 & 0x7) == 7)
283  divisor3++; // round x.7/8 up to x+1
284 
285  baud_value = divisor3 >> 3;
286  divisor3 &= 0x7;
287 
288  if(divisor3 == 1) baud_value |= 0xc000;
289  else // 0.125
290  if(divisor3 >= 4) baud_value |= 0x4000;
291  else // 0.5
292  if(divisor3 != 0) baud_value |= 0x8000; // 0.25
293  if(baud_value == 1) baud_value = 0; /* special case for maximum baud rate */
294  } else {
295  static const uint8_t divfrac [8] = {0, 3, 2, 0, 1, 1, 2, 3};
296  static const uint8_t divindex[8] = {0, 0, 0, 1, 0, 1, 1, 1};
297 
298  baud_value = divisor3 >> 3;
299  baud_value |= divfrac [divisor3 & 0x7] << 14;
300  baud_index = divindex[divisor3 & 0x7];
301 
302  /* Deal with special cases for highest baud rates. */
303  if(baud_value == 1) baud_value = 0;
304  else // 1.0
305  if(baud_value == 0x4001) baud_value = 1; // 1.5
306  }
307  USBTRACE2("baud_value:", baud_value);
308  USBTRACE2("baud_index:", baud_index);
309  uint8_t rv = pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_SET_BAUD_RATE, baud_value & 0xff, baud_value >> 8, baud_index, 0, 0, NULL, NULL);
310  if(rv && rv != hrNAK) {
311  Release();
312  }
313  return rv;
314 }
315 
316 uint8_t FTDI::SetModemControl(uint16_t signal) {
317  uint8_t rv = pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_MODEM_CTRL, signal & 0xff, signal >> 8, 0, 0, 0, NULL, NULL);
318  if(rv && rv != hrNAK) {
319  Release();
320  }
321  return rv;
322 }
323 
324 uint8_t FTDI::SetFlowControl(uint8_t protocol, uint8_t xon, uint8_t xoff) {
325  uint8_t rv = pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_SET_FLOW_CTRL, xon, xoff, protocol << 8, 0, 0, NULL, NULL);
326  if(rv && rv != hrNAK) {
327  Release();
328  }
329  return rv;
330 }
331 
332 uint8_t FTDI::SetData(uint16_t databm) {
333  uint8_t rv = pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_SET_DATA, databm & 0xff, databm >> 8, 0, 0, 0, NULL, NULL);
334  if(rv && rv != hrNAK) {
335  Release();
336  }
337  return rv;
338 }
339 
340 uint8_t FTDI::RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr) {
341  uint8_t rv = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, dataptr);
342  if(rv && rv != hrNAK) {
343  Release();
344  }
345  return rv;
346 }
347 
348 uint8_t FTDI::SndData(uint16_t nbytes, uint8_t *dataptr) {
349  uint8_t rv = pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, nbytes, dataptr);
350  if(rv && rv != hrNAK) {
351  Release();
352  }
353  return rv;
354 }
355 
356 void FTDI::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr) {
357  Notify(PSTR("Endpoint descriptor:"), 0x80);
358  Notify(PSTR("\r\nLength:\t\t"), 0x80);
359  D_PrintHex<uint8_t > (ep_ptr->bLength, 0x80);
360  Notify(PSTR("\r\nType:\t\t"), 0x80);
361  D_PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80);
362  Notify(PSTR("\r\nAddress:\t"), 0x80);
363  D_PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80);
364  Notify(PSTR("\r\nAttributes:\t"), 0x80);
365  D_PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80);
366  Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
367  D_PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80);
368  Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
369  D_PrintHex<uint8_t > (ep_ptr->bInterval, 0x80);
370  Notify(PSTR("\r\n"), 0x80);
371 }
uint8_t getConfDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t *dataptr)
Definition: Usb.cpp:784
uint8_t bmRcvToggle
Definition: address.h:48
#define bmREQ_FTDI_OUT
Definition: cdcftdi.h:22
EpInfo * epinfo
Definition: address.h:83
void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep)
Definition: cdcftdi.cpp:223
bool lowspeed
Definition: address.h:86
#define USB_ERROR_EPINFO_IS_NULL
Definition: UsbCore.h:94
uint8_t SetBaudRate(uint32_t baud)
Definition: cdcftdi.cpp:276
uint8_t bmNakPower
Definition: address.h:49
#define FT232AM
Definition: cdcftdi.h:31
uint16_t bcdDevice
Definition: usb_ch9.h:115
uint8_t SetModemControl(uint16_t control)
Definition: cdcftdi.cpp:316
#define FTDI_SIO_SET_BAUD_RATE
Definition: cdcftdi.h:40
uint8_t bMaxPacketSize0
Definition: usb_ch9.h:112
#define NotifyFail(...)
Definition: message.h:62
#define FTDI_SIO_SET_DATA
Definition: cdcftdi.h:41
uint8_t SetFlowControl(uint8_t protocol, uint8_t xon=0x11, uint8_t xoff=0x13)
Definition: cdcftdi.cpp:324
uint8_t setConf(uint8_t addr, uint8_t ep, uint8_t conf_value)
Definition: Usb.cpp:823
#define USB_TRANSFER_TYPE_INTERRUPT
Definition: usb_ch9.h:93
#define NotifyFailGetDevDescr(...)
Definition: message.h:57
uint8_t setEpInfoEntry(uint8_t addr, uint8_t epcount, EpInfo *eprecord_ptr)
Definition: Usb.cpp:71
uint8_t RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr)
Definition: cdcftdi.cpp:340
virtual void FreeAddress(uint8_t addr)=0
uint8_t ctrlReq(uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bRequest, uint8_t wValLo, uint8_t wValHi, uint16_t wInd, uint16_t total, uint16_t nbytes, uint8_t *dataptr, USBReadParser *p)
Definition: Usb.cpp:133
virtual UsbDevice * GetUsbDevicePtr(uint8_t addr)=0
#define Notify(...)
Definition: message.h:51
#define USBTRACE2(s, r)
Definition: macros.h:84
uint8_t setAddr(uint8_t oldaddr, uint8_t ep, uint8_t newaddr)
Definition: Usb.cpp:814
#define NotifyFailGetConfDescr(...)
Definition: message.h:59
uint8_t epAddr
Definition: address.h:40
#define USB_NAK_MAX_POWER
Definition: address.h:34
FTDI(USB *pusb, FTDIAsyncOper *pasync, uint16_t idProduct=FTDI_PID)
Definition: cdcftdi.cpp:23
uint8_t Poll()
Definition: cdcftdi.cpp:261
Definition: address.h:39
uint8_t outTransfer(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t *data)
Definition: Usb.cpp:300
#define hrNAK
Definition: max3421e.h:218
uint16_t wMaxPacketSize
Definition: usb_ch9.h:153
#define bmUSB_TRANSFER_TYPE
Definition: usb_ch9.h:94
uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed)
Definition: cdcftdi.cpp:41
#define FTDI_SIO_SET_FLOW_CTRL
Definition: cdcftdi.h:39
virtual uint8_t AllocAddress(uint8_t parent, bool is_hub=false, uint8_t port=0)=0
uint8_t bEndpointAddress
Definition: usb_ch9.h:151
virtual uint8_t OnInit(FTDI *pftdi)
Definition: cdcftdi.h:82
uint8_t bmSndToggle
Definition: address.h:47
#define USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE
Definition: UsbCore.h:96
#define PSTR(str)
uint8_t SndData(uint16_t nbytes, uint8_t *dataptr)
Definition: cdcftdi.cpp:348
#define USB_NAK_NOWAIT
Definition: address.h:36
#define USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL
Definition: UsbCore.h:93
virtual uint8_t OnRelease(FTDI *pftdi)
Definition: cdcftdi.h:86
#define FTDI_VID
Definition: cdcftdi.h:28
#define USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED
Definition: UsbCore.h:88
uint8_t Release()
Definition: cdcftdi.cpp:250
uint16_t idProduct
Definition: usb_ch9.h:114
uint8_t inTransfer(uint8_t addr, uint8_t ep, uint16_t *nbytesptr, uint8_t *data, uint8_t bInterval=0)
Definition: Usb.cpp:213
uint8_t bNumConfigurations
Definition: usb_ch9.h:119
#define USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL
Definition: UsbCore.h:91
#define FTDI_SIO_MODEM_CTRL
Definition: cdcftdi.h:38
uint8_t maxPktSize
Definition: address.h:41
AddressPool & GetAddressPool()
Definition: UsbCore.h:224
Definition: UsbCore.h:208
#define USB_TRANSFER_TYPE_BULK
Definition: usb_ch9.h:92
uint8_t RegisterDeviceClass(USBDeviceConfig *pdev)
Definition: UsbCore.h:228
#define NotifyFailSetConfDescr(...)
Definition: message.h:60
uint8_t SetData(uint16_t databm)
Definition: cdcftdi.cpp:332
#define FTDI_MAX_ENDPOINTS
Definition: cdcftdi.h:94
#define USBTRACE(s)
Definition: macros.h:82
uint8_t getDevDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t *dataptr)
defined(USB_METHODS_INLINE)
Definition: Usb.cpp:779
#define NotifyFailSetDevTblEntry(...)
Definition: message.h:58