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

Вниз

сбои в асинхронном приеме с сом порта   Найти похожие ветки 

 
Who_is_you? ©   (2010-06-22 12:48) [0]

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

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


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<i_wrEND do //меняем байт в файле данных старший на младший
          begin
            noChet:=Data_wr[i];
            Chet  :=Data_wr[i+1];
            Data_wr[i]:=Chet;
            Data_wr[i+1]:=noChet;
            inc(i,2);
          end;
         FlagReadData:=true; //пришли данные
         FlagRead:=false; //Завершился прием данных
         byte_wr:= BufSize_wr;
         ErrChannel :=1;                   // "0" - ошибка № канала
         WriteFile(hOutFile,ErrChannel,1,Shapka_byte,nil);
         WriteFile(hOutFile,Data_wr,i_wrEND,byte_wr,nil);
         FlushFileBuffers(hOutFile);
         i_wr:= 0;
       end;
      if CloseReadComm then break;
    end;//mask

     //получаем состояние модемных линий
//      GetCommModemStatus(cId,ModemState);
//     if     then EscapeCommFunction(cId, SETRTS)
//          else EscapeCommFunction(cId, CLRRTS);
//проверяем маску эвентов на эвент изменения модемных линий
   if ((Mask and EV_DSR) = EV_DSR) or
      ((Mask and EV_CTS) = EV_CTS) then
     begin
      if CloseReadComm then break;
//получаем состояние модемных линий
       GetCommModemStatus(hCom,ModemState);
//запоминаем состояние модемных линий
       State_DSR_ON := (ModemState and MS_DSR_ON)= MS_DSR_ON;
       State_CTS_ON := (ModemState and MS_CTS_ON)= MS_CTS_ON;
     end;  //end состояние модемных линий

   end;//while
 end;


 
RWolf ©   (2010-06-22 13:15) [1]

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


 
Who_is_you? ©   (2010-06-22 14:53) [2]

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

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


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


> 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; //пришли данные
Где они потом используются и как? Это сигнализация в другой поток? Если да, то  как там эта переменная используется, если она там пишется - то это уже не правильно....


 
RWolf ©   (2010-06-22 14:58) [4]


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

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


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


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


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


 
RWolf ©   (2010-06-22 15:21) [6]


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

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


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


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

ПРобовал?


 
RWolf ©   (2010-06-22 15:51) [8]


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

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


 
tesseract ©   (2010-06-22 15:51) [9]


> ПРобовал?


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


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


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

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

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

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



Страницы: 1 вся ветка

Текущий архив: 2010.09.19;
Скачать: CL | DM;

Наверх




Память: 0.51 MB
Время: 0.013 c
11-1222555772
AnarchyMob
2008-09-28 02:49
2010.09.19
Lazarus и KOL &amp; MCK


2-1277558905
HF-Trade
2010-06-26 17:28
2010.09.19
Блокировать доступ к памяти процесса


15-1277125976
laao
2010-06-21 17:12
2010.09.19
Как получить доступ к SVN-ревизии .DFM в run-time ?


2-1277704401
И. Павел
2010-06-28 09:53
2010.09.19
Общий обработчик ошибок, завершающий программу.


2-1277699293
linuxoid
2010-06-28 08:28
2010.09.19
treeview &amp; memo