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

Вниз

Асинхронный ввод/выод com-порта   Найти похожие ветки 

 
bobah ©   (2005-07-19 14:01) [0]

На сайте Королевство Делфи мне попался код. Вроде с ним разобрался, однако один блок не дает мне покоя (см. пояснение в тексте // начало непонятного блока; // конец непонятного блока)

//инициализируем TOverlapped структуру
 FillChar(Ovr,SizeOf(TOverlapped),0);
 Ovr.hEvent := CreateEvent(nil,TRUE,FALSE,#0);
//стартуем бесконечный цикл
 while not Parms.Terminated do with Parms do begin
   if Terminated then break;
   Mask := 0;
//запрашиваем ожилаемую маску ивэнтов
//-----------------------------------
// Начало непонятного блока
//------------------------------------
   if not WaitCommEvent(cId,Mask,@Ovr) then begin
     if GetLastError() = ERROR_IO_PENDING
      then GetOverlappedResult(cId,Ovr,Trans,False);
   end;
// -------------------------------
// Конец непонятного блока
// ------------------------------
    //очищаем ошибки
   ClearCommError(cId,Errs,@Stat);
   if Terminated then break;
   if Mask = 0  then continue;
   if (Mask and EV_RXCHAR) = EV_RXCHAR then begin
   //Если принят хотя бы один байт
    if Stat.cbInQue < 512
     then Kols := Stat.cbInQue
      else Kols := 512;
     if Terminated then break;
   //пытаемся считать принятые байты
     ReadFile(cId,Buff,Kols,Kols,@Ovr);
.........................................

А именно не понятно зачем здесь GetOverlappedResult? И вообще, если несложно, объясните зачем она нужна эта функция?


 
tesseract   (2005-07-19 14:13) [1]

Данный блок ждёт события Com-порта по маске. GetOverlappedResult  возвращает результат операции отложенного чтения. ERROR_IO_PENDING операция незавершена.

ЗЫ Код кстати не совсем грамотный.


 
bobah ©   (2005-07-19 14:32) [2]

Насчет код несовсем грамотный нельзя ли поподробнее?
Хотел спросить еще, насколько я знаяю при вызове WaitCommEvent, ReadFile, WriteFile в асинхронном режиме они запускаются, но прграмма не зависает, так вот как можно этот запущенный waitcommevent остановить, т.е. освободить hevent(случайно не с помощью ли GetOverlappedResult или WaitForSingleObject)?


 
tesseract   (2005-07-19 16:18) [3]

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


function trThread.InitPort:boolean;
var
   CommTimeOuts:TCOMMTIMEOUTS;
begin
// Не верим, что получится
 Result:=false;
// реагируем на символ
 fMask:=EV_RXCHAR and  not EV_RING; // в NT/2k/XP reqired!!!!!
 fPortname:=PChar("COM"+inttostr(fScaleSet.Port));
// создаём дескриптор
//crit.Acquire;
 try
  hCom:=CreateFile(fPortName,GENERIC_READ OR GENERIC_WRITE,0,NIL,OPEN_EXISTING,FILE_FLAG_OVERLAPPED{FILE_ATTRIBUTE_NORMAL},0);
// Если неверен выходим
    if GetLastError=ERROR_ALREADY_EXISTS then
     begin
      CloseHandle(hCOM);
      status:=GetLastError;
      AddLog("Порт занят"+ fPortName)
     end;
     FillChar(ReadOl,SizeOF(ReadOL),0);

    ReadOl.hevent:=CreateEvent(nil,true,true,nil);
    Status:=GetLastError;

   if (hCom=0) or (hCom=INVALID_HANDLE_VALUE) then
    begin
     Status:=GetLastError;
     AddLog("Ошибка порта "+ fportName);
     // crit.Release;
     exit;
    end
    else
        AddLog("Открыт порт "+ fportName);
// Устанавливаем буфер
   if not(SetupComm(hCom,22,10)) then
    begin
     status:=GetLastError;
    AddLog("SetupComm Error "+ fPortName);
     exit;
    end;
// Чистим буфер
   if not(PurgeComm(hCom,PURGE_TXABORT or PURGE_RXABORT or PURGE_TXCLEAR or PURGE_RXCLEAR )) then exit;
// Устанавливаем задержки/время ожидания
     CommTimeOuts.ReadIntervalTimeout:= 50;
     CommTimeOuts.ReadTotalTimeoutMultiplier := 10;
     CommTimeOuts.ReadTotalTimeoutConstant := 00;
     CommTimeOuts.WriteTotalTimeoutMultiplier := 10;
     CommTimeOuts.WriteTotalTimeoutConstant := 00;
// DTR и RTS нам на фиг не нужен
    EscapeCommFunction(hCom,SETDTR);
    EscapeCommFunction(hCom,CLRRTS);
  //Если не получилось выходим
    SetCommTimeouts(hCom,CommTimeOuts);
 // Устанавливаем параметры порта через DCB
  if not(GetCommState(hCom,mDCB)) then
   begin
    status:=GetLastError;
    AddLog("GetCommState Error "+ fPortName);
    exit;
   end;

   MDCB.BaudRate:=fScalePar.hDCB.BaudRate;
   MDCB.ByteSize:=fScalePAr.hDCB.ByteSize;
   MDCB.Parity:=FscalePar.hDCB.Parity;
   MDCB.StopBits:=FScalePar.hDCB.StopBits;

//Заполняем нужные параметры
   // Устанавливаем параметры порта и перхвата
   if not(SetCommState(hCom,mDCB)) then
    begin
     Status:=GetLastError;
     Addlog("SetCommState Error "+ fPortName);
     exit;
    end;
// устанавливаем маску перехвата
    if not(SetCommMask(hCom,fMask)) then
     begin
       Status:=GetLastError;
       Addlog("SetComMask Error" +fportName);
       exit;
     end;
// Если дошли до сюда то всё ок
    Result:=true;
 finally
 end;
end;

// Чтение

function trThread.AsyncRead:boolean;
var tMask:DWord;
 begin
result:=false;
if terminated  then  exit;
// убираем событие - идёт запись

fWait.ReSetEvent;
{if State<>"Чтение" then
begin
  State:="Чтение";
  ChangeState;
 end;
 }
if hCom=0 then exit;
// Если надо синхронизироваться, то делаем это

// Ждём сообщения о чтении
WaitCommEvent(hCom,tMask,@READOL);

    // смотрим что у нас
    fSignaled:= WaitForSingleObject(ReadOl.hEvent,WaitInt);
    // Если событие произошло то
     if (fSignaled = WAIT_OBJECT_0) then
      begin
         // Читаем
        if GetOverlappedResult(hCom, REadOL, BytesTrans,false) then
         begin
           // Сравниваем произошедшее событие с прибытием символа
           if (tMask and EV_RXCHAR)<>0 then
            begin
             AvBytes:=GetAvBytes; // Сколько байтов пришло
             if AvBytes>=fScalePar.Size then
              begin
               //try
                // Если пришло нужное кол-во то
                 //buf:="";
                 if ReadFile(hCom,buf^,AvBytes,ReadBytes,@ReadOL) then
                 begin
                   // Чистим буфер
                   PurgeComm(hCom,PURGE_RXCLEAR);
                   result:=true;
                   // Если прочитали нужное кол-во
                   if (ReadBytes>=fScalePAr.Size) then
                   begin
                     if not terminated
                      then
                      begin
                      fWeight:=ScaleRead;
//                       ChangeWeight;
                      State:="Данные разобраны";
                     end;
                    end;
                 end// if REadFile
                 else
                  begin
                   // Ошибка
                   fWait.setEvent;
                   Status:=GetLastError;
                   Addlog("Чтение невозможно");
                  end; // if REadFile

               //  end;
                 end; // if AvBytes
            end; // if Fmask
         end;// if GetOVerlappedResult
      end; // if Signaled
  // end;
    end; // waitcommevent
CancelIO(hCom); // это отмена операций чтения
fWait.SetEvent;
end;

function trThread.ClosePort:boolean;
begin
// Закрываем отложенное чтение
if REadOL.hEvent<> 0 then
 CloseHandle(REadOL.hEvent);
// Сбро настроек порта
if hCom<>0 then
 begin
  try
  SetCommMask(hCom,0);
  CloseHandle(hCom);
  Status:=GetLastError;
  except
     AddLog(" Ошибка порта COM" + inttostr(fScaleSet.port));
  end;
 end;
  AddLog("Порт  COM" + inttostr(fScaleSet.port)+ " закрыт");
 result:=true;
end;

function tRthread.GetAvBytes:cardinal;
var hCurState:TCOMSTAT;
    ErrCode:cardinal;
begin
  ClearCommError(hCom, ErrCode, @hCurState);
  result:=hCurState.cbInQue;
end;


 
ZlDoc ©   (2005-07-19 17:28) [4]

WaitComEvent Возвращается сразу. Для ожидания завершения операции нужно  WaitForSingleObject. Освобождается event ,вроде, CloseHandle(надо проверить).


 
tesseract ©   (2005-07-20 10:02) [5]

to ZlDoc >> Ну а у нас что
  WaitCommEvent(hCom,tMask,@READOL);
  // смотрим что у нас
   fSignaled:= WaitForSingleObject(ReadOl.hEvent,WaitInt);


 
bobah ©   (2005-07-20 11:08) [6]

У меня появились следующие вопросы (уж простите если они вам покажутся глупыми):
1. Правильно ли вызывать функцию CreateEvent( то есть создовать собыие) в функции чтения, с учетом того что она не блокируется, т.е. вызывается n-ое количество раз в потоке, не накладно ли это для системы?
2. В каких случаях следует вызывать ResetEvent и SetEvent, например у меня функции чтения и записи в одном отдельном потоке, они не конкурируют... есть надобность в вызове этих функций для моего случая?
3. Какой смысл в вызове функции отмены операции чтения (CancelIO), когда ее следует использовать?
4. Как понять, что сработал таймаут, определенный в структуре COMMTIMEOUTS (можно на примере, предложенным tesseract, за который ему спасибо)?


 
Digitman ©   (2005-07-20 12:23) [7]

1. Ивент нужно создать до первого обращения к нему.

2. Справка на эту тему отвечает так :

..system sets the hEvent member of the OVERLAPPED structure to the not-signaled state before WaitCommEvent returns, and then it sets it to the signaled state when one of the specified events or an error occurs

т.е. если ты используешь WaitCommEvent, то о сбросе/установке ивента заботиться не нужно

3. CancelIO нужен для немедленной отмены ранее стартованной асинхронной операции ввода/вывода, когда та вернула ERROR_IO_PENDING

4. Ф-ции GetOverlappedResult, WaitCommEvent, Read/Write в этом случае вернут отказ с кодом ошибки ERROR_TIMEOUT = 1460



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

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

Наверх




Память: 0.5 MB
Время: 0.055 c
1-1124036570
_Odi_
2005-08-14 20:22
2005.09.04
аналог ACDSee.Подскажите


3-1122291015
ArchValentin
2005-07-25 15:30
2005.09.04
Экспорт из Paradox в StringGrid или в Exel


14-1123812340
Думкин
2005-08-12 06:05
2005.09.04
12 августа. С днем рождения!


14-1123749680
GRAND25
2005-08-11 12:41
2005.09.04
Шахтер - Интер (продолжение)


3-1122279717
salexn
2005-07-25 12:21
2005.09.04
Проблема с Oracle под дебагером