Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: WinAPI и системное программирование > Зацикливание при чтение из COM порта


Автор: cemick 1.11.2011, 15:26
Вообщем делаю чтение в overlapped режиме из последовательного порта в отдельном потоке. Но регулярно происходит зацикливание получения данных после нескольких десятков считываний из COM порта, даже если данных на вход перестали поступать. Выглядит как будто событие  TOverlapped.hEvent никогда не сбрасывается в не сигнальное состояние и в строчке с WaitForSingleObject(FOverlap.hEvent, INFINITE); не происходит остановки, а  Stat.cbInQue возвращает 0 байт. И так по кругу, пока в порт не поступят данные.
Если данные снова начинают записываться в порт, то считывания их выполняется успешно. Зацикливание легко прервать, если поставить где нибудь в теле цикла потока брекпоин, то на следующем витке выполнение успешно  застывает на  WaitForSingleObject(FOverlap.hEvent, INFINITE); до поступления данных, либо если поставить Sleep(50);. 
Такое ощущения что тогда что то успевает отработать и сбросить FOverlap.hEvent событие. Может кто то сталкивался с таким зацикливанием, или есть какие либо идеи.
 Вот код:

Код

procedure TbtkSerialPortReaderThread.Execute;
var
  dwMask, dwTemp: DWORD;
  signal : Cardinal;
  r: integer;
begin
  FillChar(FOverlap,SizeOf(TOverlapped),0);
  try
    FOverlap.hEvent := CreateEvent(nil, true, true, nil);
    if FOverlap.hEvent = 0 then
      raise EComPortException.Create('Îøèáêà ñîçäàíèÿ ñîáûòèÿ íà ÷òåíèå èç COM ïîðòà', FComPort.PortName);

    r := integer(SetCommMask(FComPort.FPortHandle, EV_RXCHAR or EV_BREAK)); //
    if r = 0 then
      RaiseLastWin32Error;

    ClearCommBreak(FComPort.FPortHandle);
    PurgeComm(FComPort.FPortHandle, PURGE_RXABORT or PURGE_RXCLEAR);

    while not Terminated do
    begin
       if not WaitCommEvent(FComPort.FPortHandle, dwMask, @FOverlap) then
      begin
       if GetLastError <> ERROR_IO_PENDING then
          raise Exception.Create('Error waiting port event');
      end;
      signal := WaitForSingleObject(FOverlap.hEvent, INFINITE); \\ Не задерживается
      if (signal = WAIT_OBJECT_0) and not Terminated then
      begin
        if GetOverlappedResult(FComPort.FPortHandle, FOverlap, dwTemp, true)then
        begin
          if((dwMask and EV_RXCHAR)<> 0)    then
          begin
             FComPort.PortData := FComPort.ReadPort(FOverlap);
             DataReadedEvent;
             WaitForSingleObject(FEvent, INFINITE);
             ResetEvent(FEvent);
          end;
        end;
      end;
    end;
  except
    FException := ExceptObject as Exception;
    ProcessException;
  end;
end;

function TbtkSerialPort.ReadPort(var AOverlapped: TOverlapped): string;
var
  byteCount, Errs: DWORD;
  stat: TComStat;
  p: PChar;
  Buff: array of byte;
begin

  ClearCommError(FPortHandle,errs,@stat);
  if errs <> 0 then
     RaiseLastWin32Error;
  byteCount := Stat.cbInQue;   //0
  // 1 - место под символ конца строки
  SetLength(Buff, byteCount+1);
  try
    FillChar(Buff[0], byteCount+1, #0);
    ReadFile(FPortHandle, Buff[0], byteCount, byteCount, @AOverlapped);
    if ByteCount > 0 then //÷òî-òî ïðèøëî
      Result := String(Buff)
    else
      Result := '';
  finally
    SetLength(Buff, 0);
  end;
end;


Порт открыт в overlapped режиме:
    
Код

 FPortHandle := CreateFile(PChar(PortName),
                   GENERIC_READ or GENERIC_WRITE,
                   0,
                   nil,
                   OPEN_EXISTING,
//                   0,
                   FILE_FLAG_OVERLAPPED,
                   0);

Автор: northener 1.11.2011, 23:28
Цитата(cemick @  1.11.2011,  15:26 Найти цитируемый пост)
Вообщем делаю чтение в overlapped режиме из последовательного порта в отдельном потоке.

Так вы Доктор Франкенштейн?

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)