USB Host Shield 2.0
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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 {
30  for(uint8_t i=0; i<FTDI_MAX_ENDPOINTS; i++)
31  {
32  epInfo[i].epAddr = 0;
33  epInfo[i].maxPktSize = (i) ? 0 : 8;
34  epInfo[i].epAttribs = 0;
35 
36  //if (!i)
37  epInfo[i].bmNakPower = USB_NAK_MAX_POWER;
38  }
39  if (pUsb)
40  pUsb->RegisterDeviceClass(this);
41 }
42 
43 uint8_t FTDI::Init(uint8_t parent, uint8_t port, bool lowspeed)
44 {
45  const uint8_t constBufSize = sizeof(USB_DEVICE_DESCRIPTOR);
46 
47  uint8_t buf[constBufSize];
48  uint8_t rcode;
49  UsbDevice *p = NULL;
50  EpInfo *oldep_ptr = NULL;
51  uint8_t len = 0;
52  uint16_t cd_len = 0;
53 
54  uint8_t num_of_conf; // number of configurations
55  uint8_t num_of_intf; // number of interfaces
56 
57  AddressPool &addrPool = pUsb->GetAddressPool();
58 
59  USBTRACE("FTDI Init\r\n");
60 
61  if (bAddress)
63 
64  // Get pointer to pseudo device with address 0 assigned
65  p = addrPool.GetUsbDevicePtr(0);
66 
67  if (!p)
69 
70  if (!p->epinfo)
71  {
72  USBTRACE("epinfo\r\n");
74  }
75 
76  // Save old pointer to EP_RECORD of address 0
77  oldep_ptr = p->epinfo;
78 
79  // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
80  p->epinfo = epInfo;
81 
82  p->lowspeed = lowspeed;
83 
84  // Get device descriptor
85  rcode = pUsb->getDevDescr( 0, 0, sizeof(USB_DEVICE_DESCRIPTOR), (uint8_t*)buf );
86 
87  // Restore p->epinfo
88  p->epinfo = oldep_ptr;
89 
90  if( rcode )
91  goto FailGetDevDescr;
92 
93  if (((USB_DEVICE_DESCRIPTOR*)buf)->idVendor != FTDI_VID || ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct != FTDI_PID)
95 
96  // Save type of FTDI chip
97  wFTDIType = ((USB_DEVICE_DESCRIPTOR*)buf)->bcdDevice;
98 
99  // Allocate new address according to device class
100  bAddress = addrPool.AllocAddress(parent, false, port);
101 
102  if (!bAddress)
104 
105  // Extract Max Packet Size from the device descriptor
106  epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0;
107 
108  // Assign new address to the device
109  rcode = pUsb->setAddr( 0, 0, bAddress );
110 
111  if (rcode)
112  {
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 = ((USB_DEVICE_DESCRIPTOR*)buf)->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++)
142  {
145 
146  rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump);
147  rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
148 
149  if (bNumEP > 1)
150  break;
151  } // for
152 
153  if (bNumEP < 2)
155 
156  USBTRACE2("NumEP:", bNumEP);
157 
158  // Assign epInfo to epinfo pointer
159  rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
160 
161  USBTRACE2("Conf:", bConfNum);
162 
163  // Set Configuration Value
164  rcode = pUsb->setConf(bAddress, 0, bConfNum);
165 
166  if (rcode)
167  goto FailSetConfDescr;
168 
169  rcode = pAsync->OnInit(this);
170 
171  if (rcode)
172  goto FailOnInit;
173 
174  USBTRACE("FTDI configured\r\n");
175 
176  bPollEnable = true;
177  return 0;
178 
179 FailGetDevDescr:
180  USBTRACE("getDevDescr:");
181  goto Fail;
182 
183 FailSetDevTblEntry:
184  USBTRACE("setDevTblEn:");
185  goto Fail;
186 
187 FailGetConfDescr:
188  USBTRACE("getConf:");
189  goto Fail;
190 
191 FailSetConfDescr:
192  USBTRACE("setConf:");
193  goto Fail;
194 
195 FailSetBaudRate:
196  USBTRACE("SetBaudRate:");
197  goto Fail;
198 
199 FailSetFlowControl:
200  USBTRACE("SetFlowControl:");
201  goto Fail;
202 
203 FailOnInit:
204  USBTRACE("OnInit:");
205  goto Fail;
206 
207 Fail:
208  Serial.println(rcode, HEX);
209  Release();
210  return rcode;
211 }
212 
213 
214 void FTDI::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep)
215 {
216  ErrorMessage<uint8_t>(PSTR("Conf.Val"), conf);
217  ErrorMessage<uint8_t>(PSTR("Iface Num"),iface);
218  ErrorMessage<uint8_t>(PSTR("Alt.Set"), alt);
219 
220  bConfNum = conf;
221 
222  uint8_t index;
223 
224  if ((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80)
225  index = epInterruptInIndex;
226  else
227  if ((pep->bmAttributes & 0x02) == 2)
228  index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex;
229  else
230  return;
231 
232  // Fill in the endpoint info structure
233  epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
234  epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
235  //epInfo[index].epAttribs = 0;
236 
237  bNumEP ++;
238 
239  PrintEndpointDescriptor(pep);
240 }
241 
242 uint8_t FTDI::Release()
243 {
244  pUsb->GetAddressPool().FreeAddress(bAddress);
245 
246  bAddress = 0;
247  bNumEP = 1;
248  qNextPollTime = 0;
249  bPollEnable = false;
250  return 0;
251 }
252 
253 uint8_t FTDI::Poll()
254 {
255  uint8_t rcode = 0;
256 
257  //if (!bPollEnable)
258  // return 0;
259 
260  //if (qNextPollTime <= millis())
261  //{
262  // Serial.println(bAddress, HEX);
263 
264  // qNextPollTime = millis() + 100;
265  //}
266  return rcode;
267 }
268 
269 uint8_t FTDI::SetBaudRate(uint32_t baud)
270 {
271  uint16_t baud_value, baud_index = 0;
272  uint32_t divisor3;
273 
274  divisor3 = 48000000 / 2 / baud; // divisor shifted 3 bits to the left
275 
276  if (wFTDIType == FT232AM)
277  {
278  if ((divisor3 & 0x7) == 7)
279  divisor3 ++; // round x.7/8 up to x+1
280 
281  baud_value = divisor3 >> 3;
282  divisor3 &= 0x7;
283 
284  if (divisor3 == 1) baud_value |= 0xc000; else // 0.125
285  if (divisor3 >= 4) baud_value |= 0x4000; else // 0.5
286  if (divisor3 != 0) baud_value |= 0x8000; // 0.25
287  if (baud_value == 1) baud_value = 0; /* special case for maximum baud rate */
288  }
289  else
290  {
291  static const unsigned char divfrac [8] = { 0, 3, 2, 0, 1, 1, 2, 3 };
292  static const unsigned char divindex[8] = { 0, 0, 0, 1, 0, 1, 1, 1 };
293 
294  baud_value = divisor3 >> 3;
295  baud_value |= divfrac [divisor3 & 0x7] << 14;
296  baud_index = divindex[divisor3 & 0x7];
297 
298  /* Deal with special cases for highest baud rates. */
299  if (baud_value == 1) baud_value = 0; else // 1.0
300  if (baud_value == 0x4001) baud_value = 1; // 1.5
301  }
302  USBTRACE2("baud_value:", baud_value);
303  USBTRACE2("baud_index:", baud_index);
304  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 );
305 }
306 
307 uint8_t FTDI::SetModemControl(uint16_t signal)
308 {
309  return pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_MODEM_CTRL, signal & 0xff, signal >> 8, 0, 0, 0, NULL, NULL);
310 }
311 
312 uint8_t FTDI::SetFlowControl(uint8_t protocol, uint8_t xon, uint8_t xoff)
313 {
314  return pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_SET_FLOW_CTRL, xon, xoff, protocol << 8, 0, 0, NULL, NULL);
315 }
316 
317 uint8_t FTDI::SetData(uint16_t databm)
318 {
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 {
324  return pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, dataptr);
325 }
326 
327 uint8_t FTDI::SndData(uint16_t nbytes, uint8_t *dataptr)
328 {
329  return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, nbytes, dataptr);
330 }
331 
332 void FTDI::PrintEndpointDescriptor( const USB_ENDPOINT_DESCRIPTOR* ep_ptr )
333 {
334  Notify(PSTR("Endpoint descriptor:"));
335  Notify(PSTR("\r\nLength:\t\t"));
336  PrintHex<uint8_t>(ep_ptr->bLength);
337  Notify(PSTR("\r\nType:\t\t"));
338  PrintHex<uint8_t>(ep_ptr->bDescriptorType);
339  Notify(PSTR("\r\nAddress:\t"));
340  PrintHex<uint8_t>(ep_ptr->bEndpointAddress);
341  Notify(PSTR("\r\nAttributes:\t"));
342  PrintHex<uint8_t>(ep_ptr->bmAttributes);
343  Notify(PSTR("\r\nMaxPktSize:\t"));
344  PrintHex<uint16_t>(ep_ptr->wMaxPacketSize);
345  Notify(PSTR("\r\nPoll Intrv:\t"));
346  PrintHex<uint8_t>(ep_ptr->bInterval);
347  Notify(PSTR("\r\n"));
348 }