Есть поток чтения, где мы ожидаем событие из порта по маске (EV_RXCHAR).
функция ожидание выглядит так:
DWORD signal = WaitForMultipleObjects(2, phevnt_rx, false, timeout_ms);
где
phevnt_rx - содержит предварительно созданное событие из TOverlapped и событие для остановки потока;
timeout_ms - время таймаута для подсчета времени отсутствия информации на прием.
Использование timeout_ms (равного у меня 10 мс) вместо INFINITE привело к тому, что
поток чтения не всегда считывает последний пришедший байт.
Событие порта о пришедшем последнем байте не происходит после таймаута.
Как сделать так чтобы после таймаута получить это байт?
//открытие порта:
Код:
bool TRS232::open(t_rs232_cfg &cfg) {
TDCB dcb;
TCommTimeouts TimeOuts;
if(_bIsEnable)
return _bIsEnable;
_bIsEnable = false;
AnsiString CommPort;
CommPort.sprintf("\\\\.\\%s",cfg.sz_name);
do {
_hPort = CreateFile(CommPort.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
if (_hPort == INVALID_HANDLE_VALUE)
break;
if (!SetCommMask(_hPort, EV_RXCHAR) && !SetupComm(_hPort, _nBuffSize,
_nBuffSize) && !PurgeComm(_hPort,
PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR)) {
CloseHandle(_hPort);
break;
}
GetCommState(_hPort, &dcb);
dcb.DCBlength = sizeof(TDCB);
dcb.fBinary = 1;
dcb.BaudRate = (DWORD)(cfg.ebaud);
dcb.ByteSize = (BYTE)(cfg.edbits);
dcb.StopBits = (BYTE)(cfg.esbits);
dcb.Parity = (BYTE)(cfg.eprt);
if (!SetCommState(_hPort, &dcb))
{
CloseHandle(_hPort);
long err=GetLastError();
STRING err_string="init_err:";
err_string+=IntToStr(err);
break;
}
TimeOuts.ReadIntervalTimeout = MAXDWORD;
TimeOuts.ReadTotalTimeoutConstant = 0;
TimeOuts.ReadTotalTimeoutMultiplier = 0;
TimeOuts.WriteTotalTimeoutMultiplier = 0;
TimeOuts.WriteTotalTimeoutConstant = 0;
if (!SetCommTimeouts(_hPort, &TimeOuts)) {
CloseHandle(_hPort);
break;
}
_bIsEnable = true;
}
while (0);
return _bIsEnable;
}
//поток чтения
Код:
void t_stream_rs232::_thread()
{
int ret;
_rs232.set_mask(EV_RXCHAR);//устанавливаем маску для порта
do
{
ret=_read(); //cм. ниже
}while (ret!=N_EVNT_TERM);
}
//
Код:
void TRS232::set_mask(DWORD mask)
{
_mask = mask;
SetCommMask(_hPort, mask);
_ovr_read.hEvent = CreateEvent(NULL, true, true, NULL);
}
//функция read
Код:
int __fastcall t_stream_rs232::_read(void)
{
try
{
int nread, toread;
toread = _rs232.wait_read_event(_hevnt_term_l, N_MS);//см. ниже
switch(toread)
{
case RS232_EVENT_TIMEOUT:
if (_on_timeout != NULL)
_on_timeout(N_MS);
return 0;
case RS232_EVENT_TERMINATE:
return N_EVNT_TERM;
default:
while(toread > 0)
{
nread = _rs232.read( _buf, sizeof(_buf) );
toread -= nread;
if (_on_read != NULL)
_on_read(_buf, nread);
}
return 0;
}
}
catch(Exception *ex)
{
MessageBox(NULL,ex->Message.c_str(),"t_stream_rs232::_read",MB_OK);
}
return 0;
}
//Ожидание прихода байтов данных:
Код:
int TRS232::wait_read_event(HANDLE event_terminate, DWORD timeout_ms)
{
DWORD mask, temp, signal;
COMSTAT comstat;
HANDLE phevnt_rx[2] = {_ovr_read.hEvent , event_terminate};
_ovr_read.Internal = 0;
_ovr_read.InternalHigh = 0;
_ovr_read.Offset = 0;
_ovr_read.OffsetHigh = 0;
//ClearCommError(_hPort, &temp, &comstat);
SetEvent(_ovr_read.hEvent);
WaitCommEvent(_hPort, &mask, &_ovr_read);
signal = WaitForMultipleObjects(2, phevnt_rx, false, timeout_ms);
int ret;
switch(signal)
{
case WAIT_OBJECT_0:
{
if( !GetOverlappedResult(_hPort, &_ovr_read, &temp, false) )
{
ret = EIO;
break;
}
ClearCommError(_hPort, &temp, &comstat);
ret = comstat.cbInQue;
break;
}
case WAIT_TIMEOUT:
ret = RS232_EVENT_TIMEOUT;
break;
case WAIT_OBJECT_0+1:
ret = RS232_EVENT_TERMINATE;
break;
default:
ret = 0;
break;
}
return ret;
}
//чтение из порта:
//-------------------------------------------------------------------------
Код:
int TRS232::read(BYTE* pbuf, DWORD nlen) {
DWORD nread;
if (!_bIsEnable)
return -1;
if (pbuf == NULL)
return -1;
if (nlen <= 0)
return 0;
if (!ReadFile(_hPort, pbuf, nlen, &nread, &_ovr_read))
return -1;
return nread;
}