Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 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
2-1253742041
Германн
2009-09-24 01:40
2009.11.08
Секция except


15-1252382165
AleKo
2009-09-08 07:56
2009.11.08
Опции ilink32.exe


15-1251905091
TStas
2009-09-02 19:24
2009.11.08
"Мои документы" на другом диске


15-1250661192
leonidus
2009-08-19 09:53
2009.11.08
Компонент для отображения HTML


2-1253171778
Б
2009-09-17 11:16
2009.11.08
Русский текст в консольном приложении.





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский