Форум: "WinAPI";
Текущий архив: 2005.09.04;
Скачать: [xml.tar.bz2];
Вниз
Асинхронный ввод/выод 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 вся ветка
Форум: "WinAPI";
Текущий архив: 2005.09.04;
Скачать: [xml.tar.bz2];
Память: 0.5 MB
Время: 0.012 c