Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2010.09.19;
Скачать: [xml.tar.bz2];

Вниз

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

 
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;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.5 MB
Время: 0.004 c
2-1277379241
nobody
2010-06-24 15:34
2010.09.19
Тип как массив компонентов заданного типа


2-1277184716
Miko
2010-06-22 09:31
2010.09.19
Не найдена точка входа процедуры в DLL


2-1276167910
dimds
2010-06-10 15:05
2010.09.19
Подключение к серверу из среды Delphi


15-1277670592
Юрий
2010-06-28 00:29
2010.09.19
С днем рождения ! 28 июня 2010 понедельник


15-1277414148
AKE
2010-06-25 01:15
2010.09.19
Помогите найти ошибку плиз...





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