Barst  2.0
A server that controls lab hardware.
cpl ft adc.cpp
1 
2 #include "cpl defs.h"
3 #include "ftdi device.h"
4 
5 static const unsigned char s_aucBitReverseTable256[] =
6 {
7  0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
8  0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
9  0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
10  0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
11  0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
12  0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
13  0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
14  0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
15  0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
16  0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
17  0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
18  0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
19  0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
20  0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
21  0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
22  0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
23 };
24 
25 
27 // Starting point of queue thread
28 DWORD WINAPI ADCProc(LPVOID lpParameter)
29 {
30  // Call ThreadProc function of pipe object
31  return ((CADCPeriph*)lpParameter)->ThreadProc();
32 }
33 
34 
35 CADCPeriph::CADCPeriph(const SADCInit &sADCInit, CComm *pcComm, const SInitPeriphFT &sInitFT,
36  HANDLE hNewData, int &nError, CTimer* pcTimer):
37  CPeriphFTDI(ADC_P, sInitFT),
38  m_sInit(sADCInit), m_ucDefault(1 << sADCInit.ucClk), m_ucMask(~(1 << sADCInit.ucClk|((0xFF << sADCInit.ucLowestDataBit) &
39  (0xFF >> (6 - sADCInit.ucLowestDataBit - sADCInit.ucDataBits))))),
40  m_ucConfigWriteBit(1 << (sADCInit.bReverseBytes?sADCInit.ucLowestDataBit:sADCInit.ucLowestDataBit+1+sADCInit.ucDataBits)),
41  m_ucConfigReadBit(sADCInit.bReverseBytes?(m_ucConfigWriteBit << 1):(m_ucConfigWriteBit >> 1)), m_ucReverse(sADCInit.bReverseBytes?1:0),
42  m_usConfigWord((((sADCInit.bChop?0x80:0) | (sADCInit.ucRateFilter & 0x7F)) << 8) | (sADCInit.ucDataBits+1) << 5
43  | (sADCInit.ucBitsPerData == 24?0x10:0) | (sADCInit.bChan2?0x8:0) | (sADCInit.bChan1?0x4:0) | (sADCInit.ucInputRange & 0x3)),
44  m_ucTransPerByte(0), m_hNext(hNewData),
45  m_ucNGroups(((sADCInit.ucDataBits==0) | (sADCInit.ucDataBits==2) | (sADCInit.ucDataBits==6))?(m_sInit.ucBitsPerData/8+1)*8/(sADCInit.ucDataBits+2):8),
46  m_ucNBytes(((sADCInit.ucDataBits==0) | (sADCInit.ucDataBits==2) | (sADCInit.ucDataBits==6))?(m_sInit.ucBitsPerData/8 + 1):(sADCInit.ucDataBits + 2)),
47  m_hProcessData(CreateEvent(NULL, TRUE, FALSE, NULL)), m_apsReadIdx(m_hProcessData)
48 {
49  nError= 0;
50  m_bError= true;
51  m_hThreadClose= NULL;
52  m_hReset= NULL;
53  m_hThread= NULL;
54  m_pcMemRing = NULL;
55  m_psDataHeader= NULL;
56  m_pcMemPool= new CMemPool;
57  m_pcTimer= NULL;
58  InitializeCriticalSection(&m_hStateSafe);
59  // assumption is that the ADC buffer length is the one that makes dwBuff largest, i.e. ADC buffer is always
60  // equal to dwBuff
61  if (!pcComm || (m_sInitFT.dwBuff%510 && m_sInitFT.dwBuff%62) ||
62  (m_sInit.ucBitsPerData != 16 && m_sInit.ucBitsPerData != 24) ||
63  (!m_sInit.bStatusReg) || m_sInitFT.dwMinSizeR != m_sInitFT.dwBuff ||
64  m_sInitFT.dwMinSizeW != m_sInitFT.dwBuff || !pcTimer || !hNewData || (!m_sInit.bChan1 && !m_sInit.bChan2)
65  || m_sInit.ucDataBits > 6)
66  {
67  nError= BAD_INPUT_PARAMS;
68  return;
69  }
70  m_pcComm= pcComm;
71  m_pcTimer= pcTimer;
72  m_hThreadClose= CreateEvent(NULL, TRUE, FALSE, NULL);
73  m_hReset= CreateEvent(NULL, TRUE, TRUE, NULL);
74  if (!m_hThreadClose || !m_hProcessData || !m_hReset)
75  {
76  nError= NO_SYS_RESOURCE;
77  return;
78  }
79  m_psDataHeader= (SADCData*) m_pcMemPool->PoolAcquire(sizeof(SADCData)+sizeof(DWORD)*sADCInit.dwDataPerTrans*((sADCInit.bChan1 && sADCInit.bChan2)?2:1));
80  if (!m_psDataHeader)
81  {
82  nError= NO_SYS_RESOURCE;
83  return;
84  }
85  m_hThread= CreateThread(NULL, 0, ADCProc, this, 0, NULL);
86  if (!m_hThread)
87  {
88  nError= NO_SYS_RESOURCE;
89  return;
90  }
91 
92  m_psDataHeader->dwPos= 0;
93  m_psDataHeader->dwChan2Start = sADCInit.bChan1?sADCInit.dwDataPerTrans:0;
94  m_psDataHeader->dwCount1= 0;
95  m_psDataHeader->dwCount2= 0;
96  m_psDataHeader->dwChan1S= 0;
97  m_psDataHeader->dwChan2S= 0;
98  m_psDataHeader->sDataBase.dwSize=sizeof(SADCData)+sizeof(DWORD)*sADCInit.dwDataPerTrans*((sADCInit.bChan1 && sADCInit.bChan2)?2:1);
99  m_psDataHeader->sDataBase.eType= eTrigger;
100  m_psDataHeader->sDataBase.nChan= m_sInitFT.nChan;
101  m_psDataHeader->sBase.dwSize= sizeof(SADCData)+sizeof(DWORD)*sADCInit.dwDataPerTrans*((sADCInit.bChan1 && sADCInit.bChan2)?2:1)-sizeof(SBaseIn);
102  m_psDataHeader->sBase.eType= eADCData;
103  m_psDataHeader->dStartTime= 0;
104  m_adwData= (DWORD*)((unsigned char*)m_psDataHeader+sizeof(SADCData));
105  m_eConfigState = eConfigDone;
106  m_bSecond= false;
107  m_llId= -1; // so that if we send to closed comm unlikly to have this chann open
108  m_dwDataCount= 0;
109  m_usBadRead= 0;
110  m_usOverflow= 0;
111  m_bError= false;
112  m_eState= eInactivateState;
113  m_dwPos= 0;
114  m_sData.pDevice= this;
115  m_sData.dwSize= sizeof(SADCData)+sizeof(DWORD)*m_sInit.dwDataPerTrans*((sADCInit.bChan1 && sADCInit.bChan2)?2:1);
116  m_aucDecoded = (unsigned short(*)[256])m_pcMemPool->PoolAcquire(sizeof(*m_aucDecoded)*m_ucNGroups);
117  unsigned __int64 llTemp;
118  unsigned char ucTemp;
119  char cShift;
120  // we filter out the data ports, align it to the MSB of the 64 bit int and add it
121  // into a short which will be or'd with a 64 bit int when reconstructing.
122  // m_aucGroups says how far from the start (LSB, 0th byte) of the 8 byte we
123  // or the short with. Highest is 6 and it goes down.
124  // for negative values we never use i that high anyway when recosntructing. e.g. if ucDataBits + 2 = 8
125  // then 6 - 7*8/8 == -1, but when recosntructing max i is 4.
126  // Data is sent from ADC MSB first.
127  for (char i = 0; i<m_ucNGroups; ++i)
128  if (i*(m_sInit.ucDataBits + 2)/8 > m_ucNBytes - 2)
129  m_aucGroups[i] = 0;
130  else
131  m_aucGroups[i] = m_ucNBytes - 2 - i*(m_sInit.ucDataBits + 2)/8;
132  for (unsigned short i = 0; i< 256; ++i)
133  {
134  ucTemp = (i & ~(m_ucMask | 1 << m_sInit.ucClk));
135  if (m_sInit.bReverseBytes)
136  {
137  cShift = m_sInit.ucLowestDataBit - (8 - (m_sInit.ucLowestDataBit + m_sInit.ucDataBits + 2));
138  ucTemp = cShift>=0 ? s_aucBitReverseTable256[ucTemp] << cShift: s_aucBitReverseTable256[ucTemp] >> -cShift;
139  }
140  ucTemp <<= 8 - (m_sInit.ucLowestDataBit + m_sInit.ucDataBits + 2); // allign data at MSB
141  llTemp = (unsigned __int64)ucTemp << 8 * (m_ucNBytes - 1); // shift it up to allign with MSB of num bytes
142  for (char j = 0; j<m_ucNGroups; ++j)
143  {
144  m_aucDecoded[j][i] = ((llTemp >> m_aucGroups[j] * 8) & 0xFFFF);
145  llTemp >>= m_sInit.ucDataBits + 2;
146  }
147  }
148  switch (sADCInit.ucDataBits)
149  {
150  case 0:
151  case 2:
152  case 6:
153  m_cBuffSize = m_ucNBytes;
154  break;
155  default:
156  m_cBuffSize = m_ucNBytes*(m_sInit.ucBitsPerData/8 + 1);
157  break;
158  }
159  m_aucBuff = (unsigned char*)m_pcMemPool->PoolAcquire(m_cBuffSize);
160  memset(m_aucBuff, 0, m_cBuffSize);
161  m_cDataOffset = m_ucNBytes * (m_cBuffSize / m_ucNBytes - 1);
162 };
163 
164 DWORD CADCPeriph::GetInfo(void* pHead, DWORD dwSize)
165 {
166  if (!pHead)
167  return sizeof(SBaseOut)+2*sizeof(SBase)+sizeof(SADCInit)+sizeof(SInitPeriphFT);
168  if (dwSize<sizeof(SBaseOut)+2*sizeof(SBase)+sizeof(SADCInit)+sizeof(SInitPeriphFT))
169  return 0;
170 
171  ((SBaseOut*)pHead)->sBaseIn.dwSize= sizeof(SBaseOut)+2*sizeof(SBase)+sizeof(SADCInit)+sizeof(SInitPeriphFT);;
172  ((SBaseOut*)pHead)->sBaseIn.eType= eResponseEx;
173  ((SBaseOut*)pHead)->sBaseIn.nChan= m_sInitFT.nChan;
174  ((SBaseOut*)pHead)->sBaseIn.nError= 0;
175  ((SBaseOut*)pHead)->bActive= GetState() == eActive;
176  _tcsncpy_s(((SBaseOut*)pHead)->szName, DEVICE_NAME_SIZE, m_csName.c_str(), _TRUNCATE);
177  pHead= (char*)pHead+ sizeof(SBaseOut);
178 
179  ((SBase*)pHead)->dwSize= sizeof(SInitPeriphFT)+sizeof(SBase);
180  ((SBase*)pHead)->eType= eFTDIPeriphInit;
181  pHead= (char*)pHead+ sizeof(SBase);
182  memcpy(pHead, &m_sInitFT, sizeof(SInitPeriphFT));
183  pHead= (char*)pHead+ sizeof(SInitPeriphFT);
184 
185  ((SBase*)pHead)->dwSize= sizeof(SADCInit)+sizeof(SBase);
186  ((SBase*)pHead)->eType= eFTDIADCInit;
187  pHead= (char*)pHead+ sizeof(SBase);
188  memcpy(pHead, &m_sInit, sizeof(SADCInit));
189 
190  return sizeof(SBaseOut)+2*sizeof(SBase)+sizeof(SADCInit)+sizeof(SInitPeriphFT);
191 }
192 
193 CADCPeriph::~CADCPeriph()
194 {
195  // wait max 2sec
196  if (m_hThread && (WAIT_OBJECT_0 != SignalObjectAndWait(m_hThreadClose, m_hThread, 2000, FALSE)))
197  TerminateThread(m_hThread, 0);
198  DeleteCriticalSection(&m_hStateSafe);
199  if (m_hThread) CloseHandle(m_hThread);
200  STimedRead *psRead = NULL;
201  bool bNotEmpty;
202  while (m_pcMemRing && m_apsReadIdx.GetSize())
203  {
204  psRead = m_apsReadIdx.Front(true, bNotEmpty);
205  if (psRead && bNotEmpty)
206  {
207  m_pcMemRing->ReleaseIndex(psRead->nIdx);
208  delete psRead;
209  }
210  }
211  if (m_hProcessData) CloseHandle(m_hProcessData);
212  if (m_hReset) CloseHandle(m_hReset);
213  if (m_hThreadClose) CloseHandle(m_hThreadClose);
214  if (m_psDataHeader)
215  m_pcMemPool->PoolRelease(m_psDataHeader);
216  delete m_pcMemPool;
217 }
218 
219 bool CADCPeriph::DoWork(void *pHead, DWORD dwSize, FT_HANDLE ftHandle, EStateFTDI eReason, int nError)
220 {
221  if (m_bError)
222  return true;
223  unsigned char *aucBuff= (unsigned char *)pHead;
224  switch (eReason)
225  {
226  case eActivateState:
227  EnterCriticalSection(&m_hStateSafe);
228  m_eState= eActivateState;
229  SetEvent(m_hNext); // make sure we keep writing even if user forgot to trigger (although we'll send data to -1 ID)
230  LeaveCriticalSection(&m_hStateSafe);
231  if (m_sInit.bConfigureADC)
232  m_ucBitOutput = m_sInitFT.ucBitOutput | m_ucConfigWriteBit;
233  m_eConfigState = eConfigStart;
234  break;
235  case eInactivateState:
236  SData sData;
237  sData.dwSize= sizeof(SBaseIn);
238  sData.pDevice= this;
239  sData.pHead= m_pcMemPool->PoolAcquire(sizeof(SBaseIn));
240  if (sData.pHead)
241  {
242  ((SBaseIn*)sData.pHead)->eType= eResponse;
243  ((SBaseIn*)sData.pHead)->nChan= m_sInitFT.nChan;
244  ((SBaseIn*)sData.pHead)->nError= DEVICE_CLOSING;
245  ((SBaseIn*)sData.pHead)->dwSize= sizeof(SBaseIn);
246  }
247  EnterCriticalSection(&m_hStateSafe);
248  m_eState= eInactivateState;
249  if (sData.pHead)
250  m_pcComm->SendData(&sData, m_llId);
251  m_llId= -1; // unlikly to have comm with this ID
252  LeaveCriticalSection(&m_hStateSafe);
253  break;
254  case eRecover:
255  EnterCriticalSection(&m_hStateSafe);
256  if (m_eState == eActive || m_eState == eActivateState) // start over again
257  {
258  m_eState= eActivateState;
259  m_eConfigState = eConfigStart;
260  m_ucBitOutput = m_sInitFT.ucBitOutput;
261  }
262  LeaveCriticalSection(&m_hStateSafe);
263  break;
264  case ePreWrite:
265  if (m_eState == eActivateState)
266  {
267  switch (m_eConfigState)
268  {
269  case eConfigStart:
270  {
271  SetEvent(m_hReset);
272  m_dwRestartE= GetTickCount() + ADC_RESET_DELAY; // time when device should finish reseting
273  // the first time we clock out initialization seq so it can reset
274  DWORD i = 0;
275  for (; i<90; ++i)
276  {
277  aucBuff[i++] = (aucBuff[i] & m_ucMask) | m_ucDefault | m_ucConfigWriteBit;
278  aucBuff[i] = (aucBuff[i] & m_ucMask) | m_ucConfigWriteBit;
279  }
280  for (; i<m_sInitFT.dwBuff;++i)
281  aucBuff[i]= (aucBuff[i]&m_ucMask) | m_ucDefault | m_ucConfigWriteBit;
282  break;
283  }
284  case eConfigWrite:
285  {
286  DWORD i = 0;
287  for (; i<90; ++i) // initialization seq, (keep in mind min packet is also 3*62)
288  {
289  aucBuff[i++] = (aucBuff[i] & m_ucMask) | m_ucDefault | m_ucConfigWriteBit;
290  aucBuff[i] = (aucBuff[i] & m_ucMask) | m_ucConfigWriteBit;
291  }
292  aucBuff[90] = (aucBuff[90] & m_ucMask) | m_ucDefault | m_ucConfigWriteBit;
293  aucBuff[91] = (aucBuff[91] & m_ucMask) | m_ucDefault | m_ucConfigWriteBit;
294  for (DWORD i = 0; i<10; ++i)
295  {
296  aucBuff[2*i + 92] = (aucBuff[2*i + 92] & m_ucMask) | m_ucDefault | m_ucConfigWriteBit;
297  aucBuff[2*i + 1 + 92] = (aucBuff[2*i + 1 + 92] & m_ucMask) | m_ucDefault;
298  }
299  aucBuff[112] = (aucBuff[112] & m_ucMask) | m_ucDefault | m_ucConfigWriteBit;
300  aucBuff[113] = (aucBuff[113] & m_ucMask) | m_ucDefault | m_ucConfigWriteBit;
301  char value;
302  for (DWORD i= 0; i<16; ++i)
303  {
304  value = (m_usConfigWord & (1 << (15-i)))?m_ucConfigWriteBit:0;
305  aucBuff[3*i+114] = (aucBuff[3*i+114] & m_ucMask) | m_ucDefault | value;
306  aucBuff[3*i+1+114] = (aucBuff[3*i+1+114] & m_ucMask) | value;
307  aucBuff[3*i+2+114] = (aucBuff[3*i+2+114] & m_ucMask) | m_ucDefault | value;
308  }
309  break;
310  }
311  }
312  } else if (m_eState == eInactivateState)
313  {
314  m_ucBitOutput = m_sInitFT.ucBitOutput;
315  m_eConfigState = eConfigDone;
316  SetEvent(m_hReset);
317  for (DWORD i= 0; i<m_sInitFT.dwBuff;++i)
318  aucBuff[i]= (aucBuff[i]&m_ucMask)|m_ucDefault;
319  EnterCriticalSection(&m_hStateSafe);
320  m_eState = eInactive;
321  ResetEvent(m_hNext); // stop R/W
322  LeaveCriticalSection(&m_hStateSafe);
323  } else if (m_eState == eActive)
324  {
325  m_dTimeTemp = g_cTimer.Seconds(); // get start time when we're about to read
326  }
327  break;
328  case ePostWrite:
329  if (m_eState == eActivateState)
330  {
331  if (m_eConfigState == eConfigStart)
332  {
333  for (int i = 0; i<90; ++i)
334  aucBuff[i] = (aucBuff[i] & m_ucMask) | m_ucDefault | m_ucConfigWriteBit;
335  m_eConfigState = eConfigTO;
336  } else if (m_eConfigState == eConfigDone)
337  {
338  for (DWORD i= 0; i < m_sInitFT.dwBuff;++i)
339  {
340  aucBuff[i++] = (aucBuff[i] & m_ucMask) | m_ucDefault;
341  aucBuff[i] = aucBuff[i] & m_ucMask;
342  }
343  aucBuff[m_sInitFT.dwBuff-1] = (aucBuff[m_sInitFT.dwBuff-1] & m_ucMask) | m_ucDefault;
344  }
345  }
346  break;
347  case ePostRead:
348  if (m_eState == eActivateState)
349  {
350  switch (m_eConfigState)
351  {
352  case eConfigTO:
353  {
354  if (m_dwRestartE <= GetTickCount())
355  {
356  if (!m_sInit.bConfigureADC)
357  m_eConfigState = eConfigDone;
358  else
359  m_eConfigState = eConfigWrite;
360  }
361  break;
362  }
363  case eConfigWrite:
364  {
365  unsigned short usConfigWord = 0;
366  unsigned char * aucRx = (unsigned char *)m_pcMemRing->GetIndexMemoryUnsafe(*(int *)pHead);
367  for (char i = 0; i < 16; ++i)
368  if (aucRx[3*i + 116] & m_ucConfigReadBit)
369  usConfigWord |= 1 << (15 - i);
370  if (usConfigWord != m_usConfigWord)
371  m_eConfigState = eConfigStart;
372  else
373  m_eConfigState = eConfigDone;
374  break;
375  }
376  case eConfigDone:
377  {
378  m_dwPos = 0;
379  m_ucBitOutput = m_sInitFT.ucBitOutput;
380  m_cDataOffset = m_ucNBytes * (m_cBuffSize / m_ucNBytes - 1);
381  m_dwDataCount = 0;
382  m_dwSpaceUsed = 0;
383  m_dwStartRead = 0;
384  m_dwStartRead = GetTickCount();
385  EnterCriticalSection(&m_hStateSafe);
386  m_eState = eActive;
387  LeaveCriticalSection(&m_hStateSafe);
388  break;
389  }
390  }
391  } else if (m_eState == eActive) // select which read buffer to use
392  {
393  STimedRead sTimed;
394  sTimed.nIdx = *(int *)pHead;
395  sTimed.dTime = m_dTimeTemp;
396  sTimed.pHead = m_pcMemRing->GetIndexMemory(sTimed.nIdx);
397  m_apsReadIdx.Push(new STimedRead(sTimed));
398  }
399  break;
400  default:
401  break;
402  }
403  return true;
404 }
405 
406 EStateFTDI CADCPeriph::GetState()
407 {
408  EnterCriticalSection(&m_hStateSafe);
409  EStateFTDI eState= m_eState;
410  LeaveCriticalSection(&m_hStateSafe);
411  return eState;
412 }
413 
414 void CADCPeriph::ProcessData(const void *pHead, DWORD dwSize, __int64 llId)
415 {
416  if(m_bError)
417  return;
418  // only trigger and only accept a trigger for cont if it's the first
419  if (!pHead || dwSize != sizeof(SBaseIn) || ((SBaseIn*)pHead)->eType != eTrigger ||
420  ((SBaseIn*)pHead)->dwSize != dwSize)
421  {
422  SData sData;
423  sData.dwSize= sizeof(SBaseIn);
424  sData.pDevice= this;
425  sData.pHead= m_pcMemPool->PoolAcquire(sizeof(SBaseIn));
426  if (sData.pHead)
427  {
428  ((SBaseIn*)sData.pHead)->dwSize= sizeof(SBaseIn);
429  ((SBaseIn*)sData.pHead)->eType= eResponse;
430  ((SBaseIn*)sData.pHead)->nChan= m_sInitFT.nChan;
431  ((SBaseIn*)sData.pHead)->nError= INVALID_COMMAND;
432  m_pcComm->SendData(&sData, llId);
433  }
434  return;
435  }
436 
437  int nError= 0;
438  EnterCriticalSection(&m_hStateSafe);
439  // XXX activateststae should not be allowed, this can be fixed when ftdi device.cpp line 834 is fixed
440  // (individual devices respond when active so we don't have to guess).
441  if (m_eState == eActive || m_eState == eActivateState)
442  {
443  if (m_llId == -1) // hasn't been triggered yet (so that we cannot retrigger)
444  m_llId= llId; // pipe to send reads (hNewData has been set when activated)
445  else
446  nError= ALREADY_OPEN;
447  } else
448  nError= INACTIVE_DEVICE;
449  LeaveCriticalSection(&m_hStateSafe);
450 
451  if (nError)
452  {
453  SData sData;
454  sData.dwSize= sizeof(SBaseIn);
455  sData.pDevice= this;
456  sData.pHead= m_pcMemPool->PoolAcquire(sizeof(SBaseIn));
457  if (sData.pHead)
458  {
459  ((SBaseIn*)sData.pHead)->dwSize= sizeof(SBaseIn);
460  ((SBaseIn*)sData.pHead)->eType= eResponse;
461  ((SBaseIn*)sData.pHead)->nChan= m_sInitFT.nChan;
462  ((SBaseIn*)sData.pHead)->nError= nError;
463  m_pcComm->SendData(&sData, llId);
464  }
465  }
466 }
467 
468 DWORD CADCPeriph::ThreadProc()
469 {
470  HANDLE ahEvents[]= {m_hThreadClose, m_hProcessData, m_hReset};
471  bool bDone= false, bNotEmpty;
472  DWORD dwStart, dwMid, dwEnd;
473  DWORD dwInitialRead= 0;
474  STimedRead *psRead = NULL;
475 
476  while (!bDone)
477  {
478  dwStart= GetTickCount();
479  switch (WaitForMultipleObjects(3, ahEvents, FALSE, INFINITE))
480  {
481  case WAIT_OBJECT_0:
482  bDone= true;
483  break;
484  case WAIT_OBJECT_0 + 1:
485  psRead = m_apsReadIdx.Front(true, bNotEmpty);
486  if (psRead && bNotEmpty)
487  {
488  dwInitialRead= m_psDataHeader->dwCount1+m_psDataHeader->dwCount2;
489  m_dwAmountRead= 0;
490  dwMid= GetTickCount();
491  ExtractData(psRead);
492  dwEnd= GetTickCount();
493  m_dwAmountRead += m_psDataHeader->dwCount1+m_psDataHeader->dwCount2;
494  m_fTimeWorked= (float)((double)(dwEnd-dwMid)/(dwEnd-dwStart));
495  //m_fSpaceFull= (float)((double)(m_dwAmountRead-dwInitialRead)/(m_sInitFT.dwBuff/
496  // (2*((m_sInit.ucBitsPerData/8+(m_sInit.bStatusReg?1:0))*m_ucTransPerByte+1))));
497  //m_fDataRate= (float)((double)(m_dwAmountRead-dwInitialRead)/(dwEnd-dwStart)*1000/((m_sInit.bChan1 && m_sInit.bChan2)?2:1));
498  m_pcMemRing->ReleaseIndex(psRead->nIdx);
499  delete psRead;
500  }
501  m_apsReadIdx.ResetIfEmpty();
502  break;
503  case WAIT_OBJECT_0 + 2:
504  m_psDataHeader->dwCount1= 0;
505  m_psDataHeader->dwCount2= 0;
506  m_dwSpaceUsed = 0;
507  m_fTimeWorked= 0;
508  //m_fDataRate= 0;
509  m_psDataHeader->ucError= 0;
510  m_psDataHeader->sDataBase.nError= 0;
511  m_dwDataCount= 0;
512  m_usBadRead= 0;
513  m_usOverflow= 0;
514  m_bSecond= false;
515  //m_ucLastByte= 0xFF;
516  ResetEvent(m_hReset);
517  break;
518  default:
519  break;
520  }
521  }
522  return 0;
523 }
524 
525 // this needs to take faster than a single read/write, otherwise we'd lose data
526 void CADCPeriph::ExtractData(STimedRead *psRead)
527 {
528  if (m_bError)
529  return;
530  unsigned char* rx = (unsigned char *)psRead->pHead;
531  m_psDataHeader->dStartTime = psRead->dTime;
532  EnterCriticalSection(&m_hStateSafe);
533  __int64 llId = m_llId; // get most recent ID
534  LeaveCriticalSection(&m_hStateSafe);
535 
536  m_psDataHeader->dwChan1S = m_psDataHeader->dwCount1;
537  m_psDataHeader->dwChan2S = m_psDataHeader->dwCount2;
538  unsigned char ucTemp1, ucTemp2;
539 
540  // start at one since 1 has new clocked in data (read before write and last to writes are same)
541  for (DWORD i= 0; i<=m_sInitFT.dwBuff-1;++i)
542  {
543  ++m_dwSpaceUsed;
544  // check if this is the start data signal
545  if (!(rx[i]&1<<m_sInit.ucClk) && (unsigned char)(rx[i]&~(m_ucMask|m_ucConfigWriteBit)) == (unsigned char)(~rx[i+1]&~(m_ucMask|m_ucConfigWriteBit))
546  && (rx[i] & m_ucConfigWriteBit) == (rx[i+1] & m_ucConfigWriteBit))
547  {
548  if (m_dwDataCount) // if we're in the middle of another data segment bad read
549  {
550  ++m_usBadRead;
551  m_dwDataCount = 0;
552  } else
553  {
554  memset(m_aucBuff+m_cDataOffset, 0, m_ucNBytes);
555  m_dwDataCount= 1;
556  *(unsigned short*)(m_aucBuff+m_aucGroups[0]+m_cDataOffset) = m_aucDecoded[0][rx[i]];
557  }
558  continue;
559  }
560  ucTemp1 = rx[i]&~m_ucMask;
561  ucTemp2 = rx[i+1]&~m_ucMask;
562  // if data was not changed or clock is high
563  if ((ucTemp1&~(1<<m_sInit.ucClk)) == (ucTemp2&~(1<<m_sInit.ucClk)) || ucTemp1&(1<<m_sInit.ucClk))
564  continue;
565  // haven't hit start or they are not complemented
566  if (!m_dwDataCount || ucTemp1 != (unsigned char)((~ucTemp2)&(~m_ucMask)))
567  {
568  ++m_usBadRead;
569  m_dwDataCount = 0;
570  continue;
571  }
572  *(unsigned short*)(m_aucBuff+m_aucGroups[m_dwDataCount] + m_cDataOffset) |= m_aucDecoded[m_dwDataCount][rx[i]];
573  ++m_dwDataCount;
574 
575  if (m_dwDataCount == m_ucNGroups)
576  {
577  m_dwDataCount = 0;
578  m_cDataOffset -= m_ucNBytes;
579  }
580 #pragma NOTE("m_aucBuff only works on little endian systems.")
581  const char cADCSize = m_sInit.ucBitsPerData/8 + 1;
582  unsigned char ucStatusReg;
583  DWORD dwDataPoint;
584  if (m_cDataOffset == -m_ucNBytes) // we have a multiple of a full transection set
585  {
586  m_cDataOffset = m_ucNBytes * (m_cBuffSize / m_ucNBytes - 1);
587  for (char j = m_cBuffSize/cADCSize - 1; j >= 0; --j)
588  {
589  // full so send data
590  if (m_psDataHeader->dwCount1 == m_sInit.dwDataPerTrans || m_psDataHeader->dwCount2 == m_sInit.dwDataPerTrans)
591  {
592  m_psDataHeader->sDataBase.nError = m_usBadRead | (m_usOverflow<<16);
593  m_psDataHeader->dwPos= m_dwPos++;
594  m_dwAmountRead += m_psDataHeader->dwCount1+m_psDataHeader->dwCount2;
595  if (m_dwSpaceUsed)
596  m_psDataHeader->fSpaceFull = (float)((m_psDataHeader->dwCount1 + m_psDataHeader->dwCount2) * cADCSize * 8 / (double)((m_sInit.ucDataBits + 2) * m_dwSpaceUsed));
597  else
598  m_psDataHeader->fSpaceFull = 0.0;
599  m_dwSpaceUsed = 0;
600  m_psDataHeader->fTimeWorked = m_fTimeWorked;
601  m_psDataHeader->fDataRate = (float)((m_psDataHeader->dwCount1 + m_psDataHeader->dwCount2) / (double)(GetTickCount() - m_dwStartRead) * 1000);
602  m_psDataHeader->fDataRate /= ((m_sInit.bChan1 && m_sInit.bChan2)?2:1);
603  m_dwStartRead = GetTickCount();
604  m_sData.pHead = m_psDataHeader;
605  m_pcComm->SendData(&m_sData, llId);
606  m_psDataHeader = (SADCData*) m_pcMemPool->PoolAcquire(sizeof(SADCData)+sizeof(DWORD)*m_sInit.dwDataPerTrans*((m_sInit.bChan1 && m_sInit.bChan2)?2:1));
607  if (!m_psDataHeader)
608  {
609  m_bError = true;
610  return;
611  }
612  m_psDataHeader->dwChan2Start = m_sInit.bChan1?m_sInit.dwDataPerTrans:0;
613  m_psDataHeader->dwCount1 = 0;
614  m_psDataHeader->dwCount2 = 0;
615  m_psDataHeader->sDataBase.dwSize =sizeof(SADCData)+sizeof(DWORD)*m_sInit.dwDataPerTrans*((m_sInit.bChan1 && m_sInit.bChan2)?2:1);
616  m_psDataHeader->sDataBase.eType = eTrigger;
617  m_psDataHeader->sDataBase.nChan = m_sInitFT.nChan;
618  m_psDataHeader->sBase.dwSize = sizeof(SADCData)+sizeof(DWORD)*m_sInit.dwDataPerTrans*((m_sInit.bChan1 && m_sInit.bChan2)?2:1)-sizeof(SBaseIn);
619  m_psDataHeader->sBase.eType = eADCData;
620  m_psDataHeader->dStartTime = 0;
621  m_psDataHeader->dwChan1S = 0;
622  m_psDataHeader->dwChan2S = 0;
623  m_adwData = (DWORD*)((unsigned char*)m_psDataHeader+sizeof(SADCData));
624  memset(m_adwData, 0, sizeof(DWORD)*m_sInit.dwDataPerTrans*((m_sInit.bChan1 && m_sInit.bChan2)?2:1));
625  m_psDataHeader->ucError = 0;
626  m_psDataHeader->sDataBase.nError = 0;
627  m_usBadRead = 0;
628  m_usOverflow = 0;
629  }
630  ucStatusReg = m_aucBuff[j * cADCSize + cADCSize - 1];
631  m_bSecond = (ucStatusReg & 0x40) != 0;
632  if (ucStatusReg & 0x80) // get overflow flag
633  ++m_usOverflow;
634  dwDataPoint = 0;
635  memcpy(&dwDataPoint, m_aucBuff + j * cADCSize, cADCSize - 1);
636  if (ucStatusReg & 0x20 || !(ucStatusReg & 0x08)) // make sure the status register matches
637  {
638  ++m_usBadRead;
639  continue;
640  } else
641  m_psDataHeader->ucError |= (ucStatusReg & 0x05) << (m_bSecond?4:0); // chan1 or 2 error
642  if (m_bSecond)
643  {
644  if (m_sInit.bChan2)
645  m_adwData[m_psDataHeader->dwChan2Start + m_psDataHeader->dwCount2++] = dwDataPoint;
646  else
647  {
648  ++m_usBadRead;
649  continue;
650  }
651  } else
652  {
653  if (m_sInit.bChan1)
654  m_adwData[m_psDataHeader->dwCount1++]= dwDataPoint;
655  else
656  {
657  ++m_usBadRead;
658  continue;
659  }
660 
661  }
662  }
663  }
664  }
665 }
bool DoWork(void *pHead, DWORD dwSize, FT_HANDLE ftHandle, EStateFTDI eReason, int nError)
Definition: cpl ft adc.cpp:219
unsigned char ucDataBits
Definition: cpl defs.h:340
bool bChan1
Definition: cpl defs.h:349
void ProcessData(const void *pHead, DWORD dwSize, __int64 llId)
Definition: cpl ft adc.cpp:414
bool bChan2
Definition: cpl defs.h:351
DWORD dwDataPerTrans
Definition: cpl defs.h:331
DWORD GetInfo(void *pHead, DWORD dwSize)
Definition: cpl ft adc.cpp:164
double Seconds() const
Definition: misc tools.cpp:63