Всем доброго времени суток.
Опишу все вкратце
Задача такова: на порт приходят приерно раз в секунду несколько байтов данных
использую с++ builder 6 (пробовал этот же проект в 2010 , ситуация та же),
пользуюсь функциями из SDK(правильно ли оперирую терминами , поправьте если что)
код собран из примеров
http://msdn.microsoft.com/en-us/library/ms810467.aspx
может важно а может нет - на компьютере нет com порта!! , для эмуляции всего процесса используется программа VSPD которая создает два порта и программа PROTEUS которая эмулирует устройство
на эти вещи не грешу - изначально делал в NONOVERLAPPED режиме и данные читались без проблем
НО как оказалось, это дубовый способ, ибо я жду прерывания (раз в секунду же) , а если ничего не приходит (сломалось устройство оторвался провод...) то функция WaitCommEvent будет ждать ждать ждать...
причем если делать чтение в отделном потоке а потом его пытатся завершить то виснет и основной поток
поэтому решил делать в OVERLAPPED режиме(ну и тоже в отделном потоке) ,
но тут возникает непонятная проблема - вроде все как показано на ссылке выше, НО функция чтения ReadFile возвращает false а функция GetLastError возвращает 998 ошибку (error_noaccess)
порядок действий в коде ниже таков:
создаем хендл для чтения (типа открываем файл с именем "COM7" скажем)
устнавливаем настройки (может тут где проблема) bcb структура , временные интервалы для чтения, тип прерывания,OVERLAPPED структура
далее в цикле WaitCommEvent возвращает ERROR_IO_PENDING и начинаем ждать функцией WaitForSingleObject когда они прибудут
данные прибыли , функция возвратила WAIT_OBJECT_0 и мы ждем функцией GetOverlappedResult когда будут прочитан байт
вот тут самое интересное - функция возвращает true
и numbytes_ok содержит "4" ,хотя во-первых я посылаю 6 байт(5 и символ перевода строки)
а во-вторых GetOverlappedResult выполняется после каждого принятого байта
причем читается всего 5 байтов!!
вызываем функцию ReadFile , она возвращает FALSE а GetLastError возвращает ошибку 998(error_noaccess)
numbytes_ok после этого равна 0
и причем numbytes_ok = 4 устанавливается после первого же принятого байта (точнее после первого захода в WAIT_OBJECT_0 из пяти между секундными интервалами)
какие либо перестановки в коде ничего толком не дали,
если все элементы не принадлежащие потоку засунуть в метод и вызывать через Synchronize то ситуация все та же
в общем наверно где-то допустил тупую ошибку и прошу беглым взглядом проверить сведущих людей данный код
заранее спасибо!
Код:
DCB dcb;
_COMSTAT ComState;
DWORD numbytes_ok;
DWORD dwEvtMask;
HANDLE hCom = CreateFile( portName,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
0
);
READ = GetCommState(hCom, &dcb);
dcb.BaudRate = 9600;
dcb.ByteSize = 8;
dcb.Parity = NOPARITY;
dcb.StopBits = ONESTOPBIT;
READ = SetCommState( hCom, &dcb );
COMMTIMEOUTS CT;
GetCommTimeouts( hCom, &CT) ;
CT.ReadIntervalTimeout = 1;
CT.ReadTotalTimeoutMultiplier = MAXDWORD;
CT.ReadTotalTimeoutConstant = MAXDWORD;
SetCommTimeouts( hCom, &CT );
if (!SetCommMask(hCom,EV_RXCHAR))
Form1->Memo1->Lines->Add("error setting communications mask; abort");
int STATUS_CHECK_TIMEOUT =1300 ; // Milliseconds
DWORD dwCommEvent;
BOOL fWaitingOnStat = FALSE;
OVERLAPPED osStatus ;
osStatus.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (osStatus.hEvent == NULL)
Form1->Memo1->Lines->Add("error creating event; abort");
if(READ)Form1->Memo1->Lines->Append("ОК");
char *buf_in;
while (!Thr->Terminated && READ)
{
if (!fWaitingOnStat && !Thr->Terminated)
{
if (!WaitCommEvent(hCom, &dwCommEvent, &osStatus))
{
if (GetLastError() == ERROR_IO_PENDING)
{
Form1->Memo1->Lines->Add("ERROR_IO_PENDING");
fWaitingOnStat = TRUE;
// Form1->Memo1->Lines->Add(AnsiString(numbytes_ok)+" "+ "0");
}
else
{
Form1->Memo1->Lines->Add(" error in WaitCommEvent; abort");
break;
}
}
else
{
Form1->Memo1->Lines->Add("WaitCommEvent returned immediately");
}
}
// Check on overlapped operation.
if (fWaitingOnStat && READ)
{
switch(WaitForSingleObject(osStatus.hEvent, STATUS_CHECK_TIMEOUT))
{
case WAIT_OBJECT_0:
if (!GetOverlappedResult(hCom, &osStatus, &numbytes_ok, TRUE))
{
Form1->Memo1->Lines->Add("An error occurred in the overlapped operation");
}
else
{
/////////////////////////////////////////////////////////////////////////////////READING
if(ReadFile(hCom, buf_in, 1, &numbytes_ok, &osStatus))
{
Form1->Memo1->Lines->Add(buf_in);
}
else
{
Form1->Memo1->Lines->Add(GetLastError());
}
Form1->Memo1->Lines->Add(numbytes_ok);
}
fWaitingOnStat = FALSE;
break;
case WAIT_TIMEOUT:
Form1->Memo1->Lines->Add("WAIT_TIMEOUT");
break;
default:
Form1->Memo1->Lines->Add("CloseHandle");
CloseHandle(osStatus.hEvent);
}
}
}