Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Программирование и базы данных (http://forum.oszone.net/forumdisplay.php?f=21)
-   -   Win32API: Оптимальная организация асинхронного чтения COM-порта в отдельном потоке (http://forum.oszone.net/showthread.php?t=74547)

CyraxZ 13-11-2006 22:50 511233

Win32API: Оптимальная организация асинхронного чтения COM-порта в отдельном потоке
 
Нашёл в инете несколько неплохих док по работе с COM-портом на Win32API (Титов, Кузан, Терехов и др.).
В одной из них предлагается следующий код для потока:
Код:

procedure TReadThread.Execute;
var
 ComStat: TComStat;
 dwMask, dwError: DWORD;
 OverRead: TOverlapped;
 Buf: array[0..$FF] of Byte;
 dwRead: DWORD;
begin
 OverRead.hEvent := CreateEvent(nil, True, False, nil);
 if OverRead.hEvent = Null then
  raise Exception.Create('Error creating read event');
 FreeOnTerminate := True;

 while not Terminated do
 begin
  if not WaitCommEvent(hPort, dwMask, @OverRead) then
  begin
    if GetLastError = ERROR_IO_PENDING then
      WaitForSingleObject(OverRead.hEvent, INFINITE)

    else
      raise Exception.Create('Error waiting port event');
  end;
  if not ClearCommError(hPort, dwError, @ComStat) then
    raise Exception.Create('Error clearing port');
  dwRead := ComStat.cbInQue;
  if dwRead > 0 then
  begin
    if not ReadFile(hPort, Buf, dwRead, dwRead, @OverRead) then
      raise Exception.Create('Error reading port');
    // В Buf находятся прочитанные байты
    // Далее идет обработка принятых байтов
  end;
end; {while}
end;

1. Не совсем ясен выделенный фрагмент. Функция WaitCommEvent инициирует процесс слежки за возникновением событий, отслеживаемых портом. После выполнения этой функции объект hEvent структуры OverRead будет установлен в сигнальное сотояние, если произойдёт какое-либо событие, отслеживаемое портом. Далее мы ждём функцией WaitForSingleObject(OverRead.hEvent, INFINITE), пока объект OverRead.hEvent не будет установлен в сигнальное сотояние. Нам здесь нужно ждать до тех пор, пока не придёт первый символ (во входной буфер COM-порта). Но объект Event может быть установлен в сигнальное сотояние при любом событии, отслеживаемом портом.

Допустим, в этом фрагменте кода подразумевается, что порт отслеживает только событие прихода во входной буфер первого символа (т.е. установили только флаг RXChar функцией SetCommEvent). Тогда всё сработает корректно. Но если порт отслеживает несколько событий ? - следовало бы определить тип события, которое установило hEvent в сигнальное сотояние. И если это не приход символа, то снова вызывать функцию WaitCommEvent, затем WaitForSingleObject, пока не возникнет событие прихода симола.
Но как определить тип события, ведь в структуре OverRead (типа Overlapped) нет полей с информацией о типе произошедшего события, а данные по указателю dwMask не будут определять тип произошедшего события, т.к. функция WaitCommEvent завершится до наступления события (т.е. параметр wdMask функции WaitCommEvent при асинхронных операциях бесполезен) ?

2. Функция ClearCommError в данном фрагменте кода используется только для того, чтобы получить число символов во входном буфере (cbInQue) ?
Или здесь обязателен сброс признака ошибки (т.е. что будет, если ошибку не сбросить) ?

3. Может ли функция WaitCommEvent в данном фрагменте вернуть 0 (теоретически), в коде этот случай не рассматривается...
Т.е. может ли произойти событие в ходе выполнения этой функции (после сброса hEvent'а функцией) ?

4. Можно ли получить число символов во входном буфере без использования функции ClearCommError ?

CyraxZ 15-11-2006 21:46 512275

Неужели с Com-портом никто не работал ?

pva 16-11-2006 09:27 512410

никакой специфики тут нет. Просто читайте программу.
Код:

while not Terminated do
 begin
  // >> 3. Может ли функция WaitCommEvent в данном фрагменте вернуть 0 (теоретически),
  // >> в коде этот случай не рассматривается...
  // это почему?
  // bool WaitCommEvent(...) bool - это 0(false) или 1(true)

  if not WaitCommEvent(hPort, dwMask, @OverRead) then
  begin
    // вернула 0
    // "не дождались", а ошибка - "идёт передача данных",
    // дожидаемся окончания это передачи
    if GetLastError = ERROR_IO_PENDING then
      WaitForSingleObject(OverRead.hEvent, INFINITE)
    else
      raise Exception.Create('Error waiting port event');
  end; // not WaitCommEvent

  // сюда попадаем только когда началась передача данных
  // если порт был занят, подождали. Если нет, попали сюда сразу

  if not ClearCommError(hPort, dwError, @ComStat) then
    raise Exception.Create('Error clearing port');


Nick64 19-02-2007 10:02 552267

Объясните мне плиз, функция WaitCommEvent() запрашивает событие по маске, а функция WaitForSingleObject ждет это событие, так получается? И тогда цикл while останавливается или продолжает выполнятся?


Время: 12:55.

Время: 12:55.
© OSzone.net 2001-