【Delphi】modbus-TCP 协议库
在日常开发中,也会遇到使用modbus的部件,比如温度控制器、读卡器等等,那么使用Delphi开发,也就必须遵守modbus-TCP协议,如果自己使用TCP控件写也没有问题,不过如果有开源的三方库,别人已经调试过了,就不必要自己也造车轮了!
Delphi ModbusTCP components 下载地址
截至 2024-12-02 最新版本为:1.7.3 支持到 Delphi 12 版本。
如果上述连接无法下载,请在这里下载。
源代码如下:
一、ModbusConsts.pas
{$I ModBusCompiler.inc}unit ModbusConsts;interfaceconstMB_PORT = 502;MB_IGNORE_UNITID = 255;MB_PROTOCOL = 0;// Define constants for the ModBus functions
constmbfReadCoils = $01;mbfReadInputBits = $02;mbfReadHoldingRegs = $03;mbfReadInputRegs = $04;mbfWriteOneCoil = $05;mbfWriteOneReg = $06;mbfWriteCoils = $0F;mbfWriteRegs = $10; mbfReportSlaveID = $11;mbfReadFileRecord = $14;mbfWriteFileRecord = $15;mbfMaskWriteReg = $16;mbfReadWriteRegs = $17;mbfReadFiFoQueue = $18;// Define constants for the ModBus exceptions
constmbeOk = $00;mbeIllegalFunction = $01;mbeIllegalRegister = $02;mbeIllegalDataValue = $03;mbeServerFailure = $04;mbeAcknowledge = $05;mbeServerBusy = $06;mbeGatewayPathNotAvailable = $0A;mbeGatewayNoResponseFromTarget = $0B;constMaxBlockLength = 125;MaxCoils = 2000;constDMB_VERSION = '1.7.3'; {Do not Localize}constDefaultLogTimeFormat = 'yyyy-mm-dd hh:nn:ss.zzz'; {Do not Localize}implementationend.
二、ModbusTypes.pas
{$I ModBusCompiler.inc}unit ModbusTypes;interfacetypeTModBusFunction = Byte;typeTModBusDataBuffer = array[0..260] of Byte;typeTModBusHeader = packed recordTransactionID: Word;ProtocolID: Word;RecLength: Word;UnitID: Byte;end;typeTModBusRequestBuffer = packed recordHeader: TModBusHeader;FunctionCode: TModBusFunction;MBPData: TModBusDataBuffer;end;typeTModBusResponseBuffer = packed recordHeader: TModBusHeader;FunctionCode: TModBusFunction;MBPData: TModBusDataBuffer;end;typeTModBusExceptionBuffer = packed recordHeader: TModBusHeader;ExceptionFunction: TModBusFunction;ExceptionCode: Byte;end;implementationend.
三、ModbusUtils.pas
{$I ModBusCompiler.inc}unit ModbusUtils;interfacefunction BufferToHex(const Buffer: array of Byte): String;
function CalculateCRC16(const Buffer: array of Byte): Word;
function CalculateLRC(const Buffer: array of Byte): Byte;function Swap16(const DataToSwap: Word): Word;procedure GetCoilsFromBuffer(const Buffer: PByte; const Count: Word; var Data: array of Word);
procedure PutCoilsIntoBuffer(const Buffer: PByte; const Count: Word; const Data: array of Word);procedure GetReportFromBuffer(const Buffer: PByte; const Count: Word; var Data: array of Word);procedure GetRegistersFromBuffer(const Buffer: PWord; const Count: Word; var Data: array of Word);
procedure PutRegistersIntoBuffer(const Buffer: PWord; const Count: Word; const Data: array of Word);implementationusesSysUtils;constCRC16Table: array[0..255] of Word = ($0000, $C0C1, $C181, $0140, $C301, $03C0, $0280, $C241,$C601, $06C0, $0780, $C741, $0500, $C5C1, $C481, $0440,$CC01, $0CC0, $0D80, $CD41, $0F00, $CFC1, $CE81, $0E40,$0A00, $CAC1, $CB81, $0B40, $C901, $09C0, $0880, $C841,$D801, $18C0, $1980, $D941, $1B00, $DBC1, $DA81, $1A40,$1E00, $DEC1, $DF81, $1F40, $DD01, $1DC0, $1C80, $DC41,$1400, $D4C1, $D581, $1540, $D701, $17C0, $1680, $D641,$D201, $12C0, $1380, $D341, $1100, $D1C1, $D081, $1040,$F001, $30C0, $3180, $F141, $3300, $F3C1, $F281, $3240,$3600, $F6C1, $F781, $3740, $F501, $35C0, $3480, $F441,$3C00, $FCC1, $FD81, $3D40, $FF01, $3FC0, $3E80, $FE41,$FA01, $3AC0, $3B80, $FB41, $3900, $F9C1, $F881, $3840,$2800, $E8C1, $E981, $2940, $EB01, $2BC0, $2A80, $EA41,$EE01, $2EC0, $2F80, $EF41, $2D00, $EDC1, $EC81, $2C40,$E401, $24C0, $2580, $E541, $2700, $E7C1, $E681, $2640,$2200, $E2C1, $E381, $2340, $E101, $21C0, $2080, $E041,$A001, $60C0, $6180, $A141, $6300, $A3C1, $A281, $6240,$6600, $A6C1, $A781, $6740, $A501, $65C0, $6480, $A441,$6C00, $ACC1, $AD81, $6D40, $AF01, $6FC0, $6E80, $AE41,$AA01, $6AC0, $6B80, $AB41, $6900, $A9C1, $A881, $6840,$7800, $B8C1, $B981, $7940, $BB01, $7BC0, $7A80, $BA41,$BE01, $7EC0, $7F80, $BF41, $7D00, $BDC1, $BC81, $7C40,$B401, $74C0, $7580, $B541, $7700, $B7C1, $B681, $7640,$7200, $B2C1, $B381, $7340, $B101, $71C0, $7080, $B041,$5000, $90C1, $9181, $5140, $9301, $53C0, $5280, $9241,$9601, $56C0, $5780, $9741, $5500, $95C1, $9481, $5440,$9C01, $5CC0, $5D80, $9D41, $5F00, $9FC1, $9E81, $5E40,$5A00, $9AC1, $9B81, $5B40, $9901, $59C0, $5880, $9841,$8801, $48C0, $4980, $8941, $4B00, $8BC1, $8A81, $4A40,$4E00, $8EC1, $8F81, $4F40, $8D01, $4DC0, $4C80, $8C41,$4400, $84C1, $8581, $4540, $8701, $47C0, $4680, $8641,$8201, $42C0, $4380, $8341, $4100, $81C1, $8081, $4040);function BufferToHex(const Buffer: array of Byte): String;
vari: Integer;
beginResult := '';for i := Low(Buffer) to High(Buffer) doResult := Result + IntToHex(Buffer[i], 2);
end;function CalculateCRC16(const Buffer: array of Byte): Word;
vari: Integer;bTemp: Byte;
beginResult := 0;for i := Low(Buffer) to High(Buffer) dobeginbTemp := Buffer[i] xor Result;Result := Result shr 8;Result := Result xor CRC16Table[bTemp];end;
end;function CalculateLRC(const Buffer: array of Byte): Byte;
vari: Integer;CheckSum: Word;
beginCheckSum := 0;for i := Low(Buffer) to High(Buffer) doCheckSum := WordRec(CheckSum).Lo + Buffer[i];Result := - WordRec(CheckSum).Lo;
end;function Swap16(const DataToSwap: Word): Word;
beginResult := (DataToSwap div 256) + ((DataToSwap mod 256) * 256);
end;procedure GetCoilsFromBuffer(const Buffer: PByte; const Count: Word; var Data: array of Word);
varBytePtr: PByte;BitMask: Byte;i: Integer;
beginif (Length(Data) < ((Count div 16) - 1)) or (Length(Data) = 0) or (Count = 0) thenraise Exception.Create('GetCoilsFromBuffer: Data array length cannot be less then Count');BytePtr := Buffer;BitMask := 1;for i := 0 to (Count - 1) dobeginif (i < Length(Data)) thenbeginif ((BytePtr^ and BitMask) <> 0) thenData[i] := 1elseData[i] := 0;if (BitMask = $80) thenbeginBitMask := 1;Inc(BytePtr);endelseBitMask := (Bitmask shl 1);end;end;
end;procedure PutCoilsIntoBuffer(const Buffer: PByte; const Count: Word; const Data: array of Word);
varBytePtr: PByte;BitMask: Byte;i: Word;
beginif (Length(Data) < ((Count div 16) - 1)) or (Length(Data) = 0) or (Count = 0) thenraise Exception.Create('PutCoilsIntoBuffer: Data array length cannot be less then Count');BytePtr := Buffer;BitMask := 1;for i := 0 to (Count - 1) dobeginif (i < Length(Data)) thenbeginif (BitMask = 1) thenBytePtr^ := 0;if (Data[i] <> 0) thenBytePtr^ := BytePtr^ or BitMask;if (BitMask = $80) thenbeginBitMask := 1;Inc(BytePtr);endelseBitMask := (Bitmask shl 1);end;end;
end;procedure GetRegistersFromBuffer(const Buffer: PWord; const Count: Word; var Data: array of Word);
varWordPtr: PWord;i: Word;
beginif (Length(Data) < (Count - 1)) or (Length(Data) = 0) or (Count = 0) thenraise Exception.Create('GetRegistersFromBuffer: Data array length cannot be less then Count');WordPtr := Buffer;for i := 0 to (Count - 1) dobeginData[i] := Swap16(WordPtr^);Inc(WordPtr);end;
end;procedure GetReportFromBuffer(const Buffer: PByte; const Count: Word; var Data: array of Word);
varWordPtr: PByte;i: Word;
beginif (Length(Data) < (Count - 1)) or (Length(Data) = 0) or (Count = 0) thenraise Exception.Create('GetRegistersFromBuffer: Data array length cannot be less then Count');WordPtr := Buffer;i:= 0;for i:= 0 to (Count - 1) dobeginData[i] := Lo(WordPtr^);Inc(WordPtr);end;
end;procedure PutRegistersIntoBuffer(const Buffer: PWord; const Count: Word; const Data: array of Word);
varWordPtr: PWord;i: Word;
beginif (Length(Data) < (Count - 1)) or (Length(Data) = 0) or (Count = 0) thenraise Exception.Create('PutRegistersIntoBuffer: Data array length cannot be less then Count');WordPtr := Buffer;for i := 0 to (Count - 1) dobeginWordPtr^ := Swap16(Data[i]);Inc(WordPtr);end;
end;end.
四、IdModBusClient.pas
{$I ModBusCompiler.inc}unit IdModBusClient;interfaceusesClasses,SysUtils,ModBusConsts,ModbusTypes
{$IFDEF DMB_DELPHI6},Types
{$ENDIF},IdGlobal,IdTCPClient;typeTModBusClientErrorEvent = procedure(const FunctionCode: Byte;const ErrorCode: Byte; const ResponseBuffer: TModBusResponseBuffer) of object;TModBusClientResponseMismatchEvent = procedure(const RequestFunctionCode: Byte;const ResponseFunctionCode: Byte; const ResponseBuffer: TModBusResponseBuffer) of object;type
{$I ModBusPlatforms.inc}TIdModBusClient = class(TIdTCPClient)privateFAutoConnect: Boolean;FBaseRegister: Word;{$IFNDEF DMB_INDY10}FConnectTimeOut: Integer;{$ENDIF}FOnResponseError: TModbusClientErrorEvent;FOnResponseMismatch: TModBusClientResponseMismatchEvent;FLastTransactionID: Word;FReadTimeout: Integer;FTimeOut: Cardinal;FUnitID: Byte;function GetVersion: String;procedure SetVersion(const Value: String);function GetNewTransactionID: Word;protectedprocedure DoResponseError(const FunctionCode: Byte; const ErrorCode: Byte;const ResponseBuffer: TModBusResponseBuffer);procedure DoResponseMismatch(const RequestFunctionCode: Byte; const ResponseFunctionCode: Byte;const ResponseBuffer: TModBusResponseBuffer);{$IFDEF DMB_INDY10}procedure InitComponent; override;{$ENDIF}function SendCommand(const AModBusFunction: TModBusFunction; const ARegNumber: Word;const ABlockLength: Word; var Data: array of Word): Boolean;publicproperty LastTransactionID: Word read FLastTransactionID;{$IFNDEF DMB_INDY10}constructor Create(AOwner: TComponent); override;{$ENDIF}{ public methods }{$IFDEF DMB_INDY10}procedure Connect; override;{$ELSE}procedure Connect(const ATimeout: Integer = IdTimeoutDefault); override;{$ENDIF}function ReadCoil(const RegNo: Word; out Value: Boolean): Boolean;function ReadCoils(const RegNo: Word; const Blocks: Word; out RegisterData: array of Boolean): Boolean;function ReadDouble(const RegNo: Word; out Value: Double): Boolean;function ReadDWord(const RegNo: Word; out Value: DWord): Boolean;function ReadHoldingRegister(const RegNo: Word; out Value: Word): Boolean;function ReadHoldingRegisters(const RegNo: Word; const Blocks: Word; out RegisterData: array of Word): Boolean;function ReadInputBits(const RegNo: Word; const Blocks: Word; out RegisterData: array of Boolean): Boolean;function ReadInputRegister(const RegNo: Word; out Value: Word): Boolean;function ReadInputRegisters(const RegNo: Word; const Blocks: Word; var RegisterData: array of Word): Boolean;function ReadSingle(const RegNo: Word; out Value: Single): Boolean;function ReadString(const RegNo: Word; const ALength: Word): String;function ReportSlaveID(const Blocks: Word; out RegisterData: array of Word):boolean;function WriteCoil(const RegNo: Word; const Value: Boolean): Boolean;function WriteCoils(const RegNo: Word; const Blocks: Word; const RegisterData: array of Boolean): Boolean;function WriteRegister(const RegNo: Word; const Value: Word): Boolean;function WriteRegisters(const RegNo: Word; const RegisterData: array of Word): Boolean;function WriteDouble(const RegNo: Word; const Value: Double): Boolean;function WriteDWord(const RegNo: Word; const Value: DWord): Boolean;function WriteSingle(const RegNo: Word; const Value: Single): Boolean;function WriteString(const RegNo: Word; const Text: String): Boolean;publishedproperty AutoConnect: Boolean read FAutoConnect write FAutoConnect default True;property BaseRegister: Word read FBaseRegister write FBaseRegister default 1; {$IFNDEF DMB_INDY10}property ConnectTimeOut: Integer read FConnectTimeOut write FConnectTimeOut default -1;{$ENDIF}property ReadTimeout: Integer read FReadTimeout write FReadTimeout default 0;property Port default MB_PORT;property TimeOut: Cardinal read FTimeOut write FTimeout default 15000;property UnitID: Byte read FUnitID write FUnitID default MB_IGNORE_UNITID;property Version: String read GetVersion write SetVersion stored False;{ events }property OnResponseError: TModbusClientErrorEvent read FOnResponseError write FOnResponseError;property OnResponseMismatch: TModBusClientResponseMismatchEvent read FOnResponseMismatch write FOnResponseMismatch;end;implementationusesModbusUtils;{ TIdModBusClient }{$IFDEF DMB_INDY10}
procedure TIdModBusClient.Connect;
{$ELSE}
procedure TIdModBusClient.Connect(const ATimeout: Integer = IdTimeoutDefault);
{$ENDIF}
begininherited;FLastTransactionID := 0;
end;{$IFDEF DMB_INDY10}
procedure TIdModBusClient.InitComponent;
{$ELSE}
constructor TIdModBusClient.Create(AOwner: TComponent);
{$ENDIF}
begin
{$IFDEF DMB_INDY10}inherited;
{$ELSE}inherited Create(AOwner);FConnectTimeOut := -1;
{$ENDIF}FAutoConnect := True;FBaseRegister := 1;FLastTransactionID := 0;FReadTimeout := 0;FUnitID := MB_IGNORE_UNITID;FTimeOut := 15000;Port := MB_PORT;FOnResponseError := nil;FOnResponseMismatch := nil;
end;procedure TIdModBusClient.DoResponseError(const FunctionCode: Byte; const ErrorCode: Byte;const ResponseBuffer: TModBusResponseBuffer);
beginif Assigned(FOnResponseError) thenFOnResponseError(FunctionCode, ErrorCode, ResponseBuffer);
end;procedure TIdModBusClient.DoResponseMismatch(const RequestFunctionCode: Byte;const ResponseFunctionCode: Byte; const ResponseBuffer: TModBusResponseBuffer);
beginif Assigned(FOnResponseMismatch) thenFOnResponseMismatch(RequestFunctionCode, ResponseFunctionCode, ResponseBuffer);
end;function TIdModBusClient.SendCommand(const AModBusFunction: TModBusFunction;const ARegNumber: Word; const ABlockLength: Word; var Data: array of Word): Boolean;
varSendBuffer: TModBusRequestBuffer;ReceiveBuffer: TModBusResponseBuffer;BlockLength: Word;RegNumber: Word;dtTimeOut: TDateTime;
{$IFDEF DMB_INDY10}Buffer: TIdBytes;RecBuffer: TIdBytes;iSize: Integer;
{$ENDIF}
begin
{$IFDEF DMB_INDY10}CheckForGracefulDisconnect(True);
{$ELSE}CheckForDisconnect(True, True);
{$ENDIF}SendBuffer.Header.TransactionID := GetNewTransactionID;SendBuffer.Header.ProtocolID := MB_PROTOCOL;
{ Initialise data related variables }RegNumber := ARegNumber - FBaseRegister;
{ Perform function code specific operations }case AModBusFunction ofmbfReadCoils,mbfReadInputBits:beginBlockLength := ABlockLength;{ Don't exceed max length }if (BlockLength > 2000) thenBlockLength := 2000;{ Initialise the data part }SendBuffer.FunctionCode := Byte(AModBusFunction); { Write appropriate function code }SendBuffer.Header.UnitID := FUnitID;SendBuffer.MBPData[0] := Hi(RegNumber);SendBuffer.MBPData[1] := Lo(RegNumber);SendBuffer.MBPData[2] := Hi(BlockLength);SendBuffer.MBPData[3] := Lo(BlockLength);SendBuffer.Header.RecLength := Swap16(6); { This includes UnitID/FuntionCode }end;mbfReadHoldingRegs,mbfReadInputRegs:beginBlockLength := ABlockLength;if (BlockLength > 125) thenBlockLength := 125; { Don't exceed max length }{ Initialise the data part }SendBuffer.FunctionCode := Byte(AModBusFunction); { Write appropriate function code }SendBuffer.Header.UnitID := FUnitID;SendBuffer.MBPData[0] := Hi(RegNumber);SendBuffer.MBPData[1] := Lo(RegNumber);SendBuffer.MBPData[2] := Hi(BlockLength);SendBuffer.MBPData[3] := Lo(BlockLength);SendBuffer.Header.RecLength := Swap16(6); { This includes UnitID/FuntionCode }end;mbfReportSlaveID:beginBlockLength := ABlockLength;if (BlockLength > 125) thenBlockLength := 125; { Don't exceed max length }{ Initialise the data part }SendBuffer.FunctionCode := Byte(AModBusFunction); { Write appropriate function code }SendBuffer.Header.UnitID := FUnitID;SendBuffer.Header.RecLength := Swap16(2); { This includes UnitID/FuntionCode }end;mbfWriteOneCoil:begin{ Initialise the data part }SendBuffer.FunctionCode := Byte(AModBusFunction); { Write appropriate function code }SendBuffer.Header.UnitID := FUnitID;SendBuffer.MBPData[0] := Hi(RegNumber);SendBuffer.MBPData[1] := Lo(RegNumber);if (Data[0] <> 0) thenSendBuffer.MBPData[2] := 255elseSendBuffer.MBPData[2] := 0;SendBuffer.MBPData[3] := 0;SendBuffer.Header.RecLength := Swap16(6); { This includes UnitID/FuntionCode }end;mbfWriteOneReg:begin{ Initialise the data part }SendBuffer.FunctionCode := Byte(AModBusFunction); { Write appropriate function code }SendBuffer.Header.UnitID := FUnitID;SendBuffer.MBPData[0] := Hi(RegNumber);SendBuffer.MBPData[1] := Lo(RegNumber);SendBuffer.MBPData[2] := Hi(Data[0]);SendBuffer.MBPData[3] := Lo(Data[0]);SendBuffer.Header.RecLength := Swap16(6); { This includes UnitID/FuntionCode }end;mbfWriteCoils:beginBlockLength := ABlockLength;{ Don't exceed max length }if (BlockLength > 1968) thenBlockLength := 1968;{ Initialise the data part }SendBuffer.FunctionCode := Byte(AModBusFunction); { Write appropriate function code }SendBuffer.Header.UnitID := FUnitID;SendBuffer.MBPData[0] := Hi(RegNumber);SendBuffer.MBPData[1] := Lo(RegNumber);SendBuffer.MBPData[2] := Hi(BlockLength);SendBuffer.MBPData[3] := Lo(BlockLength);SendBuffer.MBPData[4] := Byte((BlockLength + 7) div 8);PutCoilsIntoBuffer(@SendBuffer.MBPData[5], BlockLength, Data);SendBuffer.Header.RecLength := Swap16(7 + SendBuffer.MBPData[4]);end;mbfWriteRegs:beginBlockLength := ABlockLength;{ Don't exceed max length }if (BlockLength > 120) thenBlockLength := 120;{ Initialise the data part }SendBuffer.FunctionCode := Byte(AModBusFunction); { Write appropriate function code }SendBuffer.Header.UnitID := FUnitID;SendBuffer.MBPData[0] := Hi(RegNumber);SendBuffer.MBPData[1] := Lo(RegNumber);SendBuffer.MBPData[2] := Hi(BlockLength);SendBuffer.MBPData[3] := Lo(BlockLength);SendBuffer.MbpData[4] := Byte(BlockLength shl 1);PutRegistersIntoBuffer(@SendBuffer.MBPData[5], BlockLength, Data);SendBuffer.Header.RecLength := Swap16(7 + SendBuffer.MbpData[4]);end;end;
{ Writeout the data to the connection }
{$IFDEF DMB_INDY10}Buffer := RawToBytes(SendBuffer, Swap16(SendBuffer.Header.RecLength) + 6);IOHandler.WriteDirect(Buffer);
{$ELSE}WriteBuffer(SendBuffer, Swap16(SendBuffer.Header.RecLength) + 6);
{$ENDIF}{*** Wait for data from the PLC ***}if (FTimeOut > 0) thenbegindtTimeOut := Now + (FTimeOut / 86400000);{$IFDEF DMB_INDY10}while (IOHandler.InputBuffer.Size = 0) do{$ELSE}while (InputBuffer.Size = 0) do{$ENDIF}begin{$IFDEF DMB_INDY10}IOHandler.CheckForDataOnSource(FReadTimeout);{$ELSE}if Socket.Binding.Readable(FReadTimeout) thenReadFromStack;{$ENDIF}if (Now > dtTimeOut) thenbeginResult := False;Exit;end;end;end;Result := True;
{$IFDEF DMB_INDY10}iSize := IOHandler.InputBuffer.Size;IOHandler.ReadBytes(RecBuffer, iSize);Move(RecBuffer[0], ReceiveBuffer, iSize);
{$ELSE}ReadBuffer(ReceiveBuffer, InputBuffer.Size);
{$ENDIF}
{ Check if the result has the same function code as the request }if (AModBusFunction = ReceiveBuffer.FunctionCode) thenbegincase AModBusFunction ofmbfReadCoils,mbfReadInputBits:beginBlockLength := ReceiveBuffer.MBPData[0] * 8;if (BlockLength > 2000) thenBlockLength := 2000;GetCoilsFromBuffer(@ReceiveBuffer.MBPData[1], BlockLength, Data);end;mbfReportSlaveID:beginBlockLength := Swap16(ReceiveBuffer.Header.RecLength) - 2;GetReportFromBuffer(@ReceiveBuffer.MBPData[0], BlockLength, Data);end;mbfReadHoldingRegs,mbfReadInputRegs:beginBlockLength := (ReceiveBuffer.MBPData[0] shr 1);if (BlockLength > 125) thenBlockLength := 125;GetRegistersFromBuffer(@ReceiveBuffer.MBPData[1], BlockLength, Data);end;end;endelsebeginif ((AModBusFunction or $80) = ReceiveBuffer.FunctionCode) thenDoResponseError(AModBusFunction, ReceiveBuffer.MBPData[0], ReceiveBuffer)elseDoResponseMismatch(AModBusFunction, ReceiveBuffer.FunctionCode, ReceiveBuffer);Result := False;end;
end;function TIdModBusClient.GetNewTransactionID: Word;
beginif (FLastTransactionID = $FFFF) thenFLastTransactionID := 0elseInc(FLastTransactionID);Result := FLastTransactionID;
end;function TIdModBusClient.ReadHoldingRegister(const RegNo: Word;out Value: Word): Boolean;
varData: array[0..0] of Word;
beginResult := ReadHoldingRegisters(RegNo, 1, Data);Value := Data[0];
end;function TIdModBusClient.ReadHoldingRegisters(const RegNo, Blocks: Word;out RegisterData: array of Word): Boolean;
vari: Integer;Data: array of Word;bNewConnection: Boolean;
beginbNewConnection := False;if FAutoConnect and not Connected thenbegin{$IFDEF DMB_INDY10}Connect;{$ELSE}Connect(FConnectTimeOut);{$ENDIF}bNewConnection := True;end;trySetLength(Data, Blocks);FillChar(Data[0], Length(Data), 0);Result := SendCommand(mbfReadHoldingRegs, RegNo, Blocks, Data);for i := Low(Data) to High(Data) doRegisterData[i] := Data[i];finallyif bNewConnection thenDisConnect;end;
end;function TIdModBusClient.ReadInputBits(const RegNo, Blocks: Word;out RegisterData: array of Boolean): Boolean;
vari: Integer;Data: array of Word;bNewConnection: Boolean;
beginbNewConnection := False;if FAutoConnect and not Connected thenbegin{$IFDEF DMB_INDY10}Connect;{$ELSE}Connect(FConnectTimeOut);{$ENDIF}bNewConnection := True;end;SetLength(Data, Blocks);FillChar(Data[0], Length(Data), 0);tryResult := SendCommand(mbfReadInputBits, RegNo, Blocks, Data);for i := 0 to (Blocks - 1) doRegisterData[i] := (Data[i] = 1);finallyif bNewConnection thenDisConnect;end;
end;function TIdModBusClient.ReadInputRegister(const RegNo: Word;out Value: Word): Boolean;
varData: array[0..0] of Word;
beginResult := ReadInputRegisters(RegNo, 1, Data);Value := Data[0];
end;function TIdModBusClient.ReadInputRegisters(const RegNo, Blocks: Word;var RegisterData: array of Word): Boolean;
varbNewConnection: Boolean;
beginbNewConnection := False;if FAutoConnect and not Connected thenbegin{$IFDEF DMB_INDY10}Connect;{$ELSE}Connect(FConnectTimeOut);{$ENDIF}bNewConnection := True;end;FillChar(RegisterData[0], Length(RegisterData), 0);tryResult := SendCommand(mbfReadInputRegs, RegNo, Blocks, RegisterData);finallyif bNewConnection thenDisConnect;end;
end;function TIdModBusClient.ReadCoil(const RegNo: Word; out Value: Boolean): Boolean;
varData: array[0..0] of Boolean;
beginResult := ReadCoils(RegNo, 1, Data);Value := Data[0];
end;function TIdModBusClient.ReadCoils(const RegNo, Blocks: Word; out RegisterData: array of Boolean): Boolean;
vari: Integer;Data: array of Word;bNewConnection: Boolean;
beginbNewConnection := False;if FAutoConnect and not Connected thenbegin{$IFDEF DMB_INDY10}Connect;{$ELSE}Connect(FConnectTimeOut);{$ENDIF}bNewConnection := True;end;SetLength(Data, Blocks);FillChar(Data[0], Length(Data), 0);tryResult := SendCommand(mbfReadCoils, RegNo, Blocks, Data);for i := 0 to (Blocks - 1) doRegisterData[i] := (Data[i] = 1);finallyif bNewConnection thenDisConnect;end;
end;function TIdModbusClient.ReadDouble(const RegNo: Word; out Value: Double): Boolean;
varBuffer: array[0..3] of Word;
beginResult := ReadHoldingRegisters(RegNo, 4, Buffer);if Result thenMove(Buffer, Value, SizeOf(Value))elseValue := 0.0;
end;function TIdModbusClient.ReadDWord(const RegNo: Word; out Value: DWord): Boolean;
varBuffer: array[0..1] of Word;
beginResult := ReadHoldingRegisters(RegNo, 2, Buffer);if Result thenbeginLongRec(Value).Hi := Buffer[0];LongRec(Value).Lo := Buffer[1];endelseValue := 0;
end;function TIdModbusClient.ReadSingle(const RegNo: Word; out Value: Single): Boolean;
varBuffer: array[0..1] of Word;
beginResult := ReadHoldingRegisters(RegNo, 2, Buffer);if Result thenMove(Buffer, Value, SizeOf(Value))elseValue := 0.0;
end;function TIdModbusClient.ReadString(const RegNo: Word; const ALength: Word): String;
varBlockCount: Word;Data: array of Word;i: Integer;
beginResult := '';BlockCount := Round((ALength / 2) + 0.1);SetLength(Data, BlockCount);FillChar(Data[0], BlockCount, 0);if ReadHoldingRegisters(RegNo, BlockCount, Data) thenbeginfor i := 0 to (BlockCount - 1) dobeginResult := Result + Chr(WordRec(Data[i]).Hi);if (Length(Result) < ALength) thenResult := Result + Chr(WordRec(Data[i]).Lo);end;end;
end;function TIdModbusClient.ReportSlaveID(const Blocks: Word; out RegisterData: array of Word): Boolean;
varbNewConnection: Boolean;i: integer;
beginbNewConnection := False;if FAutoConnect and not Connected thenbegin{$IFDEF DMB_INDY10}Connect;{$ELSE}Connect(FConnectTimeOut);{$ENDIF}bNewConnection := True;end;FillChar(RegisterData[0], Length(RegisterData), 0);tryResult := SendCommand(mbfReportSlaveID, 1, 2, RegisterData);finallyif bNewConnection thenDisConnect;end;
end;function TIdModBusClient.GetVersion: String;
beginResult := DMB_VERSION;
end;procedure TIdModBusClient.SetVersion(const Value: String);
begin
{ This intentionally is a readonly property }
end;function TIdModBusClient.WriteDouble(const RegNo: Word; const Value: Double): Boolean;
varBuffer: array[0..3] of Word;
beginMove(Value, Buffer, SizeOf(Value));Result := WriteRegisters(RegNo, Buffer);
end;function TIdModBusClient.WriteDWord(const RegNo: Word; const Value: DWord): Boolean;
varBuffer: array[0..1] of Word;
beginBuffer[0] := LongRec(Value).Hi;Buffer[1] := LongRec(Value).Lo;Result := WriteRegisters(RegNo, Buffer);
end;function TIdModBusClient.WriteSingle(const RegNo: Word; const Value: Single): Boolean;
varBuffer: array[0..1] of Word;
beginMove(Value, Buffer, SizeOf(Value));Result := WriteRegisters(RegNo, Buffer);
end;function TIdModBusClient.WriteString(const RegNo: Word; const Text: String): Boolean;
varBuffer: array of Word;i: Integer;iIndex: Integer;
beginif (Text <> '') thenbeginSetLength(Buffer, Round((Length(Text) / 2) + 0.1));FillChar(Buffer[0], Length(Buffer), 0);for i := 0 to Length(Buffer) dobeginiIndex := (i * 2) + 1;if (iIndex <= Length(Text)) thenWordRec(Buffer[i]).Hi := Ord(Text[iIndex]);if ((iIndex + 1) <= Length(Text)) thenWordRec(Buffer[i]).Lo := Ord(Text[iIndex + 1]);end;Result := WriteRegisters(RegNo, Buffer);endelseResult := False;
end;function TIdModBusClient.WriteRegister(const RegNo, Value: Word): Boolean;
varData: array[0..0] of Word;bNewConnection: Boolean;
beginbNewConnection := False;Data[0] := Value;if FAutoConnect and not Connected thenbegin{$IFDEF DMB_INDY10}Connect;{$ELSE}Connect(FConnectTimeOut);{$ENDIF}bNewConnection := True;end;tryResult := SendCommand(mbfWriteOneReg, RegNo, 0, Data);finallyif bNewConnection thenDisConnect;end;
end;function TIdModBusClient.WriteRegisters(const RegNo: Word;const RegisterData: array of Word): Boolean;
vari: Integer;iBlockLength: Integer;Data: array of Word;bNewConnection: Boolean;
beginbNewConnection := False;iBlockLength := High(RegisterData) - Low(RegisterData) + 1;if FAutoConnect and not Connected thenbegin{$IFDEF DMB_INDY10}Connect;{$ELSE}Connect(FConnectTimeOut);{$ENDIF}bNewConnection := True;end;trySetLength(Data, Length(RegisterData));for i := Low(RegisterData) to High(RegisterData) doData[i] := RegisterData[i];Result := SendCommand(mbfWriteRegs, RegNo, iBlockLength, Data);finallyif bNewConnection thenDisConnect;end;
end;function TIdModBusClient.WriteCoil(const RegNo: Word; const Value: Boolean): Boolean;
varData: array[0..0] of Word;bNewConnection: Boolean;
beginbNewConnection := False;if Value thenData[0] := 1elseData[0] := 0;if FAutoConnect and not Connected thenbegin{$IFDEF DMB_INDY10}Connect;{$ELSE}Connect(FConnectTimeOut);{$ENDIF}bNewConnection := True;end;tryResult := SendCommand(mbfWriteOneCoil, RegNo, 0, Data);finallyif bNewConnection thenDisConnect;end;
end;function TIdModBusClient.WriteCoils(const RegNo, Blocks: Word; const RegisterData: array of Boolean): Boolean;
vari: Integer;iBlockLength: Integer;Data: array of Word;bNewConnection: Boolean;
beginbNewConnection := False;iBlockLength := High(RegisterData) - Low(RegisterData) + 1;if FAutoConnect and not Connected thenbegin{$IFDEF DMB_INDY10}Connect;{$ELSE}Connect(FConnectTimeOut);{$ENDIF}bNewConnection := True;end;trySetLength(Data, Length(RegisterData));for i := Low(RegisterData) to High(RegisterData) dobeginif RegisterData[i] thenData[i] := 1elseData[i] := 0;end;Result := SendCommand(mbfWriteCoils, RegNo, iBlockLength, Data);finallyif bNewConnection thenDisConnect;end;
end;end.
五、IdModBusServer.pas
{$I ModBusCompiler.inc}unit IdModBusServer;interfaceusesClasses,SysUtils
{$IFDEF DMB_INDY10},IdContext,IdCustomTCPServer,IdGlobal
{$ELSE},IdTCPClient,IdTCPServer
{$ENDIF},ModBusConsts,ModbusTypes,ModbusUtils,SyncObjs;typeTModRegisterData = array[0..MaxBlockLength] of Word;typeTModCoilData = array[0..MaxCoils] of ByteBool;{$IFDEF DMB_INDY10}
typeTModBusCoilReadEvent = procedure(const Sender: TIdContext;const RegNr, Count: Integer; var Data: TModCoilData;const RequestBuffer: TModBusRequestBuffer; var ErrorCode: Byte) of object;TModBusRegisterReadEvent = procedure(const Sender: TIdContext;const RegNr, Count: Integer; var Data: TModRegisterData;const RequestBuffer: TModBusRequestBuffer; var ErrorCode: Byte) of object;TModBusCoilWriteEvent = procedure(const Sender: TIdContext;const RegNr, Count: Integer; const Data: TModCoilData;const RequestBuffer: TModBusRequestBuffer; var ErrorCode: Byte) of object;TModBusRegisterWriteEvent = procedure(const Sender: TIdContext;const RegNr, Count: Integer; const Data: TModRegisterData;const RequestBuffer: TModBusRequestBuffer; var ErrorCode: Byte) of object;TModBusErrorEvent = procedure(const Sender: TIdContext;const FunctionCode: Byte; const ErrorCode: Byte;const RequestBuffer: TModBusRequestBuffer) of object;TModBusInvalidFunctionEvent = procedure(const Sender: TIdContext;const FunctionCode: TModBusFunction;const RequestBuffer: TModBusRequestBuffer) of object;
{$ELSE}
typeTModBusCoilReadEvent = procedure(const Sender: TIdPeerThread;const RegNr, Count: Integer; var Data: TModCoilData;const RequestBuffer: TModBusRequestBuffer; var ErrorCode: Byte) of object;TModBusRegisterReadEvent = procedure(const Sender: TIdPeerThread;const RegNr, Count: Integer; var Data: TModRegisterData;const RequestBuffer: TModBusRequestBuffer; var ErrorCode: Byte) of object;TModBusCoilWriteEvent = procedure(const Sender: TIdPeerThread;const RegNr, Count: Integer; const Data: TModCoilData;const RequestBuffer: TModBusRequestBuffer; var ErrorCode: Byte) of object;TModBusRegisterWriteEvent = procedure(const Sender: TIdPeerThread;const RegNr, Count: Integer; const Data: TModRegisterData;const RequestBuffer: TModBusRequestBuffer; var ErrorCode: Byte) of object;TModBusErrorEvent = procedure(const Sender: TIdPeerThread;const FunctionCode: Byte; const ErrorCode: Byte;const RequestBuffer: TModBusRequestBuffer) of object;TModBusInvalidFunctionEvent = procedure(const Sender: TIdPeerThread;const FunctionCode: TModBusFunction;const RequestBuffer: TModBusRequestBuffer) of object;
{$ENDIF}type
{$I ModBusPlatforms.inc}
{$IFDEF DMB_INDY10}TIdModBusServer = class(TIdCustomTCPServer)
{$ELSE}TIdModBusServer = class(TIdTCPServer)
{$ENDIF}privateFBaseRegister: Word;FOneShotConnection: Boolean;FLogCriticalSection: TCriticalSection;FLogEnabled: Boolean;FLogFile: String;FLogTimeFormat: String;FMaxRegister: Word;FMinRegister: Word;FOnError: TModBusErrorEvent;FOnInvalidFunction: TModBusInvalidFunctionEvent;FOnReadCoils: TModBusCoilReadEvent;FOnReadHoldingRegisters: TModBusRegisterReadEvent;FOnReadInputBits: TModBusCoilReadEvent;FOnReadInputRegisters: TModBusRegisterReadEvent;FOnWriteCoils: TModBusCoilWriteEvent;FOnWriteRegisters: TModBusRegisterWriteEvent;FPause: Boolean;FUnitID: Byte;function GetVersion: String;procedure SetVersion(const Value: String);function IsLogTimeFormatStored: Boolean;procedure LogByteBuffer(const LogType: String; const PeerIP: String; const ByteBuffer: array of Byte; const Size: Integer);{$IFDEF DMB_INDY10}procedure InternalReadCoils(const AContext: TIdContext; const RegNr, Count: Integer;var Data: TModRegisterData; const RequestBuffer: TModBusRequestBuffer; var ErrorCode: Byte);procedure InternalReadInputBits(const AContext: TIdContext; const RegNr, Count: Integer;var Data: TModRegisterData; const RequestBuffer: TModBusRequestBuffer; var ErrorCode: Byte);procedure InternalWriteCoils(const AContext: TIdContext; const RegNr, Count: Integer;const Data: TModRegisterData; const RequestBuffer: TModBusRequestBuffer; var ErrorCode: Byte);{$ELSE}procedure InternalReadCoils(const Sender: TIdPeerThread; const RegNr, Count: Integer;var Data: TModRegisterData; const RequestBuffer: TModBusRequestBuffer; var ErrorCode: Byte);procedure InternalReadInputBits(const Sender: TIdPeerThread; const RegNr, Count: Integer;var Data: TModRegisterData; const RequestBuffer: TModBusRequestBuffer; var ErrorCode: Byte);procedure InternalWriteCoils(const Sender: TIdPeerThread; const RegNr, Count: Integer;const Data: TModRegisterData; const RequestBuffer: TModBusRequestBuffer; var ErrorCode: Byte);{$ENDIF}protected{$IFDEF DMB_INDY10}procedure InitComponent; override;{$ENDIF}{$IFDEF DMB_INDY10}procedure DoError(const AContext: TIdContext; const FunctionCode: Byte;const ErrorCode: Byte; const RequestBuffer: TModBusRequestBuffer); virtual;function DoExecute(AContext: TIdContext): Boolean; override;procedure DoInvalidFunction(const AContext: TIdContext;const FunctionCode: TModBusFunction; const RequestBuffer: TModBusRequestBuffer); virtual;procedure DoReadHoldingRegisters(const AContext: TIdContext; const RegNr, Count: Integer;var Data: TModRegisterData; const RequestBuffer: TModBusRequestBuffer; var ErrorCode: Byte); virtual;procedure DoReadInputRegisters(const AContext: TIdContext; const RegNr, Count: Integer;var Data: TModRegisterData; const RequestBuffer: TModBusRequestBuffer; var ErrorCode: Byte); virtual;procedure DoReadCoils(const AContext: TIdContext; const RegNr, Count: Integer;var Data: TModCoilData; const RequestBuffer: TModBusRequestBuffer; var ErrorCode: Byte); virtual;procedure DoReadInputBits(const AContext: TIdContext; const RegNr, Count: Integer;var Data: TModCoilData; const RequestBuffer: TModBusRequestBuffer; var ErrorCode: Byte); virtual;procedure DoWriteCoils(const AContext: TIdContext; const RegNr, Count: Integer;const Data: TModCoilData; const RequestBuffer: TModBusRequestBuffer; var ErrorCode: Byte); virtual;procedure DoWriteRegisters(const AContext: TIdContext; const RegNr, Count: Integer;const Data: TModRegisterData; const RequestBuffer: TModBusRequestBuffer; var ErrorCode: Byte); virtual;procedure LogExceptionBuffer(const AContext: TIdContext; const Buffer: TModBusExceptionBuffer);procedure LogRequestBuffer(const AContext: TIdContext; const Buffer: TModBusRequestBuffer; const Size: Integer);procedure LogResponseBuffer(const AContext: TIdContext; const Buffer: TModBusResponseBuffer; const Size: Integer);procedure ReadCommand(const AContext: TIdContext);procedure SendError(const AContext: TIdContext; const ErrorCode: Byte;const ReceiveBuffer: TModBusRequestBuffer);procedure SendResponse(const AContext: TIdContext; const ReceiveBuffer: TModBusRequestBuffer;const Data: TModRegisterData);{$ELSE}procedure DoError(const Sender: TIdPeerThread; const FunctionCode: Byte;const ErrorCode: Byte; const RequestBuffer: TModBusRequestBuffer); virtual;function DoExecute(AThread: TIdPeerThread): Boolean; override;procedure DoInvalidFunction(const Sender: TIdPeerThread; const FunctionCode: TModBusFunction;const RequestBuffer: TModBusRequestBuffer); virtual;procedure DoReadHoldingRegisters(const Sender: TIdPeerThread; const RegNr, Count: Integer;var Data: TModRegisterData; const RequestBuffer: TModBusRequestBuffer; var ErrorCode: Byte); virtual;procedure DoReadInputRegisters(const Sender: TIdPeerThread; const RegNr, Count: Integer;var Data: TModRegisterData; const RequestBuffer: TModBusRequestBuffer; var ErrorCode: Byte); virtual;procedure DoReadCoils(const Sender: TIdPeerThread; const RegNr, Count: Integer;var Data: TModCoilData; const RequestBuffer: TModBusRequestBuffer; var ErrorCode: Byte); virtual;procedure DoReadInputBits(const Sender: TIdPeerThread; const RegNr, Count: Integer;var Data: TModCoilData; const RequestBuffer: TModBusRequestBuffer; var ErrorCode: Byte); virtual;procedure DoWriteCoils(const Sender: TIdPeerThread; const RegNr, Count: Integer;const Data: TModCoilData; const RequestBuffer: TModBusRequestBuffer; var ErrorCode: Byte); virtual;procedure DoWriteRegisters(const Sender: TIdPeerThread; const RegNr, Count: Integer;const Data: TModRegisterData; const RequestBuffer: TModBusRequestBuffer; var ErrorCode: Byte); virtual;procedure LogExceptionBuffer(const AThread: TIdPeerThread; const Buffer: TModBusExceptionBuffer);procedure LogRequestBuffer(const AThread: TIdPeerThread; const Buffer: TModBusRequestBuffer; const Size: Integer);procedure LogResponseBuffer(const AThread: TIdPeerThread; const Buffer: TModBusResponseBuffer; const Size: Integer);procedure ReadCommand(const AThread: TIdPeerThread);procedure SendError(const AThread: TIdPeerThread; const ErrorCode: Byte;const ReceiveBuffer: TModBusRequestBuffer);procedure SendResponse(const AThread: TIdPeerThread; const ReceiveBuffer: TModBusRequestBuffer;const Data: TModRegisterData);{$ENDIF}public{$IFNDEF DMB_INDY10}constructor Create(AOwner: TComponent); override;{$ENDIF}destructor Destroy(); override;{ public properties }property Pause: Boolean read FPause write FPause;publishedproperty BaseRegister: Word read FBaseRegister write FBaseRegister default 1; property DefaultPort default MB_PORT;property LogEnabled: Boolean read FLogEnabled write FLogEnabled default False;property LogFile: String read FLogFile write FLogFile;property LogTimeFormat: String read FLogTimeFormat write FLogTimeFormat stored IsLogTimeFormatStored;property OneShotConnection: Boolean read FOneShotConnection write FOneShotConnection default False;property MaxRegister: Word read FMaxRegister write FMaxRegister default $FFFF;property MinRegister: Word read FMinRegister write FMinRegister default 1;property UnitID: Byte read FUnitID write FUnitID default MB_IGNORE_UNITID;property Version: String read GetVersion write SetVersion stored False;{ events }property OnError: TModBusErrorEvent read FOnError write FOnError;property OnInvalidFunction: TModBusInvalidFunctionEvent read FOnInvalidFunction write FOnInvalidFunction;property OnReadCoils: TModBusCoilReadEvent read FOnReadCoils write FOnReadCoils;property OnReadHoldingRegisters: TModBusRegisterReadEvent read FOnReadHoldingRegisters write FOnReadHoldingRegisters;property OnReadInputBits: TModBusCoilReadEvent read FOnReadInputBits write FOnReadInputBits;property OnReadInputRegisters: TModBusRegisterReadEvent read FOnReadInputRegisters write FOnReadInputRegisters;property OnWriteCoils: TModBusCoilWriteEvent read FOnWriteCoils write FOnWriteCoils;property OnWriteRegisters: TModBusRegisterWriteEvent read FOnWriteRegisters write FOnWriteRegisters;end; { TIdModBusServer }implementationusesMath;{ TIdModBusServer }{$IFDEF DMB_INDY10}
procedure TIdModBusServer.InitComponent;
{$ELSE}
constructor TIdModBusServer.Create(AOwner: TComponent);
{$ENDIF}
begin
{$IFDEF DMB_INDY10}inherited;
{$ELSE}inherited Create(AOwner);
{$ENDIF}FBaseRegister := 1;DefaultPort := MB_PORT;FLogCriticalSection := SyncObjs.TCriticalSection.Create;FLogEnabled := False;FLogFile := '';FLogTimeFormat := DefaultLogTimeFormat;FMaxRegister := $FFFF;FMinRegister := 1;FOneShotConnection := False;FOnError := nil;FOnInvalidFunction := nil;FOnReadCoils := nil;FOnReadHoldingRegisters := nil;FOnReadInputBits := nil;FOnReadInputRegisters := nil;FOnWriteCoils := nil;FOnWriteRegisters := nil;FPause := False;FUnitID := MB_IGNORE_UNITID;
end;destructor TIdModBusServer.Destroy();
begininherited;// freed AFTER inherited destructor because this will first stop the serverFLogCriticalSection.Free();
end;procedure TIdModBusServer.LogByteBuffer(const LogType: String;const PeerIP: String; const ByteBuffer: array of Byte; const Size: Integer);
varF: TextFile;
beginif FLogEnabled and (FLogFile <> '') thenbeginFLogCriticalSection.Enter;tryAssignFile(F, FLogFile);if FileExists(FLogFile) thenAppend(F)elseRewrite(F);tryWriteLn(F, FormatDateTime(FLogTimeFormat, Now),'; ', LogType,'; ', PeerIP,'; ', IntToStr(Size),'; ', BufferToHex(ByteBuffer));finallyCloseFile(F);end;finallyFLogCriticalSection.Leave;end;end;
end;{$IFDEF DMB_INDY10}
procedure TIdModBusServer.InternalReadCoils(const AContext: TIdContext;const RegNr, Count: Integer; var Data: TModRegisterData;const RequestBuffer: TModBusRequestBuffer; var ErrorCode: Byte);
{$ELSE}
procedure TIdModBusServer.InternalReadCoils(const Sender: TIdPeerThread;const RegNr, Count: Integer; var Data: TModRegisterData;const RequestBuffer: TModBusRequestBuffer; var ErrorCode: Byte);
{$ENDIF}
varCoilData: TModCoilData;i: Integer;
beginFillChar(CoilData, SizeOf(CoilData), 0);
{$IFDEF DMB_INDY10}DoReadCoils(AContext, RegNr, Count, CoilData, RequestBuffer, ErrorCode);
{$ELSE}DoReadCoils(Sender, RegNr, Count, CoilData, RequestBuffer, ErrorCode);
{$ENDIF}for i := 0 to (Count - 1) dobeginif CoilData[i] thenData[i] := 1;end;
end;{$IFDEF DMB_INDY10}
procedure TIdModBusServer.InternalReadInputBits(const AContext: TIdContext;const RegNr, Count: Integer; var Data: TModRegisterData;const RequestBuffer: TModBusRequestBuffer; var ErrorCode: Byte);
{$ELSE}
procedure TIdModBusServer.InternalReadInputBits(const Sender: TIdPeerThread;const RegNr, Count: Integer; var Data: TModRegisterData;const RequestBuffer: TModBusRequestBuffer; var ErrorCode: Byte);
{$ENDIF}
varCoilData: TModCoilData;i: Integer;
beginFillChar(CoilData, SizeOf(CoilData), 0);
{$IFDEF DMB_INDY10}DoReadInputBits(AContext, RegNr, Count, CoilData, RequestBuffer, ErrorCode);
{$ELSE}DoReadInputBits(Sender, RegNr, Count, CoilData, RequestBuffer, ErrorCode);
{$ENDIF}for i := 0 to (Count - 1) dobeginif CoilData[i] thenData[i] := 1;end;end;{$IFDEF DMB_INDY10}
procedure TIdModBusServer.InternalWriteCoils(const AContext: TIdContext;const RegNr, Count: Integer; const Data: TModRegisterData;const RequestBuffer: TModBusRequestBuffer; var ErrorCode: Byte);
{$ELSE}
procedure TIdModBusServer.InternalWriteCoils(const Sender: TIdPeerThread;const RegNr, Count: Integer; const Data: TModRegisterData;const RequestBuffer: TModBusRequestBuffer; var ErrorCode: Byte);
{$ENDIF}
varCoilData: TModCoilData;i: Integer;
beginFillChar(CoilData, SizeOf(CoilData), 0);for i := 0 to (Count - 1) doCoilData[i] := (Data[i] = 1);
{$IFDEF DMB_INDY10}DoWriteCoils(AContext, RegNr, Count, CoilData, RequestBuffer, ErrorCode);
{$ELSE}DoWriteCoils(Sender, RegNr, Count, CoilData, RequestBuffer, ErrorCode);
{$ENDIF}
end;{$IFDEF DMB_INDY10}
procedure TIdModBusServer.LogExceptionBuffer(const AContext: TIdContext;const Buffer: TModBusExceptionBuffer);
{$ELSE}
procedure TIdModBusServer.LogExceptionBuffer(const AThread: TIdPeerThread;const Buffer: TModBusExceptionBuffer);
{$ENDIF}
varPeerIP: String;ByteBuffer: array of Byte;
begin
{$IFDEF DMB_INDY10}PeerIP := AContext.Connection.Socket.Binding.PeerIP;
{$ELSE}PeerIP := AThread.Connection.Socket.Binding.PeerIP;
{$ENDIF}SetLength(ByteBuffer, SizeOf(Buffer));Move(Buffer, ByteBuffer[0], SizeOf(Buffer));LogByteBuffer('excp', PeerIP, ByteBuffer, SizeOf(Buffer));
end;{$IFDEF DMB_INDY10}
procedure TIdModBusServer.LogRequestBuffer(const AContext: TIdContext;const Buffer: TModBusRequestBuffer; const Size: Integer);
{$ELSE}
procedure TIdModBusServer.LogRequestBuffer(const AThread: TIdPeerThread;const Buffer: TModBusRequestBuffer; const Size: Integer);
{$ENDIF}
varPeerIP: String;ByteBuffer: array of Byte;
begin
{$IFDEF DMB_INDY10}PeerIP := AContext.Connection.Socket.Binding.PeerIP;
{$ELSE}PeerIP := AThread.Connection.Socket.Binding.PeerIP;
{$ENDIF}SetLength(ByteBuffer, SizeOf(Buffer));Move(Buffer, ByteBuffer[0], SizeOf(Buffer));LogByteBuffer('recv', PeerIP, ByteBuffer, Size);
end;{$IFDEF DMB_INDY10}
procedure TIdModBusServer.LogResponseBuffer(const AContext: TIdContext;const Buffer: TModBusResponseBuffer; const Size: Integer);
{$ELSE}
procedure TIdModBusServer.LogResponseBuffer(const AThread: TIdPeerThread;const Buffer: TModBusResponseBuffer; const Size: Integer);
{$ENDIF}
varPeerIP: String;ByteBuffer: array of Byte;
begin
{$IFDEF DMB_INDY10}PeerIP := AContext.Connection.Socket.Binding.PeerIP;
{$ELSE}PeerIP := AThread.Connection.Socket.Binding.PeerIP;
{$ENDIF}SetLength(ByteBuffer, SizeOf(Buffer));Move(Buffer, ByteBuffer[0], SizeOf(Buffer));LogByteBuffer('sent', PeerIP, ByteBuffer, Size);
end;{$IFDEF DMB_INDY10}
procedure TIdModBusServer.ReadCommand(const AContext: TIdContext);
{$ELSE}
procedure TIdModBusServer.ReadCommand(const AThread: TIdPeerThread);
{$ENDIF}function GetRegNr(const RegNr: Integer): Integer;beginResult := RegNr;if (RegNr < 0) thenResult := Result + $FFFFelse if (RegNr > $FFFF) thenResult := RegNr - ($FFFF + 1);Result := Result + FBaseRegister;end; { GetRegNr }variCount: Integer;iRegNr: Integer;ErrorCode: Byte;ReceiveBuffer: TModBusRequestBuffer;Data: TModRegisterData;
{$IFDEF DMB_INDY10}Buffer: TIdBytes;
{$ENDIF}
begin
{ Initialize all register data to 0 }FillChar(Data[0], SizeOf(Data), 0);FillChar(ReceiveBuffer, SizeOf(ReceiveBuffer), 0);
{ Read the data from the peer connection }
{$IFDEF DMB_INDY10}
{ Ensure receiving databuffer is completely empty, and filled with zeros }SetLength(Buffer, SizeOf(ReceiveBuffer));FillChar(Buffer[0], SizeOf(ReceiveBuffer), 0);
{ Wait max. 250 msecs. for available data }AContext.Connection.IOHandler.CheckForDataOnSource(250);if not AContext.Connection.IOHandler.InputBufferIsEmpty thenbeginAContext.Connection.IOHandler.InputBuffer.ExtractToBytes(Buffer, -1, False, -1);iCount := Length(Buffer);if (iCount > 0) thenbeginMove(Buffer[0], ReceiveBuffer, Min(iCount, SizeOf(ReceiveBuffer)));if FLogEnabled thenLogRequestBuffer(AContext, ReceiveBuffer, iCount);endelseExit;endelseExit;
{$ELSE}iCount := AThread.Connection.Socket.Recv(ReceiveBuffer, SizeOf(ReceiveBuffer));if (iCount > 0) thenbeginif FLogEnabled thenLogRequestBuffer(AThread, ReceiveBuffer, iCount);endelseExit;
{$ENDIF}
{ Process the data }if ((FUnitID <> MB_IGNORE_UNITID) and (ReceiveBuffer.Header.UnitID <> FUnitID)) or(ReceiveBuffer.Header.ProtocolID <> MB_PROTOCOL)thenbegin// When listening for a specific UnitID, only except data for that ID{$IFDEF DMB_INDY10}SendError(AContext, mbeServerFailure, ReceiveBuffer);{$ELSE}SendError(AThread, mbeServerFailure, ReceiveBuffer);{$ENDIF}endelse if ((Byte(ReceiveBuffer.FunctionCode) and $80) <> 0) thenbeginErrorCode := Integer(ReceiveBuffer.MBPData[0]);{$IFDEF DMB_INDY10}DoError(AContext, ReceiveBuffer.FunctionCode and not $80, ErrorCode, ReceiveBuffer);{$ELSE}DoError(AThread, ReceiveBuffer.FunctionCode and not $80, ErrorCode, ReceiveBuffer);{$ENDIF}endelsebeginErrorCode := mbeOk;case ReceiveBuffer.FunctionCode ofmbfReadCoils,mbfReadInputBits:beginiRegNr := GetRegNr(Swap16(Word((@ReceiveBuffer.MBPData[0])^)));iCount := Swap16(Word((@ReceiveBuffer.MBPData[2])^));if ((iRegNr < FMinRegister) or ((iRegNr + iCount - 1) > FMaxRegister)) then{$IFDEF DMB_INDY10}SendError(AContext, mbeIllegalRegister, ReceiveBuffer){$ELSE}SendError(AThread, mbeIllegalRegister, ReceiveBuffer){$ENDIF}elsebegin{ Signal the user that data is needed }{$IFDEF DMB_INDY10}if (ReceiveBuffer.FunctionCode = mbfReadCoils) thenInternalReadCoils(AContext, iRegNr, iCount, Data, ReceiveBuffer, ErrorCode)elseInternalReadInputBits(AContext, iRegNr, iCount, Data, ReceiveBuffer, ErrorCode);if (ErrorCode = mbeOk) thenSendResponse(AContext, ReceiveBuffer, Data)elseSendError(AContext, ErrorCode, ReceiveBuffer);{$ELSE}if (ReceiveBuffer.FunctionCode = mbfReadCoils) thenInternalReadCoils(AThread, iRegNr, iCount, Data, ReceiveBuffer, ErrorCode)elseInternalReadInputBits(AThread, iRegNr, iCount, Data, ReceiveBuffer, ErrorCode);if (ErrorCode = mbeOk) thenSendResponse(AThread, ReceiveBuffer, Data)elseSendError(AThread, ErrorCode, ReceiveBuffer);{$ENDIF}end;end;mbfReadInputRegs,mbfReadHoldingRegs:beginiRegNr := GetRegNr(Swap16(Word((@ReceiveBuffer.MBPData[0])^)));iCount := Swap16(Word((@ReceiveBuffer.MBPData[2])^));if ((iRegNr < FMinRegister) or ((iRegNr + iCount - 1) > FMaxRegister)) then{$IFDEF DMB_INDY10}SendError(AContext, mbeIllegalRegister, ReceiveBuffer){$ELSE}SendError(AThread, mbeIllegalRegister, ReceiveBuffer){$ENDIF}elsebegin{ Signal the user that data is needed }{$IFDEF DMB_INDY10}if (ReceiveBuffer.FunctionCode = mbfReadInputRegs) thenDoReadInputRegisters(AContext, iRegNr, iCount, Data, ReceiveBuffer, ErrorCode)elseDoReadHoldingRegisters(AContext, iRegNr, iCount, Data, ReceiveBuffer, ErrorCode);if (ErrorCode = mbeOk) thenSendResponse(AContext, ReceiveBuffer, Data)elseSendError(AContext, ErrorCode, ReceiveBuffer);{$ELSE}if (ReceiveBuffer.FunctionCode = mbfReadInputRegs) thenDoReadInputRegisters(AThread, iRegNr, iCount, Data, ReceiveBuffer, ErrorCode)elseDoReadHoldingRegisters(AThread, iRegNr, iCount, Data, ReceiveBuffer, ErrorCode);if (ErrorCode = mbeOk) thenSendResponse(AThread, ReceiveBuffer, Data)elseSendError(AThread, ErrorCode, ReceiveBuffer);{$ENDIF}end;end;mbfWriteOneCoil:beginiRegNr := GetRegNr(Swap16(Word((@ReceiveBuffer.MBPData[0])^)));iCount := 1;if ((iRegNr < FMinRegister) or ((iRegNr + iCount - 1) > FMaxRegister)) then{$IFDEF DMB_INDY10}SendError(AContext, mbeIllegalRegister, ReceiveBuffer){$ELSE}SendError(AThread, mbeIllegalRegister, ReceiveBuffer){$ENDIF}elsebegin{ Decode the contents of the Registers }GetCoilsFromBuffer(@ReceiveBuffer.MBPData[2], iCount, Data);{ Send back the response to the master }{$IFDEF DMB_INDY10}InternalWriteCoils(AContext, iRegNr, iCount, Data, ReceiveBuffer, ErrorCode);if (ErrorCode = mbeOk) thenSendResponse(AContext, ReceiveBuffer, Data)elseSendError(AContext, ErrorCode, ReceiveBuffer);{$ELSE}InternalWriteCoils(AThread, iRegNr, iCount, Data, ReceiveBuffer, ErrorCode);if (ErrorCode = mbeOk) thenSendResponse(AThread, ReceiveBuffer, Data)elseSendError(AThread, ErrorCode, ReceiveBuffer);{$ENDIF}end;end;mbfWriteOneReg:begin{ Get the register number }iRegNr := GetRegNr(Swap16(Word((@ReceiveBuffer.MBPData[0])^)));{ Get the register value }Data[0] := Swap16(Word((@ReceiveBuffer.MBPData[2])^));{ This function always writes one register }iCount := 1;if ((iRegNr < FMinRegister) or ((iRegNr + iCount - 1) > FMaxRegister)) then{$IFDEF DMB_INDY10}SendError(AContext, mbeIllegalRegister, ReceiveBuffer){$ELSE}SendError(AThread, mbeIllegalRegister, ReceiveBuffer){$ENDIF}elsebegin{ Send back the response to the master }{$IFDEF DMB_INDY10}DoWriteRegisters(AContext, iRegNr, iCount, Data, ReceiveBuffer, ErrorCode);if (ErrorCode = mbeOk) thenSendResponse(AContext, ReceiveBuffer, Data)elseSendError(AContext, ErrorCode, ReceiveBuffer);{$ELSE}DoWriteRegisters(AThread, iRegNr, iCount, Data, ReceiveBuffer, ErrorCode);if (ErrorCode = mbeOk) thenSendResponse(AThread, ReceiveBuffer, Data)elseSendError(AThread, ErrorCode, ReceiveBuffer);{$ENDIF}end;end;mbfWriteRegs:beginiRegNr := GetRegNr(Swap16(Word((@ReceiveBuffer.MBPData[0])^)));iCount := Swap16(Word((@ReceiveBuffer.MBPData[2])^));if ((iRegNr < FMinRegister) or ((iRegNr + iCount - 1) > FMaxRegister)) then{$IFDEF DMB_INDY10}SendError(AContext, mbeIllegalRegister, ReceiveBuffer){$ELSE}SendError(AThread, mbeIllegalRegister, ReceiveBuffer){$ENDIF}elsebegin{ Decode the contents of the Registers }GetRegistersFromBuffer(@ReceiveBuffer.MbpData[5], iCount, Data);{ Send back the response to the master }{$IFDEF DMB_INDY10}DoWriteRegisters(AContext, iRegNr, iCount, Data, ReceiveBuffer, ErrorCode);if (ErrorCode = mbeOk) thenSendResponse(AContext, ReceiveBuffer, Data)elseSendError(AContext, ErrorCode, ReceiveBuffer);{$ELSE}DoWriteRegisters(AThread, iRegNr, iCount, Data, ReceiveBuffer, ErrorCode);if (ErrorCode = mbeOk) thenSendResponse(AThread, ReceiveBuffer, Data)elseSendError(AThread, ErrorCode, ReceiveBuffer);{$ENDIF}end;end;mbfWriteCoils:beginiRegNr := GetRegNr(Swap16(Word((@ReceiveBuffer.MBPData[0])^)));iCount := Swap16(Word((@ReceiveBuffer.MBPData[2])^));if ((iRegNr < FMinRegister) or ((iRegNr + iCount - 1) > FMaxRegister)) then{$IFDEF DMB_INDY10}SendError(AContext, mbeIllegalRegister, ReceiveBuffer){$ELSE}SendError(AThread, mbeIllegalRegister, ReceiveBuffer){$ENDIF}elsebegin{ Decode the contents of the Registers }GetCoilsFromBuffer(@ReceiveBuffer.MbpData[5], iCount, Data);{ Send back the response to the master }{$IFDEF DMB_INDY10}InternalWriteCoils(AContext, iRegNr, iCount, Data, ReceiveBuffer, ErrorCode);if (ErrorCode = mbeOk) thenSendResponse(AContext, ReceiveBuffer, Data)elseSendError(AContext, ErrorCode, ReceiveBuffer);{$ELSE}InternalWriteCoils(AThread, iRegNr, iCount, Data, ReceiveBuffer, ErrorCode);if (ErrorCode = mbeOk) thenSendResponse(AThread, ReceiveBuffer, Data)elseSendError(AThread, ErrorCode, ReceiveBuffer);{$ENDIF}end;end;elseif (ReceiveBuffer.FunctionCode <> 0) thenbegin{ Illegal or unsupported function code }{$IFDEF DMB_INDY10}SendError(AContext, mbeIllegalFunction, ReceiveBuffer);DoInvalidFunction(AContext, ReceiveBuffer.FunctionCode, ReceiveBuffer);{$ELSE}SendError(AThread, mbeIllegalFunction, ReceiveBuffer);DoInvalidFunction(AThread, ReceiveBuffer.FunctionCode, ReceiveBuffer);{$ENDIF}end;end;end;
{ If needed: the server terminates the connection, after the request has been handled }if FOneShotConnection then{$IFDEF DMB_INDY10}AContext.Connection.Disconnect;{$ELSE}AThread.Connection.Disconnect;{$ENDIF}
end;{$IFDEF DMB_INDY10}
procedure TIdModBusServer.DoError(const AContext: TIdContext;const FunctionCode: Byte; const ErrorCode: Byte; const RequestBuffer: TModBusRequestBuffer);
{$ELSE}
procedure TIdModBusServer.DoError(const Sender: TIdPeerThread;const FunctionCode: Byte; const ErrorCode: Byte; const RequestBuffer: TModBusRequestBuffer);
{$ENDIF}
beginif Assigned(FOnError) then{$IFDEF DMB_INDY10}FOnError(AContext, FunctionCode, ErrorCode, RequestBuffer);{$ELSE}FOnError(Sender, FunctionCode, ErrorCode, RequestBuffer);{$ENDIF}
end;{$IFDEF DMB_INDY10}
function TIdModBusServer.DoExecute(AContext: TIdContext): Boolean;
{$ELSE}
function TIdModBusServer.DoExecute(AThread: TIdPeerThread): Boolean;
{$ENDIF}
beginResult := False;if not FPause thenbegin{$IFDEF DMB_INDY10}ReadCommand(AContext);Result := inherited DoExecute(AContext);{$ELSE}ReadCommand(AThread);Result := inherited DoExecute(AThread);{$ENDIF}end;
end;{$IFDEF DMB_INDY10}
procedure TIdModBusServer.DoInvalidFunction(const AContext: TIdContext;const FunctionCode: TModBusFunction; const RequestBuffer: TModBusRequestBuffer);
{$ELSE}
procedure TIdModBusServer.DoInvalidFunction(const Sender: TIdPeerThread;const FunctionCode: TModBusFunction; const RequestBuffer: TModBusRequestBuffer);
{$ENDIF}
beginif Assigned(FOnInvalidFunction) then{$IFDEF DMB_INDY10}FOnInvalidFunction(AContext, FunctionCode, RequestBuffer);{$ELSE}FOnInvalidFunction(Sender, FunctionCode, RequestBuffer);{$ENDIF}
end;{$IFDEF DMB_INDY10}
procedure TIdModBusServer.DoReadCoils(const AContext: TIdContext;const RegNr, Count: Integer; var Data: TModCoilData;const RequestBuffer: TModBusRequestBuffer; var ErrorCode: Byte);
{$ELSE}
procedure TIdModBusServer.DoReadCoils(const Sender: TIdPeerThread;const RegNr, Count: Integer; var Data: TModCoilData;const RequestBuffer: TModBusRequestBuffer; var ErrorCode: Byte);
{$ENDIF}
beginif Assigned(FOnReadCoils) then{$IFDEF DMB_INDY10}FOnReadCoils(AContext, RegNr, Count, Data, RequestBuffer, ErrorCode);{$ELSE}FOnReadCoils(Sender, RegNr, Count, Data, RequestBuffer, ErrorCode);{$ENDIF}
end;{$IFDEF DMB_INDY10}
procedure TIdModBusServer.DoReadInputBits(const AContext: TIdContext;const RegNr, Count: Integer; var Data: TModCoilData;const RequestBuffer: TModBusRequestBuffer; var ErrorCode: Byte);
{$ELSE}
procedure TIdModBusServer.DoReadInputBits(const Sender: TIdPeerThread;const RegNr, Count: Integer; var Data: TModCoilData;const RequestBuffer: TModBusRequestBuffer; var ErrorCode: Byte);
{$ENDIF}
beginif Assigned(FOnReadInputBits) then{$IFDEF DMB_INDY10}FOnReadInputBits(AContext, RegNr, Count, Data, RequestBuffer, ErrorCode);{$ELSE}FOnReadInputBits(Sender, RegNr, Count, Data, RequestBuffer, ErrorCode);{$ENDIF}
end;{$IFDEF DMB_INDY10}
procedure TIdModBusServer.DoReadHoldingRegisters(const AContext: TIdContext;const RegNr, Count: Integer; var Data: TModRegisterData;const RequestBuffer: TModBusRequestBuffer; var ErrorCode: Byte);
{$ELSE}
procedure TIdModBusServer.DoReadHoldingRegisters(const Sender: TIdPeerThread;const RegNr, Count: Integer; var Data: TModRegisterData;const RequestBuffer: TModBusRequestBuffer; var ErrorCode: Byte);
{$ENDIF}
beginif Assigned(FOnReadHoldingRegisters) then{$IFDEF DMB_INDY10}FOnReadHoldingRegisters(AContext, RegNr, Count, Data, RequestBuffer, ErrorCode);{$ELSE}FOnReadHoldingRegisters(Sender, RegNr, Count, Data, RequestBuffer, ErrorCode);{$ENDIF}
end;{$IFDEF DMB_INDY10}
procedure TIdModBusServer.DoReadInputRegisters(const AContext: TIdContext;const RegNr, Count: Integer; var Data: TModRegisterData;const RequestBuffer: TModBusRequestBuffer; var ErrorCode: Byte);
{$ELSE}
procedure TIdModBusServer.DoReadInputRegisters(const Sender: TIdPeerThread;const RegNr, Count: Integer; var Data: TModRegisterData;const RequestBuffer: TModBusRequestBuffer; var ErrorCode: Byte);
{$ENDIF}
beginif Assigned(FOnReadInputRegisters) then{$IFDEF DMB_INDY10}FOnReadInputRegisters(AContext, RegNr, Count, Data, RequestBuffer, ErrorCode);{$ELSE}FOnReadInputRegisters(Sender, RegNr, Count, Data, RequestBuffer, ErrorCode);{$ENDIF}
end;{$IFDEF DMB_INDY10}
procedure TIdModBusServer.DoWriteCoils(const AContext: TIdContext;const RegNr, Count: Integer; const Data: TModCoilData;const RequestBuffer: TModBusRequestBuffer; var ErrorCode: Byte);
{$ELSE}
procedure TIdModBusServer.DoWriteCoils(const Sender: TIdPeerThread;const RegNr, Count: Integer; const Data: TModCoilData;const RequestBuffer: TModBusRequestBuffer; var ErrorCode: Byte);
{$ENDIF}
beginif Assigned(FOnWriteCoils) then{$IFDEF DMB_INDY10}FOnWriteCoils(AContext, RegNr, Count, Data, RequestBuffer, ErrorCode);{$ELSE}FOnWriteCoils(Sender, RegNr, Count, Data, RequestBuffer, ErrorCode);{$ENDIF}
end;{$IFDEF DMB_INDY10}
procedure TIdModBusServer.DoWriteRegisters(const AContext: TIdContext;const RegNr, Count: Integer; const Data: TModRegisterData;const RequestBuffer: TModBusRequestBuffer; var ErrorCode: Byte);
{$ELSE}
procedure TIdModBusServer.DoWriteRegisters(const Sender: TIdPeerThread;
const RegNr, Count: Integer; const Data: TModRegisterData;
const RequestBuffer: TModBusRequestBuffer; var ErrorCode: Byte);
{$ENDIF}
beginif Assigned(FOnWriteRegisters) then{$IFDEF DMB_INDY10}FOnWriteRegisters(AContext, RegNr, Count, Data, RequestBuffer, ErrorCode);{$ELSE}FOnWriteRegisters(Sender, RegNr, Count, Data, RequestBuffer, ErrorCode);{$ENDIF}
end;{$IFDEF DMB_INDY10}
procedure TIdModBusServer.SendError(const AContext: TIdContext;const ErrorCode: Byte; const ReceiveBuffer: TModBusRequestBuffer);
{$ELSE}
procedure TIdModBusServer.SendError(const AThread: TIdPeerThread;const ErrorCode: Byte; const ReceiveBuffer: TModBusRequestBuffer);
{$ENDIF}
varSendBuffer: TModBusExceptionBuffer;
{$IFDEF DMB_INDY10}Buffer: TIdBytes;
{$ENDIF}
beginif Active thenbeginSendBuffer.Header := ReceiveBuffer.Header;SendBuffer.ExceptionFunction := ReceiveBuffer.FunctionCode or $80;SendBuffer.ExceptionCode := ErrorCode;SendBuffer.Header.RecLength := Swap16(3);{$IFDEF DMB_INDY10}Buffer := RawToBytes(SendBuffer, SizeOf(SendBuffer));AContext.Connection.Socket.WriteDirect(Buffer);if FLogEnabled thenLogExceptionBuffer(AContext, SendBuffer);{$ELSE}AThread.Connection.Socket.Send(SendBuffer, SizeOf(SendBuffer));if FLogEnabled thenLogExceptionBuffer(AThread, SendBuffer);{$ENDIF}end;
end;{$IFDEF DMB_INDY10}
procedure TIdModBusServer.SendResponse(const AContext: TIdContext;const ReceiveBuffer: TModBusRequestBuffer; const Data: TModRegisterData);
{$ELSE}
procedure TIdModBusServer.SendResponse(const AThread: TIdPeerThread;const ReceiveBuffer: TModBusRequestBuffer; const Data: TModRegisterData);
{$ENDIF}
varSendBuffer: TModBusResponseBuffer;L: Integer;ValidRequest : Boolean;
{$IFDEF DMB_INDY10}Buffer: TIdBytes;
{$ENDIF}
beginif Active thenbegin{Check Valid }ValidRequest := false;FillChar(SendBuffer, SizeOf(SendBuffer), 0);SendBuffer.Header.TransactionID := ReceiveBuffer.Header.TransactionID;SendBuffer.Header.ProtocolID := ReceiveBuffer.Header.ProtocolID;SendBuffer.Header.UnitID := ReceiveBuffer.Header.UnitID;SendBuffer.FunctionCode := ReceiveBuffer.FunctionCode;SendBuffer.Header.RecLength := Swap16(0);case ReceiveBuffer.FunctionCode ofmbfReadCoils,mbfReadInputBits:beginL := Swap16(Word((@ReceiveBuffer.MBPData[2])^));if (L > 0) and (L <= MaxCoils) thenbeginSendBuffer.MBPData[0] := Byte((L + 7) div 8);PutCoilsIntoBuffer(@SendBuffer.MBPData[1], L, Data);SendBuffer.Header.RecLength := Swap16(3 + SendBuffer.MBPData[0]);ValidRequest := true;end;end;mbfReadInputRegs,mbfReadHoldingRegs:beginL := Swap16(Word((@ReceiveBuffer.MBPData[2])^));if (L > 0) and (L <= MaxBlockLength) thenbeginSendBuffer.MBPData[0] := Byte(L shl 1);PutRegistersIntoBuffer(@SendBuffer.MBPData[1], L, Data);SendBuffer.Header.RecLength := Swap16(3 + SendBuffer.MBPData[0]);ValidRequest := true;end;end;elsebeginSendBuffer.MBPData[0] := ReceiveBuffer.MBPData[0];SendBuffer.MBPData[1] := ReceiveBuffer.MBPData[1];SendBuffer.MBPData[2] := ReceiveBuffer.MBPData[2];SendBuffer.MBPData[3] := ReceiveBuffer.MBPData[3];SendBuffer.Header.RecLength := Swap16(6);ValidRequest := true;end;end;{Send buffer if Request is Valid}if ValidRequest thenbegin{$IFDEF DMB_INDY10}Buffer := RawToBytes(SendBuffer, Swap16(SendBuffer.Header.RecLength) + 6);AContext.Connection.Socket.WriteDirect(Buffer);if FLogEnabled thenLogResponseBuffer(AContext, SendBuffer, Swap16(SendBuffer.Header.RecLength) + 6);{$ELSE}AThread.Connection.Socket.Send(SendBuffer, Swap16(SendBuffer.Header.RecLength) + 6);if FLogEnabled thenLogResponseBuffer(AThread, SendBuffer, Swap16(SendBuffer.Header.RecLength) + 6);{$ENDIF}endelsebegin{Send error for invalid request}{$IFDEF DMB_INDY10}SendError(AContext, mbeServerFailure, ReceiveBuffer);{$ELSE}SendError(AThread, mbeServerFailure, ReceiveBuffer);{$ENDIF}exit;end;end;
end;function TIdModBusServer.GetVersion: String;
beginResult := DMB_VERSION;
end;function TIdModBusServer.IsLogTimeFormatStored: Boolean;
beginResult := (FLogTimeFormat <> DefaultLogTimeFormat);
end;procedure TIdModBusServer.SetVersion(const Value: String);
begin
{ This intentionally is a readonly property }
end;end.
六、ModBusCompiler.inc
{ Logic to detect the used Delphi compiler version: }
{$IFDEF VER120}{$DEFINE DMB_DELPHI1}{$DEFINE DMB_DELPHI2}{$DEFINE DMB_DELPHI3}{$DEFINE DMB_DELPHI4}{$DEFINE DMB_DELPHI4_ONLY}
{$ENDIF}
{$IFDEF VER130}{$DEFINE DMB_DELPHI1}{$DEFINE DMB_DELPHI2}{$DEFINE DMB_DELPHI3}{$DEFINE DMB_DELPHI4}{$DEFINE DMB_DELPHI5}{$DEFINE DMB_DELPHI5_ONLY}
{$ENDIF}
{$IFDEF VER140}{$DEFINE DMB_DELPHI1}{$DEFINE DMB_DELPHI2}{$DEFINE DMB_DELPHI3}{$DEFINE DMB_DELPHI4}{$DEFINE DMB_DELPHI5}{$DEFINE DMB_DELPHI6}{$DEFINE DMB_DELPHI6_ONLY}
{$ENDIF}
{$IFDEF VER150}{$DEFINE DMB_DELPHI1}{$DEFINE DMB_DELPHI2}{$DEFINE DMB_DELPHI3}{$DEFINE DMB_DELPHI4}{$DEFINE DMB_DELPHI5}{$DEFINE DMB_DELPHI6}{$DEFINE DMB_DELPHI7}{$DEFINE DMB_DELPHI7_ONLY}
{$ENDIF}
{$IFDEF VER170}{$DEFINE DMB_DELPHI1}{$DEFINE DMB_DELPHI2}{$DEFINE DMB_DELPHI3}{$DEFINE DMB_DELPHI4}{$DEFINE DMB_DELPHI5}{$DEFINE DMB_DELPHI6}{$DEFINE DMB_DELPHI7}{$DEFINE DMB_DELPHI2005}{$DEFINE DMB_DELPHI2005_ONLY}
{$ENDIF}
{$IFDEF VER180}{$DEFINE DMB_DELPHI1}{$DEFINE DMB_DELPHI2}{$DEFINE DMB_DELPHI3}{$DEFINE DMB_DELPHI4}{$DEFINE DMB_DELPHI5}{$DEFINE DMB_DELPHI6}{$DEFINE DMB_DELPHI7}{$DEFINE DMB_DELPHI2005}{$DEFINE DMB_DELPHI2006}{$IFNDEF VER185}{$DEFINE DMB_DELPHI2006_ONLY}{$ENDIF}
{$ENDIF}
{$IFDEF VER185}{$DEFINE DMB_DELPHI1}{$DEFINE DMB_DELPHI2}{$DEFINE DMB_DELPHI3}{$DEFINE DMB_DELPHI4}{$DEFINE DMB_DELPHI5}{$DEFINE DMB_DELPHI6}{$DEFINE DMB_DELPHI7}{$DEFINE DMB_DELPHI2005}{$DEFINE DMB_DELPHI2006}{$DEFINE DMB_DELPHI2007}{$DEFINE DMB_DELPHI2007_ONLY}
{$ENDIF}
{$IFDEF VER200}{$DEFINE DMB_DELPHI1}{$DEFINE DMB_DELPHI2}{$DEFINE DMB_DELPHI3}{$DEFINE DMB_DELPHI4}{$DEFINE DMB_DELPHI5}{$DEFINE DMB_DELPHI6}{$DEFINE DMB_DELPHI7}{$DEFINE DMB_DELPHI2005}{$DEFINE DMB_DELPHI2006}{$DEFINE DMB_DELPHI2007}{$DEFINE DMB_DELPHI2009}{$DEFINE DMB_DELPHI2009_ONLY}
{$ENDIF}
{$IFDEF VER210}{$DEFINE DMB_DELPHI1}{$DEFINE DMB_DELPHI2}{$DEFINE DMB_DELPHI3}{$DEFINE DMB_DELPHI4}{$DEFINE DMB_DELPHI5}{$DEFINE DMB_DELPHI6}{$DEFINE DMB_DELPHI7}{$DEFINE DMB_DELPHI2005}{$DEFINE DMB_DELPHI2006}{$DEFINE DMB_DELPHI2007}{$DEFINE DMB_DELPHI2009}{$DEFINE DMB_DELPHI2010}{$DEFINE DMB_DELPHI2010_ONLY}
{$ENDIF}
{$IFDEF VER220}{$DEFINE DMB_DELPHI1}{$DEFINE DMB_DELPHI2}{$DEFINE DMB_DELPHI3}{$DEFINE DMB_DELPHI4}{$DEFINE DMB_DELPHI5}{$DEFINE DMB_DELPHI6}{$DEFINE DMB_DELPHI7}{$DEFINE DMB_DELPHI2005}{$DEFINE DMB_DELPHI2006}{$DEFINE DMB_DELPHI2007}{$DEFINE DMB_DELPHI2009}{$DEFINE DMB_DELPHI2010}{$DEFINE DMB_DELPHIXE}{$DEFINE DMB_DELPHIXE_ONLY}
{$ENDIF}
{$IFDEF VER230}{$DEFINE DMB_DELPHI1}{$DEFINE DMB_DELPHI2}{$DEFINE DMB_DELPHI3}{$DEFINE DMB_DELPHI4}{$DEFINE DMB_DELPHI5}{$DEFINE DMB_DELPHI6}{$DEFINE DMB_DELPHI7}{$DEFINE DMB_DELPHI2005}{$DEFINE DMB_DELPHI2006}{$DEFINE DMB_DELPHI2007}{$DEFINE DMB_DELPHI2009}{$DEFINE DMB_DELPHI2010}{$DEFINE DMB_DELPHIXE}{$DEFINE DMB_DELPHIXE2}{$DEFINE DMB_DELPHIXE2_ONLY}
{$ENDIF}
{$IFDEF VER240}{$DEFINE DMB_DELPHI1}{$DEFINE DMB_DELPHI2}{$DEFINE DMB_DELPHI3}{$DEFINE DMB_DELPHI4}{$DEFINE DMB_DELPHI5}{$DEFINE DMB_DELPHI6}{$DEFINE DMB_DELPHI7}{$DEFINE DMB_DELPHI2005}{$DEFINE DMB_DELPHI2006}{$DEFINE DMB_DELPHI2007}{$DEFINE DMB_DELPHI2009}{$DEFINE DMB_DELPHI2010}{$DEFINE DMB_DELPHIXE}{$DEFINE DMB_DELPHIXE2}{$DEFINE DMB_DELPHIXE3}{$DEFINE DMB_DELPHIXE3_ONLY}
{$ENDIF}
{$IFDEF VER250}{$DEFINE DMB_DELPHI1}{$DEFINE DMB_DELPHI2}{$DEFINE DMB_DELPHI3}{$DEFINE DMB_DELPHI4}{$DEFINE DMB_DELPHI5}{$DEFINE DMB_DELPHI6}{$DEFINE DMB_DELPHI7}{$DEFINE DMB_DELPHI2005}{$DEFINE DMB_DELPHI2006}{$DEFINE DMB_DELPHI2007}{$DEFINE DMB_DELPHI2009}{$DEFINE DMB_DELPHI2010}{$DEFINE DMB_DELPHIXE}{$DEFINE DMB_DELPHIXE2}{$DEFINE DMB_DELPHIXE3}{$DEFINE DMB_DELPHIXE4}{$DEFINE DMB_DELPHIXE4_ONLY}
{$ENDIF}
{$IFDEF VER260}{$DEFINE DMB_DELPHI1}{$DEFINE DMB_DELPHI2}{$DEFINE DMB_DELPHI3}{$DEFINE DMB_DELPHI4}{$DEFINE DMB_DELPHI5}{$DEFINE DMB_DELPHI6}{$DEFINE DMB_DELPHI7}{$DEFINE DMB_DELPHI2005}{$DEFINE DMB_DELPHI2006}{$DEFINE DMB_DELPHI2007}{$DEFINE DMB_DELPHI2009}{$DEFINE DMB_DELPHI2010}{$DEFINE DMB_DELPHIXE}{$DEFINE DMB_DELPHIXE2}{$DEFINE DMB_DELPHIXE3}{$DEFINE DMB_DELPHIXE4}{$DEFINE DMB_DELPHIXE5}{$DEFINE DMB_DELPHIXE5_ONLY}
{$ENDIF}
{$IFDEF VER270}{$DEFINE DMB_DELPHI1}{$DEFINE DMB_DELPHI2}{$DEFINE DMB_DELPHI3}{$DEFINE DMB_DELPHI4}{$DEFINE DMB_DELPHI5}{$DEFINE DMB_DELPHI6}{$DEFINE DMB_DELPHI7}{$DEFINE DMB_DELPHI2005}{$DEFINE DMB_DELPHI2006}{$DEFINE DMB_DELPHI2007}{$DEFINE DMB_DELPHI2009}{$DEFINE DMB_DELPHI2010}{$DEFINE DMB_DELPHIXE}{$DEFINE DMB_DELPHIXE2}{$DEFINE DMB_DELPHIXE3}{$DEFINE DMB_DELPHIXE4}{$DEFINE DMB_DELPHIXE5}{$DEFINE DMB_DELPHIXE6}{$DEFINE DMB_DELPHIXE6_ONLY}
{$ENDIF}
{$IFDEF VER280}{$DEFINE DMB_DELPHI1}{$DEFINE DMB_DELPHI2}{$DEFINE DMB_DELPHI3}{$DEFINE DMB_DELPHI4}{$DEFINE DMB_DELPHI5}{$DEFINE DMB_DELPHI6}{$DEFINE DMB_DELPHI7}{$DEFINE DMB_DELPHI2005}{$DEFINE DMB_DELPHI2006}{$DEFINE DMB_DELPHI2007}{$DEFINE DMB_DELPHI2009}{$DEFINE DMB_DELPHI2010}{$DEFINE DMB_DELPHIXE}{$DEFINE DMB_DELPHIXE2}{$DEFINE DMB_DELPHIXE3}{$DEFINE DMB_DELPHIXE4}{$DEFINE DMB_DELPHIXE5}{$DEFINE DMB_DELPHIXE6}{$DEFINE DMB_DELPHIXE7}{$DEFINE DMB_DELPHIXE7_ONLY}
{$ENDIF}
{$IFDEF VER290}{$DEFINE DMB_DELPHI1}{$DEFINE DMB_DELPHI2}{$DEFINE DMB_DELPHI3}{$DEFINE DMB_DELPHI4}{$DEFINE DMB_DELPHI5}{$DEFINE DMB_DELPHI6}{$DEFINE DMB_DELPHI7}{$DEFINE DMB_DELPHI2005}{$DEFINE DMB_DELPHI2006}{$DEFINE DMB_DELPHI2007}{$DEFINE DMB_DELPHI2009}{$DEFINE DMB_DELPHI2010}{$DEFINE DMB_DELPHIXE}{$DEFINE DMB_DELPHIXE2}{$DEFINE DMB_DELPHIXE3}{$DEFINE DMB_DELPHIXE4}{$DEFINE DMB_DELPHIXE5}{$DEFINE DMB_DELPHIXE6}{$DEFINE DMB_DELPHIXE7}{$DEFINE DMB_DELPHIXE8}{$DEFINE DMB_DELPHIXE8_ONLY}
{$ENDIF}
{$IFDEF VER300}{$DEFINE DMB_DELPHI1}{$DEFINE DMB_DELPHI2}{$DEFINE DMB_DELPHI3}{$DEFINE DMB_DELPHI4}{$DEFINE DMB_DELPHI5}{$DEFINE DMB_DELPHI6}{$DEFINE DMB_DELPHI7}{$DEFINE DMB_DELPHI2005}{$DEFINE DMB_DELPHI2006}{$DEFINE DMB_DELPHI2007}{$DEFINE DMB_DELPHI2009}{$DEFINE DMB_DELPHI2010}{$DEFINE DMB_DELPHIXE}{$DEFINE DMB_DELPHIXE2}{$DEFINE DMB_DELPHIXE3}{$DEFINE DMB_DELPHIXE4}{$DEFINE DMB_DELPHIXE5}{$DEFINE DMB_DELPHIXE6}{$DEFINE DMB_DELPHIXE7}{$DEFINE DMB_DELPHIXE8}{$DEFINE DMB_DELPHI10_SEATTLE}{$DEFINE DMB_DELPHI10_SEATTLE_ONLY}
{$ENDIF}
{$IFDEF VER310}{$DEFINE DMB_DELPHI1}{$DEFINE DMB_DELPHI2}{$DEFINE DMB_DELPHI3}{$DEFINE DMB_DELPHI4}{$DEFINE DMB_DELPHI5}{$DEFINE DMB_DELPHI6}{$DEFINE DMB_DELPHI7}{$DEFINE DMB_DELPHI2005}{$DEFINE DMB_DELPHI2006}{$DEFINE DMB_DELPHI2007}{$DEFINE DMB_DELPHI2009}{$DEFINE DMB_DELPHI2010}{$DEFINE DMB_DELPHIXE}{$DEFINE DMB_DELPHIXE2}{$DEFINE DMB_DELPHIXE3}{$DEFINE DMB_DELPHIXE4}{$DEFINE DMB_DELPHIXE5}{$DEFINE DMB_DELPHIXE6}{$DEFINE DMB_DELPHIXE7}{$DEFINE DMB_DELPHIXE8}{$DEFINE DMB_DELPHI10_SEATTLE}{$DEFINE DMB_DELPHI10_1_BERLIN}{$DEFINE DMB_DELPHI10_1_BERLIN_ONLY}
{$ENDIF}{$IFDEF VER320}{$DEFINE DMB_DELPHI1}{$DEFINE DMB_DELPHI2}{$DEFINE DMB_DELPHI3}{$DEFINE DMB_DELPHI4}{$DEFINE DMB_DELPHI5}{$DEFINE DMB_DELPHI6}{$DEFINE DMB_DELPHI7}{$DEFINE DMB_DELPHI2005}{$DEFINE DMB_DELPHI2006}{$DEFINE DMB_DELPHI2007}{$DEFINE DMB_DELPHI2009}{$DEFINE DMB_DELPHI2010}{$DEFINE DMB_DELPHIXE}{$DEFINE DMB_DELPHIXE2}{$DEFINE DMB_DELPHIXE3}{$DEFINE DMB_DELPHIXE4}{$DEFINE DMB_DELPHIXE5}{$DEFINE DMB_DELPHIXE6}{$DEFINE DMB_DELPHIXE7}{$DEFINE DMB_DELPHIXE8}{$DEFINE DMB_DELPHI10_SEATTLE}{$DEFINE DMB_DELPHI10_1_BERLIN}{$DEFINE DMB_DELPHI10_2_TOKYO}{$DEFINE DMB_DELPHI10_2_TOKYO_ONLY}
{$ENDIF}{$IFDEF VER330}{$DEFINE DMB_DELPHI1}{$DEFINE DMB_DELPHI2}{$DEFINE DMB_DELPHI3}{$DEFINE DMB_DELPHI4}{$DEFINE DMB_DELPHI5}{$DEFINE DMB_DELPHI6}{$DEFINE DMB_DELPHI7}{$DEFINE DMB_DELPHI2005}{$DEFINE DMB_DELPHI2006}{$DEFINE DMB_DELPHI2007}{$DEFINE DMB_DELPHI2009}{$DEFINE DMB_DELPHI2010}{$DEFINE DMB_DELPHIXE}{$DEFINE DMB_DELPHIXE2}{$DEFINE DMB_DELPHIXE3}{$DEFINE DMB_DELPHIXE4}{$DEFINE DMB_DELPHIXE5}{$DEFINE DMB_DELPHIXE6}{$DEFINE DMB_DELPHIXE7}{$DEFINE DMB_DELPHIXE8}{$DEFINE DMB_DELPHI10_SEATTLE}{$DEFINE DMB_DELPHI10_1_BERLIN}{$DEFINE DMB_DELPHI10_2_TOKYO}{$DEFINE DMB_DELPHI10_3_RIO}{$DEFINE DMB_DELPHI10_3_RIO_ONLY}
{$ENDIF}{$IFDEF VER340}{$DEFINE DMB_DELPHI1}{$DEFINE DMB_DELPHI2}{$DEFINE DMB_DELPHI3}{$DEFINE DMB_DELPHI4}{$DEFINE DMB_DELPHI5}{$DEFINE DMB_DELPHI6}{$DEFINE DMB_DELPHI7}{$DEFINE DMB_DELPHI2005}{$DEFINE DMB_DELPHI2006}{$DEFINE DMB_DELPHI2007}{$DEFINE DMB_DELPHI2009}{$DEFINE DMB_DELPHI2010}{$DEFINE DMB_DELPHIXE}{$DEFINE DMB_DELPHIXE2}{$DEFINE DMB_DELPHIXE3}{$DEFINE DMB_DELPHIXE4}{$DEFINE DMB_DELPHIXE5}{$DEFINE DMB_DELPHIXE6}{$DEFINE DMB_DELPHIXE7}{$DEFINE DMB_DELPHIXE8}{$DEFINE DMB_DELPHI10_SEATTLE}{$DEFINE DMB_DELPHI10_1_BERLIN}{$DEFINE DMB_DELPHI10_2_TOKYO}{$DEFINE DMB_DELPHI10_3_RIO}{$DEFINE DMB_DELPHI10_4_SYDNEY}{$DEFINE DMB_DELPHI10_4_SYDNEY_ONLY}
{$ENDIF}{$IFDEF VER350}{$DEFINE DMB_DELPHI1}{$DEFINE DMB_DELPHI2}{$DEFINE DMB_DELPHI3}{$DEFINE DMB_DELPHI4}{$DEFINE DMB_DELPHI5}{$DEFINE DMB_DELPHI6}{$DEFINE DMB_DELPHI7}{$DEFINE DMB_DELPHI2005}{$DEFINE DMB_DELPHI2006}{$DEFINE DMB_DELPHI2007}{$DEFINE DMB_DELPHI2009}{$DEFINE DMB_DELPHI2010}{$DEFINE DMB_DELPHIXE}{$DEFINE DMB_DELPHIXE2}{$DEFINE DMB_DELPHIXE3}{$DEFINE DMB_DELPHIXE4}{$DEFINE DMB_DELPHIXE5}{$DEFINE DMB_DELPHIXE6}{$DEFINE DMB_DELPHIXE7}{$DEFINE DMB_DELPHIXE8}{$DEFINE DMB_DELPHI10_SEATTLE}{$DEFINE DMB_DELPHI10_1_BERLIN}{$DEFINE DMB_DELPHI10_2_TOKYO}{$DEFINE DMB_DELPHI10_3_RIO}{$DEFINE DMB_DELPHI10_4_SYDNEY}{$DEFINE DMB_DELPHI11_ALEXANDRIA}
{$ENDIF}{$IFDEF VER360}{$DEFINE DMB_DELPHI1}{$DEFINE DMB_DELPHI2}{$DEFINE DMB_DELPHI3}{$DEFINE DMB_DELPHI4}{$DEFINE DMB_DELPHI5}{$DEFINE DMB_DELPHI6}{$DEFINE DMB_DELPHI7}{$DEFINE DMB_DELPHI2005}{$DEFINE DMB_DELPHI2006}{$DEFINE DMB_DELPHI2007}{$DEFINE DMB_DELPHI2009}{$DEFINE DMB_DELPHI2010}{$DEFINE DMB_DELPHIXE}{$DEFINE DMB_DELPHIXE2}{$DEFINE DMB_DELPHIXE3}{$DEFINE DMB_DELPHIXE4}{$DEFINE DMB_DELPHIXE5}{$DEFINE DMB_DELPHIXE6}{$DEFINE DMB_DELPHIXE7}{$DEFINE DMB_DELPHIXE8}{$DEFINE DMB_DELPHI10_SEATTLE}{$DEFINE DMB_DELPHI10_1_BERLIN}{$DEFINE DMB_DELPHI10_2_TOKYO}{$DEFINE DMB_DELPHI10_3_RIO}{$DEFINE DMB_DELPHI10_4_SYDNEY}{$DEFINE DMB_DELPHI11_ALEXANDRIA}{$DEFINE DMB_DELPHI12_ATHENS}{$DEFINE DMB_DELPHI12_ATHENS_ONLY}
{$ENDIF}{$IFDEF DMB_DELPHI2005}
{ By default use Indy 10 starting from Delphi 2005 }{$DEFINE DMB_INDY10}
{$ELSE}
{ Older Delphi versions use Indy 9 }{$DEFINE DMB_INDY9}
{$ENDIF}{$IFDEF FPC}
{ Force the Free Pascal Compiler in Delphi mode, and use Indy 10 }{$MODE DELPHI}{$UNDEF DMB_INDY9}{$DEFINE DMB_INDY10}
{$ENDIF}{ Allow user defines to overrule the Indy version being used }
{$IFDEF FORCE_INDY9}{$UNDEF DMB_INDY10}{$DEFINE DMB_INDY9}
{$ELSE}{$IFDEF FORCE_INDY10}{$UNDEF DMB_INDY9}{$DEFINE DMB_INDY10}{$ENDIF}
{$ENDIF}
相关文章:
【Delphi】modbus-TCP 协议库
在日常开发中,也会遇到使用modbus的部件,比如温度控制器、读卡器等等,那么使用Delphi开发,也就必须遵守modbus-TCP协议,如果自己使用TCP控件写也没有问题,不过如果有开源的三方库,别人已经调试过…...
乐橙云小程序插件接入HbuilderX
乐橙插件使用: 1.配置app.json文件,uniapp中在mainfest.json中配置 https://uniapp.dcloud.net.cn/collocation/manifest.html#mp-weixin ** 2、集成插件页面.json文件 ** uniapp在 pages.json 对应页面的 style -> usingComponents 引入组件&…...
Python世界:复制粘贴?没那么简单!浅谈深拷贝与浅拷贝
Python世界:复制粘贴?没那么简单!浅谈深拷贝与浅拷贝 问题引入切片拷贝是深还是浅?深拷贝和浅拷贝到底有啥区别?本文小结 问题引入 Python实现中,最近遇到个小问题,对其中的拷贝理解更深了些&a…...
vue3实现el-table的拖拽
我这里使用的是 sortablejs 插件; 安装命令: npm install sortablejs --save 注意点: 你的表格数据中要有id作为key去使用; <div class"draggable"><el-table row-key"id" :data"form.tableData" style"width: 100%" max-…...
Apache SSI 远程命令执行漏洞
目录 1、漏洞描述 2、访问页面 3、dirsearch工具爆破出上传目录 编辑 4、登录后台 5、上传shell.shtml一句话木马文件 6、拿到flag 1、漏洞描述 在测试任意文件上传漏洞的时候,目标服务端可能不允许上传php后缀的文件。如果目标服务器开启了SSI与CGI支持&a…...
高效集成:将聚水潭数据导入MySQL的实战案例
聚水潭数据集成到MySQL:店铺信息查询案例分享 在数据驱动的业务环境中,如何高效、准确地实现跨平台的数据集成是每个企业面临的重要挑战。本文将聚焦于一个具体的系统对接集成案例——将聚水潭的店铺信息查询结果集成到MySQL数据库中,以供BI…...
Elasticsearch面试内容整理-面试注意事项
在准备 Elasticsearch 面试时,除了掌握技术知识外,还需要注意如何有效展示你的技能和经验。以下是一些 Elasticsearch 面试的注意事项和建议: 掌握基础概念 在面试中,面试官通常会首先评估你对 Elasticsearch 基础概念的理解,包括集群架构、分片、副本、节点类型等。这些是…...
学习threejs,使用specularMap设置高光贴图
👨⚕️ 主页: gis分享者 👨⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨⚕️ 收录于专栏:threejs gis工程师 文章目录 一、🍀前言1.1 ☘️THREE.MeshPhongMaterial高…...
Cannot resolve symbol ‘ActivityThread‘ | Android 语法
背景 ActivityThread 是 Android 系统内部使用的一个类,它位于 android.app 包中,但在 Android SDK 的公共 API 中并没有公开。 由于 ActivityThread 是隐藏的内部类,因此在编写单元测试或功能开发时,无法直接引用它。可以使用反射来访问内部 API,或者使用依赖注入的方式…...
Cypress内存溢出奔溃问题汇总
内存溢出报错信息 <--- Last few GCs ---> [196:0xe58001bc000] 683925 ms: Scavenge 1870.7 (1969.9) -> 1865.6 (1969.9) MB, 6.07 / 0.00 ms (average mu 0.359, current mu 0.444) task; [196:0xe58001bc000] 683999 ms: Scavenge 1872.4 (1969.9) -> 1867.1…...
debian 11 虚拟机环境搭建过坑记录
目录 安装过程系统配置修改 sudoers 文件网络配置换源安装桌面mount nfs 挂载安装复制功能tab 无法补全其他安装 软件配置eclipse 配置git 配置老虚拟机硬盘挂载 参考 原来去 debian 官网下载了一个最新的 debian 12,安装后出现包依赖问题,搞了半天&…...
【k8s深入学习之 event 记录】初步了解 k8s event 记录机制
event 事件记录初始化 一般在控制器都会有如下的初始化函数,初始化 event 记录器等参数 1. 创建 EventBroadcaster record.NewBroadcaster(): 创建事件广播器,用于记录和分发事件。StartLogging(klog.Infof): 将事件以日志的形式输出。StartRecording…...
InterHub:为自动驾驶提供密集互动事件的自然驾驶轨迹数据集
InterHub 是一个为自动驾驶领域设计的自然驾驶轨迹数据集,它通过深入挖掘自然驾驶记录中的密集互动事件而构建。 InterHub 的特点在于其形式化的方法,这使得数据集能够精确描述和提取多智能体之间的互动事件,揭示了现有自动驾驶解决方案的局限…...
鸿蒙Next星河版基础用例
目录: 1、鸿蒙箭头函数的写法2、鸿蒙数据类型的定义3、枚举的定义以及使用4、position绝对定位及层级zIndex5、字符串的拼接转换以及数据的处理(1)字符串转数字(2)数字转字符串(3)布尔值转换情况(4)数组的增删改查 6、三元表达式7、鸿蒙for循环的几种写法7.1、基本用…...
ScribblePrompt 医学图像分割工具,三种标注方式助力图像处理
ScribblePrompt 的主要目标是简化医学图像的分割过程,这在肿瘤检测、器官轮廓描绘等应用中至关重要。相比依赖大量人工标注数据,该工具允许用户通过少量输入(例如简单的涂鸦或点位)来引导模型优化分割结果。这种方式减少了医学专家…...
PKO-LSSVM-Adaboost班翠鸟优化最小二乘支持向量机结合AdaBoost分类模型
PKO-LSSVM-Adaboost班翠鸟优化最小二乘支持向量机结合AdaBoost分类模型 目录 PKO-LSSVM-Adaboost班翠鸟优化最小二乘支持向量机结合AdaBoost分类模型效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.PKO-LSSVM-Adaboost班翠鸟优化最小二乘支持向量机结合AdaBoost分类模…...
5G学习笔记之随机接入
目录 1. 概述 2. MSG1 2.1 选择SSB 2.2 选择Preamble Index 2.3 选择发送Preamble的时频资源 2.4 确定RA-RNTI 2.5 确定发送功率 3. MSG2 4. MSG3 5. MSG4 6. 其它 6.1 切换中的随机接入 6.2 SI请求的随机接入 6.3 通过PDCCH order重新建立同步 1. 概述 随机接入…...
爬虫专栏第二篇:Requests 库实战:从基础 GET 到 POST 登录全攻略
简介:本文聚焦 Requests 库的强大功能与应用实战。首先介绍其安装步骤及版本选择要点,随后深入讲解 GET 请求,以百度页面为例,展示如何发起基本 GET 请求、巧妙添加 headers 与参数以精准搜索,以及正确设置 encoding 避…...
Android Studio更改项目使用的JDK
一、吐槽 过去,在安卓项目中配置JDK和Gradle的过程非常直观,只需要进入Android Studio的File菜单中的Project Structure即可进行设置,十分方便。 原本可以在这修改JDK: 但大家都知道,Android Studio的狗屎性能,再加…...
鸿蒙技术分享:Navigation页面管理-鸿蒙@fw/router框架源码解析(二)
本文是系列文章,其他文章见: 鸿蒙fw/router框架源码解析(一)-Router页面管理 鸿蒙fw/router框架源码解析(三)-Navigation页面容器封装 鸿蒙fw/router框架源码解析(四)-路由Hvigor插件…...
数据结构:树
树的基本定义: 树是一种数据结构,它是由n(n>1)个有限节点组成一个具有层次关系的集合。把它叫做 “树” 是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。它具有以下的特点: …...
矩阵sum,prod函数
s u m sum sum表示求和, p r o d prod prod表示求乘积 s u m sum sum函数 对于矩阵,可以对某一行或某一列求和,也可以对矩阵整体求和 s u m ( a , 1 ) sum(a,1) sum(a,1)计算每一列的和 s u m ( a , 2 ) sum(a,2) sum(a,2)计算每一行的和 计算矩阵整体…...
Cursor安装与使用,5分钟完成需求
Cursor简单介绍 Cursor是一款基于AI的代码编辑器,旨在帮助开发者更高效地编写和管理代码。它提供了智能代码补全、AI对话和跨文件编辑等创新功能。 一、安装下载 1、下载cursor:https://www.cursor.com/ 2、注册账号,直接拿自己的邮箱登录…...
嵌入式系统应用-LVGL的应用-平衡球游戏 part1
平衡球游戏 part1 1 平衡球游戏的界面设计2 界面设计2.1 背景设计2.2 球的设计2.3 移动球的坐标2.4 用鼠标移动这个球2.5 增加边框规则2.6 效果图 3 为小球增加增加动画效果3.1 增加移动效果代码3.2 具体效果图片 平衡球游戏 part2 第二部分文章在这里 1 平衡球游戏的界面设计…...
Vue基本语法
Options API 选项式/配置式api 需要在script中的export default一个对象对象中可以包含data、method、components等keydata是数据,数据必须是一个方法(如果是对象,会导致多组件的时候,数据互相影响,因为对象赋值后&…...
UIE与ERNIE-Layout:智能视频问答任务初探
内容来自百度飞桨ai社区UIE与ERNIE-Layout:智能视频问答任务初探: 如有侵权,请联系删除 1 环境准备 In [2] # 安装依赖库 !pip install paddlenlp --upgrade !pip install paddleocr --upgrade !pip install paddlespeech --upgrade In …...
Mac启动服务慢问题解决,InetAddress.getLocalHost().getHostAddress()慢问题。
项目启动5分钟,很明显有问题。像网上其他的提高jvm参数就不说了,应该不是这个问题,也就快一点。 首先找到自己的电脑名称(用命令行也行,只要能找到自己电脑名称就行,这里直接在共享里看)。 复制…...
Django 视图层
from django.shortcuts import render, HttpResponse, redirectfrom django.http import JsonResponse1. render: 渲染模板 def index(request):print(reverse(index))return render(request, "index.html")return render(request, index.html, context{name: lisi})…...
HickWall 详解
优质博文:IT-BLOG-CN 一、监控分类 【1】Tracing调用链: 【2】Logging日志: 【3】Metrics指标:在应用发布之后,会长时间存在的度量维度。某个接口的请求量、响应时间。 Metrics数据模型 二、Metirc 接入 【1】pom…...
开源的跨平台SQL 编辑器Beekeeper Studio
一款开源的跨平台 SQL 编辑器,提供 SQL 语法高亮、自动补全、数据表内容筛选与过滤、连接 Web 数据库、存储历史查询记录等功能。该编辑器支持 SQLite、MySQL、MariaDB、Postgres 等主流数据库,并兼容 Windows、macOS、Linux 等桌面操作系统。 项目地址…...
Linux应用层学习——Day4(进程处理)
system #include<stdio.h> #include<stdlib.h>int main(int argc, char const *argv[]) {//使用标准库函数创建子进程//int system (const char *__command);//const char *__command:使用linux命令直接创建一个子进程//return:成功返回0 失败返回失败编号int sys…...
起别名typedef
#include<stdio.h> //typedef int myType1; //typedef char myType2; typedef struct { int a; int b; }po; int main() { /*myType1 a5; myType2 bo; printf("%d\n",a); printf("%c\n",b);*/ po p;//不需要加struct关键…...
【Linux内核】ashmem pin/unpin
前言 在 Linux 内核的 ASHMEM(Android Shared Memory)实现中,pin 和 unpin 操作主要用于管理共享内存的生命周期和可用性。这些操作有助于确保在内存使用期间,特定的共享内存区域不会被回收或释放。 Pin 操作 定义 Pin 操作用…...
【docker】docker网络六种网络模式
Docker 网络模式总结 网络模式描述使用场景bridge默认的网络模式,容器之间通过虚拟网桥通信,容器与宿主机隔离。单机部署、本地开发、小型项目host容器与宿主机共享网络堆栈,容器直接使用宿主机的 IP 地址。高性能网络应用、日志处理、大量与…...
永磁同步电机谐波抑制算法(11)——基于矢量比例积分调节器(vector PI controller,VPI controller)的谐波抑制策略
1.前言 相比于传统的谐振调节器,矢量比例积分调节器(vector PI controller,VPI controller)多一个可调零点,能够实现电机模型的零极点对消。因此VPI调节器也被广泛应用于交流控制/谐波抑制中。 2.参考文献 [1] A. G…...
排序算法中稳定性的意义和作用
多关键字排序:当需要对数据进行多个关键字排序时,稳定性变得非常重要。例如,先按次要关键字排序,再按主要关键字排序。如果排序算法是稳定的,那么在按主要关键字排序后,次要关键字的顺序将被保留。保持关联…...
网站怎么防御https攻击
HTTPS攻击,它不仅威胁到网站的数据安全,还可能影响用户隐私和业务稳定运行。 HTTPS攻击主要分为以下几种类型: 1.SSL劫持:攻击者通过中间人攻击手段,篡改HTTPS流量,从而实现对数据的窃取或伪造。 2.中间人攻…...
gitignore 不起作用
.gitignore不起作用 文件已提交至远程仓库,已经被Git跟踪。清除缓存.gitignore位置可能不是与 .git隐藏文件夹同级目录。将文件移至同级目录缓存未清除 清除缓存 清楚git缓存步骤 进入项目路径 清除本地当前的Git缓存 git rm -r --cached . 应用.gitignore等本地…...
Hive学习基本概念
基本概念 hive是什么? Facebook 开源,用于解决海量结构化日志的数据统计。 基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张表,并提供类SQL查询功能 本质是将HQL转化为MapReduce程序。 Hive处理的数据存储在H…...
在 Ubuntu 使用 fonts-noto-cjk 设置 Matplotlib 支持中文的完整教程
在 Ubuntu 使用 fonts-noto-cjk 设置 Matplotlib 支持中文的完整教程 1. 为什么需要配置中文字体?2. 安装 fonts-noto-cjk安装命令:检查字体安装是否成功 3. 配置 Matplotlib 支持中文3.1 手动加载字体3.2 设置全局字体(可选)修改…...
《C++ Primer Plus》学习笔记|第10章 对象和类 (24-12-2更新)
文章目录 10.3 类的构造函数和析构函数10.3.2 使用构造函数显式地调用构造函数隐式地调用构造函数使用对象指针 10.3.3默认构造函数10.3.4 析构函数析构函数示例 10.4 this指针三个const的作用 10.5 对象数组10.6 类作用域10.9 复习题1.什么是类?2.类如何实现抽象、…...
SpringMVC接收数据
一、访问路径设置: RequestMapping注解的作用就是将请求的URL地址和处理请求的方式(handler方法)关联起来,建立映射关系;SpringMVC接收到指定的请求,就会来找到在映射关系中对应的方法来处理这个请求 1.精准路径匹配: 在RequestMapping注解指定URL地址…...
Python数组拆分(array_split())
天行健,君子以自强不息;地势坤,君子以厚德载物。 每个人都有惰性,但不断学习是好好生活的根本,共勉! 文章均为学习整理笔记,分享记录为主,如有错误请指正,共同学习进步。…...
Git 使用总结
下载 git bash:http://git-scm.com/download/win 第一次使用 git 时,配置用户信息: git config --global user.email "your.emailexample.com" 从github仓库中下载项目到本地,修改后重新上传: git clone 项…...
NaviveUI框架的使用 ——安装与引入(图标安装与引入)
文章目录 概述安装直接引入引入图标样式库 概述 🍉Naive UI 是一个轻量、现代化且易于使用的 Vue 3 UI 组件库,它提供了一组简洁、易用且功能强大的组件,旨在为开发者提供更高效的开发体验,特别是对于构建现代化的 web 应用程序。…...
YOLOv11 NCNN安卓部署
YOLOv11 NCNN安卓部署 之前自己在验证更换relu激活函数重新训练部署模型的时候,在使用ncnn代码推理验证效果很好,但是部署到安卓上cpu模式会出现大量的错误检测框,现已更换会官方默认的权重 前言 YOLOv11 NCNN安卓部署 目前的帧率可以稳定…...
多线程安全单例模式的传统解决方案与现代方法
在多线程环境中实现安全的单例模式时,传统的双重检查锁(Double-Checked Locking)方案和新型的std::once_flag与std::call_once机制是两种常见的实现方法。它们在实现机制、安全性和性能上有所不同。 1. 传统的双重检查锁方案 双重检查锁&am…...
golang debug调试
1. 本地调试 1:Add Configurations 添加配置文件(Run kind :Directory) 2:进入run运行窗口 3:debug断点调试模式 1. Resume Program (继续运行) 图标: ▶️ 或 ► 快捷键: F9(Windows/Linux&a…...
安装 RabbitMQ 服务
安装 RabbitMQ 服务 一. RabbitMQ 需要依赖 Erlang/OTP 环境 (1) 先去 RabbitMQ 官网,查看 RabbitMQ 需要的 Erlang 支持:https://www.rabbitmq.com/ 进入官网,在 Docs -> Install and Upgrade -> Erlang Version Requirements (2) …...
pandas 大数据获取某列所有唯一值
目录 方法1: 方法2: 方法3 处理大数据: 方法1: data.groupby().groups.keys() import pandas as pd# 假设我们有以下的数据 data = {RTDR_name: [A, B, A, C, B, A],value: [1, 2, 3, 4, 5, 6] }# 创建 DataFrame temp_data = pd.DataFrame(data)# 获取 RTDR_name 列的…...