Barst  2.0
A server that controls lab hardware.
ftdi device.cpp
1 
11 #include "base classses.h"
12 #include "named pipes.h"
13 #include "ftdi device.h"
14 #include "ftd2xx.h"
15 #include "misc tools.h"
16 #include <iostream>
17 
18 FT_STATUS (WINAPI *lpfFT_GetDeviceInfoList)(FT_DEVICE_LIST_INFO_NODE *pDest, LPDWORD lpdwNumDevs)= NULL;
19 FT_STATUS (WINAPI *lpfFT_CreateDeviceInfoList)(LPDWORD lpdwNumDevs)= NULL;
20 FT_STATUS (WINAPI *lpfFT_SetLatencyTimer)(FT_HANDLE ftHandle, UCHAR ucLatency)= NULL;
21 FT_STATUS (WINAPI *lpfFT_OpenEx)(PVOID pArg1, DWORD Flags, FT_HANDLE *pHandle)= NULL;
22 FT_STATUS (WINAPI *lpfFT_Close)(FT_HANDLE ftHandle)= NULL;
23 FT_STATUS (WINAPI *lpfFT_Read)(FT_HANDLE ftHandle, LPVOID lpBuffer, DWORD dwBytesToRead, LPDWORD lpBytesReturned)= NULL;
24 FT_STATUS (WINAPI *lpfFT_Write)(FT_HANDLE ftHandle, LPVOID lpBuffer, DWORD dwBytesToWrite, LPDWORD lpBytesWritten)= NULL;
25 FT_STATUS (WINAPI *lpfFT_SetBaudRate)(FT_HANDLE ftHandle, ULONG BaudRate)= NULL;
26 FT_STATUS (WINAPI *lpfFT_SetBitMode)(FT_HANDLE ftHandle, UCHAR ucMask, UCHAR ucEnable)= NULL;
27 FT_STATUS (WINAPI *lpfFT_Purge)(FT_HANDLE ftHandle, ULONG Mask)= NULL;
28 FT_STATUS (WINAPI *lpfFT_SetUSBParameters)(FT_HANDLE ftHandle, ULONG ulInTransferSize, ULONG ulOutTransferSize)= NULL;
29 FT_STATUS (WINAPI *lpfFT_CyclePort)(FT_HANDLE ftHandle)= NULL;
30 FT_STATUS (WINAPI *lpfFT_ResetPort)(FT_HANDLE ftHandle)= NULL;
31 FT_STATUS (WINAPI *lpf_FT_GetLibraryVersion)(LPDWORD lpdwVersion)= NULL;
32 
33 
34 
35 CManagerFTDI::CManagerFTDI(CComm* pcComm, const TCHAR szPipe[], int nChan, int &nError) :
36  CManager(FTDI_MAN_STR, std::tstring(szPipe), nChan)
37 {
38  nError= 0;
39  m_bError= true;
40  m_pcComm= NULL;
41  m_pcLogBuffer= NULL;
42  m_pcMemPool= new CMemPool;
43  m_hLib= NULL;
44 
45  if (!pcComm || !szPipe)
46  {
47  nError= BAD_INPUT_PARAMS;
48  return;
49  }
50  BOOL bRes= GetProcAddresses(&m_hLib, _T("ftd2xx.dll"), 14, &lpfFT_GetDeviceInfoList, "FT_GetDeviceInfoList",
51  &lpfFT_CreateDeviceInfoList, "FT_CreateDeviceInfoList",
52  &lpfFT_SetLatencyTimer, "FT_SetLatencyTimer", &lpfFT_OpenEx, "FT_OpenEx", &lpfFT_Close, "FT_Close",
53  &lpfFT_Read, "FT_Read", &lpfFT_Write, "FT_Write", &lpfFT_SetBaudRate, "FT_SetBaudRate", &lpfFT_SetBitMode, "FT_SetBitMode",
54  &lpfFT_Purge, "FT_Purge", &lpfFT_SetUSBParameters, "FT_SetUSBParameters", &lpfFT_CyclePort, "FT_CyclePort",
55  &lpfFT_ResetPort, "FT_ResetPort", &lpf_FT_GetLibraryVersion, "FT_GetLibraryVersion");
56  if (!bRes || !m_hLib)
57  {
58  nError= DRIVER_ERROR;
59  return;
60  }
61  DWORD dwVersion;
62  if ((nError= FT_ERROR(lpf_FT_GetLibraryVersion(&dwVersion), nError)) != 0)
63  return;
64  if (dwVersion < MIN_FTDI_LIB_VER)
65  {
66  nError= DRIVER_ERROR;
67  return;
68  }
69  m_dwNumDevs= 0;
70  m_bError= false;
71  m_pcComm= pcComm;
72 }
73 
74 DWORD CManagerFTDI::GetInfo(void* pHead, DWORD dwSize)
75 {
76  if (!pHead)
77  return sizeof(SBaseOut);
78  if (dwSize<sizeof(SBaseOut))
79  return 0;
80 
81  ((SBaseOut*)pHead)->sBaseIn.dwSize= sizeof(SBaseOut);
82  ((SBaseOut*)pHead)->sBaseIn.eType= eResponseEx;
83  ((SBaseOut*)pHead)->sBaseIn.nChan= m_nChan;
84  ((SBaseOut*)pHead)->sBaseIn.nError= 0;
85  ((SBaseOut*)pHead)->bActive= true;
86  _tcsncpy_s(((SBaseOut*)pHead)->szName, DEVICE_NAME_SIZE, m_csName.c_str(), _TRUNCATE);
87 
88  return sizeof(SBaseOut);
89 }
90 
91 CManagerFTDI::~CManagerFTDI()
92 {
93  for (size_t i= 0; i<m_acFTDevices.size(); ++i)
94  delete m_acFTDevices[i];
95  if (m_hLib != NULL)
96  FreeLibrary(m_hLib);
97  delete m_pcMemPool;
98 }
99 
100 void CManagerFTDI::ProcessData(const void *pHead, DWORD dwSize, __int64 llId)
101 {
102  if (m_bError)
103  return;
104  SBaseIn* pBase;
105  SData sData;
106  sData.pDevice= this;
107  SBaseIn sBase;
108  sBase.dwSize= sizeof(SBaseIn);
109  sBase.nChan= -1;
110  sBase.nError= 0;
111  bool bRes= true;
112  if (!pHead || dwSize < sizeof(SBaseIn) || dwSize != ((SBaseIn*)pHead)->dwSize) // incorrect size read
113  {
114  sBase.nError= SIZE_MISSMATCH;
115  } else if (((SBaseIn*)pHead)->eType == eQuery && dwSize == sizeof(SBaseIn)) // need info
116  {
117  bRes= false;
118  sBase.eType= eQuery;
119  if (((SBaseIn*)pHead)->nChan == -1) // send all devices if chan is -1
120  {
121 
122  sBase.nError= FT_ERROR(lpfFT_CreateDeviceInfoList(&m_dwNumDevs), sBase.nError); // reload deice list
123  if (!sBase.nError)
124  {
125  m_asFTChanInfo.assign(max(m_dwNumDevs, 1), FT_DEVICE_LIST_INFO_NODE());
126  sBase.nError= FT_ERROR(lpfFT_GetDeviceInfoList(&m_asFTChanInfo[0], &m_dwNumDevs), sBase.nError); // copy back device list from driver
127  if (!sBase.nError)
128  {
129  DWORD i= 0, dwInfoSize= 0;
130  std::vector<int> anDev;
131  anDev.assign(max(m_dwNumDevs, 1), -1);
132  // find the total size of the info
133  for (; i<m_dwNumDevs; ++i) // each device compare to opened device to see if requesting open device
134  {
135  m_asFTChanInfo[i].ftHandle= NULL; // so that we can compare
136  m_asFTChanInfo[i].Flags &= ~FT_FLAGS_OPENED; // reset this flag because initially unopened
137  memset(&m_asFTChanInfo[i].Description[strlen(m_asFTChanInfo[i].Description)], 0,
138  sizeof(m_asFTChanInfo[i].Description)-strlen(m_asFTChanInfo[i].Description));
139  memset(&m_asFTChanInfo[i].SerialNumber[strlen(m_asFTChanInfo[i].SerialNumber)], 0,
140  sizeof(m_asFTChanInfo[i].SerialNumber)-strlen(m_asFTChanInfo[i].SerialNumber));
141  int j= 0;
142  for (;j<m_acFTDevices.size(); ++j) // all open devices
143  {
144  if (m_acFTDevices[j]) // may be null
145  {
146  if (!memcmp(&m_asFTChanInfo[i], &m_acFTDevices[j]->m_FTInfo, sizeof(FT_DEVICE_LIST_INFO_NODE)))
147  {
148  anDev[i]= j; // this device is open
149  break;
150  }
151  }
152  }
153  if (anDev[i] == -1) // didn't find; un-opened channel
154  {
155  dwInfoSize+= sizeof(SBaseOut)+sizeof(SBase)+sizeof(FT_DEVICE_LIST_INFO_NODE_OS);
156  } else // get info from that channel
157  {
158  dwInfoSize+= m_acFTDevices[j]->GetInfo(NULL, 0);
159  }
160  }
161  i= 0;
162  // now copy the info
163  if (dwInfoSize)
164  {
165  dwInfoSize+= sizeof(SBaseIn);
166  pBase= (SBaseIn*)m_pcMemPool->PoolAcquire(dwInfoSize);
167  SBaseOut* pBaseO= (SBaseOut*)((char*)pBase+sizeof(SBaseIn)); // current position
168  if(pBase)
169  {
170  memset(pBase, 0, dwInfoSize);
171  for (; i<m_dwNumDevs; ++i)
172  {
173  if (anDev[i] == -1) // didn't find, un-opened channel
174  {
175  pBaseO->sBaseIn.dwSize= sizeof(SBaseOut)+sizeof(SBase)+sizeof(FT_DEVICE_LIST_INFO_NODE_OS);
176  pBaseO->sBaseIn.eType= eResponseEx;
177  pBaseO->sBaseIn.nChan= -1;
178  SBase* pBaseS= (SBase*)(++pBaseO);
179  pBaseS->dwSize= sizeof(SBase)+sizeof(FT_DEVICE_LIST_INFO_NODE_OS);
180  pBaseS->eType= eFTDIChan;
181  memcpy(++pBaseS, &m_asFTChanInfo[i], sizeof(FT_DEVICE_LIST_INFO_NODE));
182  pBaseO= (SBaseOut*)((char*)pBaseS+sizeof(FT_DEVICE_LIST_INFO_NODE_OS));
183  } else // get info from that channel
184  {
185  m_acFTDevices[anDev[i]]->GetInfo(pBaseO, dwInfoSize-(int)((char*)pBaseO-(char*)pBase));
186  pBaseO= (SBaseOut*)((char*)pBaseO+m_acFTDevices[anDev[i]]->GetInfo(NULL, 0));
187  }
188  }
189  pBase->dwSize= dwInfoSize;
190  pBase->eType= eQuery;
191  pBase->nChan= -1;
192  pBase->nError= 0;
193  sData.dwSize= dwInfoSize;
194  sData.pHead= pBase;
195  m_pcComm->SendData(&sData, llId);
196  }
197  } else
198  sBase.nError= NO_CHAN;
199  }
200  }
201  } else if (((SBaseIn*)pHead)->nChan < 0 || ((SBaseIn*)pHead)->nChan >= m_acFTDevices.size() ||
202  !m_acFTDevices[((SBaseIn*)pHead)->nChan]) // invalid channel
203  {
204  sBase.nError= INVALID_CHANN;
205  } else // send info on particular chann
206  {
207  DWORD dwSizeInfo= m_acFTDevices[((SBaseIn*)pHead)->nChan]->GetInfo(NULL, 0);
208  pBase= (SBaseIn*)m_pcMemPool->PoolAcquire(dwSizeInfo);
209  if (pBase)
210  {
211  m_acFTDevices[((SBaseIn*)pHead)->nChan]->GetInfo(pBase, dwSizeInfo);
212  sData.dwSize= dwSizeInfo;
213  sData.pHead= pBase;
214  m_pcComm->SendData(&sData, llId);
215  }
216  }
217  } else if (dwSize == sizeof(SBaseIn) && ((SBaseIn*)pHead)->eType == eDelete) // delete a channel
218  {
219  sBase.eType= eDelete;
220  if (((SBaseIn*)pHead)->nChan < 0 || ((SBaseIn*)pHead)->nChan >= m_acFTDevices.size() ||
221  !m_acFTDevices[((SBaseIn*)pHead)->nChan])
222  sBase.nError= INVALID_CHANN;
223  else
224  {
225  delete m_acFTDevices[((SBaseIn*)pHead)->nChan];
226  m_acFTDevices[((SBaseIn*)pHead)->nChan]= NULL;
227  sBase.nChan= ((SBaseIn*)pHead)->nChan;
228  }
229  } else if (dwSize == sizeof(SBaseIn) && ((SBaseIn*)pHead)->eType == eVersion &&
230  ((SBaseIn*)pHead)->nChan == -1) // delete a channel
231  {
232  sBase.nError= FT_ERROR(lpf_FT_GetLibraryVersion(&sBase.dwInfo), sBase.nError);
233  sBase.eType= eVersion;
234  } else if (((SBaseIn*)pHead)->nChan >= 0 && ((SBaseIn*)pHead)->nChan < (int)m_dwNumDevs &&
235  ((SBaseIn*)pHead)->eType == eSet && ((SBaseIn*)pHead)->dwSize > sizeof(SBaseIn)+sizeof(SBase)+
236  sizeof(SChanInitFTDI) && ((SBase*)((char*)pHead+sizeof(SBaseIn)))->eType == eFTDIChanInit) // set a channel
237  {
238  bRes= false;
239  sBase.eType= eSet;
240  int i= 0;
241  LARGE_INTEGER llStart;
242  for (; i<m_acFTDevices.size() && m_acFTDevices[i]; ++i); // get index where we add new channel
243  if (i == m_acFTDevices.size())
244  m_acFTDevices.push_back(NULL);
245 
246  std::tstringstream ss; // ftdi channel
247  ss<<i;
248  std::tstringstream ss2; // ftdi manager index
249  ss2<<m_nChan;
250  std::tstring csPipeName= m_csPipeName+_T(":")+ss2.str()+_T(":")+ss.str(); // new channel pipe name
251  //SChanInitFTDI sChan= *(SChanInitFTDI*)((char*)pHead+sizeof(SBaseIn));
252  CChannelFTDI* pcChan= new CChannelFTDI(*(SChanInitFTDI*)((char*)pHead+sizeof(SBase)+sizeof(SBaseIn)),
253  (SBase*)((char*)pHead+sizeof(SBase)+sizeof(SBaseIn)+sizeof(SChanInitFTDI)),
254  dwSize-sizeof(SBase)-sizeof(SBaseIn)-sizeof(SChanInitFTDI),
255  m_asFTChanInfo[((SBaseIn*)pHead)->nChan], csPipeName.c_str(), i, sBase.nError, llStart);
256  if (!sBase.nError)
257  {
258  m_acFTDevices[i]= pcChan;
259  SBaseOut* pBaseO= (SBaseOut*)m_pcMemPool->PoolAcquire(sizeof(SBaseOut));
260  if (pBaseO)
261  {
262  pBaseO->sBaseIn.dwSize= sizeof(SBaseOut);
263  pBaseO->sBaseIn.eType= eResponseExL;
264  pBaseO->sBaseIn.nChan= i;
265  pBaseO->sBaseIn.nError= 0;
266  pBaseO->llLargeInteger= llStart;
267  pBaseO->bActive= true;
268  sData.pHead= pBaseO;
269  sData.dwSize= sizeof(SBaseOut);
270  m_pcComm->SendData(&sData, llId);
271  }
272  } else
273  delete pcChan;
274  } else
275  sBase.nError= INVALID_COMMAND;
276 
277  if (sBase.nError || bRes)
278  {
279  sData.pHead= (SBaseIn*)m_pcMemPool->PoolAcquire(sizeof(SBaseIn));
280  if (sData.pHead)
281  {
282  sData.dwSize= sizeof(SBaseIn);
283  memcpy(sData.pHead, &sBase, sizeof(SBaseIn));
284  m_pcComm->SendData(&sData, llId);
285  }
286  }
287 }
288 
289 
290 
291 
292 
293 DWORD WINAPI FTChanProc(LPVOID lpParameter)
294 {
295  // Call ThreadProc function of ftdi channel
296  return ((CChannelFTDI*)lpParameter)->ThreadProc();
297 }
298 
299 CChannelFTDI::CChannelFTDI(SChanInitFTDI &sChanInit, SBase* pInit, DWORD dwSize, FT_DEVICE_LIST_INFO_NODE &sFTInfo,
300  const TCHAR szPipe[], int nChan, int &nError, LARGE_INTEGER &llStart) : CDevice(FTDI_CHAN_STR), m_FTInfo(sFTInfo),
301  m_csPipeName(szPipe), m_hUpdate(CreateEvent(NULL,TRUE, TRUE, NULL)), m_asUpdates(m_hUpdate), m_sChanInit(sChanInit),
302  m_nChan(nChan)
303 {
304  m_bError= true;
305  m_ftHandle= NULL;
306  m_hStop= NULL;
307  m_hNext= NULL;
308  m_hThread= NULL;
309  m_aucTx= NULL;
310  m_pcComm= NULL;
311  m_pcMemPool= new CMemPool;
312  m_pcMemRing = NULL;
313 
314  nError= 0;
315 
316  if (!pInit || !szPipe)
317  {
318  nError= BAD_INPUT_PARAMS;
319  return;
320  }
321 
322  // open device by loc
323  nError= FT_ERROR(lpfFT_OpenEx((PVOID)m_FTInfo.LocId, FT_OPEN_BY_LOCATION, &m_ftHandle), nError);
324  if (nError)
325  return;
326  // shouldn't ever need to time out
327  nError= FT_ERROR(lpfFT_SetLatencyTimer(m_ftHandle, 255), nError);
328  if (nError)
329  return;
330 
331  m_hStop= CreateEvent(NULL, TRUE, FALSE, NULL);
332  m_hNext= CreateEvent(NULL, TRUE, FALSE, NULL);
333  if (!m_hStop || !m_hNext || !m_hUpdate)
334  {
335  nError= NO_SYS_RESOURCE;
336  return;
337  }
338  m_ahEvents.push_back(m_hStop);
339  m_ahEvents.push_back(m_hUpdate);
340  m_ahEvents.push_back(m_hNext);
341 
342 
343  SInitPeriphFT sPeriphInit;
344  SBase *pBase= pInit;
345  DWORD dwMaxWrite= 0; // XXX: if we ever read more than write we will have to verify that it's large enough (since we equate them later).
346  bool bPadd= false; // if we pad r/w packets to match 62/510 boundries
347  // writing multiples of 510/62 makes it faster
348  const DWORD dwPacket= sFTInfo.Flags&FT_FLAGS_HISPEED ? 510 : 62;
349  // the max size we can ever write
350  const DWORD dwMaxPacket= sFTInfo.Flags&FT_FLAGS_HISPEED ? FTDI_MAX_BUFF_H : FTDI_MAX_BUFF_L;
351  DWORD dwBuffSizeRead= sChanInit.dwBuffIn;
352  DWORD dwBuffSizeWrite= sChanInit.dwBuffOut;
353  // we first need to find the max write buffer so we can pass it to all devices
354  // at each step we make sure dwMaxWrite doesn't become larger than dwMaxPacket
355  while ((char*)pBase + sizeof(SBase) <= (char*)pInit + dwSize)
356  {
357  switch (pBase->eType)
358  {
359  case eFTDIMultiWriteInit:
360  if ((char*)pBase + pBase->dwSize <= (char*)pInit + dwSize && pBase->dwSize == sizeof(SValveInit)+sizeof(SBase))
361  {
362  SValveInit* psValveInit= (SValveInit*)++pBase;
363  dwMaxWrite= max((psValveInit->dwBoards*8*2+2)*psValveInit->dwClkPerData, dwMaxWrite);
364  dwBuffSizeRead= max(dwBuffSizeRead, psValveInit->dwBoards*8*sizeof(bool));
365  pBase= (SBase*)((char*)pBase +sizeof(SValveInit));
366  bPadd = true;
367  if ((psValveInit->dwBoards*8*2+2)*psValveInit->dwClkPerData > dwMaxPacket)
368  {
369  nError= BUFF_TOO_SMALL;
370  return;
371  }
372  } else
373  {
374  nError= SIZE_MISSMATCH;
375  return;
376  }
377  break;
378  case eFTDIMultiReadInit:
379  if ((char*)pBase + pBase->dwSize <= (char*)pInit + dwSize && pBase->dwSize == sizeof(SValveInit)+sizeof(SBase))
380  {
381  SValveInit* psValveInit= (SValveInit*)++pBase;
382  dwMaxWrite= max((psValveInit->dwBoards*8*2+2+4)*psValveInit->dwClkPerData, dwMaxWrite);
383  dwBuffSizeWrite= max(dwBuffSizeWrite, psValveInit->dwBoards*8*sizeof(bool));
384  pBase= (SBase*)((char*)pBase +sizeof(SValveInit));
385  bPadd= true;
386  if ((psValveInit->dwBoards*8*2+2+4)*psValveInit->dwClkPerData > dwMaxPacket)
387  {
388  nError= BUFF_TOO_SMALL;
389  return;
390  }
391  } else
392  {
393  nError= SIZE_MISSMATCH;
394  return;
395  }
396  break;
397  case eFTDIPinWriteInit:
398  if ((char*)pBase + pBase->dwSize <= (char*)pInit + dwSize && pBase->dwSize == sizeof(SPinInit)+sizeof(SBase))
399  {
400  SPinInit* psPinInit= (SPinInit*)++pBase;
401  dwMaxWrite= max(psPinInit->usBytesUsed, dwMaxWrite);
402  dwBuffSizeRead= max(dwBuffSizeRead, psPinInit->usBytesUsed*sizeof(SPinWData));
403  pBase= (SBase*)((char*)pBase +sizeof(SPinInit));
404  bPadd = true;
405  if (psPinInit->usBytesUsed > dwMaxPacket)
406  {
407  nError= BUFF_TOO_SMALL;
408  return;
409  }
410  } else
411  {
412  nError= SIZE_MISSMATCH;
413  return;
414  }
415  break;
416  case eFTDIPinReadInit:
417  if ((char*)pBase + pBase->dwSize <= (char*)pInit + dwSize && pBase->dwSize == sizeof(SPinInit)+sizeof(SBase))
418  {
419  SPinInit* psPinInit= (SPinInit*)++pBase;
420  dwMaxWrite= max(psPinInit->usBytesUsed, dwMaxWrite);
421  dwBuffSizeWrite= max(dwBuffSizeWrite, psPinInit->usBytesUsed);
422  pBase= (SBase*)((char*)pBase +sizeof(SPinInit));
423  bPadd= true;
424  if (psPinInit->usBytesUsed > dwMaxPacket)
425  {
426  nError= BUFF_TOO_SMALL;
427  return;
428  }
429  } else
430  {
431  nError= SIZE_MISSMATCH;
432  return;
433  }
434  break;
435  case eFTDIADCInit:
436  if ((char*)pBase + pBase->dwSize <= (char*)pInit + dwSize && pBase->dwSize == sizeof(SADCInit)+sizeof(SBase))
437  {
438  ++pBase;
439  SADCInit* sADCInit= (SADCInit*)pBase;
440  if (sADCInit->fUSBBuffToUse >= 100.0)
441  dwMaxWrite= max(dwMaxPacket, dwMaxWrite);
442  else if (sADCInit->fUSBBuffToUse/100 <= 3*(float)dwPacket/(float)dwMaxPacket)
443  dwMaxWrite= max(max(90, 3*dwPacket), dwMaxWrite);
444  else
445  dwMaxWrite= max((DWORD)ceil(sADCInit->fUSBBuffToUse/100*dwMaxPacket)-(DWORD)ceil(sADCInit->fUSBBuffToUse/100*dwMaxPacket)%dwPacket, dwMaxWrite);
446  bPadd= true;
447  pBase= (SBase*)((char*)pBase +sizeof(SADCInit));
448  dwBuffSizeWrite= max(dwBuffSizeWrite, sizeof(SADCInit)+sizeof(DWORD)*sADCInit->dwDataPerTrans*(sADCInit->bChan2&&sADCInit->bChan1?2:1));
449  } else
450  {
451  nError= SIZE_MISSMATCH;
452  return;
453  }
454  break;
455  default:
456  nError= INVALID_DEVICE;
457  return;
458  }
459  }
460  if (bPadd) // align to 510/62
461  dwMaxWrite= dwPacket*(DWORD)ceil((double)dwMaxWrite/dwPacket);
462 
463  m_pcComm= new CPipeServer; // our pipe over which comm to devices will occur
464  nError= static_cast<CPipeServer*>(m_pcComm)->Init(szPipe, ~0x80000000, dwBuffSizeRead+MIN_BUFF_IN,
465  dwBuffSizeWrite+MIN_BUFF_OUT, this, NULL);
466  if (nError)
467  return;
468 
469  // now we decode which devices to create and verify them
470  // ADC buffer size MUST be as large as dwBuff, i.e. it must be the largest user
471  pBase= (SBase*)pInit;
472  HANDLE hEvent;
473  while ((char*)pBase + sizeof(SBase) <= (char*)pInit + dwSize)
474  {
475  switch (pBase->eType)
476  {
477  case eFTDIMultiWriteInit:
478  {
479  SValveInit sValveInit= *(SValveInit*)(++pBase);
480  sPeriphInit.dwMinSizeW= dwPacket*(DWORD)ceil((sValveInit.dwBoards*8*2+2)*sValveInit.dwClkPerData/(double)dwPacket);
481  sPeriphInit.dwMinSizeR= sPeriphInit.dwMinSizeW;
482  sPeriphInit.nChan= (int)m_aDevices.size();
483  sPeriphInit.ucBitMode= FT_BITMODE_SYNC_BITBANG;
484  switch(sFTInfo.Type)
485  {
486  case FT_DEVICE_2232H:
487  sPeriphInit.dwMaxBaud= FTDI_BAUD_2232H; // 1MHz/5
488  break;
489  default:
490  sPeriphInit.dwMaxBaud= FTDI_BAUD_DEFAULT; // 1MHz/16
491  break;
492  }
493  sPeriphInit.ucBitOutput= 1<<sValveInit.ucLatch|1<<sValveInit.ucClk|1<<sValveInit.ucData;
494  sPeriphInit.dwBuff= dwMaxWrite;
495  hEvent= CreateEvent(NULL,TRUE, FALSE, NULL);
496  m_ahEvents.push_back(hEvent);
497  m_aDevices.push_back(new CMultiWPeriph(sValveInit, m_pcComm, sPeriphInit, nError, hEvent, &m_cTimer));
498  if (nError)
499  return;
500  pBase= (SBase*)((char*)pBase +sizeof(SValveInit));
501  break;
502  }
503  case eFTDIMultiReadInit:
504  {
505  SValveInit sValveInit= *(SValveInit*)(++pBase);
506  sPeriphInit.dwMinSizeR= dwPacket*(DWORD)ceil((sValveInit.dwBoards*8*2+2+4)*sValveInit.dwClkPerData/(double)dwPacket);
507  sPeriphInit.dwMinSizeW= sPeriphInit.dwMinSizeR;
508  sPeriphInit.nChan= (int)m_aDevices.size();
509  sPeriphInit.ucBitMode= FT_BITMODE_SYNC_BITBANG;
510  switch(sFTInfo.Type)
511  {
512  case FT_DEVICE_2232H:
513  sPeriphInit.dwMaxBaud= FTDI_BAUD_2232H; // 1MHz/5
514  break;
515  default:
516  sPeriphInit.dwMaxBaud= FTDI_BAUD_DEFAULT; // 1MHz/16
517  break;
518  }
519  sPeriphInit.ucBitOutput= 1<<sValveInit.ucLatch|1<<sValveInit.ucClk;
520  sPeriphInit.dwBuff= dwMaxWrite;
521  hEvent= CreateEvent(NULL,TRUE, FALSE, NULL);
522  m_ahEvents.push_back(hEvent);
523  m_aDevices.push_back(new CMultiRPeriph(sValveInit, m_pcComm, sPeriphInit, nError, hEvent, &m_cTimer));
524  if (nError)
525  return;
526  pBase= (SBase*)((char*)pBase +sizeof(SValveInit));
527  break;
528  }
529  case eFTDIPinWriteInit:
530  {
531  SPinInit sPinInit= *(SPinInit*)(++pBase);
532  sPeriphInit.dwMinSizeW= dwPacket*(DWORD)ceil(sPinInit.usBytesUsed/(double)dwPacket);
533  sPeriphInit.dwMinSizeR= sPeriphInit.dwMinSizeW;
534  sPeriphInit.nChan= (int)m_aDevices.size();
535  sPeriphInit.ucBitMode= FT_BITMODE_SYNC_BITBANG;
536  switch(sFTInfo.Type)
537  {
538  case FT_DEVICE_2232H:
539  sPeriphInit.dwMaxBaud= FTDI_BAUD_2232H; // 1MHz/5
540  break;
541  default:
542  sPeriphInit.dwMaxBaud= FTDI_BAUD_DEFAULT; // 1MHz/16
543  break;
544  }
545  sPeriphInit.ucBitOutput= sPinInit.ucActivePins;
546  sPeriphInit.dwBuff= dwMaxWrite;
547  hEvent= CreateEvent(NULL,TRUE, FALSE, NULL);
548  m_ahEvents.push_back(hEvent);
549  m_aDevices.push_back(new CPinWPeriph(sPinInit, m_pcComm, sPeriphInit, nError, hEvent, &m_cTimer));
550  if (nError)
551  return;
552  pBase= (SBase*)((char*)pBase +sizeof(SPinInit));
553  break;
554  }
555  case eFTDIPinReadInit:
556  {
557  SPinInit sPinInit= *(SPinInit*)(++pBase);
558  sPeriphInit.dwMinSizeR= dwPacket*(DWORD)ceil(sPinInit.usBytesUsed/(double)dwPacket);
559  sPeriphInit.dwMinSizeW= sPeriphInit.dwMinSizeR;
560  sPeriphInit.nChan= (int)m_aDevices.size();
561  sPeriphInit.ucBitMode= FT_BITMODE_SYNC_BITBANG;
562  switch(sFTInfo.Type)
563  {
564  case FT_DEVICE_2232H:
565  sPeriphInit.dwMaxBaud= FTDI_BAUD_2232H; // 1MHz/5
566  break;
567  default:
568  sPeriphInit.dwMaxBaud= FTDI_BAUD_DEFAULT; // 1MHz/16
569  break;
570  }
571  sPeriphInit.ucBitOutput= 0;
572  sPeriphInit.dwBuff= dwMaxWrite;
573  hEvent= CreateEvent(NULL,TRUE, FALSE, NULL);
574  m_ahEvents.push_back(hEvent);
575  m_aDevices.push_back(new CPinRPeriph(sPinInit, m_pcComm, sPeriphInit, nError, hEvent, &m_cTimer));
576  if (nError)
577  return;
578  pBase= (SBase*)((char*)pBase +sizeof(SPinInit));
579  break;
580  }
581  case eFTDIADCInit:
582  {
583  SADCInit sADCInit= *(SADCInit*)(++pBase);
584  sPeriphInit.dwBuff= dwMaxWrite;
585  sPeriphInit.dwMinSizeR= dwMaxWrite;
586  sPeriphInit.dwMinSizeW= dwMaxWrite;
587  sPeriphInit.nChan= (int)m_aDevices.size();
588  sPeriphInit.ucBitMode= FT_BITMODE_SYNC_BITBANG;
589  switch(sFTInfo.Type)
590  {
591  case FT_DEVICE_2232H:
592  sPeriphInit.dwMaxBaud= FTDI_BAUD_2232H; // 1MHz/5
593  break;
594  default:
595  sPeriphInit.dwMaxBaud= FTDI_BAUD_DEFAULT; // 1MHz/16
596  break;
597  }
598  sPeriphInit.ucBitOutput = 1<<sADCInit.ucClk;
599  hEvent= CreateEvent(NULL,TRUE, FALSE, NULL);
600  m_ahEvents.push_back(hEvent);
601  m_aDevices.push_back(new CADCPeriph(sADCInit, m_pcComm, sPeriphInit, hEvent, nError, &m_cTimer));
602  if (nError)
603  return;
604  pBase= (SBase*)((char*)pBase +sizeof(SADCInit));
605  break;
606  }
607  default:
608  nError= INVALID_DEVICE;
609  return;
610  }
611  }
612  if (!m_aDevices.size()) // no devcies added
613  {
614  nError= NO_CHAN;
615  return;
616  }
617  // we cannot wait on more events
618  if (m_ahEvents.size() > MAXIMUM_WAIT_OBJECTS)
619  {
620  nError= NO_SYS_RESOURCE;
621  return;
622  }
623 
624  // verify values
625  unsigned char ucMode= 0xFF;
626  DWORD dwWrite= 0, dwRead= 0;
627  for (DWORD i= 0; i<m_aDevices.size(); ++i)
628  {
629  ucMode &= m_aDevices[i]->m_sInitFT.ucBitMode;
630  dwWrite= max(m_aDevices[i]->m_sInitFT.dwMinSizeW, dwWrite);
631  dwRead= max(m_aDevices[i]->m_sInitFT.dwMinSizeR, dwRead);
632  }
633  ucMode= ucMode&(~ucMode+1); // lowest bit (async bit bang mode preffered)
634  if (ucMode&FT_BITMODE_SYNC_BITBANG) // if Read is less than write (for diff devices), in combo read might be less than write in bit bang mode
635  {
636  dwWrite= max(dwWrite, dwRead);
637  dwRead= dwWrite;
638  }
639  // at least one output mode (sync/async bit bang..., )
640  if (!ucMode || dwRead>dwMaxPacket || dwWrite>dwMaxPacket || !dwWrite ||
641  (dwRead && !dwWrite))
642  {
643  nError= BAD_INPUT_PARAMS;
644  return;
645  }
646  // we never read without writing
647  if (dwWrite)
648  {
649  m_aucTx= (unsigned char*)m_pcMemPool->PoolAcquire(dwWrite);
650  if (!m_aucTx)
651  {
652  nError= NO_SYS_RESOURCE;
653  return;
654  }
655  memset(m_aucTx, 0, dwWrite);
656  }
657  if (dwRead)
658  {
659  m_pcMemRing = new CMemRing(dwRead+2, 1, 100);
660  int nIdx;
661  if (!m_pcMemRing->GetFree(&nIdx)) // make sure at least one buffer is available
662  {
663  nError= NO_SYS_RESOURCE;
664  return;
665  }
666  for (int i = 0; i < m_aDevices.size(); ++i)
667  m_aDevices[i]->m_pcMemRing = m_pcMemRing;
668  }
669 
670  DWORD dwBaud = FTDI_BAUD_2232H;
671  for (DWORD i= 0; i<m_aDevices.size(); ++i)
672  {
673  dwBaud= min(m_aDevices[i]->m_sInitFT.dwMaxBaud, dwBaud);
674  }
675  m_sChanInit.dwBaud = 0;
676  if (sChanInit.dwBaud)
677  m_sChanInit.dwBaud = min(dwBaud, sChanInit.dwBaud);
678  m_sChanInit.dwBuffIn = dwBuffSizeRead + MIN_BUFF_IN;
679  m_sChanInit.dwBuffOut = dwBuffSizeWrite + MIN_BUFF_OUT;
680 
681  m_hThread= CreateThread(NULL, 0, FTChanProc, this, 0, NULL);
682  if (!m_hThread)
683  {
684  nError= NO_SYS_RESOURCE;
685  return;
686  }
687  llStart= m_cTimer.GetStart();
688  m_bError= false;
689 }
690 
691 DWORD CChannelFTDI::GetInfo(void* pHead, DWORD dwSize)
692 {
693  if (!pHead)
694  return 2*sizeof(SBaseOut)+2*sizeof(SBase)+sizeof(FT_DEVICE_LIST_INFO_NODE_OS)+sizeof(SChanInitFTDI);
695  if (dwSize<2*sizeof(SBaseOut)+2*sizeof(SBase)+sizeof(FT_DEVICE_LIST_INFO_NODE_OS)+sizeof(SChanInitFTDI))
696  return 0;
697 
698  ((SBaseOut*)pHead)->sBaseIn.dwSize= 2*sizeof(SBaseOut)+2*sizeof(SBase)+sizeof(FT_DEVICE_LIST_INFO_NODE_OS)+sizeof(SChanInitFTDI);
699  ((SBaseOut*)pHead)->sBaseIn.eType= eResponseEx;
700  ((SBaseOut*)pHead)->sBaseIn.nChan= m_nChan;
701  ((SBaseOut*)pHead)->sBaseIn.nError= 0;
702  ((SBaseOut*)pHead)->bActive= true;
703  _tcsncpy_s(((SBaseOut*)pHead)->szName, DEVICE_NAME_SIZE, m_csName.c_str(), _TRUNCATE);
704  pHead= (char*)pHead + sizeof(SBaseOut);
705 
706  ((SBaseOut*)pHead)->sBaseIn.dwSize = sizeof(SBaseOut);
707  ((SBaseOut*)pHead)->sBaseIn.eType = eResponseExL;
708  ((SBaseOut*)pHead)->sBaseIn.nChan = m_nChan;
709  ((SBaseOut*)pHead)->sBaseIn.nError = 0;
710  ((SBaseOut*)pHead)->bActive = true;
711  ((SBaseOut*)pHead)->llLargeInteger = m_cTimer.GetStart();
712  pHead = (char*)pHead + sizeof(SBaseOut);
713 
714  ((SBase*)pHead)->dwSize= sizeof(FT_DEVICE_LIST_INFO_NODE_OS)+sizeof(SBase);
715  ((SBase*)pHead)->eType= eFTDIChan;
716  pHead= (char*)pHead+ sizeof(SBase);
717  memcpy(pHead, &m_FTInfo, sizeof(FT_DEVICE_LIST_INFO_NODE));
718  pHead= (char*)pHead+ sizeof(FT_DEVICE_LIST_INFO_NODE_OS);
719 
720  ((SBase*)pHead)->dwSize= sizeof(SChanInitFTDI)+sizeof(SBase);
721  ((SBase*)pHead)->eType= eFTDIChanInit;
722  pHead= (char*)pHead+ sizeof(SBase);
723  memcpy(pHead, &m_sChanInit, sizeof(SChanInitFTDI));
724 
725  return 2*sizeof(SBaseOut)+2*sizeof(SBase)+sizeof(FT_DEVICE_LIST_INFO_NODE_OS)+sizeof(SChanInitFTDI);
726 }
727 
728 CChannelFTDI::~CChannelFTDI()
729 {
730  if (m_hThread && (WAIT_OBJECT_0 != SignalObjectAndWait(m_hStop, m_hThread, 2000, FALSE)))
731  TerminateThread(m_hThread, 0);
732  if (m_pcComm) m_pcComm->Close(); // turn off but don't delete comm so that we can safley delete devices b/c they might call comm when closing
733  for(DWORD i= 0; i<m_aDevices.size(); ++i)
734  delete m_aDevices[i];
735  delete m_pcComm;
736  if (m_hStop) CloseHandle(m_hStop);
737  if (m_hNext) CloseHandle(m_hNext);
738  if (m_hUpdate) CloseHandle(m_hUpdate);
739  for (size_t i= 3; i<m_ahEvents.size(); ++i)
740  if (m_ahEvents[i])
741  CloseHandle(m_ahEvents[i]);
742  if (m_hThread) CloseHandle(m_hThread);
743  lpfFT_Close(m_ftHandle);
744  if (m_pcMemPool && m_aucTx) m_pcMemPool->PoolRelease(m_aucTx);
745  delete m_pcMemPool;
746  delete m_pcMemRing;
747 }
748 
749 void CChannelFTDI::ProcessData(const void *pHead, DWORD dwSize, __int64 llId)
750 {
751  if (m_bError)
752  return;
753  int nError= 0;
754  SBaseIn* pBase= (SBaseIn*)pHead;
755  if (!pBase || dwSize < sizeof(SBaseIn) || dwSize != pBase->dwSize) // incorrect size read
756  nError= SIZE_MISSMATCH;
757  else if (pBase->nChan >= (int)m_aDevices.size() || (pBase->nChan < 0 && pBase->eType != eQuery))
758  nError= INVALID_CHANN;
759  else if (!(((pBase->eType == eActivate || pBase->eType == eInactivate || pBase->eType == eQuery) && dwSize == sizeof(SBaseIn)) ||
760  pBase->eType == ePassOn))
761  nError= INVALID_COMMAND;
762 
763  SData sData;
764  sData.pDevice= this;
765  sData.dwSize= sizeof(SBaseIn);
766  if (nError) // bad read
767  {
768  pBase= (SBaseIn*)m_pcMemPool->PoolAcquire(sData.dwSize);
769  if (pBase)
770  {
771  pBase->dwSize= sizeof(SBaseIn);
772  pBase->eType= eResponse;
773  pBase->nChan= -1;
774  pBase->nError= nError;
775  sData.pHead= pBase;
776  m_pcComm->SendData(&sData, llId);
777  }
778  }
779  else if (pBase->eType == ePassOn) // pass it on top device
780  m_aDevices[pBase->nChan]->ProcessData((char*)pHead+sizeof(SBaseIn), dwSize-sizeof(SBaseIn), llId);
781  else if (pBase->eType == eQuery) // send back info on devices
782  {
783  if (pBase->nChan < 0) // general chan info
784  {
785  sData.dwSize= GetInfo(NULL, 0);
786  sData.pHead= m_pcMemPool->PoolAcquire(sData.dwSize);
787  if (sData.pHead && GetInfo(sData.pHead, sData.dwSize) == sData.dwSize)
788  m_pcComm->SendData(&sData, llId);
789 
790  } else // specific chan info
791  {
792  sData.dwSize= m_aDevices[pBase->nChan]->GetInfo(NULL, 0);
793  sData.pHead= m_pcMemPool->PoolAcquire(sData.dwSize);
794  if (sData.pHead && m_aDevices[pBase->nChan]->GetInfo(sData.pHead, sData.dwSize) == sData.dwSize)
795  m_pcComm->SendData(&sData, llId);
796  }
797  }
798  else // start or stop device, respond with ok
799  {
800  pBase= (SBaseIn*)m_pcMemPool->PoolAcquire(sData.dwSize);
801  if (pBase)
802  {
803  pBase->dwSize= sizeof(SBaseIn);
804  pBase->eType= ((SBaseIn*)pHead)->eType;
805  pBase->nChan= ((SBaseIn*)pHead)->nChan;
806  pBase->nError= 0;
807  sData.pHead= pBase;
808  SFTUpdates sUp;
809  sUp.llId= llId;
810  sUp.sData= sData;
811  m_asUpdates.Push(sUp);
812  }
813  }
814 }
815 
816 DWORD CChannelFTDI::ThreadProc()
817 {
818  bool bUpdating= false, bNotEmpty;
819  DWORD dwWrite, dwRead= 0, dwBytes, dwBaud, dwROld= 0, dwRes;
820  int nError= 0, nIdx;
821  bool bDone= false;
822  unsigned char ucMode= 0, ucOutput= 0, ucModeOld= 0, ucOutputOld;
823  const DWORD dwPacket= m_FTInfo.Flags&FT_FLAGS_HISPEED ? 510 : 62;
824  void *pHead;
825  SetEvent(m_hUpdate);
826 
827  while (!bDone)
828  {
829  switch (dwRes= WaitForMultipleObjects((DWORD)m_ahEvents.size(), &m_ahEvents[0], FALSE, INFINITE))
830  {
831  case WAIT_OBJECT_0: // m_hStop
832  bDone= true;
833  break;
834  case WAIT_OBJECT_0 + 1: // m_hUpdate, either error, something added to updates or finished updating
835  if (nError) // need to recover device, previous write would have notified of error to source
836  {
837  if (lpfFT_ResetPort(m_ftHandle)) // failed, try full cycle
838  lpfFT_CyclePort(m_ftHandle);
839  lpfFT_Close(m_ftHandle); // either way close and open again
840  if (lpfFT_OpenEx((PVOID)m_FTInfo.LocId, FT_OPEN_BY_LOCATION, &m_ftHandle)) // keep trying until canceled or success
841  {
842  Sleep(100);
843  break;
844  }
845  lpfFT_SetLatencyTimer(m_ftHandle, 255);
846  ucMode= 0;
847  dwROld= 0;
848  nError= 0;
849  dwRead= 0;
850  for (DWORD i= 0; i<m_aDevices.size(); ++i)
851  m_aDevices[i]->DoWork(NULL, 0, m_ftHandle, eRecover, 0);
852  }
853  while (m_asUpdates.GetSize()) // apply user updates, i.e. activate or inactivate
854  {
855  SFTUpdates sUp= m_asUpdates.Front(true, bNotEmpty);
856  if (bNotEmpty)
857  {
858  m_aDevices[((SBaseIn*)sUp.sData.pHead)->nChan]->DoWork(NULL, 0, m_ftHandle,
859  ((SBaseIn*)sUp.sData.pHead)->eType == eActivate? eActivateState: eInactivateState, 0);
860  m_pcComm->SendData(&sUp.sData, sUp.llId); // XXX this should be responded to by individual devices not here (in case not done yet)
861  }
862  }
863  ResetEvent(m_hUpdate);
864  ResetEvent(m_hNext);
865  // now setup devices
866  ucModeOld= ucMode;
867  ucMode= 0xFF;
868  ucOutputOld= ucOutput;
869  ucOutput= 0;
870  dwBaud= ~0;
871  dwROld= dwRead;
872  dwWrite= 0;
873  dwRead= 0;
874  bUpdating= false;
875  for (DWORD i= 0; i<m_aDevices.size(); ++i)
876  {
877  EStateFTDI eType= m_aDevices[i]->GetState();
878  if (eType != eInactive)
879  {
880  dwBaud= min(m_aDevices[i]->m_sInitFT.dwMaxBaud, dwBaud);
881  dwWrite= max(m_aDevices[i]->m_sInitFT.dwMinSizeW, dwWrite);
882  dwRead= max(m_aDevices[i]->m_sInitFT.dwMinSizeR, dwRead);
883  }
884  ucMode &= m_aDevices[i]->m_sInitFT.ucBitMode;
885  ucOutput |= m_aDevices[i]->GetOutputBits();
886  bUpdating = bUpdating || eType == eActivateState || eType == eInactivateState;
887  }
888  ucMode &= (~ucMode+1); // get lowest bit
889  if (ucMode&FT_BITMODE_SYNC_BITBANG)
890  {
891  dwWrite= max(dwWrite, dwRead);
892  dwWrite= dwPacket*(DWORD)ceil((double)dwWrite/dwPacket); // reduce timeouts
893  dwRead= dwWrite;
894  if (dwRead != dwROld)
895  lpfFT_SetUSBParameters(m_ftHandle, (dwRead/dwPacket)*(dwPacket+2), 0);
896  }
897  if (ucMode!=ucModeOld || ucOutput!=ucOutputOld)
898  {
899  lpfFT_Purge(m_ftHandle, FT_PURGE_RX|FT_PURGE_TX);
900  lpfFT_SetBitMode(m_ftHandle, ucOutput, ucMode);
901  if (m_sChanInit.dwBaud)
902  dwBaud = min(m_sChanInit.dwBaud, dwBaud);
903  lpfFT_SetBaudRate(m_ftHandle, dwBaud);
904  }
905  if (!bUpdating) // read/write next so that we go active or inactive
906  break;
907  else
908  {
909  dwRes= WAIT_OBJECT_0 + 2;
910  SetEvent(m_hNext);
911  }
912  default:
913  if (dwRes > WAIT_OBJECT_0 + 1 && dwRes < WAIT_OBJECT_0 + m_ahEvents.size())
914  {
915  if (dwWrite)
916  {
917  for (DWORD i= 0; i<m_aDevices.size(); ++i)
918  m_aDevices[i]->DoWork(m_aucTx, dwWrite, m_ftHandle, ePreWrite, 0);
919  nError= FT_ERROR(lpfFT_Write(m_ftHandle, m_aucTx, dwWrite, &dwBytes), nError);
920  for (DWORD i= 0; i<m_aDevices.size(); ++i)
921  m_aDevices[i]->DoWork(m_aucTx, dwBytes, m_ftHandle, ePostWrite, nError);
922  }
923  if (dwRead && !nError)
924  {
925  while (!(pHead = m_pcMemRing->GetFree(&nIdx)));
926  nError= FT_ERROR(lpfFT_Read(m_ftHandle, pHead, dwRead, &dwBytes), nError);
927  for (DWORD i= 0; i<m_aDevices.size() && !nError; ++i)
928  m_aDevices[i]->DoWork((void *)&nIdx, dwBytes, m_ftHandle, ePostRead, nError);
929  }
930  if (nError)
931  {
932  SetEvent(m_hUpdate);
933  break;
934  }
935 
936  // if any device can go into updating state internally remove this conditional, or give access to the updating event to that device
937  if (bUpdating)
938  {
939  bUpdating= false;
940  for (DWORD i= 0; i<m_aDevices.size(); ++i) // are we still updating?
941  {
942  EStateFTDI eType= m_aDevices[i]->GetState();
943  bUpdating = bUpdating || eType == eActivateState || eType == eInactivateState;
944  }
945  if (!bUpdating) // done updating so go to update section so that params can be switched to non-updating state params
946  SetEvent(m_hUpdate);
947  }
948  } else
949  bDone= true;
950  break;
951  }
952  }
953  return 0;
954 }
virtual DWORD GetInfo(void *pHead, DWORD dwSize)
Definition: ftdi device.cpp:74
DWORD GetInfo(void *pHead, DWORD dwSize)
void ProcessData(const void *pHead, DWORD dwSize, __int64 llId)
virtual int SendData(const SData *pData, __int64 llId)=0
bool bChan1
Definition: cpl defs.h:349
LARGE_INTEGER GetStart() const
Definition: misc tools.h:69
void * GetFree(int *pnIdx)
Definition: mem pool.cpp:57
float fUSBBuffToUse
Definition: cpl defs.h:326
unsigned char ucActivePins
Definition: cpl defs.h:278
void ProcessData(const void *pHead, DWORD dwSize, __int64 llId)
bool bChan2
Definition: cpl defs.h:351
int GetSize()
Definition: cpl queue.h:52
DWORD dwDataPerTrans
Definition: cpl defs.h:331
virtual void Close()=0
CChannelFTDI(SChanInitFTDI &sChanInit, SBase *pInit, DWORD dwSize, FT_DEVICE_LIST_INFO_NODE &FTInfo, const TCHAR szPipe[], int nChan, int &nError, LARGE_INTEGER &llStart)
unsigned char ucClk
Definition: cpl defs.h:333
unsigned short usBytesUsed
Definition: cpl defs.h:275
const std::tstring m_csName
Definition: base classses.h:98
void Push(T pHead)
Definition: cpl queue.h:26
T Front(bool bPop, bool &bValid)
Definition: cpl queue.h:38