Com-порт. Потеря Последних Байтов Посылки.

decay

Member
15.04.2008
6
0
#1
Пишу консольную программу-терминалку. Предназначена для обмена данными по COM-порту между компьютером и устройством.
Режим работы порта - асинхронный (при помощи структуры типа OVERLAPPED). Приложение - двухпоточное.
Для записи в порт используется основной поток, для чтения из порта - поток ReadThread (написал свой класс UniThread).
Для синхронизации между потоками использую мьютекс hMutex.

Проблема состоит в следующем: соединяю Rx и Tx порта и при передаче на малых скоростях (например, 600, 1200 бод и т.д.) обнаруживаю, что теряются последние несколько байт. Однако при увеличении скорости до 115200 бод потерь нет. Увидел закономерность: число потерянных байт напрямую связано со скоростью и числом байт в тестовом пакете, например: при передаче (X*8) байт на скорости 600 бод теряется 8 байт, при передаче (X*8 + 1) байт на скорости 600 бод теряется 1 байт, при передаче (X*8+2) байт - 2 байт и т.д., т.е. число потерянных байт на скорости 600 бод не превышает 8. Причем они не исчезают бесследно, при повторной передаче они всплывают, т.е., очевидно, что эти байты задерживаются в каком-то внутреннем буфере COM-порта. В то же время значение поля cbInQue структуры COMSTAT равно нулю, так что тупо дочитать их с помощью ReadFile(...) я не могу. Пробывал в диспетчере задач отключать FIFO COM-порта или уменьшать его - не помогает. Чувствую ведь, что какая-то тупая ошибка. ОС Win7. Есть у кого какие идеи, отчего такое происходит и как это исправить?


<div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">"Инициализация порта"</div></div><div class="sp-body"><div class="sp-content">ComPort::itsDCB.BaudRate = 600; //задаём скорость передачи 9600 бод
ComPort::itsDCB.fBinary = TRUE; //включаем двоичный режим обмена
ComPort::itsDCB.fOutxCtsFlow = FALSE; //выключаем режим слежения за сигналом CTS
ComPort::itsDCB.fOutxDsrFlow = FALSE; //выключаем режим слежения за сигналом DSR
ComPort::itsDCB.fDtrControl = DTR_CONTROL_DISABLE; //отключаем использование линии DTR
ComPort::itsDCB.fDsrSensitivity = FALSE; //отключаем восприимчивость драйвера к состоянию линии DSR
ComPort::itsDCB.fNull = FALSE; //разрешить приём нулевых байтов
ComPort::itsDCB.fRtsControl = RTS_CONTROL_DISABLE; //отключаем использование линии RTS
ComPort::itsDCB.fAbortOnError = FALSE; //отключаем остановку всех операций чтения/записи при ошибке
ComPort::itsDCB.ByteSize = 8; //задаём 8 бит в байте
ComPort::itsDCB.Parity = NOPARITY; //отключаем проверку чётности
ComPort::itsDCB.StopBits = ONESTOPBIT; //задаём один стоп-бит
if (!SetCommState(ComPort::itsHandle, &itsDCB))
{
CloseHandle(ComPort::itsHandle);
goto PortFail;
}


//if ComPort::InitSettings()
ComPort::itsTimeouts.ReadIntervalTimeout = 100; //таймаут между двумя символами
ComPort::itsTimeouts.ReadTotalTimeoutMultiplier = 100; //общий таймаут операции чтения
ComPort::itsTimeouts.ReadTotalTimeoutConstant = 100; //константа для общего таймаута операции чтения
ComPort::itsTimeouts.WriteTotalTimeoutMultiplier = 100; //общий таймаут операции записи
ComPort::itsTimeouts.WriteTotalTimeoutConstant = 100;

<div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">"Читающий поток ReadThread"</div></div><div class="sp-body"><div class="sp-content">DWORD ReadThread::MainFunc()
{
//int cnt = 0;
char i=0;
DWORD dwWaitMutex;
DWORD dwWaitPort;

OVERLAPPED ReadOL;
DWORD Mask;
DWORD RealRead;
DWORD BytesTrans;
DWORD Err;
char Buffer[20];
int AvaibleBytes;

memset(&ReadOL,0,sizeof(ReadOL));
ReadOL.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
SetCommMask(itsOwner->itsHandle , EV_RXCHAR);

while(!m_bTerminated)
{
//dwWaitMutex = WAIT_OBJECT_0;
dwWaitMutex = WaitForSingleObject(itsOwner->hMutex,INFINITE);
switch (dwWaitMutex)
{
case WAIT_OBJECT_0:
__try
{
//cout << ReadThread::itsLabel ;
__try
{
if (itsOwner->Connected)
{
WaitCommEvent(itsOwner->itsHandle, &Mask, &ReadOL);
dwWaitPort = WaitForSingleObject(ReadOL.hEvent, INFINITE);
if (dwWaitPort == WAIT_OBJECT_0)
{

if ( GetOverlappedResult(
itsOwner->itsHandle,
&ReadOL,
&BytesTrans,
FALSE
) )
{
if ((Mask & EV_RXCHAR))
{
ClearCommError(
itsOwner->itsHandle,
&Err,
&itsOwner->itsState
);

AvaibleBytes = itsOwner->itsState.cbInQue;
ReadFile(
itsOwner->itsHandle,
&Buffer,
AvaibleBytes,
&RealRead,
&ReadOL
);
i=0;
while (i<RealRead)
{
RcvTemp[RcvCnt + i] = Buffer;
i++;
}

RcvCnt += RealRead;


}
}
}
}
}
__finally
{
//
}
//cnt++;
Sleep(1);
}
__finally
{
if (! ReleaseMutex(itsOwner->hMutex))
{
//handle error
}
}
break;
case WAIT_ABANDONED:
cout << "aband ";
//the resource is busy, let's try it again at next time
break;
default:
cout << "default ";
break;
}

}
return 0;
}