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 
24 pAsync(pasync),
25 pUsb(p),
26 bAddress(0),
27 bNumEP(1),
28 wFTDIType(0) {
29  for(uint8_t i = 0; i < FTDI_MAX_ENDPOINTS; i++) {
30  epInfo[i].epAddr = 0;
31  epInfo[i].maxPktSize = (i) ? 0 : 8;
32  epInfo[i].epAttribs = 0;
33  epInfo[i].bmNakPower = (i==epDataInIndex) ? USB_NAK_NOWAIT: USB_NAK_MAX_POWER;
34  }
35  if(pUsb)
36  pUsb->RegisterDeviceClass(this);
37 }
38 
39 uint8_t FTDI::Init(uint8_t parent, uint8_t port, bool lowspeed) {
40  const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR);
41 
42  uint8_t buf[constBufSize];
43  USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf);
44  uint8_t rcode;
45  UsbDevice *p = NULL;
46  EpInfo *oldep_ptr = NULL;
47 
48  uint8_t num_of_conf; // number of configurations
49 
50  AddressPool &addrPool = pUsb->GetAddressPool();
51 
52  USBTRACE("FTDI Init\r\n");
53 
54  if(bAddress)
56 
57  // Get pointer to pseudo device with address 0 assigned
58  p = addrPool.GetUsbDevicePtr(0);
59 
60  if(!p)
62 
63  if(!p->epinfo) {
64  USBTRACE("epinfo\r\n");
66  }
67 
68  // Save old pointer to EP_RECORD of address 0
69  oldep_ptr = p->epinfo;
70 
71  // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
72  p->epinfo = epInfo;
73 
74  p->lowspeed = lowspeed;
75 
76  // Get device descriptor
77  rcode = pUsb->getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), buf);
78 
79  // Restore p->epinfo
80  p->epinfo = oldep_ptr;
81 
82  if(rcode)
83  goto FailGetDevDescr;
84  if(udd->idVendor != FTDI_VID || udd->idProduct != FTDI_PID)
86 
87  // Save type of FTDI chip
88  wFTDIType = udd->bcdDevice;
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 = udd->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 = udd->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++) {
134 
135  rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump);
136 
137  if(rcode)
138  goto FailGetConfDescr;
139 
140  rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
141 
142  if(rcode)
143  goto FailGetConfDescr;
144 
145  if(bNumEP > 1)
146  break;
147  } // for
148 
149  if(bNumEP < 2)
151 
152  USBTRACE2("NumEP:", bNumEP);
153 
154  // Assign epInfo to epinfo pointer
155  rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
156 
157  USBTRACE2("Conf:", bConfNum);
158 
159  // Set Configuration Value
160  rcode = pUsb->setConf(bAddress, 0, bConfNum);
161 
162  if(rcode)
163  goto FailSetConfDescr;
164 
165  rcode = pAsync->OnInit(this);
166 
167  if(rcode)
168  goto FailOnInit;
169 
170  USBTRACE("FTDI configured\r\n");
171 
172  bPollEnable = true;
173  return 0;
174 
175 FailGetDevDescr:
176 #ifdef DEBUG_USB_HOST
178  goto Fail;
179 #endif
180 
181 FailSetDevTblEntry:
182 #ifdef DEBUG_USB_HOST
184  goto Fail;
185 #endif
186 
187 FailGetConfDescr:
188 #ifdef DEBUG_USB_HOST
190  goto Fail;
191 #endif
192 
193 FailSetConfDescr:
194 #ifdef DEBUG_USB_HOST
196  goto Fail;
197 #endif
198 
199 FailOnInit:
200 #ifdef DEBUG_USB_HOST
201  USBTRACE("OnInit:");
202 
203 Fail:
204  NotifyFail(rcode);
205 #endif
206  Release();
207  return rcode;
208 }
209 
210 void FTDI::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) {
211  ErrorMessage<uint8_t > (PSTR("Conf.Val"), conf);
212  ErrorMessage<uint8_t > (PSTR("Iface Num"), iface);
213  ErrorMessage<uint8_t > (PSTR("Alt.Set"), alt);
214 
215  bConfNum = conf;
216 
217  uint8_t index;
218 
219  if((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80)
220  index = epInterruptInIndex;
221  else
222  if((pep->bmAttributes & 0x02) == 2)
223  index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex;
224  else
225  return;
226 
227  // Fill in the endpoint info structure
228  epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
229  epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
230  epInfo[index].epAttribs = 0;
231 
232  bNumEP++;
233 
234  PrintEndpointDescriptor(pep);
235 }
236 
237 uint8_t FTDI::Release() {
238  pUsb->GetAddressPool().FreeAddress(bAddress);
239 
240  bAddress = 0;
241  bNumEP = 1;
242  qNextPollTime = 0;
243  bPollEnable = false;
244  return pAsync->OnRelease(this);
245 }
246 
247 uint8_t FTDI::Poll() {
248  uint8_t rcode = 0;
249 
250  //if (!bPollEnable)
251  // return 0;
252 
253  //if (qNextPollTime <= millis())
254  //{
255  // USB_HOST_SERIAL.println(bAddress, HEX);
256 
257  // qNextPollTime = millis() + 100;
258  //}
259  return rcode;
260 }
261 
262 uint8_t FTDI::SetBaudRate(uint32_t baud) {
263  uint16_t baud_value, baud_index = 0;
264  uint32_t divisor3;
265 
266  divisor3 = 48000000 / 2 / baud; // divisor shifted 3 bits to the left
267 
268  if(wFTDIType == FT232AM) {
269  if((divisor3 & 0x7) == 7)
270  divisor3++; // round x.7/8 up to x+1
271 
272  baud_value = divisor3 >> 3;
273  divisor3 &= 0x7;
274 
275  if(divisor3 == 1) baud_value |= 0xc000;
276  else // 0.125
277  if(divisor3 >= 4) baud_value |= 0x4000;
278  else // 0.5
279  if(divisor3 != 0) baud_value |= 0x8000; // 0.25
280  if(baud_value == 1) baud_value = 0; /* special case for maximum baud rate */
281  } else {
282  static const unsigned char divfrac [8] = {0, 3, 2, 0, 1, 1, 2, 3};
283  static const unsigned char divindex[8] = {0, 0, 0, 1, 0, 1, 1, 1};
284 
285  baud_value = divisor3 >> 3;
286  baud_value |= divfrac [divisor3 & 0x7] << 14;
287  baud_index = divindex[divisor3 & 0x7];
288 
289  /* Deal with special cases for highest baud rates. */
290  if(baud_value == 1) baud_value = 0;
291  else // 1.0
292  if(baud_value == 0x4001) baud_value = 1; // 1.5
293  }
294  USBTRACE2("baud_value:", baud_value);
295  USBTRACE2("baud_index:", baud_index);
296  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);
297 }
298 
299 uint8_t FTDI::SetModemControl(uint16_t signal) {
300  return pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_MODEM_CTRL, signal & 0xff, signal >> 8, 0, 0, 0, NULL, NULL);
301 }
302 
303 uint8_t FTDI::SetFlowControl(uint8_t protocol, uint8_t xon, uint8_t xoff) {
304  return pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_SET_FLOW_CTRL, xon, xoff, protocol << 8, 0, 0, NULL, NULL);
305 }
306 
307 uint8_t FTDI::SetData(uint16_t databm) {
308  return pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_SET_DATA, databm & 0xff, databm >> 8, 0, 0, 0, NULL, NULL);
309 }
310 
311 uint8_t FTDI::RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr) {
312  return pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, dataptr);
313 }
314 
315 uint8_t FTDI::SndData(uint16_t nbytes, uint8_t *dataptr) {
316  return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, nbytes, dataptr);
317 }
318 
319 void FTDI::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr) {
320  Notify(PSTR("Endpoint descriptor:"), 0x80);
321  Notify(PSTR("\r\nLength:\t\t"), 0x80);
322  D_PrintHex<uint8_t > (ep_ptr->bLength, 0x80);
323  Notify(PSTR("\r\nType:\t\t"), 0x80);
324  D_PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80);
325  Notify(PSTR("\r\nAddress:\t"), 0x80);
326  D_PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80);
327  Notify(PSTR("\r\nAttributes:\t"), 0x80);
328  D_PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80);
329  Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
330  D_PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80);
331  Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
332  D_PrintHex<uint8_t > (ep_ptr->bInterval, 0x80);
333  Notify(PSTR("\r\n"), 0x80);
334 }
uint8_t getConfDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t *dataptr)
Definition: Usb.cpp:769
#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:210
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:262
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:299
#define FTDI_SIO_SET_BAUD_RATE
Definition: cdcftdi.h:40
uint8_t bMaxPacketSize0
Definition: usb_ch9.h:105
FTDI(USB *pusb, FTDIAsyncOper *pasync)
Definition: cdcftdi.cpp:23
#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:303
uint8_t setConf(uint8_t addr, uint8_t ep, uint8_t conf_value)
Definition: Usb.cpp:808
#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:311
virtual void FreeAddress(uint8_t addr)=0
uint8_t epAttribs
Definition: address.h:37
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:799
#define NotifyFailGetConfDescr(...)
Definition: message.h:52
uint8_t epAddr
Definition: address.h:33
#define USB_NAK_MAX_POWER
Definition: address.h:27
uint8_t Poll()
Definition: cdcftdi.cpp:247
Definition: address.h:32
uint8_t outTransfer(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t *data)
Definition: Usb.cpp:292
uint16_t wMaxPacketSize
Definition: usb_ch9.h:146
#define FTDI_PID
Definition: cdcftdi.h:29
uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed)
Definition: cdcftdi.cpp:39
#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
#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:315
#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:85
#define FTDI_VID
Definition: cdcftdi.h:28
uint8_t inTransfer(uint8_t addr, uint8_t ep, uint16_t *nbytesptr, uint8_t *data)
Definition: Usb.cpp:206
#define USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED
Definition: UsbCore.h:77
uint8_t Release()
Definition: cdcftdi.cpp:237
uint16_t idProduct
Definition: usb_ch9.h:107
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:307
#define FTDI_MAX_ENDPOINTS
Definition: cdcftdi.h:92
#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:764
#define NotifyFailSetDevTblEntry(...)
Definition: message.h:51