Barst  2.0
A server that controls lab hardware.
serial device.cpp
1 
12 #include "cpl defs.h"
13 #include <Windows.h>
14 #include "serial device.h"
15 #include "named pipes.h"
16 #include "misc tools.h"
17 #include <string>
18 #include <iostream>
19 
20 BOOL (WINAPI *lpf_CancelIoEx)(HANDLE hFile, LPOVERLAPPED lpOverlapped)= NULL; // only availible in >=Vista
21 BOOL (WINAPI *lpf_CancelIo)(HANDLE hFile)= NULL;
22 
23 
24 
25 
26 DWORD WINAPI SerialProc(LPVOID lpParameter)
27 {
28  // Call ThreadProc function of pipe object
29  return ((CChannelSerial*)lpParameter)->ThreadProc();
30 }
31 
32 
33 
34 CManagerSerial::CManagerSerial(CComm* pcComm, const TCHAR szPipe[], int nChan, int &nError) :
35  CManager(SERIAL_MAN_STR, std::tstring(szPipe), nChan)
36 {
37  nError= 0;
38  m_bError= true;
39  m_pcComm= NULL;
40  m_hLib= NULL;
41  m_pcLogBuffer= NULL;
42  m_pcMemPool= new CMemPool;
43 
44  if (!pcComm || !szPipe)
45  {
46  nError= BAD_INPUT_PARAMS;
47  return;
48  }
49  m_hLib= LoadLibrary(_T("kernel32.dll"));
50  if (!m_hLib)
51  {
52  nError= LIBRARY_ERROR;
53  return;
54  }
55  *(FARPROC*)&lpf_CancelIoEx= GetProcAddress(m_hLib, _T("CancelIoEx"));
56  *(FARPROC*)&lpf_CancelIo= GetProcAddress(m_hLib, _T("CancelIo"));
57  if (!lpf_CancelIoEx && !lpf_CancelIo)
58  {
59  nError= LIBRARY_ERROR;
60  return;
61  }
62 
63  m_bError= false;
64  m_pcComm= pcComm;
65 }
66 
67 DWORD CManagerSerial::GetInfo(void* pHead, DWORD dwSize)
68 {
69  if (!pHead)
70  return sizeof(SBaseOut);
71  if (dwSize<sizeof(SBaseOut))
72  return 0;
73 
74  ((SBaseOut*)pHead)->sBaseIn.dwSize= sizeof(SBaseOut);
75  ((SBaseOut*)pHead)->sBaseIn.eType= eResponseEx;
76  ((SBaseOut*)pHead)->sBaseIn.nChan= m_nChan;
77  ((SBaseOut*)pHead)->sBaseIn.nError= 0;
78  ((SBaseOut*)pHead)->bActive= true;
79  _tcsncpy_s(((SBaseOut*)pHead)->szName, DEVICE_NAME_SIZE, m_csName.c_str(), _TRUNCATE);
80 
81  return sizeof(SBaseOut);
82 }
83 
84 CManagerSerial::~CManagerSerial()
85 {
86  for (size_t i= 0; i<m_acSerialDevices.size(); ++i)
87  delete m_acSerialDevices[i];
88  delete m_pcMemPool;
89  FreeLibrary(m_hLib);
90  lpf_CancelIoEx= NULL;
91  lpf_CancelIo= NULL;
92 }
93 
94 void CManagerSerial::ProcessData(const void *pHead, DWORD dwSize, __int64 llId)
95 {
96  if (m_bError)
97  return;
98  SBaseIn* pBase;
99  SData sData;
100  sData.pDevice= this;
101  SBaseIn sBase;
102  sBase.dwSize= sizeof(SBaseIn);
103  sBase.nChan= -1;
104  sBase.nError= 0;
105  bool bRes= true;
106  if (!pHead || dwSize < sizeof(SBaseIn) || dwSize != ((SBaseIn*)pHead)->dwSize) // incorrect size read
107  {
108  sBase.nError= SIZE_MISSMATCH;
109  } else if (((SBaseIn*)pHead)->eType == eQuery && dwSize == sizeof(SBaseIn)) // need info
110  {
111  sBase.eType= eQuery;
112  if (((SBaseIn*)pHead)->nChan < 0 || ((SBaseIn*)pHead)->nChan >= m_acSerialDevices.size() ||
113  !m_acSerialDevices[((SBaseIn*)pHead)->nChan]) // invalid channel
114  {
115  sBase.nError= INVALID_CHANN;
116  } else // send info on particular chann
117  {
118  bRes= false;
119  DWORD dwSizeInfo= m_acSerialDevices[((SBaseIn*)pHead)->nChan]->GetInfo(NULL, 0);
120  pBase= (SBaseIn*)m_pcMemPool->PoolAcquire(dwSizeInfo);
121  if (pBase)
122  {
123  m_acSerialDevices[((SBaseIn*)pHead)->nChan]->GetInfo(pBase, dwSizeInfo);
124  sData.dwSize= dwSizeInfo;
125  sData.pHead= pBase;
126  m_pcComm->SendData(&sData, llId);
127  }
128  }
129  } else if (dwSize == sizeof(SBaseIn) && ((SBaseIn*)pHead)->eType == eDelete) // delete a channel
130  {
131  sBase.eType= eDelete;
132  if (((SBaseIn*)pHead)->nChan < 0 || ((SBaseIn*)pHead)->nChan >= m_acSerialDevices.size() ||
133  !m_acSerialDevices[((SBaseIn*)pHead)->nChan])
134  sBase.nError= INVALID_CHANN;
135  else
136  {
137  delete m_acSerialDevices[((SBaseIn*)pHead)->nChan];
138  m_acSerialDevices[((SBaseIn*)pHead)->nChan]= NULL;
139  sBase.nChan= ((SBaseIn*)pHead)->nChan;
140  }
141  } else if (dwSize == sizeof(SBaseIn) && ((SBaseIn*)pHead)->eType == eVersion &&
142  ((SBaseIn*)pHead)->nChan == -1)
143  {
144  sBase.nError= 0;
145  sBase.dwInfo= GetVersion();
146  sBase.eType= eVersion;
147  } else if (((SBaseIn*)pHead)->eType == eSet &&
148  ((SBaseIn*)pHead)->dwSize == sizeof(SBaseIn)+sizeof(SBase)+sizeof(SChanInitSerial) &&
149  ((SBase*)((char*)pHead+sizeof(SBaseIn)))->eType == eSerialChanInit) // set a channel
150  {
151  bRes= false;
152  LARGE_INTEGER llStart;
153  sBase.eType= eSet; // in case of error we do respond at end
154  SChanInitSerial sChanInit= *(SChanInitSerial*)((char*)pHead+sizeof(SBase)+sizeof(SBaseIn));
155  size_t i= 0;
156  for (i = 0; i<m_acSerialDevices.size(); ++i)
157  {
158  if (m_acSerialDevices[i] && _tcscmp(m_acSerialDevices[i]->m_sChanInit.szPortName, sChanInit.szPortName) == 0)
159  {
160  sBase.nChan = (int)i;
161  sBase.nError = ALREADY_OPEN;
162  break;
163  }
164  }
165  if (!sBase.nError)
166  {
167  for (i = 0; i<m_acSerialDevices.size() && m_acSerialDevices[i]; ++i); // get index where we add new channel
168  if (i == m_acSerialDevices.size())
169  m_acSerialDevices.push_back(NULL);
170 
171  std::tstringstream ss; // channel
172  ss<<i;
173  std::tstringstream ss2; // manager index
174  ss2<<m_nChan;
175  std::tstring csPipeName= m_csPipeName+_T(":")+ss2.str()+_T(":")+ss.str(); // new channel pipe name
176  CChannelSerial* pcChan= new CChannelSerial(csPipeName.c_str(), (int)i, sChanInit, sBase.nError, llStart);
177  if (!sBase.nError)
178  {
179  m_acSerialDevices[i]= pcChan;
180  SBaseOut* pBaseO= (SBaseOut*)m_pcMemPool->PoolAcquire(sizeof(SBaseOut));
181  if (pBaseO)
182  {
183  pBaseO->sBaseIn.dwSize= sizeof(SBaseOut);
184  pBaseO->sBaseIn.eType= eResponseExL;
185  pBaseO->sBaseIn.nChan= (int)i;
186  pBaseO->sBaseIn.nError= 0;
187  pBaseO->llLargeInteger= llStart;
188  pBaseO->bActive= true;
189  sData.pHead= pBaseO;
190  sData.dwSize= pBaseO->sBaseIn.dwSize;
191  m_pcComm->SendData(&sData, llId);
192  }
193  } else
194  delete pcChan;
195  }
196  } else
197  sBase.nError= INVALID_COMMAND;
198 
199  if (sBase.nError || bRes)
200  {
201  sData.pHead= (SBaseIn*)m_pcMemPool->PoolAcquire(sizeof(SBaseIn));
202  if (sData.pHead)
203  {
204  sData.dwSize= sizeof(SBaseIn);
205  memcpy(sData.pHead, &sBase, sizeof(SBaseIn));
206  m_pcComm->SendData(&sData, llId);
207  }
208  }
209 }
210 
211 
212 
213 
214 CChannelSerial::CChannelSerial(const TCHAR szPipe[], int nChan, SChanInitSerial &sChanInit, int &nError,
215  LARGE_INTEGER &llStart) : CDevice(SERIAL_CHAN_STR), m_csPipeName(szPipe),
216  m_sChanInit(sChanInit), m_usChan(nChan), m_hWriteEvent(CreateEvent(NULL,TRUE, FALSE, NULL)),
217  m_asWPackets(m_hWriteEvent), m_hReadEvent(CreateEvent(NULL,TRUE, FALSE, NULL)),
218  m_asRPackets(m_hReadEvent)
219 {
220  m_bError= true;
221  nError = 0;
222  m_pcComm= NULL;
223  m_hStopEvent= NULL;
224  m_acReadBuffer= NULL;
225  m_hThread= NULL;
226  m_hPort= NULL;
227  memset(&m_sWOverlapped, 0, sizeof(OVERLAPPED));
228  memset(&m_sROverlapped, 0, sizeof(OVERLAPPED));
229  m_pcMemPool= new CMemPool;
230  nError= 0;
231  if (!szPipe || m_sChanInit.ucByteSize < 4 || m_sChanInit.ucByteSize > 8 ||
232  m_sChanInit.ucParity > 4 || m_sChanInit.ucStopBits > 2 ||
233  (!m_sChanInit.dwMaxStrRead && !m_sChanInit.dwMaxStrWrite))
234  {
235  nError= BAD_INPUT_PARAMS;
236  return;
237  }
238  m_hStopEvent= CreateEvent(NULL,TRUE, FALSE, NULL);
239  m_sWOverlapped.hEvent= CreateEvent(NULL,TRUE, FALSE, NULL);
240  m_sROverlapped.hEvent= CreateEvent(NULL,TRUE, FALSE, NULL);
241  m_acReadBuffer= (char*)m_pcMemPool->PoolAcquire(sizeof(char)*m_sChanInit.dwMaxStrRead);
242  if (!m_hStopEvent || !m_hWriteEvent || !m_hReadEvent ||
243  !m_sWOverlapped.hEvent || !m_sROverlapped.hEvent || !m_acReadBuffer)
244  {
245  nError= NO_SYS_RESOURCE;
246  return;
247  }
248 
249  std::tstring csName= m_sChanInit.szPortName;
250  csName= "\\\\.\\"+csName;
251  // open port
252  m_hPort= CreateFile(csName.c_str(), GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
253  if (m_hPort == INVALID_HANDLE_VALUE || !m_hPort)
254  {
255  nError= WIN_ERROR(GetLastError(), nError);
256  return;
257  }
258  DCB sDcb;
259  memset(&sDcb, 0, sizeof(DCB));
260  sDcb.DCBlength= sizeof(DCB);
261  if (!GetCommState(m_hPort, &sDcb))
262  {
263  nError= WIN_ERROR(GetLastError(), nError);
264  return;
265  }
266  sDcb.BaudRate= m_sChanInit.dwBaudRate;
267  sDcb.Parity= m_sChanInit.ucParity;
268  sDcb.ByteSize= m_sChanInit.ucByteSize;
269  sDcb.StopBits= m_sChanInit.ucStopBits;
270  sDcb.fRtsControl= RTS_CONTROL_DISABLE;
271  sDcb.fDtrControl= DTR_CONTROL_DISABLE;
272  sDcb.EofChar= 0x1A;
273  sDcb.EvtChar= 0x1A;
274  sDcb.XonChar= 0x11;
275  sDcb.XoffChar= 0x13;
276  sDcb.XonLim= 1024;
277  sDcb.XoffLim= 1024;
278  if (!SetCommState(m_hPort, &sDcb))
279  {
280  nError= WIN_ERROR(GetLastError(), nError);
281  return;
282  }
283  if (!SetCommMask(m_hPort, EV_RXCHAR))
284  {
285  nError= WIN_ERROR(GetLastError(), nError);
286  return;
287  }
288  if (!GetCommTimeouts(m_hPort, &m_sTimeouts))
289  {
290  nError= WIN_ERROR(GetLastError(), nError);
291  return;
292  }
293  COMMTIMEOUTS sTimeouts;
294  sTimeouts.ReadIntervalTimeout = MAXDWORD;
295  sTimeouts.ReadTotalTimeoutMultiplier = 0;
296  sTimeouts.ReadTotalTimeoutConstant = 0;
297  sTimeouts.WriteTotalTimeoutMultiplier = 0;
298  sTimeouts.WriteTotalTimeoutConstant = 0;
299  if (!SetCommTimeouts(m_hPort, &sTimeouts))
300  {
301  nError= WIN_ERROR(GetLastError(), nError);
302  return;
303  }
304 
305  m_pcComm= new CPipeServer; // our pipe over which comm to devices will occur
306  nError= static_cast<CPipeServer*>(m_pcComm)->Init(szPipe, ~0x80000000, MIN_BUFF_IN+m_sChanInit.dwMaxStrWrite+
307  sizeof(SBase)+sizeof(SSerialData)+sizeof(SBaseIn), MIN_BUFF_OUT+m_sChanInit.dwMaxStrRead+
308  sizeof(SBase)+sizeof(SSerialData)+sizeof(SBaseOut), this, NULL);
309  if (nError)
310  return;
311  m_hThread= CreateThread(NULL, 0, SerialProc, this, 0, NULL);
312  if (!m_hThread)
313  {
314  nError= NO_SYS_RESOURCE;
315  return;
316  }
317  llStart= m_cTimer.GetStart();
318  m_bError= false;
319 }
320 
321 DWORD CChannelSerial::GetInfo(void* pHead, DWORD dwSize)
322 {
323  if (!pHead)
324  return 2*sizeof(SBaseOut)+sizeof(SBase)+sizeof(SChanInitSerial);
325  if (dwSize<2*sizeof(SBaseOut)+sizeof(SBase)+sizeof(SChanInitSerial))
326  return 0;
327 
328  ((SBaseOut*)pHead)->sBaseIn.dwSize= 2*sizeof(SBaseOut)+sizeof(SBase)+sizeof(SChanInitSerial);
329  ((SBaseOut*)pHead)->sBaseIn.eType= eResponseEx;
330  ((SBaseOut*)pHead)->sBaseIn.nChan= m_usChan;
331  ((SBaseOut*)pHead)->sBaseIn.nError= 0;
332  ((SBaseOut*)pHead)->bActive= true;
333  _tcsncpy_s(((SBaseOut*)pHead)->szName, DEVICE_NAME_SIZE, m_csName.c_str(), _TRUNCATE);
334  pHead= (char*)pHead+ sizeof(SBaseOut);
335 
336  ((SBaseOut*)pHead)->sBaseIn.dwSize = sizeof(SBaseOut);
337  ((SBaseOut*)pHead)->sBaseIn.eType = eResponseExL;
338  ((SBaseOut*)pHead)->sBaseIn.nChan = m_usChan;
339  ((SBaseOut*)pHead)->sBaseIn.nError = 0;
340  ((SBaseOut*)pHead)->bActive = true;
341  ((SBaseOut*)pHead)->llLargeInteger = m_cTimer.GetStart();
342  pHead = (char*)pHead + sizeof(SBaseOut);
343 
344  ((SBase*)pHead)->dwSize= sizeof(SChanInitSerial)+sizeof(SBase);
345  ((SBase*)pHead)->eType= eSerialChanInit;
346  pHead= (char*)pHead+ sizeof(SBase);
347  memcpy(pHead, &m_sChanInit, sizeof(SChanInitSerial));
348 
349  return 2*sizeof(SBaseOut)+sizeof(SBase)+sizeof(SChanInitSerial);
350 }
351 
352 CChannelSerial::~CChannelSerial()
353 {
354  if (m_hThread && (WAIT_OBJECT_0 != SignalObjectAndWait(m_hStopEvent, m_hThread, 2000, FALSE)))
355  TerminateThread(m_hThread, 0);
356  if (m_hThread) CloseHandle(m_hThread);
357  if (m_hPort) PurgeComm(m_hPort, PURGE_RXABORT|PURGE_RXCLEAR|PURGE_TXABORT|PURGE_TXCLEAR);
358  if (m_hPort) SetCommTimeouts(m_hPort, &m_sTimeouts);
359  if (m_hPort) CloseHandle(m_hPort);
360  if (m_pcComm) m_pcComm->Close();
361  bool bValid;
362  SSerialPacket* psPackt;
363  while (m_asRPackets.GetSize())
364  {
365  psPackt= m_asRPackets.Front(true, bValid);
366  if (psPackt && bValid)
367  {
368  m_pcMemPool->PoolRelease(psPackt->psSerialData);
369  delete psPackt;
370  }
371  }
372  while (m_asWPackets.GetSize())
373  {
374  psPackt= m_asWPackets.Front(true, bValid);
375  if (psPackt && bValid)
376  {
377  m_pcMemPool->PoolRelease(psPackt->psSerialData);
378  delete psPackt;
379  }
380  }
381  if (m_sROverlapped.hEvent) CloseHandle(m_sROverlapped.hEvent);
382  if (m_sWOverlapped.hEvent) CloseHandle(m_sWOverlapped.hEvent);
383  if (m_hStopEvent) CloseHandle(m_hStopEvent);
384  if (m_hWriteEvent) CloseHandle(m_hWriteEvent);
385  if (m_hReadEvent) CloseHandle(m_hReadEvent);
386  m_pcMemPool->PoolRelease(m_acReadBuffer);
387  delete m_pcComm;
388  delete m_pcMemPool;
389 }
390 
391 void CChannelSerial::ProcessData(const void *pHead, DWORD dwSize, __int64 llId)
392 {
393  if (m_bError)
394  return;
395  int nError= 0;
396  SBaseIn* pBase= (SBaseIn*)pHead;
397  if (!pBase || dwSize < sizeof(SBaseIn) || dwSize != pBase->dwSize) // incorrect size read
398  nError= SIZE_MISSMATCH;
399  else if (pBase->nChan != m_usChan)
400  nError= INVALID_CHANN;
401  else if (!(dwSize == sizeof(SBaseIn) && pBase->eType == eQuery) && // query
402  !(pBase->eType == eData &&
403  ((SBase*)((char*)pBase+sizeof(SBaseIn)))->eType == eSerialWriteData && // write
404  dwSize == sizeof(SBaseIn)+sizeof(SBase)+sizeof(SSerialData)+ // correct size
405  ((SSerialData*)((char*)pBase+sizeof(SBaseIn)+sizeof(SBase)))->dwSize) &&
406  !(pBase->eType == eTrigger &&
407  ((SBase*)((char*)pBase+sizeof(SBaseIn)))->eType == eSerialReadData && // read
408  dwSize == sizeof(SBaseIn)+sizeof(SBase)+sizeof(SSerialData))) // correct size
409  nError= INVALID_COMMAND;
410  else if ((pBase->eType == eTrigger &&
411  (((SSerialData*)((char*)pBase+sizeof(SBaseIn)+sizeof(SBase)))->dwSize > m_sChanInit.dwMaxStrRead ||
412  ((SSerialData*)((char*)pBase+sizeof(SBaseIn)+sizeof(SBase)))->dwSize == 0)) ||
413  (pBase->eType == eData &&
414  (((SSerialData*)((char*)pBase+sizeof(SBaseIn)+sizeof(SBase)))->dwSize > m_sChanInit.dwMaxStrWrite ||
415  ((SSerialData*)((char*)pBase+sizeof(SBaseIn)+sizeof(SBase)))->dwSize == 0)))
416  nError= BAD_INPUT_PARAMS;
417 
418  SData sData;
419  sData.pDevice= this;
420  sData.dwSize= sizeof(SBaseIn);
421  if (nError) // bad read
422  {
423  pBase= (SBaseIn*)m_pcMemPool->PoolAcquire(sData.dwSize);
424  if (pBase)
425  {
426  pBase->dwSize= sizeof(SBaseIn);
427  pBase->eType= eResponse;
428  pBase->nChan= -1;
429  pBase->nError= nError;
430  sData.pHead= pBase;
431  m_pcComm->SendData(&sData, llId);
432  }
433  } else if (pBase->eType == eQuery) // send back info on devices
434  {
435  sData.dwSize= GetInfo(NULL, 0);
436  sData.pHead= m_pcMemPool->PoolAcquire(sData.dwSize);
437  if (sData.pHead && GetInfo(sData.pHead, sData.dwSize) == sData.dwSize)
438  m_pcComm->SendData(&sData, llId);
439  } else // start or stop device, respond with ok
440  {
441  SSerialPacket* psPacket= new SSerialPacket;
442  psPacket->psSerialData= (SBase*)m_pcMemPool->PoolAcquire(dwSize-sizeof(SBaseIn));
443  if (psPacket->psSerialData)
444  {
445  memcpy(psPacket->psSerialData, (char*)pHead+sizeof(SBaseIn), dwSize-sizeof(SBaseIn));
446  psPacket->llId= llId;
447  if (pBase->eType == eTrigger) // read
448  m_asRPackets.Push(psPacket);
449  else // write
450  m_asWPackets.Push(psPacket);
451  }
452  }
453 }
454 
455 DWORD CChannelSerial::ThreadProc()
456 {
457  HANDLE ahEvents[]= {m_hStopEvent, m_hWriteEvent, m_hReadEvent, m_sWOverlapped.hEvent, m_sROverlapped.hEvent};
458  DWORD dwToRead= 0, dwRead= 0, dwToWrite= 0, dwWrote= 0, dwError, dwWait= INFINITE, dwMask= 0;
459  double dWStart, dRStart, dWDur= 0, dRDur= 0, dCurrTime;
460  bool bDone= false, bValid, bWClear= false, bRClear= false, bRPending= false;
461  SData sData;
462  sData.pDevice= this;
463  SBaseOut sBaseOut;
464  memset(&sBaseOut, 0, sizeof(SBaseOut));
465  sBaseOut.bActive= true;
466  sBaseOut.sBaseIn.eType= eResponseExD;
467  sBaseOut.sBaseIn.nChan= m_usChan;
468  SSerialPacket* sPacket;
469  int nPos= 0;
470 
471  while (!bDone)
472  {
473  switch (WaitForMultipleObjects(sizeof(ahEvents)/sizeof(HANDLE), &ahEvents[0], FALSE, dwWait))
474  {
475  case WAIT_OBJECT_0+1: // user requested write
476  {
477  bWClear= true;
478  ResetEvent(m_hWriteEvent); // event won't be set again as long as queue is not empty
479  sPacket= m_asWPackets.Front(false, bValid);
480  if (!sPacket || !bValid) // valid queue element
481  break;
482  dwToWrite= ((SSerialData*)((char*)sPacket->psSerialData+sizeof(SBase)))->dwSize; // amount to write
483  if (!WriteFile(m_hPort, (char*)sPacket->psSerialData+sizeof(SBase)+sizeof(SSerialData),
484  dwToWrite, &dwWrote, &m_sWOverlapped)) // didn't complete immediately
485  {
486  if ((dwError= GetLastError()) != ERROR_IO_PENDING) // failed
487  sBaseOut.sBaseIn.nError= WIN_ERROR(dwError, sBaseOut.sBaseIn.nError);
488  else // pending
489  {
490  bWClear= false;
491  dWDur= (double)((SSerialData*)((char*)sPacket->psSerialData+sizeof(SBase)))->dwTimeout/1000.0;
492  dWStart= m_cTimer.Seconds();
493  }
494  } else // completed immediately
495  {
496  if (dwToWrite != dwWrote) // failed
497  sBaseOut.sBaseIn.nError= RW_FAILED;
498  }
499  break;
500  }
501  case WAIT_OBJECT_0+3: // write finished
502  {
503  bWClear= true;
504  ResetEvent(m_sWOverlapped.hEvent);
505  sPacket= m_asWPackets.Front(false, bValid);
506  if (!sPacket || !bValid)
507  break;
508  if (GetOverlappedResult(m_hPort, &m_sWOverlapped, &dwWrote, FALSE)) // success
509  {
510  if (dwToWrite != dwWrote) // failed
511  sBaseOut.sBaseIn.nError= RW_FAILED;
512  }
513  else
514  sBaseOut.sBaseIn.nError= WIN_ERROR(GetLastError(), sBaseOut.sBaseIn.nError);
515  break;
516  }
517  case WAIT_OBJECT_0+2:
518  {
519  bRClear= true;
520  ResetEvent(m_hReadEvent); // event won't be set again as long as queue is not empty
521  sPacket= m_asRPackets.Front(false, bValid);
522  if (!sPacket || !bValid) // valid queue element
523  break;
524  dwMask= 0;
525  if (!WaitCommEvent(m_hPort, &dwMask, &m_sROverlapped)) // failed
526  {
527  dwError= GetLastError();
528  if (dwError != ERROR_IO_PENDING)
529  {
530  sBaseOut.sBaseIn.nError= WIN_ERROR(dwError, sBaseOut.sBaseIn.nError);
531  break;
532  }
533  bRPending= true;
534  } else
535  SetEvent(m_sROverlapped.hEvent); // read right after this
536  dRDur= ((SSerialData*)((char*)sPacket->psSerialData+sizeof(SBase)))->dwTimeout/1000.0;
537  dRStart= m_cTimer.Seconds();
538  bRClear= false;
539  break;
540  }
541  case WAIT_OBJECT_0+4:
542  {
543  bRClear= true;
544  ResetEvent(m_sROverlapped.hEvent);
545  sPacket= m_asRPackets.Front(false, bValid);
546  if (!sPacket || !bValid)
547  break;
548  if (bRPending && !GetOverlappedResult(m_hPort, &m_sROverlapped, &dwError, FALSE)) // failed, only call if pending
549  {
550  sBaseOut.sBaseIn.nError= WIN_ERROR(GetLastError(), sBaseOut.sBaseIn.nError); // done with error
551  break;
552  }
553  dwError= 0;
554  if (!ClearCommError(m_hPort, &dwError, &m_sComStat))
555  {
556  sBaseOut.sBaseIn.nError= WIN_ERROR(GetLastError(), sBaseOut.sBaseIn.nError);
557  break;
558  }
559  if (bRPending && !(dwMask&EV_RXCHAR))
560  {
561  sBaseOut.sBaseIn.nError= RW_FAILED;
562  break;
563  }
564  dwRead= 0;
565  if (!ReadFile(m_hPort, &m_acReadBuffer[nPos], min(m_sComStat.cbInQue,
566  ((SSerialData*)((char*)sPacket->psSerialData+sizeof(SBase)))->dwSize-nPos),
567  &dwRead, &m_sROverlapped)) // failed
568  {
569  sBaseOut.sBaseIn.nError= WIN_ERROR(GetLastError(), sBaseOut.sBaseIn.nError);
570  break;
571  }
572  bool bCompleted= false;
573  if (((SSerialData*)((char*)sPacket->psSerialData+sizeof(SBase)))->bStop)
574  {
575  int i= nPos;
576  for (; i<nPos+(int)dwRead && (m_acReadBuffer[i]!=((SSerialData*)((char*)sPacket->psSerialData+sizeof(SBase)))->cStop);++i);
577  bCompleted= i<nPos+(int)dwRead;
578  } else
579  bCompleted= nPos+dwRead == ((SSerialData*)((char*)sPacket->psSerialData+sizeof(SBase)))->dwSize;
580  nPos+= dwRead;
581  if (dwError) // if there was an error, finish
582  {
583  sBaseOut.sBaseIn.nError= RW_FAILED;
584  bCompleted= true;
585  }
586  if (!bCompleted) // not done, read again
587  {
588  bRPending= false;
589  if (!WaitCommEvent(m_hPort, &dwMask,&m_sROverlapped))
590  {
591  dwError= GetLastError();
592  if (dwError != ERROR_IO_PENDING) // failed
593  {
594  sBaseOut.sBaseIn.nError= WIN_ERROR(GetLastError(), sBaseOut.sBaseIn.nError);
595  break;
596  }
597  // pending, but if there's data now in read buffer, do another read so not to miss data
598  dwError= 0;
599  if (!ClearCommError(m_hPort, &dwError, &m_sComStat))
600  {
601  sBaseOut.sBaseIn.nError= WIN_ERROR(GetLastError(), sBaseOut.sBaseIn.nError);
602  break;
603  }
604  if (dwError) // if there was an error, finish
605  {
606  sBaseOut.sBaseIn.nError= RW_FAILED;
607  break;
608  }
609  if (m_sComStat.cbInQue) // don't call getoverlapped yet because we'll just do a read
610  SetEvent(m_sROverlapped.hEvent);
611  else
612  bRPending= true; // now we're pending
613  } else // success, set event so we do another read
614  SetEvent(m_sROverlapped.hEvent);
615  bRClear= false;
616  }
617  break;
618  }
619  case WAIT_TIMEOUT:
620  {
621  dCurrTime= m_cTimer.Seconds();
622  if (lpf_CancelIoEx) // OS >= Vista
623  {
624  if (dWDur && dCurrTime > dWDur+dWStart)
625  lpf_CancelIoEx(m_hPort, &m_sWOverlapped);
626  if (dRDur && dCurrTime > dRDur+dRStart)
627  lpf_CancelIoEx(m_hPort, &m_sROverlapped);
628  } else if (lpf_CancelIo) // WinXP
629  {
630  if (dWDur && dCurrTime > dWDur+dWStart)
631  lpf_CancelIo(m_hPort);
632  if (dRDur && dCurrTime > dRDur+dRStart)
633  lpf_CancelIo(m_hPort);
634  }
635  break;
636  }
637  case WAIT_OBJECT_0:
638  default:
639  bDone= true;
640  break;
641  }
642 
643  if (bRClear) // respond to client, only from reads
644  {
645  sPacket= m_asRPackets.Front(true, bValid);
646  if (m_asRPackets.GetSize())
647  SetEvent(m_hReadEvent);
648  if (sPacket && bValid)
649  {
650  sBaseOut.dDouble= g_cTimer.Seconds();
651  sData.dwSize= sizeof(SBaseOut)+sizeof(SBase)+sizeof(SSerialData)+sizeof(char)*nPos;
652  sBaseOut.sBaseIn.dwSize= sData.dwSize;
653  SBaseOut* pBase= (SBaseOut*)m_pcMemPool->PoolAcquire(sData.dwSize);
654  if (pBase)
655  {
656  sData.pHead= pBase;
657  memcpy(pBase, &sBaseOut, sizeof(SBaseOut));
658  ((SBase*)((char*)pBase+sizeof(SBaseOut)))->dwSize= sData.dwSize-sizeof(SBaseOut);
659  ((SBase*)((char*)pBase+sizeof(SBaseOut)))->eType= eSerialReadData;
660  ((SSerialData*)((char*)pBase+sizeof(SBaseOut)+sizeof(SBase)))->dwSize= nPos;
661  memcpy((char*)pBase+sizeof(SBaseOut)+sizeof(SBase)+sizeof(SSerialData), m_acReadBuffer, sizeof(char)*nPos);
662  m_pcComm->SendData(&sData, sPacket->llId);
663  }
664  m_pcMemPool->PoolRelease(sPacket->psSerialData);
665  delete sPacket;
666  }
667  bRClear= false;
668  nPos= 0;
669  dRDur= 0;
670  bRPending= false;
671  }
672  if (bWClear) // respond to client, only from writes
673  {
674  sPacket= m_asWPackets.Front(true, bValid);
675  if (m_asWPackets.GetSize())
676  SetEvent(m_hWriteEvent);
677  if (sPacket && bValid)
678  {
679  sBaseOut.dDouble= g_cTimer.Seconds();
680  sData.dwSize= sizeof(SBaseOut)+sizeof(SBase)+sizeof(SSerialData);
681  sBaseOut.sBaseIn.dwSize= sData.dwSize;
682  SBaseOut* pBase= (SBaseOut*)m_pcMemPool->PoolAcquire(sData.dwSize);
683  if (pBase)
684  {
685  sData.pHead= pBase;
686  memcpy(pBase, &sBaseOut, sizeof(SBaseOut));
687  ((SBase*)((char*)pBase+sizeof(SBaseOut)))->dwSize= sizeof(SBase)+sizeof(SSerialData);
688  ((SBase*)((char*)pBase+sizeof(SBaseOut)))->eType= eSerialWriteData;
689  ((SSerialData*)((char*)pBase+sizeof(SBaseOut)+sizeof(SBase)))->dwSize= dwWrote;
690  m_pcComm->SendData(&sData, sPacket->llId);
691  }
692  m_pcMemPool->PoolRelease(sPacket->psSerialData);
693  delete sPacket;
694  }
695  dWDur= 0;
696  dwWrote= 0;
697  bWClear= false;
698  }
699  sBaseOut.sBaseIn.nError= 0;
700  dwWait= INFINITE;
701  dCurrTime= m_cTimer.Seconds();
702  if (dWDur)
703  dwWait= (DWORD)((dWDur-(dCurrTime-dWStart))<0.004?4:ceil(1000*(dWDur-(dCurrTime-dWStart))));
704  if (dRDur)
705  dwWait= (DWORD)min((dRDur-(dCurrTime-dRStart))<0.004?4:ceil(1000*(dRDur-(dCurrTime-dRStart))), dwWait);
706  }
707 
708  sBaseOut.sBaseIn.dwSize= sizeof(SBaseIn);
709  sBaseOut.sBaseIn.eType= eResponse;
710  sBaseOut.sBaseIn.nError= DEVICE_CLOSING;
711  sData.dwSize= sizeof(SBaseIn);
712  while (m_asRPackets.GetSize())
713  {
714  sPacket= m_asRPackets.Front(true, bValid);
715  if (!sPacket || !bValid)
716  continue;
717  sData.pHead= m_pcMemPool->PoolAcquire(sData.dwSize);
718  if (sData.pHead)
719  {
720  memcpy(sData.pHead, &sBaseOut.sBaseIn, sData.dwSize);
721  m_pcComm->SendData(&sData, sPacket->llId);
722  }
723  m_pcMemPool->PoolRelease(sPacket->psSerialData);
724  delete sPacket;
725  }
726  while (m_asWPackets.GetSize())
727  {
728  sPacket= m_asWPackets.Front(true, bValid);
729  if (!sPacket || !bValid)
730  continue;
731  sData.pHead= m_pcMemPool->PoolAcquire(sData.dwSize);
732  if (sData.pHead)
733  {
734  memcpy(sData.pHead, &sBaseOut.sBaseIn, sData.dwSize);
735  m_pcComm->SendData(&sData, sPacket->llId);
736  }
737  m_pcMemPool->PoolRelease(sPacket->psSerialData);
738  delete sPacket;
739  }
740  return 0;
741 }
DWORD GetInfo(void *pHead, DWORD dwSize)
void ProcessData(const void *pHead, DWORD dwSize, __int64 llId)
virtual int SendData(const SData *pData, __int64 llId)=0
virtual DWORD GetInfo(void *pHead, DWORD dwSize)
LARGE_INTEGER GetStart() const
Definition: misc tools.h:69
int GetSize()
Definition: cpl queue.h:52
double Seconds() const
Definition: misc tools.cpp:63
virtual void Close()=0
void ProcessData(const void *pHead, DWORD dwSize, __int64 llId)
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
CChannelSerial(const TCHAR szPipe[], int nChan, SChanInitSerial &sChanInit, int &nError, LARGE_INTEGER &llStart)