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

Вниз

Различное поведение различных СОМ портов при асинхронном доступе   Найти похожие ветки 

 
Balkon   (2006-07-17 14:25) [0]

Приветствую опять!

Пишу управляющую программу для девайса, работающего в режиме запрос-ответ. Работу с портом организую во вторичном потоке в режиме асинхронного доступа.

Столкнулся со следующей проблемой. На физически различных портах событие EV_RXCHAR генерится по появлению различного количества байт. Например жду ответа длинною 12 байт. На моей машине на родном порту прилетают все 12 байт. На соседней машине событие генерится по прилету 8,0,4 байт на каждый ответ. Если же пользую на своей машине УСБ-СОМ адаптер, то событие генерится 12 раз по байту. Соответственно в последнем случае ответы обрабатываются дольше всего и при настройках частоты опроса, подобранных для первого случая начинает "забиваться" командная очередь.

Конечно можно увеличить интервал опроса девайсов. Но хотелось бы знать причину и может быть поправить код так, чтобы работало одинаково на всех портах.

В чем может быть причина?
Может быть некорректно написаны нижеприведенные процедуры?
Спасибо за внимание.


procedure TAKRThread.Execute;
Var CurrentState : TComStat;
   AvaibleBytes, ErrCode, RealRead : Cardinal;
   ReadOL : TOverLapped;
   Signaled, Mask : DWORD;
   BytesTrans : DWORD;
   Success: Boolean;
   TmpPackage: TReadPackage;
Begin
 if WriteAKRComand then
   Try
     FillChar(ReadOL, SizeOf(ReadOL), 0);
     ReadOL.hEvent:= CreateEvent(nil, True, True, nil);
     while (not Terminated) do
     begin
       Success := WaitCommEvent(FPortHandle, Mask, @ReadOL) or
         (GetLastError = ERROR_IO_PENDING);
       Signaled:= WaitForSingleObject(ReadOL.hEvent, 1000);
       if Success and (Signaled  = WAIT_OBJECT_0) and
         GetOverlappedResult(FPortHandle, ReadOL, BytesTrans, False) then
       begin
         If (Mask and EV_RXCHAR) <> 0 then
         begin
           ClearCommError(FPortHandle, ErrCode, @CurrentState);
           AvaibleBytes:= CurrentState.cbInQue;
           PostMessage(FOwner,WM_MESFROMTHREAD,AvaibleBytes,0);
           if (AvaibleBytes > 0) then
           begin
             Success := ReadFile(FPortHandle, TmpPackage, AvaibleBytes, RealRead, @ReadOL)
               or (GetLastError = ERROR_IO_PENDING);
             if Success and GetOverlappedResult(FPortHandle, ReadOL, BytesTrans, False) then
               CheckBytes(TmpPackage,BytesTrans);
           end;
         End;
       end
       else
         RepeatAKRComand;
     End;
   Finally
     CloseHandle(ReadOL.hEvent);
     SetCommMask(FPortHandle, 0);
   End
 else
   raise Exception.Create("...");
End;

function TAKRThread.OpenPort(ComNumber: Integer): boolean;
Var
 ComName : String;
Begin
Result := false;
ComName:= Format("\\.\COM%-d", [ComNumber]);
FPortHandle:= CreateFile(PChar(ComName),GENERIC_READ or GENERIC_WRITE,
           0,nil,OPEN_EXISTING,
           FILE_FLAG_OVERLAPPED,0);
if not(
  SetCommMask(FPortHandle, EV_RXCHAR) and
  SetupComm(FPortHandle,48,48) and
  PurgeComm(FPortHandle,PURGE_TXABORT or PURGE_RXABORT or
                        PURGE_TXCLEAR or PURGE_RXCLEAR) and
  ApplyComSettings) then
begin
  CloseHandle(FPortHandle);
  Exit;
end;
Result := true;
end;

function TAKRThread.ApplyComSettings: boolean;
Var
 dcb: TDCB;
 CommTimeOut: TCommTimeOuts;
Begin
 if FPortHandle <> INVALID_HANDLE_VALUE then
 begin
    FillChar(dcb, SizeOf(dcb), 0);
    dcb.DCBLength:= SizeOf(dcb);
    dcb.BaudRate := CBR_9600;
    dcb.Flags    := dcb_Binary;
    dcb.ByteSize := 8;
    dcb.Parity   := 0;
    dcb.StopBits := 0;

    FillChar(CommTimeOut,SizeOf(CommTimeOut),0);
    CommTimeOut.ReadTotalTimeoutConstant := 200;

    Result := SetCommState(FPortHandle, dcb) and SetCommTimeOuts(FPortHandle,CommTimeOut);
 end
 else
   Result := false;
End;


 
tesseract ©   (2006-07-17 14:29) [1]


> В чем может быть причина?


Вроде сам ответил - в различных портах. Совершенно нормальное явление.


 
Balkon   (2006-07-17 14:47) [2]

>Совершенно нормальное явление.
Интуитивно понятно, что нормальное.

Однако мне не ясно почему задание

CommTimeOut.ReadTotalTimeoutConstant := 200;

не форсирует программу при чтении ждать интервал 200 милисек за которые гарантированно должны прилететь все байты.

Или это должно работать только в синхронном режиме доступа?


 
tesseract ©   (2006-07-17 15:43) [3]

ну так это для чтения, а не для EV_RXCHAR.

А судя по коду, ты считываешь кол-во байт пришедших в порт по событию. Т.Е всё верно :-)


 
GanibalLector ©   (2006-07-19 00:11) [4]

2 tesseract,Balkon
Я попридираюсь ;)

>ReadOL.hEvent:= CreateEvent(nil, True, True, nil);
На мой взгляд, очень кривой подход. В идеале, создать евент нужно в главном потоке...до операции чтения. А при чтении,например,выводить форму с кнопкой "Остановить"(при нажатии сбрасывать евент). Вот тогда будет сладко ;) Тогда и на  WaitFor можно ставить Infinite - пусть ждет.

З.Ы. Естественно, это мое ИМХО.


 
tesseract ©   (2006-07-19 11:02) [5]


> На мой взгляд, очень кривой подход. В идеале, создать евент
> нужно в главном потоке...до операции чтения.


Это само собой :-)


 
Balkon   (2006-07-19 14:48) [6]

Спасибо всем.

Схема то приложения вообще следующая.
Есть основной интерфейсный поток, в котором заполняется командная очередь. Есть вторичный (промежуточный) поток, который получает команду, выгребает ее из очереди, создает третий поток работы с портом и ждет его завершения. Т.е. на каждую команду для девайса создается поток (третий),
который на входе получает команду и номер порта. С помощью промежуточного потока достигается некая буферизация команд - пока не будет обработана полностью одна команда следующая в порт не посылается.

Третий поток отправляет команду и если в течении определенного времени Т не получает правильного (или вообще никакого) ответа, повторяет команду N раз. Поток либо после получения правильного ответа, либо после N неудачных попыток дождаться такового добавляет ответ в очередь и завершает исполнение.

Поэтому и WaitForSingleObject ждет только конечное время Т.
Идея заключается в том, чтобы всю работу с портом выделить в один вторичный поток. Создаваемый и убиваемый под каждую команду.

Ж) Сумбурненькое объяснение получилось, но надеюсь понятно.

Не слишком ли схема приложения и реализация кривые? Мне кажется, что все довольно изящно.


 
Balkon   (2006-07-19 14:55) [7]

Есть следующий вопрос по моему же коду.

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

...Try
    FillChar(ReadOL, SizeOf(ReadOL), 0);
    ReadOL.hEvent:= CreateEvent(nil, True, True, nil);
    while (not Terminated) do
    begin
      Success := WaitCommEvent(FPortHandle, Mask, @ReadOL) or
        (GetLastError = ERROR_IO_PENDING);
      Signaled:= WaitForSingleObject(ReadOL.hEvent, 1000);
      if Success and (Signaled  = WAIT_OBJECT_0) and
        GetOverlappedResult(FPortHandle, ReadOL, BytesTrans, False) then
      begin
        If (Mask and EV_RXCHAR) <> 0 then
        begin
          ClearCommError(FPortHandle, ErrCode, @CurrentState);
          AvaibleBytes:= CurrentState.cbInQue;...

упростить до:

...Try
    FillChar(ReadOL, SizeOf(ReadOL), 0);
    ReadOL.hEvent:= CreateEvent(nil, True, True, nil);
    while (not Terminated) do
    begin
      Success := WaitCommEvent(FPortHandle, Mask, @ReadOL) or
        (GetLastError = ERROR_IO_PENDING);
      Signaled:= WaitForSingleObject(ReadOL.hEvent, 1000);
      if Success and (Signaled  = WAIT_OBJECT_0) then
      begin
          ClearCommError(FPortHandle, ErrCode, @CurrentState);
          AvaibleBytes:= CurrentState.cbInQue;...

?


 
Balkon   (2006-07-19 15:25) [8]

Еще момент, будте добры, просвятите:

Ни в одном из примеров работы с последовательным портом (drkb23,delphikingdom) не встречал чтобы люди проверяли результат функции GetOverlappedResult, вызываемой после ReadFile. В доке написано про, что в случае параметра bWait=False "if FALSE and the operation is still pending, the function returns FALSE and the GetLastError function returns ERROR_IO_INCOMPLETE".

Нет ли смысла после ReadFile проверять еще и результат GetOverlappedResult и в случае ошибки сравнивать ее код с ERROR_IO_INCOMPLETE?
Или правивльнее просто после ReadFile вызывать еще и WaitFOrSingleObject?

...ClearCommError(FPortHandle, ErrCode, @CurrentState);
          AvaibleBytes:= CurrentState.cbInQue;
          if (AvaibleBytes > 0) then
          begin
            ReadFile(FPortHandle, TmpPackage, AvaibleBytes, RealRead, @ReadOL)
            if WaitForSingleObject(ReadOL.hEvent,SOMEVALUE) = WAIT_OBJECT_0 then
            then
            begin
              GetOverlappedResult(FPortHandle, ReadOL, BytesTrans, False) then
              CheckBytes(TmpPackage,BytesTrans);
            end;
          end;
...


 
GanibalLector ©   (2006-07-20 01:27) [9]

2 Balkon [6]
Да, нормально.

2 Balkon   (19.07.06 15:25) [8]
В книге П.Агурова есть такой сабж, но...правда не на ReadFile, а на WriteFile.


 
tesseract ©   (2006-07-20 11:20) [10]


> Нет ли смысла после ReadFile проверять еще и результат GetOverlappedResult
> и в случае ошибки сравнивать ее код с ERROR_IO_INCOMPLETE?
>

Я проверяю.
Просто не всегда это нужно, если нужно ждать определённое кол-во времени, и GetOverlapped не вернул значение, то проверять в общем бесполезно, будет ERROR_IO_INCOMPLETE



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

Форум: "WinAPI";
Текущий архив: 2006.12.03;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.49 MB
Время: 0.04 c
6-1152735417
papaP
2006-07-13 00:16
2006.12.03
Проблема с ошибкой 302 Found


2-1163616691
Zancik
2006-11-15 21:51
2006.12.03
Трей


15-1163178255
Ne-Ld
2006-11-10 20:04
2006.12.03
Назовите, пожалуйста, главные признаки проектов, в которых не сто


15-1163749228
TohaNik
2006-11-17 10:40
2006.12.03
Вот они, те кто влияет на неокрепшие души.


15-1163387593
vidiv
2006-11-13 06:13
2006.12.03
Вопрос по Active Directory





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