Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

сбои в асинхронном приеме с сом порта [D7, XP]


Who_is_you? ©   (2010-06-22 12:48:00) 

Посылаю устройству команду прислать данные в комп. Смотрю: светодиод мигает, что данные идут.
Но данные то читаются, то нечитаются. Такое ощущение, что проблема во временах и реакции на событие.

Вот настройки порта и программа чтения:


procedure TForm1.SetupOpenPort(Sender: TObject); //Setup & open порт
Var
TimeOuts : TCommTimeouts; // таймауты порта
begin
 ComX:= PChar('COM' + IntToStr(NumCom));
     //создание порта и получение его хэндла в асинхронном режиме
 hCom:=CreateFile(PChar('\\.\COM' + IntToStr(NumCom)),Generic_Read or GENERIC_WRITE,0,nil,Open_Existing,
                   File_Attribute_normal or FILE_FLAG_OVERLAPPED,0);
 if hCom=Invalid_handle_Value then
   begin
     ShowMessage('Не могу открыть порт. Задайте параметры порта.');
     CloseHandle(hCom);       //закрытие порта
   end;

 PurgeComm(hCom,PURGE_TXABORT or PURGE_RXABORT or
               PURGE_TXCLEAR or PURGE_RXCLEAR);
//устанавливаем маску эвентов (фактически маску прерываний)
//в данном случае будем иметь возникновение эвентов по принятию
//хотя бы одного байта и возможности записи в порт еще байт(ов)
   if not (SetCommMask(hCom,EV_RXCHAR or EV_DSR or EV_CTS)
//устанавливаем размер внутренних буферов приема-передачи в драйвере порта
           and SetupComm(hCom,256,256)
//       SetupComm(hCom,BufSize_rd,BufSize_rd);
        //получаем текущее DCB порта
        //построение DCB и иницализация порта
        //что бы не заполнять всю структуру самим,
        // сначалf считываем ее, потом поменяем нужные поля
            and  GetCommState(hCom,DCB)
                                        )
           then begin
             CloseHandle(hCom);
             ShowMessage('Порт не настроен');
             Exit;
            end;
 with DCB do
   begin
     BaudRate:=9600;
     ByteSize:=8;
     Parity:=NoParity;
     StopBits:=OneStopBit;
   end;
 if not SetCommState(hCom,DCB) then     //устанавливаем DCB
   begin
     CloseHandle(hCom);
     ShowMessage('Порт не настроен');
   end;

//получаем текущие параметры таймаутов
   GetCommTimeouts(hCom,TimeOuts);
//настраиваем текущие параметры таймаутов таким образом,
//чтобы ReadFile и WriteFile возвращали значения немедленно
   TimeOuts.ReadIntervalTimeout := MAXDWORD;
   TimeOuts.ReadTotalTimeoutMultiplier := 0;
   TimeOuts.ReadTotalTimeoutConstant := 0;
   TimeOuts.WriteTotalTimeoutMultiplier := 0;
   TimeOuts.WriteTotalTimeoutConstant := 0;
//выполняем настройку порта с новыми таймаутами
   if not SetCommTimeouts(hCom,TimeOuts) then
      begin
       CloseHandle(hCom);
       ShowMessage('Tаймауты порта не настроены.');
       Exit;
      end;
//опускаем флаг завершения дочернего потока
   CloseReadComm := False;
end;

procedure ReadComm;
 var
  i     :byte;
  Trans, ModemState              : DWord;

 begin
 i_wr:= 0;
//выполняем инициализацию структуры для асинхронного режима
 FillChar(Ovr,SizeOf(TOverlapped),0);
 Ovr.hEvent := CreateEvent(nil,TRUE,FALSE,#0);
 while not CloseReadComm do
  begin
   for i:=1 to BufSize_Data_rd  do Data_rd[i]:=0;  // ??
//**
   Mask := 0;
   if not WaitCommEvent(hCom,Mask,@Ovr) then   //ждем
   begin
     if ERROR_IO_PENDING = GetLastError() then
     begin
       //это случай, когда ожидание переводится в фоновый режим
       //и для получения маски эвентов нужно дождаться
       //выставления эвента Ovr.hEvent в сигнальное состояние
       //и вызвать GetOverlappedResult
       if WaitForSingleObject(Ovr.hEvent,INFINITE)= WAIT_OBJECT_0 then
          GetOverlappedResult(hCom,Ovr,Trans,False);
     end;
   end;

   if CloseReadComm then break;

   if (Mask and EV_RXCHAR)=EV_RXCHAR then //проверяем нужное событие
    begin
     FlagRead:=true; //Прием данных
     ClearCommError(hCom,Errs,@Stat);//сбрасываем флаг, читаем Stat
     byteRead := Stat.cbInQue;
     ReadFile(hCom,Data_rd,byteRead,byteRead,@Ovr);//читаем
     // обработка принятой информации из Data_rd
     if byteRead > BufSize_Data_rd then
           byteRead:=BufSize_Data_rd;

     for i:=1 to byteRead do
         begin
         i_wr := i_wr+1;
         Data_wr[i_wr]:=Data_rd[i];
         end;
     if (i_wr=i_wrEND) or (i_wr>i_wrEND) then   //??
       begin
         i:=3;
         while i


Вариант   (2010-06-22 15:54:00) [1]


> RWolf ©   (22.06.10 15:51) [8]

Увы это так, в свое время что только не пробовал, и маску менять ... но это такой неприятный факт для NT систем,для 95 и 98 уже не помню как

> tesseract ©   (22.06.10 15:51) [9]

В  синхронном режиме WaitCommEvent ?


RWolf   (2010-06-22 15:51:00) [2]


> Вариант   (22.06.10 15:24) [7]

Попробовал — не работает, и даже вешает весь процесс. Увы мне.
Нелогично, конечно — из ReadFile/WriteFile выкидывает, а из WaitCommEvent — нет.


tesseract   (2010-06-22 15:51:00) [3]


> ПРобовал?


Да. Возвращает ошибку типа "операция прервана".


Вариант   (2010-06-22 15:24:00) [4]


> RWolf ©   (22.06.10 15:21) [6]

ПРобовал?


RWolf   (2010-06-22 15:21:00) [5]


> Вариант   (22.06.10 15:14) [5]
> синхронном режиме WaitCommEvent
> проблемный вызов из-за возможностью долго висеть.... и так
> и не отвиснуть.

Чтобы WaitCommEvent завершился с кодом ошибки, достаточно закрыть переданный ему хэндл в любом из работающих потоков.


Вариант   (2010-06-22 15:14:00) [6]


> RWolf ©   (22.06.10 14:58) [4]


В синхронном режиме WaitCommEvent проблемный вызов из-за возможностью долго висеть.... и так и не отвиснуть. Его можно не использовать конечно, но   overlapped режим все же удобнее(гибче) для COM порта когда надо действительно отслеживать несколько типов событий, и конечно когда правильно им пользуешься, .


RWolf   (2010-06-22 14:58:00) [7]


> синхронный всегда в ожидании,а асинхронный по приходу события:
>  потому меньше загружает комп.

синхронный ReadFile всегда в ожидании, именно поэтому он не загружает процессор вовсе.


Вариант   (2010-06-22 14:54:00) [8]


> Who_is_you? ©   (22.06.10 12:48)

Проблемный код, слишком много разной  по функциональности логики в одной процедуре ReadComm. Удобней было бы разбить на разные функции, читать тяжело.
Почти нигде нет анализа возврата функций на возвращаемое значение (не предусматривается возможность возврата ошибки)
КРоме того есть вопрос к тому что я заметил:
Ovr.hEvent := CreateEvent(nil,TRUE,FALSE, #0);-что бы создать неименованный Event, надо передать nil, а не #0 Не знаю как это будет  ли это валидным именем в NT подобных системах, поэтому если и ты не знаешь, то думаю следует заменить. Далее


> if WaitForSingleObject(Ovr.hEvent,INFINITE)= WAIT_OBJECT_0
> then
>           GetOverlappedResult(hCom,Ovr,Trans,False);


А если не равно  WAIT_OBJECT_0....??? То все равно продолжим выполнение кода без GetOverlappedResult.

ClearCommError(hCom,Errs,@Stat);//сбрасываем флаг, читаем Stat
    byteRead := Stat.cbInQue;
    ReadFile(hCom,Data_rd,byteRead,byteRead,@Ovr);//читаем


Какое значение вернули функции мы не знаем. И хотя скорее всего true  для ClearCommError, и хотя скорее всего ReadFile  вернет true, так как читаем уже то, что есть в буфере - но дать 100 % за это я не могу. А потому следовало бы делать проверку.

if byteRead > BufSize_Data_rd then
          byteRead:=BufSize_Data_rd;


Не знаю бывает ли у тебя ситуация, когда число пришедших из порта байт больше буфера.... но если да, ты просто взял и выкинул часть данных.... Насколько это верно?
Да и вызывают сомнение переменные типа FlagReadData:=true; //пришли данные
Где они потом используются и как? Это сигнализация в другой поток? Если да, то  как там эта переменная используется, если она там пишется - то это уже не правильно....


Who_is_you?   (2010-06-22 14:53:00) [9]

Ранее работал в синхронном режиме с СОМ портом, но тоже были подобные проблемы в ХР.
Сейчас перешел на асинхронный, а он задается через FILE_FLAG_OVERLAPPED.

Насколько я понимаю синхронный всегда в ожидании,
а асинхронный по приходу события: потому меньше загружает комп.


RWolf   (2010-06-22 13:15:00) [10]

а обязательно использовать Overlapped-режим? это нужно только, если пишем в файл из двух и более потоков.


Наверх

Титульная страница Поиск, карта сайта Написать письмо