|
|
Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
|
Опции темы | Поиск в этой теме | Опции просмотра |
#1
|
|||
|
|||
Грамотно организовать поток для отлова событий COM порта
Уважаемые форумчане, всем добрый день! Подскажите путь решения. Ситуация следующая. Пишу приложение на delphi7, которое через ком порт общается с устройствами в сети (до 255 устройств может быть). Пользуюсь компонентом-библиотекой для работы с ком-портом ComPort Library 4.10 от Dejan Crnila. Приложение сначала сделал однопоточное, ибо программка большую часть времени простаивает и ждет пакет, приходящий в ком порт от любого из устройств. События прихода данных в ком порт отслеживаются и обрабатываются процедурой onRxChar, которая является частью класса этой самой библиотеки. В этой процедуре-обработчике выполняется вся обработка поступивших пакетов, вся реакция на них. Все бы было хорошо, если бы не 2 нюанса.
1. Иногда из сети от устройства может прийти пакет, который должен "усыпить" программу на определенное время. Усыпление я делаю с помощью вызова модального окна без кнопки закрыть его, а только с предупреждением о том, что программа временно приостановлена. (Такой способ приемлем или можно как-то более красиво?): Код:
procedure TF_Main.ComPort1RxChar(Sender: TObject; Count: Integer); begin ComPort1.Read(P_vhod,15); If (P_vhod[9]=1) and (P_vhod[10]=2) and (P_vhod[12]=20)//Если пришел пакет на "засыпание" программы then begin FWait:= TFWait.Create(Self); FWait.ShowModal; end; if (P_vhod[9]=1) and (P_vhod[10]=2) and (P_vhod[12]=21)//Программе надо проснуться then FWait.Close; ... еще много других реакций ... Но когда запущено модальное окно, управление не переходит на прием следующего пакета, который выведет программу из спящего состояния, а все выполнение останавливается на строчке FWait.ShowModal. Типа программа зависла. 2.В программе есть кнопка опроса устройств и отправки данных на устройства. В обработчике кнопки "опросить" запускается цикл от 1 до 255 каждые 50 мс по 3 раза на каждое устройство (765 итераций). Цикл длится примерно 40 секунд. В цикле я отправил пакет на устройство 1. Оно ответило пакетом. Этот пакет пришел в порт, НО обработчик ComPort1RxChar НЕ может пока сработать, ибо сейчас выполняется обработчик нажатия кнопки и выполняется цикл. Первое устройство ответило, мы не обработали пакет, второе ответило, мы не обработали....Я так понимаю, пока размера буфера хватает, эти байты там сохраняются. После окончания цикла мы, может быть, сможем обработать первые 10-15 пакетов с первых 10-15 устройств. И пропустим почти все пришедшие пакеты с остальных устройств. А если еще вдруг в процессе опроса придет пакет на засыпание программы. Мы его тоже можем не отловить получается. Я решил по нажатии кнопки "опросить" запустить дополнительный поток, слушающий ком порт: Код:
procedure TF_Main.Btn_SchitSoStellyClick(Sender: TObject); var i,t:integer; begin ... T1:= ToolkPort.Create(false); T1.FreeOnTerminate:= True; Но в самом потоке не знаю, как вызвать процедуру из основного потока, что бы она продолжала слушать ком порт и обрабатывать пакеты, а в случае чего еще и приостанавливать поток основной программы и выводить модальное окно с предупреждением? и Так же в потоке ловить пакет выхода из спячки и убирать модальное окно Код:
unit U_PortToolk; interface uses Classes, CPortCtl, ExtCtrls, CPort, Dialogs, Windows, Messages, SysUtils, Formirovatel_Paketov, U_StopModal; type ToolkPort = class(TThread) ComPort: TComPort; private protected procedure Execute; override; end; implementation uses U_Main; procedure ToolkPort.Execute; begin {Вот здесь не знаю как правильно вызвать обработчик TF_Main.ComPort1RxChar, чтобы и в цикле он реагировал на приходящие пакеты} until Terminated; end; end. Что в Execute потока прописать, что бы корректно все работало? Не заново же дублировать весь код обработчика TF_Main.ComPort1RxChar... Спасибо всем кто откликнется |
#2
|
||||
|
||||
1. всю работу с портом вынести в левый тред.
2. выкинуть нафиг модальное окно. 3. прогу не усыплять, а устанавливать флаг "прога_спит" и продолжать слушать порт в ожидании сообщения "проснуться", игнорив остальные. 4. по принятию "проснуться" просто сбрасывать флаг "прога_спит" и всё. Flash, Flash, Hundred Yard Dash! Buddy, it's nice to see you. |
#3
|
|||
|
|||
Цитата:
Что нужно сделать с потоком, когда установлен флаг "прога_спит"?) Мне конкретно нужно, что бы главное окно во время засыпания проги не реагировало на нажатие клавиш пользователя. Каким образом лучше всего тогда приостановить поток в тот момент, когда в порт придет команда на остановку проги? И в левом треде тогда что, все время крутить бесконечный цикл? Код:
repeat ComPort.Read(P_vhod,15); .... Разлчные действия ... until Terminated; |
#4
|
||||
|
||||
Цитата:
Цитата:
Flash, Flash, Hundred Yard Dash! Buddy, it's nice to see you. |
#5
|
|||
|
|||
Цитата:
Это нормально? |
#6
|
||||
|
||||
Цитата:
Есть такое понятие: задача. Задача должна быть быстрой и может выполняться в любом свободном потоке, который может выделить пул потоков. Задача может сама себя по новой поставить в очередь задач. — Как тебя понимать? — Понимать меня не обязательно. Обязательно меня любить и кормить вовремя. На Delphi, увы, больше не программирую. Рекомендуемая литература по программированию |
#7
|
|||
|
|||
Цитата:
|
#8
|
||||
|
||||
Цитата:
Flash, Flash, Hundred Yard Dash! Buddy, it's nice to see you. |
#9
|
|||
|
|||
Народ, тема не закрыта. Помогите советом пожалуйста. Почитав статей и книг по организации работы с com портом в параллельном потоке, все сходятся на мысли что поток чтения данных с ком порта надо делать так:
Код:
... procedure COM_Thread.Execute; begin While not Terminated do begin If not WaitCommEvent(hCOM,TMask,@Ovr) then if GetLastError = ERROR_IO_PENDING then WaitForSingleObject(Ovr.hEvent, INFINITE);//Ожидаем приема до бесконечности ClearCommError(hCOM,xn,@StatCOM);//Получаем состояние порта в StatCOM xn:= StatCOM.cbInQue;//Реальное количество байт в буфере If xn>0 then If ReadFile(hCOM,paket,xn,xn,@ovr) then SendMessage(Form1.Handle,wmCOM,1,0); end; end; Код:
Ovr.hEvent:= CreateEvent(nil,True,False,nil) Все хорошо, но только тогда, когда приложение ничего не делает и только ждет каких то данных от порта. Тогда да, пакет пришел в порт, дополнительный поток его принял, обработал, отправил сообщение главному окну, в главном потоке сообщение обработалось. Но у меня приложение регулярно в цикле опрашивает 255 устройств. Опрос идет из главного потока. Там я пишу в порт Код:
WriteFile(hCOM,paket,15,xn,@Ovr); Так вот, когда идет последовательный опрос, с устройств тут же приходит пакет-ответ. НО дополнительный поток НЕ обрабатывает эти пакеты, пока не прогонится весь цикл. А когда цикл прогонится, обрабатывается всего лишь один или два пакета, которые остались в буфере. остальное пропадает. Подскажите как сделать синхронизацию между потоками грамотно и можно ли это сделать в делфи7 вообще? |