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)
58 
59  // Get pointer to pseudo device with address 0 assigned
60  p = addrPool.GetUsbDevicePtr(0);
61 
62  if(!p)
64 
65  if(!p->epinfo) {
66  USBTRACE("epinfo\r\n");
68  }
69 
70  // Save old pointer to EP_RECORD of address 0
71  oldep_ptr = p->epinfo;
72 
73  // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
74  p->epinfo = epInfo;
75 
76  p->lowspeed = lowspeed;
77 
78  // Get device descriptor
79  rcode = pUsb->getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), buf);
80 
81  // Restore p->epinfo
82  p->epinfo = oldep_ptr;
83 
84  if(rcode)
85  goto FailGetDevDescr;
86  if(udd->idVendor != FTDI_VID || udd->idProduct != wIdProduct)
87  {
88  USBTRACE("FTDI Init: Product not supported\r\n");
89  USBTRACE2("Expected VID:", FTDI_VID);
90  USBTRACE2("Found VID:", udd->idVendor);
91 
92  USBTRACE2("Expected PID:", wIdProduct);
93  USBTRACE2("Found PID:", udd->idProduct);
95  }
96 
97  // Save type of FTDI chip
98  wFTDIType = udd->bcdDevice;
99 
100  // Allocate new address according to device class
101  bAddress = addrPool.AllocAddress(parent, false, port);
102 
103  if(!bAddress)
105 
106  // Extract Max Packet Size from the device descriptor
107  epInfo[0].maxPktSize = udd->bMaxPacketSize0;
108 
109  // Assign new address to the device
110  rcode = pUsb->setAddr(0, 0, bAddress);
111 
112  if(rcode) {
113  p->lowspeed = false;
114  addrPool.FreeAddress(bAddress);
115  bAddress = 0;
116  USBTRACE2("setAddr:", rcode);
117  return rcode;
118  }
119 
120  USBTRACE2("Addr:", bAddress);
121 
122  p->lowspeed = false;
123 
124  p = addrPool.GetUsbDevicePtr(bAddress);
125 
126  if(!p)
128 
129  p->lowspeed = lowspeed;
130 
131  num_of_conf = udd->bNumConfigurations;
132 
133  // Assign epInfo to epinfo pointer
134  rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
135 
136  if(rcode)
137  goto FailSetDevTblEntry;
138 
139  USBTRACE2("NC:", num_of_conf);
140 
141  for(uint8_t i = 0; i < num_of_conf; i++) {
144 
145  rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump);
146 
147  if(rcode)
148  goto FailGetConfDescr;
149 
150  rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
151 
152  if(rcode)
153  goto FailGetConfDescr;
154 
155  if(bNumEP > 1)
156  break;
157  } // for
158 
159  if(bNumEP < 2)
161 
162  USBTRACE2("NumEP:", bNumEP);
163 
164  // Assign epInfo to epinfo pointer
165  rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
166 
167  USBTRACE2("Conf:", bConfNum);
168 
169  // Set Configuration Value
170  rcode = pUsb->setConf(bAddress, 0, bConfNum);
171 
172  if(rcode)
173  goto FailSetConfDescr;
174 
175  rcode = pAsync->OnInit(this);
176 
177  if(rcode)
178  goto FailOnInit;
179 
180  USBTRACE("FTDI configured\r\n");
181 
182  bPollEnable = true;
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 
213 Fail:
214  NotifyFail(rcode);
215 #endif
216  Release();
217  return rcode;
218 }
219 
220 void FTDI::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) {
221  ErrorMessage<uint8_t > (PSTR("Conf.Val"), conf);
222  ErrorMessage<uint8_t > (PSTR("Iface Num"), iface);
223  ErrorMessage<uint8_t > (PSTR("Alt.Set"), alt);
224 
225  bConfNum = conf;
226 
227  uint8_t index;
228 
229  if((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80)
230  index = epInterruptInIndex;
231  else
232  if((pep->bmAttributes & 0x02) == 2)
233  index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex;
234  else
235  return;
236 
237  // Fill in the endpoint info structure
238  epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
239  epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
240  epInfo[index].bmSndToggle = 0;
241  epInfo[index].bmRcvToggle = 0;
242 
243  bNumEP++;
244 
245  PrintEndpointDescriptor(pep);
246 }
247 
248 uint8_t FTDI::Release() {
249  pUsb->GetAddressPool().FreeAddress(bAddress);
250 
251  bAddress = 0;
252  bNumEP = 1;
253  qNextPollTime = 0;
254  bPollEnable = false;
255  return pAsync->OnRelease(this);
256 }
257 
258 uint8_t FTDI::Poll() {
259  uint8_t rcode = 0;
260 
261  //if (!bPollEnable)
262  // return 0;
263 
264  //if (qNextPollTime <= millis())
265  //{
266  // USB_HOST_SERIAL.println(bAddress, HEX);
267 
268  // qNextPollTime = millis() + 100;
269  //}
270  return rcode;
271 }
272 
273 uint8_t FTDI::SetBaudRate(uint32_t baud) {
274  uint16_t baud_value, baud_index = 0;
275  uint32_t divisor3;
276 
277  divisor3 = 48000000 / 2 / baud; // divisor shifted 3 bits to the left
278 
279  if(wFTDIType == FT232AM) {
280  if((divisor3 & 0x7) == 7)
281  divisor3++; // round x.7/8 up to x+1
282 
283  baud_value = divisor3 >> 3;
284  divisor3 &= 0x7;
285 
286  if(divisor3 == 1) baud_value |= 0xc000;
287  else // 0.125
288  if(divisor3 >= 4) baud_value |= 0x4000;
289  else // 0.5
290  if(divisor3 != 0) baud_value |= 0x8000; // 0.25
291  if(baud_value == 1) baud_value = 0; /* special case for maximum baud rate */
292  } else {
293  static const unsigned char divfrac [8] = {0, 3, 2, 0, 1, 1, 2, 3};
294  static const unsigned char divindex[8] = {0, 0, 0, 1, 0, 1, 1, 1};
295 
296  baud_value = divisor3 >> 3;
297  baud_value |= divfrac [divisor3 & 0x7] << 14;
298  baud_index = divindex[divisor3 & 0x7];
299 
300  /* Deal with special cases for highest baud rates. */
301  if(baud_value == 1) baud_value = 0;
302  else // 1.0
303  if(baud_value == 0x4001) baud_value = 1; // 1.5
304  }
305  USBTRACE2("baud_value:", baud_value);
306  USBTRACE2("baud_index:", baud_index);
307  return pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_SET_BAUD_RATE, baud_value & 0xff, baud_value >> 8, baud_index, 0, 0, NULL, NULL);
308 }
309 
310 uint8_t FTDI::SetModemControl(uint16_t signal) {
311  return pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_MODEM_CTRL, signal & 0xff, signal >> 8, 0, 0, 0, NULL, NULL);
312 }
313 
314 uint8_t FTDI::SetFlowControl(uint8_t protocol, uint8_t xon, uint8_t xoff) {
315  return pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_SET_FLOW_CTRL, xon, xoff, protocol << 8, 0, 0, NULL, NULL);
316 }
317 
318 uint8_t FTDI::SetData(uint16_t databm) {
319  return pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_SET_DATA, databm & 0xff, databm >> 8, 0, 0, 0, NULL, NULL);
320 }
321 
322 uint8_t FTDI::RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr) {
323  return pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, dataptr);
324 }
325 
326 uint8_t FTDI::SndData(uint16_t nbytes, uint8_t *dataptr) {
327  return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, nbytes, dataptr);
328 }
329 
330 void FTDI::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr) {
331  Notify(PSTR("Endpoint descriptor:"), 0x80);
332  Notify(PSTR("\r\nLength:\t\t"), 0x80);
333  D_PrintHex<uint8_t > (ep_ptr->bLength, 0x80);
334  Notify(PSTR("\r\nType:\t\t"), 0x80);
335  D_PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80);
336  Notify(PSTR("\r\nAddress:\t"), 0x80);
337  D_PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80);
338  Notify(PSTR("\r\nAttributes:\t"), 0x80);
339  D_PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80);
340  Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
341  D_PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80);
342  Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
343  D_PrintHex<uint8_t > (ep_ptr->bInterval, 0x80);
344  Notify(PSTR("\r\n"), 0x80);
345 }
uint8_t getConfDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t *dataptr)
Definition: Usb.cpp:771
uint8_t bmRcvToggle
Definition: address.h:41
#define bmREQ_FTDI_OUT
Definition: cdcftdi.h:22
EpInfo * epinfo
Definition: address.h:76
void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep)
Definition: cdcftdi.cpp:220
bool lowspeed
Definition: address.h:79
#define USB_ERROR_EPINFO_IS_NULL
Definition: UsbCore.h:83
uint8_t SetBaudRate(uint32_t baud)
Definition: cdcftdi.cpp:273
uint8_t bmNakPower
Definition: address.h:42
#define FT232AM
Definition: cdcftdi.h:31
uint16_t bcdDevice
Definition: usb_ch9.h:108
uint8_t SetModemControl(uint16_t control)
Definition: cdcftdi.cpp:310
#define FTDI_SIO_SET_BAUD_RATE
Definition: cdcftdi.h:40
uint8_t bMaxPacketSize0
Definition: usb_ch9.h:105
#define NotifyFail(...)
Definition: message.h:55
#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:314
uint8_t setConf(uint8_t addr, uint8_t ep, uint8_t conf_value)
Definition: Usb.cpp:810
#define NotifyFailGetDevDescr(...)
Definition: message.h:50
uint8_t setEpInfoEntry(uint8_t addr, uint8_t epcount, EpInfo *eprecord_ptr)
Definition: Usb.cpp:64
uint8_t RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr)
Definition: cdcftdi.cpp:322
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:126
virtual UsbDevice * GetUsbDevicePtr(uint8_t addr)=0
#define Notify(...)
Definition: message.h:44
#define USBTRACE2(s, r)
Definition: macros.h:77
uint8_t setAddr(uint8_t oldaddr, uint8_t ep, uint8_t newaddr)
Definition: Usb.cpp:801
#define NotifyFailGetConfDescr(...)
Definition: message.h:52
uint8_t epAddr
Definition: address.h:33
#define USB_NAK_MAX_POWER
Definition: address.h:27
FTDI(USB *pusb, FTDIAsyncOper *pasync, uint16_t idProduct=FTDI_PID)
Definition: cdcftdi.cpp:23
uint8_t Poll()
Definition: cdcftdi.cpp:258
Definition: address.h:32
uint8_t outTransfer(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t *data)
Definition: Usb.cpp:293
uint16_t wMaxPacketSize
Definition: usb_ch9.h:146
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:144
virtual uint8_t OnInit(FTDI *pftdi)
Definition: cdcftdi.h:82
uint8_t bmSndToggle
Definition: address.h:40
#define USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE
Definition: UsbCore.h:85
#define PSTR(str)
uint8_t SndData(uint16_t nbytes, uint8_t *dataptr)
Definition: cdcftdi.cpp:326
#define USB_NAK_NOWAIT
Definition: address.h:29
#define USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL
Definition: UsbCore.h:82
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:77
uint8_t Release()
Definition: cdcftdi.cpp:248
uint16_t idProduct
Definition: usb_ch9.h:107
uint8_t inTransfer(uint8_t addr, uint8_t ep, uint16_t *nbytesptr, uint8_t *data, uint8_t bInterval=0)
Definition: Usb.cpp:206
uint8_t bNumConfigurations
Definition: usb_ch9.h:112
#define USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL
Definition: UsbCore.h:80
#define FTDI_SIO_MODEM_CTRL
Definition: cdcftdi.h:38
uint8_t maxPktSize
Definition: address.h:34
AddressPool & GetAddressPool()
Definition: UsbCore.h:213
Definition: UsbCore.h:197
uint8_t RegisterDeviceClass(USBDeviceConfig *pdev)
Definition: UsbCore.h:217
#define NotifyFailSetConfDescr(...)
Definition: message.h:53
uint8_t SetData(uint16_t databm)
Definition: cdcftdi.cpp:318
#define FTDI_MAX_ENDPOINTS
Definition: cdcftdi.h:94
#define USBTRACE(s)
Definition: macros.h:75
uint8_t getDevDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t *dataptr)
defined(USB_METHODS_INLINE)
Definition: Usb.cpp:766
#define NotifyFailSetDevTblEntry(...)
Definition: message.h:51