Форум: "Начинающим";
Текущий архив: 2009.11.08;
Скачать: [xml.tar.bz2];
ВнизRS-232/ WaitCommEvent - как выйти? Найти похожие ветки
← →
i2e (2009-09-21 13:26) [0]возможно, в теме не очень корректно задан вопрос. более подробно будет так. есть рабочая программа, в которой организован поток приема данных по RS-232. вот часть:
while True do begin // бесконечный цикл приема данных
if not MainForm.fPortCreate then begin // если нет признака открытия порта..
CloseHandle(hCom);
TerminateThread(hThread, 0); Exit; // ..освободить и выйти
end;
//
WaitCommEvent(hCom, TransMask, @Ovr); // иначе - ждем символ $99 (заданный в ovr)
if (TransMask and EV_RXFLAG) = EV_RXFLAG then // проверяем событие: принят символ $99 - начало посылки
.... // и так далее на анализ принятого
....
end;
когда есть данные на порту, всё отрабатывается и порт освобождается.
но когда данных нет, программа ждёт приема в WaitCommEvent.
и замирает на этой фукнции. соответственно не проверяется по флагу fPortCreate необходимость освободить порт.
можно ли как-то ограничить время ожидания в WaitCommEvent, или чем-либо прерывать ее?
← →
Сергей М. © (2009-09-21 13:33) [1]Ты справку к WaitCommEvent читал ?
← →
i2e (2009-09-21 13:54) [2]читал, но наверно плохо?
← →
Сергей М. © (2009-09-21 14:15) [3]Наверно плохо.
Там есть Remarks, напрямую касающиеся твоей "беды"
← →
Вариант (2009-09-21 15:32) [4]
> i2e (21.09.09 13:26)
> WaitCommEvent(hCom, TransMask, @Ovr); // иначе - ждем
> символ $99 (заданный в ovr)
Очень интересный комментарий. Хотя бывает, конечно что комментарий по ошибке не на той строке... но хотелось бы увидеть код открытия порта... ибо если задан флаг FILE_FLAG_OVERLAPPED, то WaitCommEvent не должен как-либо "замирать", в противном случае, если FILE_FLAG_OVERLAPPED не задан, то @Ovr как бы ни к чему. Второй вопрос - к чему нужен
> MainForm.fPortCreate ?
Я так понимаю работа ведется таки в не оверлаппед режиме и надо завершить поток , на это один из вариантов ответа уже был дан в [3].
← →
i2e (2009-09-21 17:08) [5]перечитал вдоль/поперёк [3] - но пока мои попытки и пробы результата не дали.
по прежнему - нет данных -> замирание на WaitCommEvent.
скажу честно, мог накосячить.
______________________________
на [4]:
код открытия порта - основное, остальное - мои мелочи.
понимаю, что много кода, но зато всё, что делал для открытия порта..
задумка была такая: основная программа (MainForm) не успевала, на фоне остальных задач, отрабатывать непрерывные данные на RS-232, были пропуски данных.
организован поток, который обеспечивает непрерывный приём и передаёт что надо на обработку в MainForm.
в том виде как написано - работает чудесно, пропусков нет.
чтобы освободить порт из MainForm - введён fPortCreate (флаг "порт открыт").
и по сбросу в MainForm -> хотел освободить порт.
данные на порту есть -> освобождается.
данных нет - вот тут и "фигушки".
предвидя ваши ответы, пойду читать help :)procedure PortInit;
var
Port: PChar;
fResult: boolean; // удачное исполнение процедур
ThreadID: dword; // идентификатор потока
begin
...
hCom :=
CreateFile( Port, // COM1, COM2, ...
GENERIC_READ + GENERIC_WRITE, // access (read-write) mode
0, //-- share mode
nil, // address of security descriptor
OPEN_EXISTING, //-- how to create
0, // file attributes
0 ); //-- handle of file with attributes to copy
if (hCom = INVALID_HANDLE_VALUE) then
begin MessageDlg("Порт " + Port + " занят или не существует", mtError, [mbOk], 0);
CloseHandle(hCom); Exit;
end;
fResult := SetCommMask(hCom, EV_RXFLAG); // ставим маску - "по приёму определенного символа"
if not fResult then ...
fResult := GetCommState(hCom, mdcb);
...
mdcb.ByteSize := 8; // byte: number of bits/byte, 4-8
mdcb.StopBits := 0; // byte: 0,1,2 = 1, 1.5, 2
mdcb.EvtChar := chr($99); // <----- символ для старта приёма -----
...
fResult := SetCommState(hCom, mdcb);
if not fResult then ...
mCommTOut.ReadIntervalTimeout := 5; // интервал между прибытием двух символов
mCommTOut.ReadTotalTimeoutMultiplier := 1; // 1 - общая величина задержки чтения. умножается на сумму запрошенных байтов
mCommTOut.ReadTotalTimeoutConstant := 200;
mCommTOut.WriteTotalTimeoutMultiplier := 0;
mCommTOut.WriteTotalTimeoutConstant := 0;
fResult := SetCommTimeouts( hCom, mCommTOut);
if not fResult then ...
fResult := SetupComm(hCom, // handle of communications device
constMaxBuf, // size of input buffer
constMaxBuf); // size of output buffer
// создаем поток
hThread := CreateThread(nil, 0,
@ReadComm, // адрес процедуры, по которой производится обработка
nil, 0,
ThreadID); // идентификатор потока
MainForm.fPortCreate := True;
end; {PortInit}
procedure ReadComm; // процедура обработки потока
...
begin
...
while True do begin
if not MainForm.fPortCreate then begin
CloseHandle(hCom);
TerminateThread(hThread, 0);
Exit;
end;
WaitCommEvent( hCom, TransMask, @Ovr); // <--- вот здесь и тормозимся, если данных нет
if (TransMask and EV_RXFLAG) = EV_RXFLAG then // проверяем событие: найден адрес $99
... // данные готовятся для главной формы
end; {while}
end; {ReadComm}
← →
Сергей М. © (2009-09-21 21:10) [6]
> перечитал вдоль/поперёк [3]
Неужто знакомые буквы искал ?)
If a process attempts to change the device handle"s event mask by using the SetCommMask function while an overlapped WaitCommEvent operation is in progress, WaitCommEvent returns immediately
← →
Вариант (2009-09-22 07:00) [7]
> i2e (21.09.09 17:08) [5]
Еще несколько мыслей вслух.....
Ты открываешь порт в не оверлаппед режиме, а потому выброси в
> WaitCommEvent( hCom, TransMask, @Ovr)
@Ovr, оно тебе не надо. В даннорм случае это мусор в коде. Для создания потока ты используешь CreateThread. Если тебя не устраивает уже готовый класс TThread в дельфи, то рекомендую тебе использовать вместо CreateThread -> BeginThread(хотя и не обязательно, если ты знаешь, что делаешь).
Далее - ты настраиваешь интервалы чтения для порта. В связи с этим есть вопрос - EvtChar сигнализирует в твоем случае о чем? Это конец последовательности данных? Если да - то я бы сделалmCommTOut.ReadIntervalTimeout := MAXDWORD; // интервал между прибытием двух символов
mCommTOut.ReadTotalTimeoutMultiplier := 0; // 1 - общая величина задержки чтения. умножается на сумму запрошенных байтов
mCommTOut.ReadTotalTimeoutConstant := 0;
Далее - в дополнении к уже сказанному о прекращении ожидания WaitCommEvent.
Выйти из WaitCommEvent еще можно закрыв порт. Но в любом случае тебе надо проверять результат, возвращаемый WaitCommEvent. Может вернуться false. Да и проверить твой флаг
> MainForm.fPortCreate
тоже не лишнее - зачем делать дальше что-то по обработке данных, если дана команда закрыться....
← →
i2e (2009-09-22 12:04) [8]на [6]:
пробовал. то есть когда программа ждёт приёма, пробовал сделатьSetCommMask(hCom, EV_BREAK {и др значения});
висит, ждёт. вместо обещанного
WaitCommEvent returns immediately.
что-то я не то делаю...
на [7]:
пример, по которому делаю, сдул с книги, и в целом всё устраивало (по этой части не особо мастер :).
в основном окне есть кнопки Старт, Пауза, Стоп - по приему данных.
так вот, Стоп не отпускает порт, хотя принимать прекращает.
и повторный Старт работает.
по Стопу пытался в разных комбинациях сделать://
// CloseHandle(hCom);
// TerminateThread(hThread,0); {завершить поток приема данных}
// CancelIO(hCom);
// SetCommMask(hCom, EV_BREAK); //
в итоге или просто ничего (не отпускает порт), или программа останавливается. ждёт, блин.
$99 (EvtChar) - это один из признаков начала.
как пойман 99 - запускается ReadFile:WaitCommEvent(hCom, TransMask, nil);
if (TransMask and EV_RXFLAG) = EV_RXFLAG then // проверяем событие: найден адрес "99 - всем" - начало пакета
begin
TransMask := 0;
ClearCommError(hCom, Errs, @Stat); // сбрасываем флаг
//
// прием данных
Len := Stat.cbInQue;
ReadFile(hCom, PortFrame, Len, NmrOfRx, @Ovr);
...
end;
← →
Сергей М. © (2009-09-22 12:26) [9]
> что-то я не то делаю
Ты создаешь порт для работы с ним НЕ в overlapped-режиме.
← →
i2e (2009-09-22 12:30) [10]блин. придётся познавать overlapped-режим.
не было печали.
Страницы: 1 вся ветка
Форум: "Начинающим";
Текущий архив: 2009.11.08;
Скачать: [xml.tar.bz2];
Память: 0.49 MB
Время: 0.006 c