Ассинхронная связь

    unit Comm;

interface
uses
Messages,WinTypes,WinProcs,Classes,Forms;

type
TPort=(tptNone,tptOne,tptTwo,tptThree,tptFour,tptFive,tptSix,tptSeven,
tptEight);
TBaudRate=(tbr110,tbr300,tbr600,tbr1200,tbr2400,tbr4800,tbr9600,tbr14400,
tbr19200,tbr38400,tbr56000,tbr128000,tbr256000);
TParity=(tpNone,tpOdd,tpEven,tpMark,tpSpace);
TDataBits=(tdbFour,tdbFive,tdbSix,tdbSeven,tdbEight);
TStopBits=(tsbOne,tsbOnePointFive,tsbTwo);
TCommEvent=(tceBreak,tceCts,tceCtss,tceDsr,tceErr,tcePErr,tceRing,tceRlsd,
tceRlsds,tceRxChar,tceRxFlag,tceTxEmpty);
TCommEvents=set of TCommEvent;

const
PortDefault=tptNone;
BaudRateDefault=tbr9600;
ParityDefault=tpNone;
DataBitsDefault=tdbEight;
StopBitsDefault=tsbOne;
ReadBufferSizeDefault=2048;
WriteBufferSizeDefault=2048;
RxFullDefault=1024;
TxLowDefault=1024;
EventsDefault=[];

type
TNotifyEventEvent=procedure(Sender:TObject;CommEvent:TCommEvents) of object;
TNotifyReceiveEvent=procedure(Sender:TObject;Count:Word) of object;
TNotifyTransmitEvent=procedure(Sender:TObject;Count:Word) of object;

TComm=class(TComponent)
private
FPort:TPort;
FBaudRate:TBaudRate;
FParity:TParity;
FDataBits:TDataBits;
FStopBits:TStopBits;
FReadBufferSize:Word;
FWriteBufferSize:Word;
FRxFull:Word;
FTxLow:Word;
FEvents:TCommEvents;
FOnEvent:TNotifyEventEvent;
FOnReceive:TNotifyReceiveEvent;
FOnTransmit:TNotifyTransmitEvent;
FWindowHandle:hWnd;
hComm:Integer;
HasBeenLoaded:Boolean;
Error:Boolean;
procedure SetPort(Value:TPort);
procedure SetBaudRate(Value:TBaudRate);
procedure SetParity(Value:TParity);
procedure SetDataBits(Value:TDataBits);
procedure SetStopBits(Value:TStopBits);
procedure SetReadBufferSize(Value:Word);
procedure SetWriteBufferSize(Value:Word);
procedure SetRxFull(Value:Word);
procedure SetTxLow(Value:Word);
procedure SetEvents(Value:TCommEvents);
procedure WndProc(var Msg:TMessage);
procedure DoEvent;
procedure DoReceive;
procedure DoTransmit;
protected
procedure Loaded;override;
public
constructor Create(AOwner:TComponent);override;
destructor Destroy;override;
procedure Write(Data:PChar;Len:Word);
procedure Read(Data:PChar;Len:Word);
function IsError:Boolean;
published
property Port:TPort read FPort write SetPort default PortDefault;
property BaudRate:TBaudRate read FBaudRate write SetBaudRate
default BaudRateDefault;
property Parity:TParity read FParity write SetParity default ParityDefault;
property DataBits:TDataBits read FDataBits write SetDataBits
default DataBitsDefault;
property StopBits:TStopBits read FStopBits write SetStopBits
default StopBitsDefault;
property WriteBufferSize:Word read FWriteBufferSize
write SetWriteBufferSize default WriteBufferSizeDefault;
property ReadBufferSize:Word read FReadBufferSize
write SetReadBufferSize default ReadBufferSizeDefault;
property RxFullCount:Word read FRxFull write SetRxFull
default RxFullDefault;
property TxLowCount:Word read FTxLow write SetTxLow default TxLowDefault;
property Events:TCommEvents read FEvents write SetEvents
default EventsDefault;
property OnEvent:TNotifyEventEvent read FOnEvent write FOnEvent;
property OnReceive:TNotifyReceiveEvent read FOnReceive write FOnReceive;
property OnTransmit:TNotifyTransmitEvent read FOnTransmit write FOnTransmit;
end;

procedure Register;

implementation

procedure
TComm.SetPort(Value:TPort);
const
CommStr:PChar='COM1:';
begin
FPort:=Value;
if (csDesigning in ComponentState) or
(Value=tptNone) or (not HasBeenLoaded) then exit;
if hComm>=0 then CloseComm(hComm);
CommStr[3]:=chr(48+ord(Value));
hComm:=OpenComm(CommStr,ReadBufferSize,WriteBufferSize);
if hComm<0 then
begin
Error:=True;
exit;
end;
SetBaudRate(FBaudRate);
SetParity(FParity);
SetDataBits(FDataBits);
SetStopBits(FStopBits);
SetEvents(FEvents);
EnableCommNotification(hComm,FWindowHandle,FRxFull,FTxLow);
end;

procedure TComm.SetBaudRate(Value:TBaudRate);
var
DCB:TDCB;
begin
FBaudRate:=Value;
if hComm>=0 then
begin
GetCommState(hComm,DCB);
case Value of
tbr110:DCB.BaudRate:=CBR_110;
tbr300:DCB.BaudRate:=CBR_300;
tbr600:DCB.BaudRate:=CBR_600;
tbr1200:DCB.BaudRate:=CBR_1200;
tbr2400:DCB.BaudRate:=CBR_2400;
tbr4800:DCB.BaudRate:=CBR_4800;
tbr9600:DCB.BaudRate:=CBR_9600;
tbr14400:DCB.BaudRate:=CBR_14400;
tbr19200:DCB.BaudRate:=CBR_19200;
tbr38400:DCB.BaudRate:=CBR_38400;
tbr56000:DCB.BaudRate:=CBR_56000;
tbr128000:DCB.BaudRate:=CBR_128000;
tbr256000:DCB.BaudRate:=CBR_256000;
end;
SetCommState(DCB);
end;
end;

procedure TComm.SetParity(Value:TParity);
var
DCB:TDCB;
begin
FParity:=Value;
if hComm<0 then exit;
GetCommState(hComm,DCB);
case Value of
tpNone:DCB.Parity:=0;
tpOdd:DCB.Parity:=1;
tpEven:DCB.Parity:=2;
tpMark:DCB.Parity:=3;
tpSpace:DCB.Parity:=4;
end;
SetCommState(DCB);
end;

procedure TComm.SetDataBits(Value:TDataBits);
var
DCB:TDCB;
begin
FDataBits:=Value;
if hComm<0 then exit;
GetCommState(hComm,DCB);
case Value of
tdbFour:DCB.ByteSize:=4;
tdbFive:DCB.ByteSize:=5;
tdbSix:DCB.ByteSize:=6;
tdbSeven:DCB.ByteSize:=7;
tdbEight:DCB.ByteSize:=8;
end;
SetCommState(DCB);
end;

procedure TComm.SetStopBits(Value:TStopBits);
var
DCB:TDCB;
begin
FStopBits:=Value;
if hComm<0 then exit;
GetCommState(hComm,DCB);
case Value of
tsbOne:DCB.StopBits:=0;
tsbOnePointFive:DCB.StopBits:=1;
tsbTwo:DCB.StopBits:=2;
end;
SetCommState(DCB);
end;

procedure TComm.SetReadBufferSize(Value:Word);
begin
FReadBufferSize:=Value;
SetPort(FPort);
end;

procedure TComm.SetWriteBufferSize(Value:Word);
begin
FWriteBufferSize:=Value;
SetPort(FPort);
end;

procedure TComm.SetRxFull(Value:Word);
begin
FRxFull:=Value;
if hComm<0 then exit;
EnableCommNotification(hComm,FWindowHandle,FRxFull,FTxLow);
end;

procedure TComm.SetTxLow(Value:Word);
begin
FTxLow:=Value;
if hComm<0 then exit;
EnableCommNotification(hComm,FWindowHandle,FRxFull,FTxLow);
end;

procedure TComm.SetEvents(Value:TCommEvents);
var
EventMask:Word;
begin
FEvents:=Value;
if hComm<0 then exit;
EventMask:=0;
if tceBreak in FEvents then inc(EventMask,EV_BREAK);
if tceCts in FEvents then inc(EventMask,EV_CTS);
if tceCtss in FEvents then inc(EventMask,EV_CTSS);
if tceDsr in FEvents then inc(EventMask,EV_DSR);
if tceErr in FEvents then inc(EventMask,EV_ERR);
if tcePErr in FEvents then inc(EventMask,EV_PERR);
if tceRing in FEvents then inc(EventMask,EV_RING);
if tceRlsd in FEvents then inc(EventMask,EV_RLSD);
if tceRlsds in FEvents then inc(EventMask,EV_RLSDS);
if tceRxChar in FEvents then inc(EventMask,EV_RXCHAR);
if tceRxFlag in FEvents then inc(EventMask,EV_RXFLAG);
if tceTxEmpty in FEvents then inc(EventMask,EV_TXEMPTY);
SetCommEventMask(hComm,EventMask);
end;

procedure TComm.WndProc(var Msg:TMessage);
begin
with Msg do
begin
if Msg=WM_COMMNOTIFY then
begin
case lParamLo of
CN_EVENT:DoEvent;
CN_RECEIVE:DoReceive;
CN_TRANSMIT:DoTransmit;
end;
end
else
Result:=DefWindowProc(FWindowHandle,Msg,wParam,lParam);
end;
end;

procedure TComm.DoEvent;
var
CommEvent:TCommEvents;
EventMask:Word;
begin
if (hComm<0) or not Assigned(FOnEvent) then exit;
EventMask:=GetCommEventMask(hComm,Integer($FFFF));
CommEvent:=[];
if (tceBreak in Events) and (EventMask and EV_BREAK<>0) then
CommEvent:=CommEvent+[tceBreak];
if (tceCts in Events) and (EventMask and EV_CTS<>0) then
CommEvent:=CommEvent+[tceCts];
if (tceCtss in Events) and (EventMask and EV_CTSS<>0) then
CommEvent:=CommEvent+[tceCtss];
if (tceDsr in Events) and (EventMask and EV_DSR<>0) then
CommEvent:=CommEvent+[tceDsr];
if (tceErr in Events) and (EventMask and EV_ERR<>0) then
CommEvent:=CommEvent+[tceErr];
if (tcePErr in Events) and (EventMask and EV_PERR<>0) then
CommEvent:=CommEvent+[tcePErr];
if (tceRing in Events) and (EventMask and EV_RING<>0) then
CommEvent:=CommEvent+[tceRing];
if (tceRlsd in Events) and (EventMask and EV_RLSD<>0) then
CommEvent:=CommEvent+[tceRlsd];
if (tceRlsds in Events) and (EventMask and EV_Rlsds<>0) then
CommEvent:=CommEvent+[tceRlsds];
if (tceRxChar in Events) and (EventMask and EV_RXCHAR<>0) then
CommEvent:=CommEvent+[tceRxChar];
if (tceRxFlag in Events) and (EventMask and EV_RXFLAG<>0) then
CommEvent:=CommEvent+[tceRxFlag];
if (tceTxEmpty in Events) and (EventMask and EV_TXEMPTY<>0) then
CommEvent:=CommEvent+[tceTxEmpty];
FOnEvent(Self,CommEvent);
end;

procedure TComm.DoReceive;
var
Stat:TComStat;
begin
if (hComm<0) or not Assigned(FOnReceive) then exit;
GetCommError(hComm,Stat);
FOnReceive(Self,Stat.cbInQue);
GetCommError(hComm,Stat);
end;

procedure TComm.DoTransmit;
var
Stat:TComStat;
begin
if (hComm<0) or not Assigned(FOnTransmit) then exit;
GetCommError(hComm,Stat);
FOnTransmit(Self,Stat.cbOutQue);
end;

procedure TComm.Loaded;
begin
inherited Loaded;
HasBeenLoaded:=True;
SetPort(FPort);
end;


constructor TComm.Create(AOwner:TComponent);
begin
inherited Create(AOwner);
FWindowHandle:=AllocateHWnd(WndProc);
HasBeenLoaded:=False;
Error:=False;
FPort:=PortDefault;
FBaudRate:=BaudRateDefault;
FParity:=ParityDefault;
FDataBits:=DataBitsDefault;
FStopBits:=StopBitsDefault;
FWriteBufferSize:=WriteBufferSizeDefault;
FReadBufferSize:=ReadBufferSizeDefault;
FRxFull:=RxFullDefault;
FTxLow:=TxLowDefault;
FEvents:=EventsDefault;
hComm:=-1;
end;

destructor TComm.Destroy;
begin
DeallocatehWnd(FWindowHandle);
if hComm>=0 then CloseComm(hComm);
inherited Destroy;
end;

procedure TComm.Write(Data:PChar;Len:Word);
begin
if hComm<0 then exit;
if WriteComm(hComm,Data,Len)<0 then Error:=True;
GetCommEventMask(hComm,Integer($FFFF));
end;

procedure TComm.Read(Data:PChar;Len:Word);
begin
if hComm<0 then exit;
if ReadComm(hComm,Data,Len)<0 then Error:=True;
GetCommEventMask(hComm,Integer($FFFF));
end;

function TComm.IsError:Boolean;
begin
IsError:=Error;
Error:=False;
end;

procedure Register;
begin
RegisterComponents('Additional',[TComm]);
end;

end.