Теги: COMEx
Описание (Данная команда необходима для записи данных в порт)
ini
Код:
[About] Version=1.10 Author=nesco Mail=hiasm@mail.ru [Type] Class=Element Info=Асинхронный COM порт Tab=Misc [Property] Port=Номер порта|4|0|Com1,Com2,Com3,Com4,Com5,Com6,Com7,Com8,Com9 BaudRate=BaudRate=Скорость порта|14|13|50,75,110,150,300,600,1200,1800,2000,2400,3600,4800,7200,9600,14400,19200,28800,38400,57600,115200,128000,256000 @DataBits=Число битов данных|4|0|7,8 @Parity=Режим проверки ошибок передачи|4|0|None,Odd,Even,Marker,Space @StopBits=Число стоповых битов|4|0|1,2 DTR=Состояние линии DTR по умолчанию|4|0|off,on RTS=Состояние линии RTS по умолчанию|4|0|off,on [Methods] doOpen=Открывает порт|1| doClose=Закрывает порт|1| doWrite=Записывает данные в порт|1| doWriteAT=Записывает данные в порт c командой CTRL+Z|1| *doRXClear=Очищает буфер RX входа|1| *doDTR=Устанавливает/сбрасывает сигнал на линии DTR|1| *doRTS=Устанавливает/сбрасывает сигнал на линии RTS|1| *doSetComState=Переустанавливает параметры порта без его перезапуска. Буферы чтения и записи остаются нетронутыми|1| onSyncWrite=В случае успешной записи выдает в синхронном режиме кол-во записанных байт, иначе - 0|2| onRead=В случае успешного чтения выдает в асинхронном режиме прочитанную строку байт|2| onSyncRead=В случае успешного чтения выдает в синхронном режиме прочитанную строку байт|2| *onDSR=Событие происходит при изменении сигнала на линии DSR, выдавая в поток состяние этой линии в синхроннои режиме|2| *onCTS=Событие происходит при изменении сигнала на линии CTS, выдавая в поток состяние этой линии в синхроннои режиме|2| *onDCD=Событие происходит при изменении сигнала на линии DCD, выдавая в поток состяние этой линии в синхроннои режиме|2| *onRING=Событие происходит при изменении сигнала на линии RI, выдавая в поток состяние этой линии в синхроннои режиме|2| *onSetComState=Событие происходит после переустановки параметров порта (1 - успешная переустановка, 0 - неуспешная)|2| Port=Номер порта (от 1 до N)|4|1 BaudRate=Скорость порта|4|1
pas
Код:
unit hiCOMEX;
interface
uses Windows, Kol, Share, Debug;
const
_nm: string = 'NOEMS';
dtrrts: string = 'offon ';
type
_COMSTAT1 = record
Flags: DWORD;
cbInQue: DWORD;
cbOutQue: DWORD;
end;
TComStat1 = _COMSTAT1;
type
THICOMEX = class(TDebug)
private
hFile: THandle;
thrd, thwr: PThread;
OvrWr, OvrRd: TOverlapped;
ReadStr: string;
MaskRd: DWORD;
SendedWr: Integer;
procedure CloseCom;
function SetCom(BaudRate: Integer; Parity, DataBits, StopBits: Char; DTR, RTS: string): boolean;
function InitCom(BaudRate, PortNo: Integer; Parity, DataBits, StopBits: Char; DTR, RTS: string): boolean;
function ExecuteRd(Sender: PThread): Integer;
function ExecuteWr(Sender: PThread): Integer;
procedure SyncExecRd;
procedure SyncExecWr;
procedure SyncExecSt;
public
_prop_Port:byte;
_prop_BaudRate:integer;
_prop_Parity:integer;
_prop_DataBits:integer;
_prop_StopBits:integer;
_prop_DTR: byte;
_prop_RTS: byte;
_event_onSyncWrite:THI_Event;
_event_onRead:THI_Event;
_event_onSyncRead:THI_Event;
_event_onDSR:THI_Event;
_event_onCTS:THI_Event;
_event_onDCD:THI_Event;
_event_onRING:THI_Event;
_event_onSetComState:THI_Event;
_data_BaudRate:THI_Event;
_data_Port:THI_Event;
constructor Create;
destructor Destroy; override;
procedure _work_doOpen(var _Data:TData; Index:word);
procedure _work_doClose(var _Data:TData; Index:word);
procedure _work_doRXClear(var _Data:TData; Index:word);
procedure _work_doWrite(var _Data:TData; Index:word);
procedure _work_doWriteAT(var _Data:TData; Index:word);
procedure _work_doDTR(var _Data:TData; Index:word);
procedure _work_doRTS(var _Data:TData; Index:word);
procedure _work_doSetComState(var _Data:TData; Index:word);
procedure _work_doDataBits(var _Data:TData; Index:word);
procedure _work_doParity(var _Data:TData; Index:word);
procedure _work_doStopBits(var _Data:TData; Index:word);
end;
implementation
constructor THICOMEX.Create;
begin
inherited;
hFile := INVALID_HANDLE_VALUE;
FillChar(OvrWr, SizeOf(TOverlapped), #0);
OvrWr.hEvent := CreateEvent(nil, True, True, #0);
FillChar(OvrRd, SizeOf(TOverlapped), #0);
OvrRd.hEvent := CreateEvent(nil, false, false, #0);
end;
destructor THICOMEX.Destroy;
begin
// Этот костыль связан с некорректностью уничтожения класса в FPC
{$ifndef F_P}
CloseCom;
CloseHandle(OvrWr.hEvent);
CloseHandle(OvrRd.hEvent);
{$endif}
inherited Destroy;
end;
function THICOMEX.SetCom(BaudRate: Integer; Parity, DataBits, StopBits: Char; DTR, RTS: string): Boolean;
var
PortParam: string;
dcb: TDCB;
cto: _COMMTIMEOUTS;
begin
result := false;
if hFile = INVALID_HANDLE_VALUE then exit;
//установка требуемых параметров
GetCommState(hFile, dcb); //чтение текущих параметров порта
PortParam := 'baud=' + Int2Str(BaudRate) +
' data=' + DataBits +
' parity=' + Parity +
' stop=' + StopBits +
' dtr=' + DTR +
' rts=' + RTS +
' xon=off odsr=off octs=off idsr=off';
FillChar(cto, sizeof(cto), #0); // убираем все TimeOut-ы, так как будем работать с перекрытыми методами
if BuildCommDCB(PChar(PortParam), DCB) then
result := SetCommState(hFile, DCB) and SetCommTimeouts(hFile, cto);
end;
function THICOMEX.InitCom(BaudRate, PortNo: Integer; Parity, DataBits, StopBits: Char; DTR, RTS: string): Boolean;
var
FileName: string;
PortParam: string;
dcb: TDCB;
cto: _COMMTIMEOUTS;
FModems: DWORD;
begin
result := false;
CloseCom;
FileName := '\\.\Com' + Int2Str(PortNo); // имя файла
hFile := CreateFile(PChar(FileName),
GENERIC_READ or GENERIC_WRITE,
0,
nil,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
0);
if hFile = INVALID_HANDLE_VALUE then exit;
//установка требуемых параметров
GetCommState(hFile, dcb); //чтение текущих параметров порта
PortParam := 'baud=' + Int2Str(BaudRate) +
' data=' + DataBits +
' parity=' + Parity +
' stop=' + StopBits +
' dtr=' + DTR +
' rts=' + RTS +
' xon=off odsr=off octs=off idsr=off';
FillChar(cto, sizeof(cto), #0); // убираем все TimeOut-ы, так как будем работать с перекрытыми методами
if BuildCommDCB(PChar(PortParam), DCB) then
result := SetCommState(hFile, DCB) and SetCommTimeouts(hFile, cto);
if not result then
CloseCom
else
begin
thrd := {$ifdef F_P}NewThreadforFPC{$else}NewThread{$endif};
thrd.ThreadPriority := THREAD_PRIORITY_HIGHEST;
thrd.OnExecute := ExecuteRd;
thwr := {$ifdef F_P}NewThreadforFPC{$else}NewThread{$endif};
thwr.ThreadPriority := THREAD_PRIORITY_HIGHEST;
thwr.OnExecute := ExecuteWr;
PurgeComm(hFile, PURGE_TXCLEAR or PURGE_RXCLEAR);
SetCommMask(hFile, EV_RXCHAR or EV_DSR or EV_CTS or EV_RLSD or EV_RING);
if GetCommModemStatus(hFile, FModems) then
begin
_hi_onEvent(_event_onDSR, integer((FModems and MS_DSR_ON) = MS_DSR_ON));
_hi_onEvent(_event_onCTS, integer((FModems and MS_CTS_ON) = MS_CTS_ON));
_hi_onEvent(_event_onDCD, integer((FModems and MS_RLSD_ON) = MS_RLSD_ON));
_hi_onEvent(_event_onRING, integer((FModems and MS_RING_ON) = MS_RING_ON));
end;
thrd.Resume;
end;
end;
procedure THICOMEX.CloseCom;
begin
if Assigned(thrd) then
begin
thrd.Terminate;
thrd.WaitFor;
free_and_nil(thrd);
end;
if Assigned(thwr) then
begin
thwr.Terminate;
thwr.WaitFor;
free_and_nil(thwr);
end;
if hFile = INVALID_HANDLE_VALUE then exit;
PurgeComm(hFile, PURGE_TXCLEAR or PURGE_RXCLEAR);
CloseHandle(hFile);
hFile := INVALID_HANDLE_VALUE;
end;
procedure THICOMEX._work_doOpen;
begin
CloseCom;
InitCom(ReadInteger(_Data,_data_BaudRate,_prop_BaudRate),
ReadInteger(_Data,_data_Port,_prop_Port + 1),
_nm[_prop_Parity + 1],
Int2Str(_prop_DataBits + 7)[1],
Int2Str(_prop_StopBits + 1)[1],
Copy(dtrrts, _prop_DTR * 3 + 1, 3),
Copy(dtrrts, _prop_RTS * 3 + 1, 3));
end;
procedure THICOMEX._work_doClose;
begin
CloseCom;
end;
procedure THICOMEX._work_doRXClear;
begin
if hFile <> INVALID_HANDLE_VALUE then
PurgeComm(hFile, PURGE_RXCLEAR);
end;
procedure THICOMEX._work_doWrite;
var
BufferWr: string;
Sended: DWORD;
begin
if hFile = INVALID_HANDLE_VALUE then exit;
// if (not thwr.Suspended) then exit;
BufferWr := ToString(_Data);
WriteFile(hFile, BufferWr[1], Length(BufferWr), Sended, @OvrWr);
thwr.Resume;
end;
procedure THICOMEX._work_doWriteAT;
var
BufferWr: string;
Sended: DWORD;
begin
if hFile = INVALID_HANDLE_VALUE then exit;
// if (not thwr.Suspended) then exit;
BufferWr := ToString(_Data) + #$1A;
WriteFile(hFile, BufferWr[1], Length(BufferWr), Sended, @OvrWr);
thwr.Resume;
end;
function THICOMEX.ExecuteRd;
var
Signaled, BytesTrans, Err: DWORD;
BufferRd: string;
FStat: TComStat1;
begin
while not Sender.Terminated do
begin
WaitCommEvent(hFile, MaskRd, @OvrRd);
Signaled := WaitForSingleObject(OvrRd.hEvent, INFINITE);
if (Signaled = WAIT_OBJECT_0) then
begin
if GetOverlappedResult(hFile, OvrRd, BytesTrans, True) then
begin
if ((MaskRd and EV_RXCHAR) <> 0) then
begin
if ClearCommError(hFile, Err, @FStat) then
begin
if (FStat.cbInQue <> 0) then
begin
SetLength(BufferRd, FStat.cbInQue);
ReadFile(hFile, BufferRd[1], FStat.cbInQue, BytesTrans, @OvrRd);
if GetOverlappedResult(hFile, OvrRd, BytesTrans, True) then
begin
ReadStr := BufferRd + #0;
SetLength(ReadStr, BytesTrans);
_hi_onEvent(_event_onRead, ReadStr);
if Assigned(_event_onSyncRead.Event) then Sender.Synchronize(SyncExecRd);
end;
end;
end;
end
else
if Assigned(_event_onDSR.Event) or
Assigned(_event_onCTS.Event) or
Assigned(_event_onDCD.Event) or
Assigned(_event_onRING.Event) then
Sender.Synchronize(SyncExecSt);
end;
end;
end;
PurgeComm(hFile, PURGE_RXCLEAR);
Result := 0;
end;
procedure THICOMEX.SyncExecRd;
begin
_hi_onEvent(_event_onSyncRead, ReadStr);
end;
procedure THICOMEX.SyncExecSt;
var
FModems: DWORD;
begin
if GetCommModemStatus(hFile, FModems) then
if ((MaskRd and EV_DSR) <> 0) then
_hi_onEvent(_event_onDSR, integer((FModems and MS_DSR_ON) = MS_DSR_ON));
if ((MaskRd and EV_CTS) <> 0) then
_hi_onEvent(_event_onCTS, integer((FModems and MS_CTS_ON) = MS_CTS_ON));
if ((MaskRd and EV_RLSD) <> 0) then
_hi_onEvent(_event_onDCD, integer((FModems and MS_RLSD_ON) = MS_RLSD_ON));
if ((MaskRd and EV_RING) <> 0) then
_hi_onEvent(_event_onRING, integer((FModems and MS_RING_ON) = MS_RING_ON));
end;
function THICOMEX.ExecuteWr(Sender: PThread): Integer;
var
Sended, Signaled: DWORD;
begin
while not Sender.Terminated do
begin
SendedWr := 0;
Signaled := WaitForSingleObject(OvrWr.hEvent, 500);
if (Signaled = WAIT_OBJECT_0) then
if GetOverlappedResult(hFile, OvrWr, Sended, True) then
SendedWr := integer(Sended);
if Assigned(_event_onSyncWrite.Event) then Sender.Synchronize(SyncExecWr);
Sender.Suspend;
end;
PurgeComm(hFile, PURGE_TXCLEAR);
Result := 0;
end;
procedure THICOMEX.SyncExecWr;
begin
_hi_onEvent(_event_onSyncWrite, SendedWr);
end;
procedure THICOMEX._work_doDTR;
begin
if hFile = INVALID_HANDLE_VALUE then exit;
if ReadBool(_Data) then
EscapeCommFunction(hFile, SETDTR)
else
EscapeCommFunction(hFile, CLRDTR);
end;
procedure THICOMEX._work_doRTS;
begin
if hFile = INVALID_HANDLE_VALUE then exit;
if ReadBool(_Data) then
EscapeCommFunction(hFile, SETRTS)
else
EscapeCommFunction(hFile, CLRRTS);
end;
procedure THICOMEX._work_doSetComState;
begin
if not SetCom(ReadInteger(_Data,_data_BaudRate,_prop_BaudRate),
_nm[_prop_Parity + 1],
Int2Str(_prop_DataBits + 7)[1],
Int2Str(_prop_StopBits + 1)[1],
Copy(dtrrts, _prop_DTR * 3 + 1, 3),
Copy(dtrrts, _prop_RTS * 3 + 1, 3)) then
_hi_onEvent(_event_onSetComState, 0)
else
_hi_onEvent(_event_onSetComState, 1);
end;
procedure THICOMEX._work_doDataBits;
begin
_prop_DataBits := ToInteger(_Data);
end;
procedure THICOMEX._work_doParity;
begin
_prop_Parity := ToInteger(_Data);
end;
procedure THICOMEX._work_doStopBits;
begin
_prop_StopBits := ToInteger(_Data);
end;
end.