Форум: "WinAPI";
Текущий архив: 2005.02.13;
Скачать: [xml.tar.bz2];
ВнизВопрос по работе с COM портом Найти похожие ветки
← →
Роман (2004-12-16 09:56) [0]Вопрос следующий:
При работе с СОМ портом для приёма данных пользуюсь примерно такой процедурой в отдельном потоке:
Stat : TComStat;
...
TransMask:=0;
WaitCommEvent(CommHandle,TransMask,@Ovr);
if (TransMask and EV_RXCHAR)=EV_RXCHAR Then
begin
ClearCommError(CommHandle,Errs,@Stat);
If stat.cbInQue=1 Then ...
...
При первом приёме данных (после запуска программы) почему-то в stat.cbInQue оказывается ровно восемь байт, а остальные куда-то пропадают. При повторной посылке данных принимаются все байты. В чём может быть проблема ?
← →
Digitman © (2004-12-16 10:13) [1]1. Неправильный алгоритм работы в overlapped-режиме - возврат из ф-ции WaitCommEvent() вовсе не означает, что приняты "все байты" .. следует анализировать рез-т выполнения этой ф-ции в соответствии с ее описанием
кр.того результат завершения overlapped-операции можно и, как правило, нужно проверять с пом. ф-ции GetOverlappedResult()
2. По поводу использования ф-ции ClearCommError() в справке сказано :
The function is called when a communications error occurs
Непонятно, почему ты вызываешь эту ф-цию безусловно .. на основании чего ты уверен, что возникла ошибка ?
← →
tesseract (2004-12-17 17:15) [2]2. По поводу использования ф-ции ClearCommError() - не правда! чере неё байты и смотрятся.
WaitCommEvent(CommHandle,TransMask,@Ovr);
-> а WaitForSingleObject и GetOverlappedResult???
Для избавления от лишних байт при старте программы - PurgeCom
Для получения ВСЕХ байт - Если ClearComError не вернул нужное ко-во ну подожди ещё 100 мс :-) Или опять же ReadFile - сколько нужно байт и подождать до их прибытия в буфер.
← →
ECM © (2004-12-17 18:11) [3]2 tesseract
ClearCommError возвращает
cbInQue
Number of bytes received by the serial provider but not yet read by a ReadFile operation.
Это состояние внутренних буферов драйвера но не ReadFile
Поэтому смотреть через нее -не верно. Только через GetOverlappedResult.
Можешь поверить - http://kolibdb.100free.com/wTerm.zip 80kB - иммено так и построен.. Работает без проблем :)
← →
ECM © (2004-12-17 18:17) [4]Совет: в MSDN есть великолепный пример асинхронной работы с COM-портом - в поиске-MSDN - "mttty"
← →
Роман (2004-12-20 10:17) [5]2 ECM
А как с помощью GetOverlappedResult посмотреть кол-во принятой инф-ии, в хелпе написано:
pNumberOfBytesTransferred
... For a ConnectNamedPipe or WaitCommEvent operation, this value is undefined.
И возвращается совсем не то...
← →
tesseract (2004-12-20 10:29) [6]to ECM именно то что надо эта функция и возвращает. количество оставшихся байт в буфере! Если их меньше, чем надо ,то ждём пока они придут!
← →
ECM © (2004-12-20 10:53) [7]
function ReaderAndStatusThread(Param: Pointer): DWORD;
var
lpoEv: TOverlapped;
lpoRd: TOverlapped;
bStop: Boolean;
//bTmp: Boolean;
cbRead,dwMask: DWORD;
dwRet,dwOvRes: DWORD;
evArr: Array[0..2] of THandle;
bWaitingOnStat: Boolean;
bWaitingOnRead: Boolean;
pCom: PComPort absolute Param;
begin
Assert(Assigned(pCom));
with pCom^ do begin
FillChar(lpoEv,SizeOf(lpoEv),0);
lpoEv.hEvent := CreateEvent(nil,TRUE,FALSE,nil);
Assert(lpoEv.hEvent<>0, SysErrorMessage(GetLastError()));
FillChar(lpoRd,SizeOf(lpoRd),0);
lpoRd.hEvent := CreateEvent(nil,TRUE,FALSE,nil);
Assert(lpoRd.hEvent<>0, SysErrorMessage(GetLastError()));
bStop := SetCommMask(hComPort,dwCommMask);
Assert(bStop,SysErrorMessage(GetLastError()));
bStop := FALSE;
bWaitingOnStat := FALSE;
bWaitingOnRead := FALSE;
evArr[0] := evGlThreadExit;
evArr[1] := lpoRd.hEvent;
evArr[2] := lpoEv.hEvent;
FillChar(OldComStat,SizeOf(OldComStat),0);
repeat
if WaitForSingleObject(evGlThreadExit,0) = WAIT_OBJECT_0 then break;
if not bWaitingOnRead then begin
if not ReadFile(hComPort,RBuffer^,16384,cbRead,@lpoRd) then begin
dwRet := GetLastError();
if dwRet <> ERROR_IO_PENDING then begin
Assert(FALSE,SysErrorMessage(dwRet));
PostMessage(WinHandle,WM_CLOSE_ON_COM_ERR,dwRet,0);
// bStop := TRUE;
break;
end else bWaitingOnRead := TRUE;
//Assert(FALSE,"Read TO!");
end else begin
dwRet := GetLastError();
if dwRet = ERROR_IO_PENDING then begin
bWaitingOnRead := TRUE;
end else
Assert(FALSE,SysErrorMessage(dwRet));
end;
end;
if bNoEvents then bWaitingOnStat := TRUE;
if not bWaitingOnStat then begin
if (bNoEvents) or (dwCommMask = 0) then bWaitingOnStat := TRUE
else if not WaitCommEvent(hComPort,dwMask,@lpoEv) then begin
dwRet := GetLastError();
if dwRet <> ERROR_IO_PENDING then begin
Assert(FALSE,SysErrorMessage(dwRet));
PostMessage(WinHandle,WM_CLOSE_ON_COM_ERR,dwRet,0);
// bStop := TRUE;
break;
end else bWaitingOnStat := TRUE;
end;
end;
if bWaitingOnRead and bWaitingOnStat then begin
dwRet := WaitForMultipleObjects(3,@evArr,FALSE,INFINITE);
Case dwRet of
WAIT_OBJECT_0,WAIT_ABANDONED_0..WAIT_ABANDONED_0+2: begin
bStop := TRUE;
end;
WAIT_OBJECT_0+1: begin
if GetOverlappedResult(hComPort,lpoRd,cbRead,TRUE) then begin
if cbRead > 0 then begin
Assert(pCom^.WinHandle <> 0, "Не установлен ComPort.WinHandle!");
// if bMirror then ComWriter.WriteBuffer(@RBuffer[0],cbRead);
SendMessage(WinHandle,WM_READ_BUFFER,Integer(RBuffer),cbRead);
ReadTotal := ReadTotal + cbRead;
SendMessage(WinHandle,WM_RD_TOTAL_UPDATE,0,0);
end else begin
// CheckComStat();
SendMessage(WinHandle,WM_READSTAT_TO,0,0);
end;
end else begin
dwRet := GetLastError();
// bStop := TRUE;
if (dwRet <> ERROR_OPERATION_ABORTED) and (WaitForSingleObject(evGlThreadExit,0) <> WAIT_OBJECT_0) then begin
Assert(FALSE,SysErrorMessage(dwRet));
PostMessage(WinHandle,WM_CLOSE_ON_COM_ERR,dwRet,0);
end;
// bStop := TRUE;
break;
end;
if WaitForSingleObject(evGlThreadExit,0) = WAIT_OBJECT_0 then
bStop := TRUE;
bWaitingOnRead := FALSE;
end;
WAIT_OBJECT_0+2: begin
if GetOverlappedResult(hComPort,lpoEv,dwOvRes,FALSE) then
HandleComEvent(pCom,dwMask)
else begin
dwRet := GetLastError();
if (dwRet <> ERROR_OPERATION_ABORTED) and (WaitForSingleObject(evGlThreadExit,0) = WAIT_OBJECT_0) then
// bStop := TRUE
else begin
Assert(FALSE,SysErrorMessage(dwRet));
PostMessage(WinHandle,WM_CLOSE_ON_COM_ERR,dwRet,0);
end;
// bStop := TRUE;
break;
end;
bWaitingOnStat := FALSE;
end;
{
WAIT_TIMEOUT: begin
// PostMessage(WinHandle,WM_READSTAT_TO,0,0);
end;
}
end;
end;
until bStop;
CloseHandle(lpoRd.hEvent);
CloseHandle(lpoEv.hEvent);
end;
Result := 0;
end;
← →
Роман (2004-12-20 10:56) [8]PurgeComm(CommHandle,PURGE_RXCLEAR);
TransMask:=0;
WaitCommEvent(CommHandle,TransMask,@Ovr);
if (TransMask and EV_RXCHAR)=EV_RXCHAR Then
begin
WaitForSingleObject(CommHandle,100);
ClearCommError(CommHandle,Errs,@Stat);
GetOverlappedResult(CommHandle,Ovr,Num,True);
...
И в Num всегда ноль... Поясните пожалуйста поподробней как в данном случае из GetOverlappedResult получить кол-во байт в буфере.
← →
ECM © (2004-12-20 11:11) [9]См. выше
← →
Роман_ (2004-12-22 09:50) [10]Спасибо всем кто ответил. Пробема решилась путём ожидания перед ClearComError. Видимо, действительно не успевали все байты дойти. Теперь нормально
Страницы: 1 вся ветка
Форум: "WinAPI";
Текущий архив: 2005.02.13;
Скачать: [xml.tar.bz2];
Память: 0.49 MB
Время: 0.038 c