Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2009.11.08;
Скачать: CL | DM;

Вниз

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;
Скачать: CL | DM;

Наверх




Память: 0.51 MB
Время: 0.013 c
2-1253656832
redlord
2009-09-23 02:00
2009.11.08
ansistring


11-1207381883
Сашик
2008-04-05 11:51
2009.11.08
Запись в ресурсы DLL


15-1252640404
Дмитрий С
2009-09-11 07:40
2009.11.08
Символ неразрывного пробела


15-1252345693
oldman
2009-09-07 21:48
2009.11.08
Поиск и группировка файлов по "тэгам"


2-1253179117
5645454
2009-09-17 13:18
2009.11.08
какова допустимая длина имени класса, модуля?