mirror of
https://github.com/netdata-be/libnodave
synced 2025-10-20 00:52:46 +08:00
1636 lines
62 KiB
ObjectPascal
Executable File
1636 lines
62 KiB
ObjectPascal
Executable File
// NoDaveComponent.pas
|
|
//
|
|
// A unit implementing a wrapper component for easy access to a S7-PLC with
|
|
// the libnodave.dll of Thomas Hergenhahn (http://libnodave.sourceforge.net)
|
|
//
|
|
// (C) 2005, 2006 Gebr. Schmid GmbH + Co., Freudenstadt, Germany
|
|
//
|
|
// Author: Axel Kinting (akinting@schmid-online.de)
|
|
//
|
|
// This library is free software; you can redistribute it and/or modify it
|
|
// under the terms of the GNU Lesser General Public License as published by
|
|
// the Free Software Foundation; either version 2.1 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This library is distributed in the hope that it will be useful, but
|
|
// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
// or FITNESS FOR A PARTICULAR PURPOSE.
|
|
// See the GNU Lesser General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Lesser General Public License
|
|
// along with this library; if not, write to the Free Software Foundation, Inc.,
|
|
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
{$IFDEF FPC}
|
|
{$MODE Delphi}
|
|
{$ENDIF}
|
|
|
|
unit NoDaveComponent;
|
|
|
|
//The Unit NoDaveComponent implements the class TNoDave, which encapsulates the access to the libnodave.dll.~[BR]
|
|
//With TNoDave and libnodave.dll it is very easy to read and write data from and to a S7 PLC.~[BR]~[BR]
|
|
//Simatic, Simatic S5, Simatic S7, S7-200, S7-300, S7-400 are registered Trademarks of Siemens Aktiengesellschaft, Berlin und Muenchen.
|
|
//~Author Axel Kinting - Gebr. Schmid GmbH + Co.
|
|
//~todo Before Installation:~[BR]
|
|
//Please copy the file \pascal\nodave.pas into the directory, where the file nodavecomponent.pas is located !~[BR]~[BR]
|
|
//Delphi-Installation:~[BR]
|
|
//1. Select Component - Install in the Delphi-menu~[BR]
|
|
//2. Select Add... button~[BR]
|
|
//3. Select Browse~[BR]
|
|
//4. Select NoDaveComponent.pas~[BR]
|
|
//5. Select OK~[BR]~[BR]
|
|
//Lazarus-Installation:~[BR]
|
|
//1. Select Components - Open package file~[BR]
|
|
//2. Select nodavepackage.lpk~[BR]
|
|
//3. Select Open~[BR]
|
|
//4. Select Compile~[BR]
|
|
//5. Select Install~[BR]
|
|
//6. Select Yes~[BR]
|
|
|
|
interface
|
|
|
|
uses
|
|
SysUtils, Classes, NoDave, SyncObjs, Controls, {$IFDEF FPC} LCLIntf, LResources {$ELSE} Windows {$ENDIF};
|
|
|
|
type
|
|
|
|
TNoDaveArea = ( //The area of the PLC-Data for the TNoDave-Component.
|
|
daveSysInfo, //System information of 200 family
|
|
daveSysFlags, //System flag area of 200 family
|
|
daveAnaIn, //Analog input words of 200 family
|
|
daveAnaOut, //Analog output words of 200 family
|
|
daveInputs, //Input memory image
|
|
daveOutputs, //Output memory image
|
|
daveFlags, //Flags/Markers
|
|
daveDB, //Data Blocks (global data)
|
|
daveDI, //Data Blocks (instance data) ?
|
|
daveLocal, //Data Blocks (local data) ?
|
|
daveV, //unknown Area
|
|
daveCounter, //Counter
|
|
daveTimer, //Timer
|
|
daveP //Peripherie Input/Output
|
|
);
|
|
|
|
TNoDaveDebugOption = ( //The debug-options for the libnodave.dll
|
|
daveDebugRawRead,
|
|
daveDebugSpecialChars,
|
|
daveDebugRawWrite,
|
|
daveDebugListReachables,
|
|
daveDebugInitAdapter,
|
|
daveDebugConnect,
|
|
daveDebugPacket,
|
|
daveDebugByte,
|
|
daveDebugCompare,
|
|
daveDebugExchange,
|
|
daveDebugPDU,
|
|
daveDebugUpload,
|
|
daveDebugMPI,
|
|
daveDebugPrintErrors,
|
|
daveDebugPassive
|
|
);
|
|
|
|
TNoDaveDebugOptions = Set of TNoDaveDebugOption;
|
|
|
|
TNoDaveProtocol = ( //The type of the communication-protocol for the TNoDave-Component.
|
|
daveProtoMPI, //MPI-Protocol
|
|
daveProtoMPI2, //MPI-Protocol (Andrew's version without STX)
|
|
daveProtoMPI3, //MPI-Protocol (Step 7 Version version)
|
|
daveProtoMPI4, //MPI-Protocol (Andrew's version with STX)
|
|
daveProtoPPI, //PPI-Protocol
|
|
daveProtoISOTCP, //ISO over TCP
|
|
daveProtoISOTCP243, //ISO over TCP (for CP243)
|
|
daveProtoIBH, //IBH-Link TCP/MPI-Adapter
|
|
daveProtoIBH_PPI, //IBH-Link TCP/MPI-Adapter with PPI-Protocol
|
|
daveProtoS7Online, //use S7Onlinx.dll for transport via Siemens CP
|
|
daveProtoAS511, //S5 via programmer-port
|
|
daveProtoNLPro //Deltalogic NetLink-PRO TCP/MPI-Adapter
|
|
);
|
|
|
|
TNoDaveSpeed = ( //The speed of the MPI-protocol for the TNoDave-Component.
|
|
daveSpeed9k,
|
|
daveSpeed19k,
|
|
daveSpeed187k,
|
|
daveSpeed500k,
|
|
daveSpeed1500k,
|
|
daveSpeed45k,
|
|
daveSpeed93k
|
|
);
|
|
|
|
TNoDaveComSpeed = ( //The speed of the COM-Port for the TNoDave-Component.
|
|
daveComSpeed9_6k,
|
|
daveComSpeed19_2k,
|
|
daveComSpeed38_4k,
|
|
daveComSpeed57_6k,
|
|
daveComSpeed115_2k
|
|
);
|
|
|
|
//This is the type of the Event-Handler for the OnError-Event of the TNoDave component.
|
|
//~param Sender The TNoDave-instance which is the source of the event.
|
|
//~param ErrorMsg A clear text message describing the error.
|
|
TNoDaveOnErrorEvent = procedure(Sender: TObject; ErrorMsg: String) of Object;
|
|
|
|
//List of reachable Partners in the MPI-Network, True = Station is available at this address.
|
|
TNoDaveReachablePartnersMPI = Array [0..126] of Boolean;
|
|
|
|
//The Class TNoDave encapsulates the access to the libnodave.dll of Thomas Hergenhahn.
|
|
//All the settings for the communication are available in the properties of TNoDave.
|
|
TNoDave = class(TComponent)
|
|
private
|
|
FActive: Boolean;
|
|
FArea: TNoDaveArea;
|
|
FBuffer: Pointer;
|
|
FBufLen: Integer;
|
|
FBufOffs: Integer;
|
|
FComPort: String;
|
|
FCpuRack: Integer;
|
|
FCpuSlot: Integer;
|
|
FCycleTime: Cardinal;
|
|
FDBNumber: Integer;
|
|
FDebugOptions: Integer;
|
|
FInterval: Cardinal;
|
|
FIntfName: String;
|
|
FIntfTimeout: Integer;
|
|
FIPAddress: String;
|
|
FIPPort: Integer;
|
|
FMPILocal: Integer;
|
|
FMPIRemote: Integer;
|
|
FMPISpeed: TNoDaveSpeed;
|
|
FLastError: Integer;
|
|
FOnConnect: TNotifyEvent;
|
|
FOnDisconnect: TNotifyEvent;
|
|
FOnError: TNoDaveOnErrorEvent;
|
|
FOnRead: TNotifyEvent;
|
|
FOnWrite: TNotifyEvent;
|
|
FProtocol: TNoDaveProtocol;
|
|
FSZLBuffer: Pointer;
|
|
FComSpeed: TNoDaveComSpeed;
|
|
FHandle: THandle;
|
|
function GetActive: Boolean;
|
|
function GetBuffer: String;
|
|
function GetDebugOptions: TNoDaveDebugOptions;
|
|
function GetLastErrMsg: String;
|
|
procedure SetActive(V: Boolean);
|
|
procedure SetArea(V: TNoDaveArea);
|
|
procedure SetBufLen(V: Integer);
|
|
procedure SetBufOffs(V: Integer);
|
|
procedure SetComPort(V: String);
|
|
procedure SetCpuRack(V: Integer);
|
|
procedure SetCpuSlot(V: Integer);
|
|
procedure SetDBNumber(V: Integer);
|
|
procedure SetDebugOptions(V: TNoDaveDebugOptions);
|
|
procedure SetInterval(V: Cardinal);
|
|
procedure SetIntfName(V: String);
|
|
procedure SetIntfTimeout(V: Integer);
|
|
procedure SetIPAddress(V: String);
|
|
procedure SetIPPort(V: Integer);
|
|
procedure SetMPILocal(V: Integer);
|
|
procedure SetMPIRemote(V: Integer);
|
|
procedure SetMPISpeed(V: TNoDaveSpeed);
|
|
procedure SetProtocol(V: TNoDaveProtocol);
|
|
function GetSZLCount: Integer;
|
|
function GetSZLItemSize: Integer;
|
|
function GetSZLItem(Index: Integer): Pointer;
|
|
function GetMaxPDUData: Integer;
|
|
procedure SetComSpeed(V: TNoDaveComSpeed);
|
|
function GetHandle: THandle;
|
|
protected
|
|
ConnectPending: Boolean;
|
|
DaveFDS: _daveOSSerialType;
|
|
DaveConn: PDaveConnection;
|
|
DaveIntf: PDaveInterface;
|
|
LockNoDave: TCriticalSection;
|
|
ReadThread: TThread;
|
|
procedure DoConnect(OnlyIntf: Boolean = False);
|
|
procedure DoOnConnect;
|
|
procedure DoOnDisconnect;
|
|
procedure DoOnError(ErrorMsg: String);
|
|
procedure DoOnRead;
|
|
procedure DoOnWrite;
|
|
procedure DoReadBytes(Area: TNoDaveArea; DB, Start, Size: Integer; Buffer: Pointer = Nil);
|
|
procedure DoWriteBytes(Area: TNoDaveArea; DB, Start, Size: Integer; Buffer: Pointer = Nil);
|
|
procedure DoWriteValue(Address, Size: Integer; Value: Pointer);
|
|
procedure Loaded; override;
|
|
procedure WriteBit(Area: TNoDaveArea; DB, Address, Bit: Integer; Value: Boolean); overload;
|
|
function AreaCode(Area: TNoDaveArea): Integer;
|
|
function ProtCode(Prot: TNoDaveProtocol): Integer;
|
|
function BufferAt(Address: Integer; Size: Integer = 1; Buffer: Pointer = Nil; BufOffs: Integer = 0; BufLen: Integer = 0): Pointer;
|
|
public
|
|
AreaID: Integer; //S7-ID of the selected ~[link .Area Area]
|
|
constructor Create(aOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
procedure Connect(Wait: Boolean = True);
|
|
procedure Disconnect;
|
|
procedure Lock;
|
|
procedure Unlock;
|
|
procedure ResetInterface;
|
|
procedure DoSetDebug(Options: Integer);
|
|
procedure ReadBytes(Buffer: Pointer = Nil); overload;
|
|
Procedure WriteBytes(Buffer: Pointer = Nil); overload;
|
|
procedure ReadBytes(Area: TNoDaveArea; DB, Start, Size: Integer; Buffer: Pointer = Nil); overload;
|
|
procedure WriteBytes(Area: TNoDaveArea; DB, Start, Size: Integer; Buffer: Pointer = Nil); overload;
|
|
procedure WriteBit(Address, Bit: Integer; Value: Boolean); overload;
|
|
procedure WriteByte(Address: Integer; Value: Byte);
|
|
procedure WriteWord(Address: Integer; Value: Word);
|
|
procedure WriteInt(Address: Integer; Value: SmallInt);
|
|
procedure WriteDWord(Address: Integer; Value: LongWord);
|
|
procedure WriteDInt(Address: Integer; Value: LongInt);
|
|
procedure WriteFloat(Address: Integer; Value: Single);
|
|
function GetBit(Address, Bit: Integer; Buffer: Pointer = Nil; BufOffs: Integer = 0; BufLen: Integer = 0): Boolean;
|
|
function GetByte(Address: Integer; Buffer: Pointer = Nil; BufOffs: Integer = 0; BufLen: Integer = 0): Byte;
|
|
function GetWord(Address: Integer; Buffer: Pointer = Nil; BufOffs: Integer = 0; BufLen: Integer = 0): Word;
|
|
function GetInt(Address: Integer; Buffer: Pointer = Nil; BufOffs: Integer = 0; BufLen: Integer = 0): SmallInt;
|
|
function GetDWord(Address: Integer; Buffer: Pointer = Nil; BufOffs: Integer = 0; BufLen: Integer = 0): LongWord;
|
|
function GetDInt(Address: Integer; Buffer: Pointer = Nil; BufOffs: Integer = 0; BufLen: Integer = 0): LongInt;
|
|
function GetFloat(Address: Integer; Buffer: Pointer = Nil; BufOffs: Integer = 0; BufLen: Integer = 0): Double;
|
|
function GetDBSize(DB: Integer): Integer;
|
|
function ListReachablePartners: TNoDaveReachablePartnersMPI;
|
|
function Swap16(Value: SmallInt): SmallInt;
|
|
function Swap32(Value: Integer): Integer;
|
|
function GetErrorMsg(Error: Integer): String;
|
|
function ReadSZL(ID, Index: Integer): Integer;
|
|
property SZLCount: Integer read GetSZLCount; //Property for the number of items in the internal SZL-Buffer
|
|
property SZLItem[Index: Integer]: Pointer read GetSZLItem; //Property for the items in the internal SZL-Buffer
|
|
property SZLItemSize: Integer read GetSZLItemSize; //Property for the size of one item in the internal SZL-Buffer
|
|
property MaxPDUData: Integer read GetMaxPDUData; //Property for the maximum datasize of one read-request
|
|
property Handle: THandle read GetHandle; //Property for the Windows-Handle used for system-calls
|
|
published
|
|
property Active: Boolean read GetActive write SetActive; //Property for the connection-status.
|
|
property Area: TNoDaveArea read FArea write SetArea; //Property for the PLC-area
|
|
property Buffer: String read GetBuffer; //Property for the pointer to the internal buffer memory.
|
|
property BufLen: Integer read FBufLen write SetBufLen; //Property for the length of the buffer.
|
|
property BufOffs: Integer read FBufOffs write SetBufOffs; //Property for the offset of the buffer within the address-range of the PLC.
|
|
property COMPort: String read FComPort write SetComPort; //Property for the name of the COM-Port used for the serial-to-MPI adapter.
|
|
property COMSpeed: TNoDaveComSpeed read FComSpeed write SetComSpeed; //Property for the speed of the COM-Port used for the serial-to-MPI adapter.
|
|
property CPURack: Integer read FCpuRack write SetCpuRack; //Property for the number of the rack containing the CPU of the PLC.
|
|
property CPUSlot: Integer read FCpuSlot write SetCpuSlot; //Property for the number of the slot containing the CPU of the PLC.
|
|
property CycleTime: Cardinal read FCycleTime; //Property for the duration in ms of the last communication cycle.
|
|
property DBNumber: Integer read FDBNumber write SetDBNumber; //Property for the number of the datablock in the PLC.
|
|
property DebugOptions: TNoDaveDebugOptions read GetDebugOptions write SetDebugOptions; //Property for the debug-options.
|
|
property Interval: Cardinal read FInterval write SetInterval; //Property for the minimal round-trip cycle time for the background-communication with the PLC in milliseconds.
|
|
property IntfName: String read FIntfName write SetIntfName; //Property for the symbolic name of the interface.
|
|
property IntfTimeout: Integer read FIntfTimeout write SetIntfTimeout; //Property for the timeout of the interface in milliseconds.
|
|
property IPAddress: String read FIPAddress write SetIPAddress; //Property for the IP-address or name of the TCP/IP partner station.
|
|
property IPPort: Integer read FIPPort write SetIPPort; //Property for the IP-port of the TCP/IP partner station.
|
|
property LastError: Integer read FLastError; //Property for the return-code of the last call of a communication-method.
|
|
property LastErrMsg: String read GetLastErrMsg; //Property for the text describing the code in ~[link .LastError LastError].
|
|
property MPILocal: Integer read FMPILocal write SetMPILocal; //Property for the local MPI-address used for the MPI-communication.
|
|
property MPIRemote: Integer read FMPIRemote write SetMPIRemote; //Property for the remote MPI-address used for the MPI-communication.
|
|
property MPISpeed: TNoDaveSpeed read FMPISpeed write SetMPISpeed; //Property for the MPI-speed used for the MPI-communication.
|
|
property OnConnect: TNotifyEvent read FOnConnect write FOnConnect; //Property for the OnConnect-eventhandler
|
|
property OnDisconnect: TNotifyEvent read FOnDisconnect write FOnDisconnect; //Property for the OnDisconnect-eventhandler
|
|
property OnError: TNoDaveOnErrorEvent read FOnError write FOnError; //Property for the OnError-eventhandler
|
|
property OnRead: TNotifyEvent read FOnRead write FOnRead; //Property for the OnRead-eventhandler
|
|
property OnWrite: TNotifyEvent read FOnWrite write FOnWrite; //Property for the OnWrite-eventhandler
|
|
property Protocol: TNoDaveProtocol read FProtocol write SetProtocol; //Property for the Protocol used for the communication with the PLC.
|
|
end;
|
|
|
|
|
|
TSzlLed = (NONE, SF, INTF, EXTF, RUN, STOP, FRCE, CRST, BAF, USR, USR1, BUS1F, BUS2F, REDF, MSTR, RACK0, RACK1, RACK2, IFM1F, IFM2F);
|
|
|
|
TSzlBGIdent = Record
|
|
Index: Word;
|
|
MlfB: packed Array[1..20] of Char;
|
|
BGTyp: Word;
|
|
AusBG: packed Array[1..4] of Byte;
|
|
end;
|
|
PSzlBGIdent = ^TSzlBGIdent;
|
|
|
|
TSzlUserMemory = Record
|
|
Index: Word;
|
|
Code: Word;
|
|
Size: LongWord;
|
|
Mode: Word;
|
|
Granu: Word;
|
|
Area1: LongWord;
|
|
Used1: LongWord;
|
|
Free1: LongWord;
|
|
Area2: LongWord;
|
|
Used2: LongWord;
|
|
Free2: LongWord;
|
|
end;
|
|
PSzlUserMemory = ^TSzlUserMemory;
|
|
|
|
TSzlSystemMemory = Record
|
|
Index: Word;
|
|
Code: Word;
|
|
Count: Word;
|
|
Reman: Word;
|
|
end;
|
|
PSzlSystemMemory = ^TSzlSystemMemory;
|
|
|
|
TSzlBlockType = Record
|
|
Index: Word;
|
|
Count: Word;
|
|
Size: Word;
|
|
MemSize: LongWord;
|
|
end;
|
|
PSzlBlockType = TSzlBlockType;
|
|
|
|
TSzlLedState = packed Record
|
|
Index: Word;
|
|
State: Byte;
|
|
Blink: Byte;
|
|
end;
|
|
PSzlLedState = ^TSzlLedState;
|
|
|
|
TSzlBGState = Record
|
|
Addr1: Word;
|
|
Addr2: Word;
|
|
LogAddr: Word;
|
|
ConfTyp: Word;
|
|
RealTyp: Word;
|
|
Count: Word;
|
|
EAStatus: Word;
|
|
Area: Word;
|
|
end;
|
|
PSzlBGState = ^TSzlBGState;
|
|
|
|
TSzlStationState = Record
|
|
Status: packed Array[0..15] of Byte;
|
|
end;
|
|
PSzlStationState = ^TSzlStationState;
|
|
|
|
TSzlDiagMessage = packed Record
|
|
ID: Word;
|
|
Info: Array[1..5] of Word;
|
|
Year: Byte;
|
|
Month: Byte;
|
|
Day: Byte;
|
|
Hour: Byte;
|
|
Minute: Byte;
|
|
Second: Byte;
|
|
MSec: Word;
|
|
end;
|
|
PSzlDiagMessage = ^TSzlDiagMessage;
|
|
|
|
TSzlBGDiagInfo = Record
|
|
Info: packed Array[1..4] of Byte;
|
|
end;
|
|
PSzlBGDiagInfo = ^TSzlBGDiagInfo;
|
|
|
|
|
|
procedure Register;
|
|
|
|
implementation
|
|
|
|
type
|
|
|
|
//Worker-thread for asynchronous connecting with the PLC.
|
|
TNoDaveConnectThread = class(TThread)
|
|
private
|
|
NoDave: TNoDave;
|
|
ErrMsg: String;
|
|
protected
|
|
procedure DoOnError;
|
|
procedure DoOnConnect;
|
|
procedure Execute; override;
|
|
public
|
|
constructor Create(Target: TNoDave);
|
|
end;
|
|
|
|
//Worker-thread for the background-communication with the PLC.
|
|
TNoDaveReadThread = class(TThread)
|
|
private
|
|
NoDave: TNoDave;
|
|
ErrMsg: String;
|
|
protected
|
|
procedure DoOnError;
|
|
procedure DoOnRead;
|
|
procedure Execute; override;
|
|
public
|
|
constructor Create(Target: TNoDave);
|
|
end;
|
|
|
|
//Installation of TNoDave in the component palette
|
|
procedure Register;
|
|
begin
|
|
RegisterComponents('System',[TNoDave]);
|
|
end;
|
|
|
|
{ TNoDaveConnectThread }
|
|
|
|
//Create the worker-thread for asynchronous connecting with the PLC.
|
|
//~param Target The TNoDave-instance to connect with the PLC.
|
|
constructor TNoDaveConnectThread.Create(Target: TNoDave);
|
|
begin
|
|
inherited Create(False);
|
|
NoDave:=Target;
|
|
FreeOnTerminate:=True;
|
|
end;
|
|
|
|
//Synchronization-method for calling the OnConnect-Event of the TNoDave-instance.
|
|
procedure TNoDaveConnectThread.DoOnConnect;
|
|
begin
|
|
NoDave.DoOnConnect;
|
|
end;
|
|
|
|
//Synchronization-method for calling the OnError-Event of the TNoDave-instance.
|
|
procedure TNoDaveConnectThread.DoOnError;
|
|
begin
|
|
NoDave.DoOnError(ErrMsg);
|
|
end;
|
|
|
|
//Open the connection to the PLC. If successfull then call the OnConnect-Event else call the OnError-Event of the TNoDave-instance.
|
|
procedure TNoDaveConnectThread.Execute;
|
|
begin
|
|
try
|
|
NoDave.DoConnect;
|
|
If NoDave.Active then Synchronize(DoOnConnect);
|
|
except
|
|
on E: Exception do
|
|
begin
|
|
ErrMsg:='Error in function TNoDaveConnectThread.Execute: ' + E.Message;
|
|
Synchronize(DoOnError);
|
|
end;
|
|
end;
|
|
NoDave.ConnectPending:=False;
|
|
end;
|
|
|
|
{ TNoDaveReadThread }
|
|
|
|
//Create the worker-thread for the background-communication with the PLC.
|
|
//~param Target The TNoDave-instance for the communication with the PLC.
|
|
constructor TNoDaveReadThread.Create(Target: TNoDave);
|
|
begin
|
|
inherited Create(False);
|
|
NoDave:=Target;
|
|
end;
|
|
|
|
//Synchronization-method for calling the OnError-Event of the TNoDave-instance.
|
|
procedure TNoDaveReadThread.DoOnError;
|
|
begin
|
|
NoDave.DoOnError(ErrMsg);
|
|
end;
|
|
|
|
//Synchronization-method for calling the OnRead-Event of the TNoDave-instance.
|
|
procedure TNoDaveReadThread.DoOnRead;
|
|
begin
|
|
NoDave.DoOnRead;
|
|
end;
|
|
|
|
//Read the data from the PLC, call the OnRead-Event of the TNoDave-instance, wait until the round-trip cycle time is reached and
|
|
//then start again from the beginning until the Connection of the TNoDave-instance is active. Disconnect the TNoDave-instance if
|
|
//the connection is not longer valid.
|
|
procedure TNoDaveReadThread.Execute;
|
|
var
|
|
StartTime: Cardinal;
|
|
NextTime: Cardinal;
|
|
begin
|
|
While NoDave.Active and (NoDave.Interval > 0) do
|
|
begin
|
|
StartTime:=GetTickCount;
|
|
NextTime:=StartTime + NoDave.Interval;
|
|
try
|
|
NoDave.ReadBytes;
|
|
If NoDave.LastError = 0 then Synchronize(DoOnRead) else
|
|
begin
|
|
If NoDave.LastError = -1 then NoDave.Disconnect else
|
|
begin
|
|
ErrMsg:=NoDave.LastErrMsg;
|
|
Synchronize(DoOnError);
|
|
end;
|
|
end;
|
|
except
|
|
on E: Exception do
|
|
begin
|
|
ErrMsg:='Error in function TNoDaveReadThread.Execute: ' + E.Message;
|
|
Synchronize(DoOnError);
|
|
end;
|
|
end;
|
|
While GetTickCount < NextTime do Sleep(1);
|
|
end;
|
|
end;
|
|
|
|
{ TNoDave }
|
|
|
|
//Initialize a new instance of the TNoDave component.
|
|
//~param aOwner Owner of the created instance.
|
|
constructor TNoDave.Create(aOwner: TComponent);
|
|
begin
|
|
inherited;
|
|
AreaID:=-1;
|
|
FActive:=False;
|
|
FArea:=daveDB;
|
|
FBuffer:=Nil;
|
|
FBufLen:=0;
|
|
FBufOffs:=0;
|
|
FComPort:='COM1:';
|
|
FComSpeed:=daveComSpeed38_4k;
|
|
FCpuRack:=0;
|
|
FCpuSlot:=2;
|
|
FDBNumber:=1;
|
|
FDebugOptions:=0;
|
|
FIntfName:='IF1';
|
|
FIntfTimeout:=1500000;
|
|
FIPAddress:='';
|
|
FIPPort:=102;
|
|
FMPILocal:=0;
|
|
FMPIRemote:=2;
|
|
FMPISpeed:=daveSpeed187k;
|
|
FLastError:=0;
|
|
FProtocol:=daveProtoMPI;
|
|
LockNoDave:=TCriticalSection.Create;
|
|
daveSetDebug(FDebugOptions);
|
|
end;
|
|
|
|
//Close an active connection and call the inherited Destroy method.
|
|
destructor TNoDave.Destroy;
|
|
begin
|
|
Disconnect;
|
|
If Assigned(FBuffer) then
|
|
try
|
|
FreeMem(FBuffer);
|
|
except
|
|
end;
|
|
If FHandle <> 0 then
|
|
try
|
|
DeallocateHWnd(FHandle);
|
|
except
|
|
end;
|
|
FHandle:=0;
|
|
LockNoDave.Free;
|
|
inherited;
|
|
end;
|
|
|
|
//Determine the S7-ID of an Area.
|
|
//~param Area Requested Area.
|
|
//~result S7-ID of the Area.
|
|
function TNoDave.AreaCode(Area: TNoDaveArea): Integer;
|
|
begin
|
|
Result:=AreaID;
|
|
If Result = -1 then
|
|
begin
|
|
Case Area of
|
|
daveSysInfo: Result:=3;
|
|
daveSysFlags: Result:=5;
|
|
daveAnaIn: Result:=6;
|
|
daveAnaOut: Result:=7;
|
|
daveCounter: Result:=28;
|
|
daveTimer: Result:=29;
|
|
daveP: Result:=128;
|
|
daveInputs: Result:=129;
|
|
daveOutputs: Result:=130;
|
|
daveFlags: Result:=131;
|
|
daveDB: Result:=132;
|
|
daveDI: Result:=133;
|
|
daveLocal: Result:=134;
|
|
daveV: Result:=135;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//Return a Pointer to the requested PLC-data point within the buffer.
|
|
//~param Address PLC-Address of the datapoint.
|
|
//~param Size Size of the datapoint in bytes.
|
|
//~param Buffer Pointer to the buffer holding the PLC-data. The internal buffer is used, if Nil (default).
|
|
//~param BufOffs Offset-address of the buffer within the address-range of the PLC.
|
|
//~param BufLen Length of the buffer in bytes.
|
|
//~result Pointer to the requested data point if the address is located in the buffer, else Nil.
|
|
function TNoDave.BufferAt(Address: Integer; Size: Integer; Buffer: Pointer; BufOffs: Integer; BufLen: Integer): Pointer;
|
|
var
|
|
Offset: Integer;
|
|
begin
|
|
Result:=Nil;
|
|
try
|
|
If Assigned(Buffer) then
|
|
begin
|
|
Offset:=Address - BufOffs;
|
|
If Offset + Size <= BufLen then Result:=Pointer(Integer(Buffer) + Offset);
|
|
end else begin
|
|
Offset:=Address - FBufOffs;
|
|
If Offset + Size <= FBufLen then Result:=Pointer(Integer(FBuffer) + Offset);
|
|
end;
|
|
except
|
|
On E: Exception do DoOnError('Error in function TNoDave.BufferAt(' + IntToStr(Address) + ', ' + IntToStr(Size) + ', $' +
|
|
IntToHex(Integer(Buffer), 8) + ', ' + IntToStr(BufOffs) + ', ' + IntToStr(BufLen) + '): ' +
|
|
E.Message);
|
|
end;
|
|
end;
|
|
|
|
//Open the connection to the PLC.
|
|
//~param Wait If False the connection is opened asyncronous in a separate thread. Default is True.
|
|
procedure TNoDave.Connect(Wait: Boolean = True);
|
|
begin
|
|
If not FActive and not ConnectPending then
|
|
begin
|
|
ConnectPending:=True;
|
|
If Wait then
|
|
begin
|
|
try
|
|
DoConnect;
|
|
If Active and not (csLoading in ComponentState) then DoOnConnect;
|
|
except
|
|
On E: Exception do DoOnError('Error in function TNoDave.Connect: ' + E.Message);
|
|
end;
|
|
ConnectPending:=False;
|
|
end else begin
|
|
TNoDaveConnectThread.Create(Self);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//Close the connection to the PLC.
|
|
procedure TNoDave.Disconnect;
|
|
begin
|
|
If Active then
|
|
begin
|
|
try
|
|
daveDisconnectPLC(DaveConn);
|
|
daveFree(DaveConn);
|
|
daveDisconnectAdapter(DaveIntf);
|
|
daveFree(DaveIntf);
|
|
If FProtocol <> daveProtoS7Online then closePort(DaveFDS.rfd) else closeS7online(DaveFDS.rfd);
|
|
except
|
|
On E: Exception do DoOnError('Error in function TNoDave.Disconnect: ' + E.Message);
|
|
end;
|
|
FActive:=False;
|
|
DoOnDisconnect;
|
|
end;
|
|
end;
|
|
|
|
//Open the connection to the PLC specified by the properties ~[link .Protocol Protocol], ~[link .CPURack CPURack], ~[link .CPUSlot CPUSlot],
|
|
//~[link .COMPort COMPort], ~[link .IPAddress IPAddress], ~[link .IPPort IPPort], ~[link .MPILocal MPILocal], ~[link .MPIRemote MPIRemote]
|
|
// and/or ~[link .MPISpeed MPISpeed]
|
|
//~param OnlyIntf Open only the interface, don't connect to the PLC
|
|
procedure TNoDave.DoConnect(OnlyIntf: Boolean = False);
|
|
var
|
|
Address: String;
|
|
Speed: PChar;
|
|
begin
|
|
If not FActive then
|
|
begin
|
|
If not (csLoading in ComponentState) then
|
|
begin
|
|
Case FProtocol of
|
|
daveProtoMPI, daveProtoMPI2, daveProtoMPI3, daveProtoMPI4, daveProtoPPI, daveProtoAS511:
|
|
begin
|
|
Address:=FComPort + #0;
|
|
Case ComSpeed of
|
|
daveComSpeed9_6k: Speed:='9600';
|
|
daveComSpeed19_2k: Speed:='19200';
|
|
daveComSpeed38_4k: Speed:='38400';
|
|
daveComSpeed57_6k: Speed:='57600';
|
|
daveComSpeed115_2k: Speed:='115200';
|
|
else Speed:='38400';
|
|
end;
|
|
DaveFDS.rfd:=SetPort(@Address[1], Speed, 'O');
|
|
end;
|
|
daveProtoISOTCP, daveProtoISOTCP243, daveProtoIBH, daveProtoIBH_PPI, daveProtoNLPro:
|
|
begin
|
|
Address:=FIPAddress + #0;
|
|
DaveFDS.rfd:=OpenSocket(FIPPort, @Address[1]);
|
|
end;
|
|
daveProtoS7Online:
|
|
begin
|
|
Address:=FComPort + #0;
|
|
DaveFDS.rfd:=OpenS7Online(@Address[1], Handle);
|
|
end;
|
|
end;
|
|
DaveFDS.wfd:=DaveFDS.rfd;
|
|
If (DaveFDS.rfd > 0) or ((DaveFDS.rfd = 0) and (FProtocol = daveProtoS7Online)) then
|
|
begin
|
|
Address:=FIntfName + #0;
|
|
DaveIntf:=daveNewInterface(DaveFDS, @Address[1], Ord(FMPIlocal), ProtCode(FProtocol), Ord(FMPISpeed));
|
|
DaveIntf^.timeout:=FIntfTimeout;
|
|
If not OnlyIntf then
|
|
begin
|
|
FLastError:=daveInitAdapter(DaveIntf);
|
|
If FLastError = 0 then
|
|
begin
|
|
DaveConn:=daveNewConnection(DaveIntf, FMPIRemote, FCpuRack, FCpuSlot);
|
|
FLastError:=daveConnectPLC(DaveConn);
|
|
FActive:=(FLastError = 0);
|
|
If Active then ReadBytes else DoOnError(daveStrerror(FLastError));
|
|
end;
|
|
end;
|
|
end;
|
|
end else FActive:=True;
|
|
end;
|
|
end;
|
|
|
|
//Create the worker-thread for cyclic reading if neccessary and call the OnConnect-eventhandler if specified.
|
|
procedure TNoDave.DoOnConnect;
|
|
begin
|
|
If (FInterval > 0) and not Assigned(ReadThread) and not (csDesigning in ComponentState)
|
|
then ReadThread:=TNoDaveReadThread.Create(Self);
|
|
If Assigned(OnConnect) then OnConnect(Self);
|
|
end;
|
|
|
|
//Stop and Destroy the worker-thread for cyclic reading if neccessary and call the OnDisconnect-eventhandler if specified.
|
|
procedure TNoDave.DoOnDisconnect;
|
|
begin
|
|
If Assigned(ReadThread) then
|
|
begin
|
|
ReadThread.WaitFor;
|
|
FreeAndNil(ReadThread);
|
|
end;
|
|
If Assigned(OnDisconnect) then OnDisconnect(Self);
|
|
end;
|
|
|
|
//Call the OnError-eventhandler if specified.
|
|
//~param ErrorMsg The text-message for the OnError-event
|
|
procedure TNoDave.DoOnError(ErrorMsg: String);
|
|
begin
|
|
If Assigned(OnError) then OnError(Self, ErrorMsg);
|
|
end;
|
|
|
|
//Call the OnRead-eventhandler if specified.
|
|
procedure TNoDave.DoOnRead;
|
|
begin
|
|
If Assigned(OnRead) then OnRead(Self);
|
|
end;
|
|
|
|
//Call the OnWrite-eventhandler if specified.
|
|
procedure TNoDave.DoOnWrite;
|
|
begin
|
|
If Assigned(OnWrite) then OnWrite(Self);
|
|
end;
|
|
|
|
//Read the PLC-data into the buffer.
|
|
//~param Area Requested PLC-area.
|
|
//~param DB Number of requested datablock. Only used, if reading from Datablocks in the PLC.
|
|
//~param Start Start-address of the requested data within the address-range of the PLC.
|
|
//~param Size Length of the requested PLC-data in bytes.
|
|
//~param Buffer Pointer to the buffer. The internal buffer of the instance is used, if Nil (default).
|
|
procedure TNoDave.DoReadBytes(Area: TNoDaveArea; DB, Start, Size: Integer; Buffer: Pointer);
|
|
var
|
|
Index, Length, MaxLen: Integer;
|
|
StartTime: Cardinal;
|
|
begin
|
|
Index:=0;
|
|
StartTime:=GetTickCount;
|
|
MaxLen:=MaxPDUData;
|
|
While (Index < Size) and (MaxLen > 0) do
|
|
begin
|
|
Length:=(Size - Index);
|
|
If Length > MaxLen then Length:=MaxLen;
|
|
try
|
|
LockNoDave.Enter;
|
|
FLastError:=daveReadBytes(DaveConn, AreaCode(Area), DB, Index+Start, Size, Pointer(Integer(Buffer) + Index));
|
|
except
|
|
On E: Exception do DoOnError('Error in function TNoDave.DoReadBytes: ' + E.Message);
|
|
end;
|
|
LockNoDave.Leave;
|
|
Inc(Index, Length);
|
|
end;
|
|
try
|
|
FCycleTime:=GetTickCount - StartTime;
|
|
except
|
|
end;
|
|
end;
|
|
|
|
//Write the Buffer-data into the PLC.
|
|
//~param Area Requested PLC-area.
|
|
//~param DB Number of requested datablock. Only used, if reading from Datablocks in the PLC.
|
|
//~param Start Start-address of the requested data within the address-range of the PLC.
|
|
//~param Size Length of the requested PLC-data in bytes.
|
|
//~param Buffer Pointer to the buffer. The internal buffer of the instance is used, if Nil (default).
|
|
procedure TNoDave.DoWriteBytes(Area: TNoDaveArea; DB, Start, Size: Integer; Buffer: Pointer);
|
|
var
|
|
Index, Length, MaxLen: Integer;
|
|
begin
|
|
Index:=0;
|
|
MaxLen:=MaxPDUData-4;
|
|
While (Index < Size) and (MaxLen > 0) do
|
|
begin
|
|
Length:=(Size - Index);
|
|
If Length > MaxLen then Length:=MaxLen;
|
|
try
|
|
LockNoDave.Enter;
|
|
FLastError:=daveWriteBytes(DaveConn, AreaCode(Area), DB, Index+Start, Size, Pointer(Integer(Buffer) + Index));
|
|
except
|
|
On E: Exception do DoOnError('Error in function TNoDave.DoWriteBytes: ' + E.Message);
|
|
end;
|
|
LockNoDave.Leave;
|
|
Inc(Index, Length);
|
|
end;
|
|
end;
|
|
|
|
//Write a single value into the specified address of the PLC without changing the properties of the TNoDave-instance.
|
|
//~param Address PLC-Address of the data point.
|
|
//~param Size Size in bytes of the value.
|
|
//~param Value The value to be written.
|
|
procedure TNoDave.DoWriteValue(Address, Size: Integer; Value: Pointer);
|
|
begin
|
|
try
|
|
LockNoDave.Enter;
|
|
FLastError:=daveWriteBytes(DaveConn, AreaCode(FArea), FDBNumber, Address, Size, Value);
|
|
except
|
|
On E: Exception do DoOnError('Error in function TNoDave.DoWriteValue: ' + E.Message);
|
|
end;
|
|
LockNoDave.Leave;
|
|
end;
|
|
|
|
//Set the debug-options of the libnodave.dll
|
|
//~param Options Value of the debug-options.
|
|
procedure TNoDave.DoSetDebug(Options: Integer);
|
|
begin
|
|
daveSetDebug(Options);
|
|
FDebugOptions:=Options;
|
|
end;
|
|
|
|
//Return the state of the connection to the PLC.
|
|
//~result True, if connection is open, else False.
|
|
function TNoDave.GetActive: Boolean;
|
|
begin
|
|
Result:=FActive and not (csLoading in ComponentState);
|
|
end;
|
|
|
|
//Return a textual representation of the content of the internal buffer.
|
|
//~result String with the hexadecimal value of the bytes in the buffer.
|
|
function TNoDave.GetBuffer: String;
|
|
var
|
|
Index: Integer;
|
|
Value: Byte;
|
|
begin
|
|
Result:='';
|
|
If Assigned(FBuffer) then
|
|
begin
|
|
Index:=0;
|
|
While Index < FBufLen do
|
|
begin
|
|
Value:=Byte(Pointer(Integer(FBuffer) + Index)^);
|
|
If Result <> '' then Result:=Result + ' ';
|
|
Result:=Result + IntToHex(Value, 2);
|
|
Inc(Index);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//Return the Bit-value read last from the PLC at the specified address.
|
|
//~param Address Byte-address of the requested value
|
|
//~param Bit Bit-address of the requested value
|
|
//~param Buffer Pointer to the buffer holding the PLC-data. The internal buffer is used, if Nil (default).
|
|
//~param BufOffs Offset-address of the buffer within the address-range of the PLC.
|
|
//~param BufLen Length of the buffer in bytes.
|
|
//~result The requested value or False, if the requested address was not found within the buffer.
|
|
function TNoDave.GetBit(Address, Bit: Integer; Buffer: Pointer; BufOffs: Integer; BufLen: Integer): Boolean;
|
|
var
|
|
BufPtr: Pointer;
|
|
begin
|
|
BufPtr:=BufferAt(Address, 1, Buffer, BufOffs, BufLen);
|
|
If Assigned(BufPtr) then Result:=(daveGetU8From(BufPtr) and (1 shl Bit)) <> 0 else Result:=False;
|
|
end;
|
|
|
|
//Return the Byte-value read last from the PLC at the specified address.
|
|
//~param Address Address of the requested value
|
|
//~param Buffer Pointer to the buffer holding the PLC-data. The internal buffer is used, if Nil (default).
|
|
//~param BufOffs Offset-address of the buffer within the address-range of the PLC.
|
|
//~param BufLen Length of the buffer in bytes.
|
|
//~result The requested value or 0, if the requested address was not found within the buffer.
|
|
function TNoDave.GetByte(Address: Integer; Buffer: Pointer; BufOffs: Integer; BufLen: Integer): Byte;
|
|
var
|
|
BufPtr: Pointer;
|
|
begin
|
|
BufPtr:=BufferAt(Address, 1, Buffer, BufOffs, BufLen);
|
|
If Assigned(BufPtr) then Result:=daveGetU8From(BufPtr) else Result:=0;
|
|
end;
|
|
|
|
//Return the LongInt-value read last from the PLC at the specified address.
|
|
//~param Address Address of the requested value
|
|
//~param Buffer Pointer to the buffer holding the PLC-data. The internal buffer is used, if Nil (default).
|
|
//~param BufOffs Offset-address of the buffer within the address-range of the PLC.
|
|
//~param BufLen Length of the buffer in bytes.
|
|
//~result The requested value or 0, if the requested address was not found within the buffer.
|
|
function TNoDave.GetDInt(Address: Integer; Buffer: Pointer; BufOffs: Integer; BufLen: Integer): LongInt;
|
|
var
|
|
BufPtr: Pointer;
|
|
begin
|
|
BufPtr:=BufferAt(Address, 4, Buffer, BufOffs, BufLen);
|
|
If Assigned(BufPtr) then Result:=daveGetS32From(BufPtr) else Result:=0;
|
|
end;
|
|
|
|
//Return the LongWord-value read last from the PLC at the specified address.
|
|
//~param Address Address of the requested value
|
|
//~param Buffer Pointer to the buffer holding the PLC-data. The internal buffer is used, if Nil (default).
|
|
//~param BufOffs Offset-address of the buffer within the address-range of the PLC.
|
|
//~param BufLen Length of the buffer in bytes.
|
|
//~result The requested value or 0, if the requested address was not found within the buffer.
|
|
function TNoDave.GetDWord(Address: Integer; Buffer: Pointer; BufOffs: Integer; BufLen: Integer): LongWord;
|
|
var
|
|
BufPtr: Pointer;
|
|
begin
|
|
BufPtr:=BufferAt(Address, 4, Buffer, BufOffs, BufLen);
|
|
If Assigned(BufPtr) then Result:=daveGetU32From(BufPtr) else Result:=0;
|
|
end;
|
|
|
|
//Return the Float-value read last from the PLC at the specified address.
|
|
//~param Address Address of the requested value
|
|
//~param Buffer Pointer to the buffer holding the PLC-data. The internal buffer is used, if Nil (default).
|
|
//~param BufOffs Offset-address of the buffer within the address-range of the PLC.
|
|
//~param BufLen Length of the buffer in bytes.
|
|
//~result The requested value or 0, if the requested address was not found within the buffer.
|
|
function TNoDave.GetFloat(Address: Integer; Buffer: Pointer; BufOffs: Integer; BufLen: Integer): Double;
|
|
var
|
|
BufPtr: Pointer;
|
|
begin
|
|
BufPtr:=BufferAt(Address, 4, Buffer, BufOffs, BufLen);
|
|
If Assigned(BufPtr) then Result:=daveGetFloatFrom(BufPtr) else Result:=0;
|
|
end;
|
|
|
|
//Return the Window-Handle (HWND) used for system-calls.
|
|
//~result The Window-Handle (HWND).
|
|
function TNoDave.GetHandle: THandle;
|
|
var
|
|
Parent: TComponent;
|
|
begin
|
|
Parent:=Self;
|
|
while Assigned(Parent.Owner) and not (Parent is TWinControl) do Parent:=Parent.Owner;
|
|
if Parent is TWinControl then Result:=TWinControl(Parent).Handle else
|
|
begin
|
|
If FHandle = 0 then FHandle:=AllocateHwnd(Nil);
|
|
Result:=FHandle;
|
|
end;
|
|
end;
|
|
|
|
//Return the SmallInt-value read last from the PLC at the specified address.
|
|
//~param Address Address of the requested value
|
|
//~param Buffer Pointer to the buffer holding the PLC-data. The internal buffer is used, if Nil (default).
|
|
//~param BufOffs Offset-address of the buffer within the address-range of the PLC.
|
|
//~param BufLen Length of the buffer in bytes.
|
|
//~result The requested value or 0, if the requested address was not found within the buffer.
|
|
function TNoDave.GetInt(Address: Integer; Buffer: Pointer; BufOffs: Integer; BufLen: Integer): SmallInt;
|
|
var
|
|
BufPtr: Pointer;
|
|
begin
|
|
BufPtr:=BufferAt(Address, 2, Buffer, BufOffs, BufLen);
|
|
If Assigned(BufPtr) then Result:=daveGetS16From(BufPtr) else Result:=0;
|
|
end;
|
|
|
|
//Return the Word-value read last from the PLC at the specified address.
|
|
//~param Address Address of the requested value
|
|
//~param Buffer Pointer to the buffer holding the PLC-data. The internal buffer is used, if Nil (default).
|
|
//~param BufOffs Offset-address of the buffer within the address-range of the PLC.
|
|
//~param BufLen Length of the buffer in bytes.
|
|
//~result The requested value or 0, if the requested address was not found within the buffer.
|
|
function TNoDave.GetWord(Address: Integer; Buffer: Pointer; BufOffs: Integer; BufLen: Integer): Word;
|
|
var
|
|
BufPtr: Pointer;
|
|
begin
|
|
BufPtr:=BufferAt(Address, 2, Buffer, BufOffs, BufLen);
|
|
If Assigned(BufPtr) then Result:=daveGetU16From(BufPtr) else Result:=0;
|
|
end;
|
|
|
|
//Return the description of the return-code in ~[link .LastError LastError].
|
|
//~result The description of the return-code.
|
|
function TNoDave.GetLastErrMsg: String;
|
|
begin
|
|
If FLastError = 0 then Result:='' else Result:=GetErrorMsg(FLastError);
|
|
end;
|
|
|
|
//Scan the MPI-bus for all reachable partners
|
|
//~result List with True for available partners and False for unavailable partners.
|
|
function TNoDave.ListReachablePartners: TNoDaveReachablePartnersMPI;
|
|
type
|
|
TByteList = Array [0..126] of Byte;
|
|
PByteList = ^TByteList;
|
|
var
|
|
List: Pointer;
|
|
WasActive: Boolean;
|
|
Index: Integer;
|
|
begin
|
|
GetMem(List, SizeOf(TByteList));
|
|
try
|
|
WasActive:=Active;
|
|
Active:=True;
|
|
If Active then
|
|
begin
|
|
daveListReachablePartners(DaveIntf, List);
|
|
Index:=0;
|
|
While Index < 127 do
|
|
begin
|
|
Result[Index]:=(PByteList(List)^[Index] = daveMPIReachable);
|
|
Inc(Index);
|
|
end;
|
|
end else begin
|
|
Index:=0;
|
|
While Index < 127 do
|
|
begin
|
|
Result[Index]:=False;
|
|
Inc(Index);
|
|
end;
|
|
end;
|
|
Active:=WasActive;
|
|
finally
|
|
FreeMem(List);
|
|
end;
|
|
end;
|
|
|
|
//Open the connection to the PLC after the instance is completely loaded from the stream and if Active is True.
|
|
procedure TNoDave.Loaded;
|
|
begin
|
|
inherited;
|
|
If FActive then
|
|
begin
|
|
FActive:=False;
|
|
Connect;
|
|
end;
|
|
end;
|
|
|
|
//Lock the communication-routines for the current tread.
|
|
procedure TNoDave.Lock;
|
|
begin
|
|
LockNoDave.Enter;
|
|
end;
|
|
|
|
//Determine the libnodave.dll-code of a protocol
|
|
//~param Prot The requested protocol
|
|
//~result The libnodave.dll code for the protocol
|
|
function TNoDave.ProtCode(Prot: TNoDaveProtocol): Integer;
|
|
begin
|
|
Result:=-1;
|
|
Case Prot of
|
|
daveProtoMPI: Result:=0;
|
|
daveProtoMPI2: Result:=1;
|
|
daveProtoMPI3: Result:=2;
|
|
daveProtoMPI4: Result:=3;
|
|
daveProtoPPI: Result:=10;
|
|
daveProtoAS511: Result:=20;
|
|
daveProtoS7Online: Result:=50;
|
|
daveProtoISOTCP: Result:=122;
|
|
daveProtoISOTCP243: Result:=123;
|
|
daveProtoIBH: Result:=223;
|
|
daveProtoIBH_PPI: Result:=224;
|
|
daveProtoNLPro: Result:=230;
|
|
end;
|
|
end;
|
|
|
|
//Read the Data specified by the properties ~[link .Area Area], ~[link .DBNumber DBNumber], ~[link .BufOffs BufOffs]
|
|
//and ~[link .BufLen BufLen] from the PLC into the buffer.
|
|
//~param Buffer Pointer to the buffer for PLC-data. The internal buffer is used, if Nil (default).
|
|
procedure TNoDave.ReadBytes(Buffer: Pointer);
|
|
begin
|
|
If not Assigned(Buffer) then Buffer:=FBuffer;
|
|
If Active then
|
|
begin
|
|
DoReadBytes(FArea, FDBNumber, FBufOffs, FBufLen, Buffer);
|
|
DoOnRead;
|
|
end;
|
|
end;
|
|
|
|
//Read the specified Data from the PLC into the buffer.
|
|
//~param Area Requested PLC-area.
|
|
//~param DB Number of requested datablock. Only used, if reading from Datablocks in the PLC.
|
|
//~param Start Start-address of the requested data within the address-range of the PLC.
|
|
//~param Size Length of the requested PLC-data in bytes.
|
|
//~param Buffer Pointer to the buffer for PLC-data. The internal buffer is used, if Nil (default).
|
|
procedure TNoDave.ReadBytes(Area: TNoDaveArea; DB, Start, Size: Integer; Buffer: Pointer);
|
|
begin
|
|
If not Assigned(Buffer) then
|
|
begin
|
|
FArea:=Area;
|
|
FDBNumber:=DB;
|
|
FBufOffs:=Start;
|
|
FBufLen:=Size;
|
|
ReadBytes(Buffer);
|
|
end else begin
|
|
DoReadBytes(Area, DB, Start, Size, Buffer);
|
|
end;
|
|
end;
|
|
|
|
//Set the property ~[link .Active Active] and call either ~[link .Connect Connect] or ~[link .Disconnect Disconnect].
|
|
//depending on the requested value.
|
|
//~param V The requested state.
|
|
procedure TNoDave.SetActive(V: Boolean);
|
|
begin
|
|
If V then Connect else Disconnect;
|
|
end;
|
|
|
|
//Set the property ~[link .Area Area].
|
|
//~param V The ~[link TNoDaveArea PLC-Area].
|
|
procedure TNoDave.SetArea(V: TNoDaveArea);
|
|
begin
|
|
FArea:=V;
|
|
If V in [daveDB, daveDI, daveLocal] then
|
|
begin
|
|
If FDBNumber = 0 then FDBNumber:=1;
|
|
end else FDBNumber:=0;
|
|
If Active and (csDesigning in ComponentState) then ReadBytes;
|
|
end;
|
|
|
|
//Set the property ~[link .BufLen BufLen] and reserve the required memory.
|
|
//~param V The length of the buffer in bytes.
|
|
procedure TNoDave.SetBufLen(V: Integer);
|
|
begin
|
|
If Assigned(FBuffer) then
|
|
try
|
|
FreeMem(FBuffer);
|
|
except
|
|
end;
|
|
FBufLen:=V;
|
|
GetMem(FBuffer, FBufLen);
|
|
If Active and (csDesigning in ComponentState) then ReadBytes;
|
|
end;
|
|
|
|
//Set the property ~[link .BufOffs BufOffs].
|
|
//~param V The address within the address-range of the PLC.
|
|
procedure TNoDave.SetBufOffs(V: Integer);
|
|
begin
|
|
FBufOffs:=V;
|
|
If Active and (csDesigning in ComponentState) then ReadBytes;
|
|
end;
|
|
|
|
//Set the property ~[link .ComPort ComPort].
|
|
//~param V The Name of the ComPort.
|
|
procedure TNoDave.SetComPort(V: String);
|
|
begin
|
|
If FProtocol in [daveProtoMPI, daveProtoMPI2, daveProtoMPI3, daveProtoMPI4, daveProtoPPI, daveProtoAS511] then Disconnect;
|
|
FComPort:=V;
|
|
end;
|
|
|
|
//Set the property ~[link .ComSpeed ComComSpeed].
|
|
//~param V The Name of the ComPort.
|
|
procedure TNoDave.SetComSpeed(V: TNoDaveComSpeed);
|
|
begin
|
|
If FProtocol in [daveProtoMPI, daveProtoMPI2, daveProtoMPI3, daveProtoMPI4, daveProtoPPI, daveProtoAS511] then Disconnect;
|
|
FComSpeed:=V;
|
|
end;
|
|
|
|
//Set the property ~[link .CpuRack CpuRack].
|
|
//~param V The rack of the PLC containing the CPU.
|
|
procedure TNoDave.SetCpuRack(V: Integer);
|
|
begin
|
|
Disconnect;
|
|
FCpuRack:=V;
|
|
end;
|
|
|
|
//Set the property ~[link .CpuSlot CpuSlot].
|
|
//~param V The Slot of the PLC containing the CPU.
|
|
procedure TNoDave.SetCpuSlot(V: Integer);
|
|
begin
|
|
Disconnect;
|
|
FCpuSlot:=V;
|
|
end;
|
|
|
|
//Set the property ~[link .DBNumber DBNumber].
|
|
//~param V The requested number of the datablock.
|
|
procedure TNoDave.SetDBNumber(V: Integer);
|
|
begin
|
|
FDBNumber:=V;
|
|
If Active and (csDesigning in ComponentState) then ReadBytes;
|
|
end;
|
|
|
|
//Set the property ~[link .Interval Interval].
|
|
//~param V The Interval for the background-communication in milliseconds. 0 if no background-communication is desired.
|
|
procedure TNoDave.SetInterval(V: Cardinal);
|
|
begin
|
|
FInterval:=V;
|
|
If Active then
|
|
begin
|
|
If (FInterval > 0) then
|
|
begin
|
|
If not Assigned(ReadThread) and not (csDesigning in ComponentState) then ReadThread:=TNoDaveReadThread.Create(Self);
|
|
end else begin
|
|
If Assigned(ReadThread) then
|
|
begin
|
|
ReadThread.WaitFor;
|
|
FreeAndNil(ReadThread);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//Set the property ~[link .IntfName IntfName].
|
|
//~param V The symbolic name of the interface.
|
|
procedure TNoDave.SetIntfName(V: String);
|
|
begin
|
|
Disconnect;
|
|
FIntfName:=V;
|
|
end;
|
|
|
|
//Set the property ~[link .IntfTimeout IntfTimeout].
|
|
//~param V The timeout of the interface in milliseconds.
|
|
procedure TNoDave.SetIntfTimeout(V: Integer);
|
|
begin
|
|
FIntfTimeout:=V;
|
|
If Active then DaveIntf^.timeout:=FIntfTimeout;
|
|
end;
|
|
|
|
//Set the property ~[link .IPAddress IPAddress].
|
|
//~param V The IP-address or name of the TCP/IP partner station.
|
|
procedure TNoDave.SetIPAddress(V: String);
|
|
begin
|
|
If FProtocol in [daveProtoISOTCP, daveProtoISOTCP243, daveProtoIBH, daveProtoIBH_PPI, daveProtoNLPro] then Disconnect;
|
|
FIPAddress:=V;
|
|
end;
|
|
|
|
//Set the property ~[link .IPPort IPPort].
|
|
//~param V The IP-Port of the TCP/IP parter station.
|
|
procedure TNoDave.SetIPPort(V: Integer);
|
|
begin
|
|
If FProtocol in [daveProtoISOTCP, daveProtoISOTCP243, daveProtoIBH, daveProtoIBH_PPI, daveProtoNLPro] then Disconnect;
|
|
FIPPort:=V;
|
|
end;
|
|
|
|
//Set the property ~[link .MPILocal MPILocal].
|
|
//~param V The local MPI-address for the MPI communication.
|
|
procedure TNoDave.SetMPILocal(V: Integer);
|
|
begin
|
|
If FProtocol in [daveProtoMPI, daveProtoMPI2, daveProtoMPI3, daveProtoMPI4, daveProtoPPI, daveProtoIBH, daveProtoIBH_PPI, daveProtoNLPro] then Disconnect;
|
|
FMPILocal:=V;
|
|
end;
|
|
|
|
//Set the property ~[link .MPIRemote MPIRemote].
|
|
//~param V The remote MPI-address for the MPI communication.
|
|
procedure TNoDave.SetMPIRemote(V: Integer);
|
|
begin
|
|
If FProtocol in [daveProtoMPI, daveProtoMPI2, daveProtoMPI3, daveProtoMPI4, daveProtoPPI, daveProtoIBH, daveProtoIBH_PPI, daveProtoNLPro] then Disconnect;
|
|
FMPIRemote:=V;
|
|
end;
|
|
|
|
//Set the property ~[link .MPISpeed MPISpeed].
|
|
//~param V The ~[link TNoDaveSpeed speed] of the MPI-bus.
|
|
procedure TNoDave.SetMPISpeed(V: TNoDaveSpeed);
|
|
begin
|
|
If FProtocol in [daveProtoMPI, daveProtoMPI2, daveProtoMPI3, daveProtoMPI4, daveProtoPPI, daveProtoIBH, daveProtoIBH_PPI, daveProtoNLPro] then Disconnect;
|
|
FMPISpeed:=V;
|
|
end;
|
|
|
|
//Set the property ~[link .Protocol Protocol].
|
|
//~param V The requested ~[link TNoDaveProtocol Protocol].
|
|
procedure TNoDave.SetProtocol(V: TNoDaveProtocol);
|
|
begin
|
|
Disconnect;
|
|
FProtocol:=V;
|
|
If FProtocol in [daveProtoIBH, daveProtoIBH_PPI] then FIPPort:=1099;
|
|
If FProtocol in [daveProtoNLPro] then FIPPort:=7777;
|
|
If FProtocol in [daveProtoISOTCP, daveProtoISOTCP243] then FIPPort:=102;
|
|
end;
|
|
|
|
//Swap the byte-order in a 16-bit value.
|
|
//~param Value The value for the conversion.
|
|
//~result The converted value.
|
|
function TNoDave.Swap16(Value: SmallInt): SmallInt;
|
|
begin
|
|
Result:=daveSwapIed_16(Value);
|
|
end;
|
|
|
|
//Swap the byte-order in a 32-bit value.
|
|
//~param Value The value for the conversion.
|
|
//~result The converted value.
|
|
function TNoDave.Swap32(Value: Integer): Integer;
|
|
begin
|
|
Result:=daveSwapIed_32(Value);
|
|
end;
|
|
|
|
//Unlock the communication-routines for other threads.
|
|
procedure TNoDave.Unlock;
|
|
begin
|
|
LockNoDave.Leave;
|
|
end;
|
|
|
|
//Write a Bit-value into the PLC at the specified address without changing the properties of the TNoDave-instance.
|
|
//~param Area Requested PLC-area.
|
|
//~param DB Number of requested datablock. Only used, if writing into datablocks of the PLC.
|
|
//~param Address Byte-address of the value
|
|
//~param Bit Bit-address of the value
|
|
//~param Value Value to write into the PLC.
|
|
procedure TNoDave.WriteBit(Area: TNoDaveArea; DB, Address, Bit: Integer; Value: Boolean);
|
|
var
|
|
Output: LongInt;
|
|
begin
|
|
try
|
|
LockNoDave.Enter;
|
|
If Value then Output:=1 else Output:=0;
|
|
FLastError:=daveWriteBits(DaveConn, AreaCode(Area), DB, (Address*8)+Bit, 1, @Output);
|
|
except
|
|
On E: Exception do DoOnError('Error in function TNoDave.WriteBit: ' + E.Message);
|
|
end;
|
|
LockNoDave.Leave;
|
|
end;
|
|
|
|
//Write the buffer into the PLC at the address specified by the properties ~[link .Area Area], ~[link .DBNumber DBNumber],
|
|
//~[link .BufOffs BufOffs] and ~[link .BufLen BufLen].
|
|
//~param Buffer Pointer to the buffer for PLC-data. The internal buffer is used, if Nil (default).
|
|
procedure TNoDave.WriteBytes(Buffer: Pointer);
|
|
begin
|
|
If not Assigned(Buffer) then Buffer:=FBuffer;
|
|
If Active then
|
|
begin
|
|
DoWriteBytes(FArea, FDBNumber, FBufOffs, FBufLen, Buffer);
|
|
DoOnWrite;
|
|
end;
|
|
end;
|
|
|
|
//Write the buffer into the PLC at the specified address after setting up the properties with the given values.
|
|
//~param Area Requested PLC-area. Changes the property ~[link .Area Area].
|
|
//~param DB Number of requested datablock. Changes the property ~[link .DBNumber DBNumber]. Only used, if writing into datablocks of the PLC.
|
|
//~param Start Start-address of the buffer within the address-range of the PLC. Changes the property ~[link BufOffs].
|
|
//~param Size Length of the buffer in bytes. Changes the property ~[link .BufLen BufLen].
|
|
//~param Buffer Pointer to the buffer for PLC-data. The internal buffer is used, if Nil (default).
|
|
procedure TNoDave.WriteBytes(Area: TNoDaveArea; DB, Start, Size: Integer; Buffer: Pointer);
|
|
begin
|
|
If not Assigned(Buffer) then
|
|
begin
|
|
FArea:=Area;
|
|
FDBNumber:=DB;
|
|
FBufOffs:=Start;
|
|
FBufLen:=Size;
|
|
WriteBytes(Buffer);
|
|
end else begin
|
|
DoWriteBytes(Area, DB, Start, Size, Buffer);
|
|
end;
|
|
end;
|
|
|
|
//Write a Bit-value into the PLC at the specified address without changing the properties of the TNoDave-instance.
|
|
//~param Address Byte-address of the value
|
|
//~param Bit Bit-address of the value
|
|
//~param Value Value to write into the PLC.
|
|
procedure TNoDave.WriteBit(Address, Bit: Integer; Value: Boolean);
|
|
begin
|
|
WriteBit(FArea, FDBNumber, Address, Bit, Value);
|
|
end;
|
|
|
|
//Write a Byte-value into the PLC at the specified address without changing the properties of the TNoDave-instance.
|
|
//~param Address Byte-address of the value
|
|
//~param Value Value to write into the PLC.
|
|
procedure TNoDave.WriteByte(Address: Integer; Value: Byte);
|
|
begin
|
|
DoWriteValue(Address, 1, @Value);
|
|
end;
|
|
|
|
//Write a LongInt-value into the PLC at the specified address without changing the properties of the TNoDave-instance.
|
|
//~param Address Byte-address of the value
|
|
//~param Value Value to write into the PLC.
|
|
procedure TNoDave.WriteDInt(Address, Value: Integer);
|
|
var
|
|
Dummy: LongInt;
|
|
begin
|
|
Dummy:=daveSwapIed_32(Value);
|
|
DoWriteValue(Address, 4, @Dummy);
|
|
end;
|
|
|
|
//Write a LongWord-value into the PLC at the specified address without changing the properties of the TNoDave-instance.
|
|
//~param Address Byte-address of the value
|
|
//~param Value Value to write into the PLC.
|
|
procedure TNoDave.WriteDWord(Address: Integer; Value: LongWord);
|
|
var
|
|
Dummy: LongInt;
|
|
begin
|
|
Dummy:=daveSwapIed_32(Value);
|
|
DoWriteValue(Address, 4, @Dummy);
|
|
end;
|
|
|
|
//Write a Float-value into the PLC at the specified address without changing the properties of the TNoDave-instance.
|
|
//~param Address Byte-address of the value
|
|
//~param Value Value to write into the PLC.
|
|
procedure TNoDave.WriteFloat(Address: Integer; Value: Single);
|
|
var
|
|
Dummy: LongInt;
|
|
FltVal: Single absolute Dummy;
|
|
begin
|
|
FltVal:=Value;
|
|
Dummy:=daveSwapIed_32(Dummy);
|
|
DoWriteValue(Address, 4, @Dummy);
|
|
end;
|
|
|
|
//Write a SmallInt-value into the PLC at the specified address without changing the properties of the TNoDave-instance.
|
|
//~param Address Byte-address of the value
|
|
//~param Value Value to write into the PLC.
|
|
procedure TNoDave.WriteInt(Address: Integer; Value: SmallInt);
|
|
var
|
|
Dummy: SmallInt;
|
|
begin
|
|
Dummy:=daveSwapIed_16(Value);
|
|
DoWriteValue(Address, 2, @Dummy);
|
|
end;
|
|
|
|
//Write a Word-value into the PLC at the specified address without changing the properties of the TNoDave-instance.
|
|
//~param Address Byte-address of the value
|
|
//~param Value Value to write into the PLC.
|
|
procedure TNoDave.WriteWord(Address: Integer; Value: Word);
|
|
var
|
|
Dummy: SmallInt;
|
|
begin
|
|
Dummy:=daveSwapIed_16(Value);
|
|
DoWriteValue(Address, 2, @Dummy);
|
|
end;
|
|
|
|
//Return the length of a DB.
|
|
//~param DB The number of the DB.
|
|
//~result Length of the DB in Bytes.
|
|
function TNoDave.GetDBSize(DB: Integer): Integer;
|
|
var
|
|
Info: daveBlockInfo;
|
|
begin
|
|
try
|
|
Result:=daveGetBlockInfo(DaveConn, @Info, daveBlockType_DB, DB);
|
|
If Result = 0 then
|
|
begin
|
|
Result:=Info.length;
|
|
end else Result:=0;
|
|
except
|
|
end;
|
|
end;
|
|
|
|
//Return the actual debug-options.
|
|
//~result Set of the actual debug-options.
|
|
function TNoDave.GetDebugOptions: TNoDaveDebugOptions;
|
|
begin
|
|
Result:=[];
|
|
If FDebugOptions and $0001 <> 0 then Result:=Result + [daveDebugRawRead];
|
|
If FDebugOptions and $0002 <> 0 then Result:=Result + [daveDebugSpecialChars];
|
|
If FDebugOptions and $0004 <> 0 then Result:=Result + [daveDebugRawWrite];
|
|
If FDebugOptions and $0008 <> 0 then Result:=Result + [daveDebugListReachables];
|
|
If FDebugOptions and $0010 <> 0 then Result:=Result + [daveDebugInitAdapter];
|
|
If FDebugOptions and $0020 <> 0 then Result:=Result + [daveDebugConnect];
|
|
If FDebugOptions and $0040 <> 0 then Result:=Result + [daveDebugPacket];
|
|
If FDebugOptions and $0080 <> 0 then Result:=Result + [daveDebugByte];
|
|
If FDebugOptions and $0100 <> 0 then Result:=Result + [daveDebugCompare];
|
|
If FDebugOptions and $0200 <> 0 then Result:=Result + [daveDebugExchange];
|
|
If FDebugOptions and $0400 <> 0 then Result:=Result + [daveDebugPDU];
|
|
If FDebugOptions and $0800 <> 0 then Result:=Result + [daveDebugUpload];
|
|
If FDebugOptions and $1000 <> 0 then Result:=Result + [daveDebugMPI];
|
|
If FDebugOptions and $2000 <> 0 then Result:=Result + [daveDebugPrintErrors];
|
|
If FDebugOptions and $4000 <> 0 then Result:=Result + [daveDebugPassive];
|
|
end;
|
|
|
|
//Set the debug-options to a new value.
|
|
//~param V The new set of debug-options.
|
|
procedure TNoDave.SetDebugOptions(V: TNoDaveDebugOptions);
|
|
var
|
|
Result: Integer;
|
|
begin
|
|
Result:=0;
|
|
If daveDebugRawRead in V then Result:=Result + $0001;
|
|
If daveDebugSpecialChars in V then Result:=Result + $0002;
|
|
If daveDebugRawWrite in V then Result:=Result + $0004;
|
|
If daveDebugListReachables in V then Result:=Result + $0008;
|
|
If daveDebugInitAdapter in V then Result:=Result + $0010;
|
|
If daveDebugConnect in V then Result:=Result + $0020;
|
|
If daveDebugPacket in V then Result:=Result + $0040;
|
|
If daveDebugByte in V then Result:=Result + $0080;
|
|
If daveDebugCompare in V then Result:=Result + $0100;
|
|
If daveDebugExchange in V then Result:=Result + $0200;
|
|
If daveDebugPDU in V then Result:=Result + $0400;
|
|
If daveDebugUpload in V then Result:=Result + $0800;
|
|
If daveDebugMPI in V then Result:=Result + $1000;
|
|
If daveDebugPrintErrors in V then Result:=Result + $2000;
|
|
If daveDebugPassive in V then Result:=Result + $4000;
|
|
DoSetDebug(Result);
|
|
end;
|
|
|
|
//Read a SZL-list from the connected PLC.
|
|
//~param ID The SZL-ID of the list.
|
|
//~param Index The SZL-Index of the list.
|
|
//~result Error code for the function result, 0 if OK.
|
|
function TNoDave.ReadSZL(ID, Index: Integer): Integer;
|
|
var
|
|
WasActive: Boolean;
|
|
HeaderID: Integer;
|
|
Size, Count: Integer;
|
|
Buffer: Pointer;
|
|
begin
|
|
WasActive:=Active;
|
|
Active:=True;
|
|
FreeMem(FSZLBuffer);
|
|
FSZLBuffer:=Nil;
|
|
GetMem(Buffer, 8{000});
|
|
HeaderID:=ID; // or $0F00;
|
|
try
|
|
LockNoDave.Enter;
|
|
Count:=daveReadSZL(daveConn, HeaderID, Index, Buffer, 8);
|
|
LockNoDave.Leave;
|
|
If Count = 0 then
|
|
begin
|
|
Size:=GetWord(4, Buffer, 0, 8);
|
|
Count:=GetWord(6, Buffer, 0, 8);
|
|
GetMem(FSZLBuffer, (Size * Count) + 8);
|
|
end;
|
|
except
|
|
Result:=-1;
|
|
Exit;
|
|
end;
|
|
If Assigned(FSZLBuffer) then
|
|
begin
|
|
LockNoDave.Enter;
|
|
Result:=daveReadSZL(daveConn, ID, Index, FSZLBuffer, (Size * Count) + 8);
|
|
LockNoDave.Leave;
|
|
end;
|
|
If Result <> 0 then
|
|
begin
|
|
FreeMem(FSZLBuffer);
|
|
FSZLBuffer:=nil;
|
|
end;
|
|
FreeMem(Buffer);
|
|
Active:=WasActive;
|
|
end;
|
|
|
|
|
|
//Return the text message for an error code.
|
|
//~param Error The error code.
|
|
//~result Text message correspondig to the error code.
|
|
function TNoDave.GetErrorMsg(Error: Integer): String;
|
|
begin
|
|
Result:=daveStrerror(FLastError);
|
|
end;
|
|
|
|
//Return the count of items in the SZL buffer
|
|
//~result Actual item count.
|
|
function TNoDave.GetSZLCount: Integer;
|
|
begin
|
|
Result:=0;
|
|
try
|
|
If Assigned(FSZLBuffer) then
|
|
begin
|
|
Result:=GetWord(6, FSZLBuffer, 0, 8);
|
|
end;
|
|
except
|
|
end;
|
|
end;
|
|
|
|
//Return the size of one single item in the SZL buffer.
|
|
//~result Actual item size.
|
|
function TNoDave.GetSZLItemSize: Integer;
|
|
begin
|
|
Result:=0;
|
|
try
|
|
If Assigned(FSZLBuffer) then
|
|
begin
|
|
Result:=GetWord(4, FSZLBuffer, 0, 8);
|
|
end;
|
|
except
|
|
end;
|
|
end;
|
|
|
|
//Return a pointer to an item in the SZL buffer.
|
|
//~param Index The SZL-Index of the list.
|
|
//~result Pointer to the Item[Index].
|
|
function TNoDave.GetSZLItem(Index: Integer): Pointer;
|
|
var
|
|
BufIdx: Integer;
|
|
begin
|
|
try
|
|
If (Index >= 0) and (SZLCount > Index) then
|
|
begin
|
|
BufIdx:=(Index * SZLItemSize) + 8;
|
|
Result:=Pointer(Integer(FSZLBuffer) + BufIdx);
|
|
end;
|
|
except
|
|
Result:=Nil;
|
|
end;
|
|
end;
|
|
|
|
//Reset the NetLink-adapter via network-command
|
|
procedure TNoDave.ResetInterface;
|
|
begin
|
|
If (Protocol in [daveProtoIBH, daveProtoIBH_PPI]) and not Active then
|
|
begin
|
|
DoConnect(True);
|
|
daveResetIBH(DaveIntf);
|
|
daveFree(DaveIntf);
|
|
closePort(DaveFDS.rfd);
|
|
Sleep(5000);
|
|
end;
|
|
end;
|
|
|
|
//Return the max. datasize in a single read-request.
|
|
//~result maximal datasize.
|
|
function TNoDave.GetMaxPDUData: Integer;
|
|
begin
|
|
Result:=0;
|
|
If Assigned(DaveConn) then
|
|
begin
|
|
Result:=DaveConn^.maxPDUlength - 24;
|
|
If Protocol in [daveProtoIBH, daveProtoIBH_PPI] then Result:=220;
|
|
end;
|
|
if Result <= 0 then Result:=200;
|
|
end;
|
|
|
|
{$IFDEF FPC}
|
|
initialization
|
|
{$I nodavecomponent.lrs}
|
|
{$ENDIF}
|
|
end.
|
|
|
|
// 24.02.2005 15:15:12 [c:\programme\borland\delphi6\User\gsfexperts\NoDave\LibNoDave.pas]
|
|
// Created !
|
|
// 02.03.2005 15:57:15 [c:\programme\borland\delphi6\User\gsfexperts\NoDave\LibNoDave.pas]
|
|
// Cyclic reading implemented in an own thread.
|
|
// 13.04.2005 16:47:25 [c:\programme\borland\delphi6\User\gsfexperts\NoDave\LibNoDave.pas]
|
|
// DelphiDoc - comments added.
|
|
// 02.05.2005 11:47:36 [c:\programme\borland\delphi6\user\gsfexperts\nodave\LibNoDave.pas]
|
|
// Property for the debug-options added.
|
|
// 03.05.2005 08:59:45 [c:\programme\borland\delphi6\user\gsfexperts\nodave\nodavecomponent.pas]
|
|
// Compatibility with FreePascal/Lazarus implemented and renamed to nodavecomponent.
|
|
// 22.09.2005 09:05:19 [c:\programme\borland\delphi6\user\gsfexperts\nodave\NoDaveComponent.pas]
|
|
// BugFixes in TNoDave.ReadBytes and TNoDave.WriteBytes.
|
|
// 22.09.2005 09:16:15 [c:\programme\borland\delphi6\user\gsfexperts\nodave\NoDaveComponent.pas]
|
|
// Closing the serial port or the socket and cleaning up memory used by libnodave in TNoDave.Disconnect now.
|
|
// 24.10.2005 08:15:29 [c:\programme\borland\delphi6\User\gsfexperts\NoDave\NoDaveComponent.pas]
|
|
// Handle = 0 for daveProtoS7Online allowed.
|
|
// 28.11.2005 10:37:45 [c:\programme\borland\delphi6\user\gsfexperts\nodave\NoDaveComponent.pas]
|
|
// Function for reading of SZL-lists added.
|
|
// 02.12.2005 09:21:42 [c:\programme\borland\delphi6\user\gsfexperts\nodave\NoDaveComponent.pas]
|
|
// Usage of daveReadManyBytes implemented.
|
|
// 06.12.2005 18:25:20 [c:\programme\borland\delphi6\user\gsfexperts\nodave\NoDaveComponent.pas]
|
|
// Changed private functions DoOnRead and DoOnWrite.
|
|
// 21.02.2006 18:18:50 [c:\programme\borland\delphi6\user\gsfexperts\nodave\NoDaveComponent.pas]
|
|
// Procedure TNoDave.ResetInterface implemented.
|
|
// 21.02.2006 19:44:04 [c:\programme\borland\delphi6\user\gsfexperts\nodave\NoDaveComponent.pas]
|
|
// Added function TNoDave.MaxPDUData.
|
|
// 27.10.2006 09:21:43 [C:\Programme\Borland\BDS\User\GsfExperts\NoDave\NoDaveComponent.pas]
|
|
// Bugfix in TNoDaveReadThread.Execute. Thanks to Jose for the hint !
|
|
// 20.12.2006 09:19:09 [C:\Programme\Borland\BDS\User\GsfExperts\NoDave\NoDaveComponent.pas]
|
|
// Using a windows-handle in OpenS7Online.
|