Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Система";
Текущий архив: 2004.02.29;
Скачать: [xml.tar.bz2];

Вниз

Проблема с COM-портом   Найти похожие ветки 

 
rus_alexey   (2003-12-10 10:54) [0]

Проблема состоит в следующем:
В потоке открывается COM порт, и поток начинает ожидать сообщения с порта (сообщение считается завершенным по приходу символа разрыва строки)

Так вот, все работает ОК, но через разные промежутки времени
порт перестает работать, перезапуск программы не помогает.
Тем не менее, порт открывается успешно. Если вызвать mode
из командной строки, то параметры порта во время неполадки
будут такими:

BaudRate: 1200
DataBits: 8
Parity: none
StopBits: 1
и т.п.


Все ок, кроме скорости порта (должно быть 9600 для работы устройства)
Рога в том, что при перезапуске проги после того, как неполадка произошла, параметры останутся НЕИЗМЕННЫМИ (хотя SetCommState не возвращает никаких ошибок)

Самое обидное, что проблема исчезает после открытия этого порта с установкой всех нужных параметров в HyperTerminal (на время ес-сно) :(

Я понимаю что косяк мой, но не могу его найти.
Привожу листинг метода Execute своего потока:


inherited;
FreeOnTerminate:= True;
FMessage:= "";
FPort:= CreateFile(PChar(PortName),GENERIC_READ or GENERIC_WRITE,0,nil,OPEN_EXISTING,FILE_FLAG_OVERLAPPED,0);
try
if FPort <> INVALID_HANDLE_VALUE then
begin
BuildCommDCB("BAUD=9600 PARITY=N DATA=8 STOP=1 to=on xon=off octs=on dtr=off rts=hs",StartDCB);
StartDCB.EvtChar:= #13;
if not SetCommState(FPort,StartDCB) then raise Exception.Create("Ошибка при установке параметров порта "+PortName+"."+#13+"Код ошибки: "+IntToStr(GetLastError));
FOverlapped.hEvent:= CreateEvent(nil,True,False,nil);
if FOverlapped.hEvent = INVALID_HANDLE_VALUE then raise Exception.Create("Ошибка при создания обработчика событий."+#13+"Код ошибки: "+IntToStr(GetLastError));
if not PurgeComm(FPort,PURGE_TXABORT or PURGE_RXABORT or PURGE_TXCLEAR or PURGE_RXCLEAR) then raise Exception.Create("Ошибка очистки буферов порта."+#13+"Код ошибки: "+IntToStr(GetLastError));
SetupComm(FPort,256,0);
SetCommMask(FPort,EV_RXFLAG);
repeat
QueryPort;
Sleep(5);
until Terminated;
CloseHandle(FOverlapped.hEvent);
CloseHandle(FPort);
end else
begin
raise Exception.Create("Ошибка при открытии порта."+#13+"Код ошибки: "+IntToStr(GetLastError));
end;
except
on E: Exception do
begin
FErrorMessage:= E.Message+#10+"Сообщите об ошибке разработчику";
Synchronize(WriteErrorMessage);
if FOverlapped.hEvent <> INVALID_HANDLE_VALUE then CloseHandle(FOverlapped.hEvent);
if FPort <> INVALID_HANDLE_VALUE then CloseHandle(FPort);
Terminate;
end;
end;


 
rus_alexey   (2003-12-10 10:59) [1]

P.S.
В процедуре QueryPort потока проверается GetOverlappedResult и читаются данные ReadFile"ом с использованием стр-ры Overlapped


 
qnx   (2003-12-10 14:30) [2]

1.BuildCommDCB не юзал (проще заполнить структуру), но проверить стоит StartDCB.
2.Про QueryPort, пожалуйста, поподробнее!!! Должно быть что-то вроде (ниже кусок обработчика нити для чтения):


var
szInputBuffer:array[0..INPUTBUFFERSIZE-1] of Char;
nNumberOfBytesRead: DWORD;
HandlesToWaitFor: array[0..3] of THandle;
dwHandleSignaled: DWORD;
dwMS,dwEventMask: DWORD;
overlappedRead: TOverlapped;
overlappedCommEvent: TOverlapped;
...
begin
...
overlappedRead.hEvent := CreateEvent( nil, True, True, nil);
overlappedCommEvent.hEvent := CreateEvent( nil, True, True, nil);
hReady := CreateEvent( nil, false, False, nil );
hCloseEvent := CreateEvent( nil, false, False, nil );

HandlesToWaitFor[0] := hCloseEvent;
HandlesToWaitFor[1] := overlappedCommEvent.hEvent;
HandlesToWaitFor[2] := overlappedRead.hEvent;
HandlesToWaitFor[3] := hReady;

if not SetCommMask(hCommFile, EV_BREAK or
EV_CTS or
EV_DSR or
EV_RING or
EV_RLSD or
EV_TXEMPTY or
EV_ERR or
EV_RX80FULL or
EV_PERR) then exit;

if not SetupCommEvent( @overlappedCommEvent, dwEventMask ) then exit;
if not SetupReadEvent( @overlappedRead,szInputBuffer,INPUTBUFFERSIZE , nNumberOfBytesRead ) then exit;

while True do
begin
dwHandleSignaled := WaitForMultipleObjects(4, @HandlesToWaitFor, False, INFINITE);

case dwHandleSignaled of
WAIT_OBJECT_0+3 :
ReceiveData( CountBytes );

WAIT_OBJECT_0: break;

WAIT_OBJECT_0 + 1: // CommEvent signaled.
begin
if not HandleCommEvent( @overlappedCommEvent, dwEventMask, TRUE ) then break;
if not SetupCommEvent( @overlappedCommEvent, dwEventMask ) then break;
WAIT_OBJECT_0 + 2: // Read Event signaled.
begin
// Get the new data!
if not HandleReadEvent( @overlappedRead,szInputBuffer, INPUTBUFFERSIZE, nNumberOfBytesRead ) then break;
// Wait for more new data.
if not SetupReadEvent( @overlappedRead,szInputBuffer, INPUTBUFFERSIZE, nNumberOfBytesRead ) then break;
end;
WAIT_FAILED:break;

end; {case dwHandleSignaled}
end; {while True}

CloseHandle( overlappedRead.hEvent );
CloseHandle( overlappedCommEvent.hEvent );
CloseHandle( hReady );
CloseHandle( hCloseEvent );

....

end;


 
rus_alexey   (2003-12-11 11:42) [3]

BuildCommDCB имеет синтаксис такой же как и у cmd-утилиты mode,
пробовал и так и так (заполнял стр-ру DCB).

Почитаю и попробую, спасибо за помощь

Query port выглядит так:

var
CommMask: DWORD;
BytesRead: DWORD;
BytesRead2: DWORD;
Buffer: array [1..256] of char;
SignalPos: integer;
begin
if GetOverlappedResult(FPort,FOverlapped,BytesRead,False) then
begin
if BytesRead > 0 then
begin
SignalPos:= ArrayPos(Buffer,#13);
if SignalPos > 0 then
begin
FMessage:= FMessage + Copy(Buffer,1,SignalPos);
Synchronize(WriteMessage);
FMessage:= "";
end else
begin
FMessage:= FMessage + Copy(Buffer,1,BytesRead);
end;
end;
FillChar(Buffer,SizeOf(Buffer),#0);
ReadFile(FPort,Buffer,SizeOf Buffer),BytesRead2,@FOverlapped);
end;
end;


 
Erik   (2003-12-11 17:42) [4]

Лучше делай GetCommState заполняй то, что тебе нужно а после
SetCommState


 
rus_alexey   (2003-12-12 06:14) [5]

To Erik

В первой версии и было так...
С тем же результатом... Я и подумал, что м/б так заработает


 
Yaga   (2003-12-12 10:45) [6]

Чем WaitCommEvent() не понравился?
Но все равно не совсем понимаю, зачем вы используете поток и еще OVERLAPPED?
Ну ладно, дело хозяйское.

Для отладки, уберите все лишнее. Уберите флаг оверлапед, оставьте только CreateFile(), GetCommState(), SetCommState(), SetCommMask(), ну и ReadFile(), если правильно работает то наращивайте код и отлавливайте после чего возникает такая ошибка.

Вы не задаете таймауты, а зря. Наверно стоит GetCommTimeouts(), SetCommTimeouts()

И еще хочу обратить ваше внимание на заполнение структуры DCB.
BuildCommDCB("BAUD=9600 PARITY=N DATA=8 STOP=1 ...
STOP=1 как понимаю стоповый бит. А почему вы так смело присваиваете 1? и НЕ ТОЛЬКО ЭТУ КОНСТАНТУ, см. хелп.
PortDCB.StopBits = ONESTOPBIT; // 0,1,2 = 1, 1.5, 2
#define ONESTOPBIT 0 // а не 1!!!
Если конечно правильно поняла, что вам нужен один стоповый а не 1.5, если нет, то сорьки.

И ручками уберите Device Manager / Communications Port (COM1/2) Properties / Flow control = None


 
y-soft   (2003-12-12 11:03) [7]

>rus_alexey ©

Возможно, Вы привели неполный код, но возникают замечания:

1. Перед чтением из порта полезно вызывать ClearCommError

2. Структуру Overlapped перед каждым вызовом ReadFile надо заполнять нулями (кроме поля hEvent), а после получения результата hEvent с ручным сбросом - принудительно сбрасывать событие

3. Необходимо проверять результат ReadFile и при возникновении ошибки, отличной от ERROR_IO_PENDING, переинициализировать порт и связанные структуры - я, например, сталкивался с вылетом при подключении питания внешнего устройства (ошибка 995 ERROR_OPERATION_ABORTED)

4. Недавно обнаружил, что GetOverlappedResult даже с установленным флагом ожидания иногда срабатывает преждевременно (помогает Sleep(10))



Страницы: 1 вся ветка

Форум: "Система";
Текущий архив: 2004.02.29;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.47 MB
Время: 0.011 c
1-93920
NoOne
2004-02-15 12:01
2004.02.29
Chart


1-93874
MadGhost
2004-02-15 12:29
2004.02.29
можно ли использовать один класс в разных модулях?


6-94073
Gefest
2003-12-22 23:41
2004.02.29
TTcpServer TTcpClient


1-93918
Demik
2004-02-15 10:13
2004.02.29
Помогите:Как использовать TDrawGrid Для вывода текста и картинок


4-94225
dima_shapkin
2003-12-24 18:16
2004.02.29
Рамка





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский