From bc91dc1ae237f1933f7b331b3c2345b64a5490e7 Mon Sep 17 00:00:00 2001 From: Forsworns <378974295@qq.com> Date: Thu, 13 Jan 2022 10:59:23 +0800 Subject: [PATCH] migrate s7 --- .../Applications/control_app/Makefile | 4 + .../Applications/control_app/s7_demo/Makefile | 3 + .../control_app/s7_demo/s7_demo.cpp | 82 + .../control/plc/interoperability/Kconfig | 4 + .../control/plc/interoperability/Makefile | 4 + .../control/plc/interoperability/s7/Makefile | 3 + .../plc/interoperability/s7/s7_client.cpp | 503 +++ .../plc/interoperability/s7/s7_client.h | 104 + .../plc/interoperability/s7/s7_firmware.h | 1256 +++++++ .../plc/interoperability/s7/s7_isotcp.cpp | 549 +++ .../plc/interoperability/s7/s7_isotcp.h | 271 ++ .../interoperability/s7/s7_micro_client.cpp | 3328 +++++++++++++++++ .../plc/interoperability/s7/s7_micro_client.h | 364 ++ .../plc/interoperability/s7/s7_peer.cpp | 122 + .../control/plc/interoperability/s7/s7_peer.h | 58 + .../plc/interoperability/s7/s7_text.cpp | 279 ++ .../control/plc/interoperability/s7/s7_text.h | 44 + .../plc/interoperability/s7/s7_types.h | 1062 ++++++ .../plc/interoperability/s7/snap7_libmain.cpp | 917 +++++ .../plc/interoperability/s7/snap7_libmain.h | 170 + .../plc/interoperability/s7/snap_msgsock.cpp | 786 ++++ .../plc/interoperability/s7/snap_msgsock.h | 308 ++ .../plc/interoperability/s7/snap_platform.h | 68 + .../plc/interoperability/s7/snap_sysutils.cpp | 48 + .../plc/interoperability/s7/snap_sysutils.h | 36 + .../plc/interoperability/s7/snap_threads.cpp | 125 + .../plc/interoperability/s7/snap_threads.h | 222 ++ .../transform_layer/rtthread/transform.c | 5 + .../transform_layer/rtthread/transform.h | 1 + .../transform_layer/xiuos/transform.c | 5 + .../transform_layer/xiuos/transform.h | 1 + .../ethernet/LwIP/include/lwip/sockets.h | 2 + 32 files changed, 10734 insertions(+) create mode 100644 APP_Framework/Applications/control_app/s7_demo/Makefile create mode 100644 APP_Framework/Applications/control_app/s7_demo/s7_demo.cpp create mode 100644 APP_Framework/Framework/control/plc/interoperability/s7/Makefile create mode 100644 APP_Framework/Framework/control/plc/interoperability/s7/s7_client.cpp create mode 100644 APP_Framework/Framework/control/plc/interoperability/s7/s7_client.h create mode 100644 APP_Framework/Framework/control/plc/interoperability/s7/s7_firmware.h create mode 100644 APP_Framework/Framework/control/plc/interoperability/s7/s7_isotcp.cpp create mode 100644 APP_Framework/Framework/control/plc/interoperability/s7/s7_isotcp.h create mode 100644 APP_Framework/Framework/control/plc/interoperability/s7/s7_micro_client.cpp create mode 100644 APP_Framework/Framework/control/plc/interoperability/s7/s7_micro_client.h create mode 100644 APP_Framework/Framework/control/plc/interoperability/s7/s7_peer.cpp create mode 100644 APP_Framework/Framework/control/plc/interoperability/s7/s7_peer.h create mode 100644 APP_Framework/Framework/control/plc/interoperability/s7/s7_text.cpp create mode 100644 APP_Framework/Framework/control/plc/interoperability/s7/s7_text.h create mode 100644 APP_Framework/Framework/control/plc/interoperability/s7/s7_types.h create mode 100644 APP_Framework/Framework/control/plc/interoperability/s7/snap7_libmain.cpp create mode 100644 APP_Framework/Framework/control/plc/interoperability/s7/snap7_libmain.h create mode 100644 APP_Framework/Framework/control/plc/interoperability/s7/snap_msgsock.cpp create mode 100644 APP_Framework/Framework/control/plc/interoperability/s7/snap_msgsock.h create mode 100644 APP_Framework/Framework/control/plc/interoperability/s7/snap_platform.h create mode 100644 APP_Framework/Framework/control/plc/interoperability/s7/snap_sysutils.cpp create mode 100644 APP_Framework/Framework/control/plc/interoperability/s7/snap_sysutils.h create mode 100644 APP_Framework/Framework/control/plc/interoperability/s7/snap_threads.cpp create mode 100644 APP_Framework/Framework/control/plc/interoperability/s7/snap_threads.h diff --git a/APP_Framework/Applications/control_app/Makefile b/APP_Framework/Applications/control_app/Makefile index e321906d1..fa20f4a2f 100755 --- a/APP_Framework/Applications/control_app/Makefile +++ b/APP_Framework/Applications/control_app/Makefile @@ -6,6 +6,10 @@ ifeq ($(CONFIG_USING_CONTROL_PLC_OPCUA), y) SRC_DIR += opcua_demo endif +ifeq ($(CONFIG_USING_CONTROL_PLC_S7), y) + SRC_DIR += s7_demo +endif + endif include $(KERNEL_ROOT)/compiler.mk diff --git a/APP_Framework/Applications/control_app/s7_demo/Makefile b/APP_Framework/Applications/control_app/s7_demo/Makefile new file mode 100644 index 000000000..9c6cf516b --- /dev/null +++ b/APP_Framework/Applications/control_app/s7_demo/Makefile @@ -0,0 +1,3 @@ +SRC_FILES :=s7_demo.c + +include $(KERNEL_ROOT)/compiler.mk diff --git a/APP_Framework/Applications/control_app/s7_demo/s7_demo.cpp b/APP_Framework/Applications/control_app/s7_demo/s7_demo.cpp new file mode 100644 index 000000000..a262d15e3 --- /dev/null +++ b/APP_Framework/Applications/control_app/s7_demo/s7_demo.cpp @@ -0,0 +1,82 @@ +#include "snap7_libmain.h" + +static S7Object Client; +static unsigned char Buffer[65536]; // 64 K buffer + +static char Address[20]="192.168.250.8"; // PLC IP Address +static int Rack = 0, Slot = 1; // Default Rack and Slot +static int Area = S7AreaDB, DBNumber = 13, Start = 0, Amount = 4, WordLen = S7WLByte; // Default Rack and Slot +static int bRead = 1; // By default read +static int bWrite = 0; // By default not write + + + +//------------------------------------------------------------------------------ +// Unit Connection +//------------------------------------------------------------------------------ +static int CliConnect() +{ + int Requested, Negotiated, res; + + res = Cli_ConnectTo(Client, Address, Rack, Slot); + if (Check(Client, res, "UNIT Connection")) + { + Cli_GetPduLength(Client, Requested, Negotiated); + printf(" Connected to : %s (Rack=%d, Slot=%d)\n", Address, Rack, Slot); + printf(" PDU Requested : %d bytes\n", Requested); + printf(" PDU Negotiated : %d bytes\n", Negotiated); + }; + return !res; +} +//------------------------------------------------------------------------------ +// Unit Disconnection +//------------------------------------------------------------------------------ +static void CliDisconnect() +{ + Cli_Disconnect(Client); +} + +//------------------------------------------------------------------------------ +// Perform tasks +//------------------------------------------------------------------------------ +void PerformTasks() +{ + while(true){ + if(bWrite){ + memset(Buffer, 0, sizeof(Buffer)); + Buffer[0] = 0x01; + Buffer[3] = 0x14; + Cli_WriteAndDump(Client, Area, DBNumber, Start, Amount, WordLen, Buffer, "write DB"); + sleep(29); + } + if(bRead){ + Cli_ReadAndDump(Client, Area, DBNumber, Start, Amount, WordLen, Buffer, "read DB"); + sleep(1); + } + if(bWrite){ + memset(Buffer, 0, sizeof(Buffer)); + Cli_WriteAndDump(Client, Area, DBNumber, Start, Amount, WordLen, Buffer, "write DB"); + sleep(29); + } + if(bRead){ + Cli_ReadAndDump(Client, Area, DBNumber, Start, Amount, WordLen, Buffer, "read DB"); + sleep(1); + } + } +} + +void s7_demo() +{ + // Client Creation + Client = Cli_Create(); + + // Connection + if (CliConnect()) + { + PerformTasks(); + CliDisconnect(); + }; + + // Deletion + Cli_Destroy(Client); +} diff --git a/APP_Framework/Framework/control/plc/interoperability/Kconfig b/APP_Framework/Framework/control/plc/interoperability/Kconfig index 66ae5f182..06bfac62a 100755 --- a/APP_Framework/Framework/control/plc/interoperability/Kconfig +++ b/APP_Framework/Framework/control/plc/interoperability/Kconfig @@ -4,3 +4,7 @@ menuconfig USING_CONTROL_PLC_OPCUA default y depends on RESOURCES_LWIP +menuconfig CONFIG_USING_CONTROL_PLC_S7 + bool "PLC support S7" + default y + depends on RESOURCES_LWIP \ No newline at end of file diff --git a/APP_Framework/Framework/control/plc/interoperability/Makefile b/APP_Framework/Framework/control/plc/interoperability/Makefile index 7f542f711..d781443e4 100755 --- a/APP_Framework/Framework/control/plc/interoperability/Makefile +++ b/APP_Framework/Framework/control/plc/interoperability/Makefile @@ -6,6 +6,10 @@ ifeq ($(CONFIG_USING_CONTROL_PLC_OPCUA), y) SRC_DIR += opcua endif +ifeq ($(CONFIG_USING_CONTROL_PLC_S7), y) + SRC_DIR += s7 +endif + endif SRC_FILES += interoperability.c diff --git a/APP_Framework/Framework/control/plc/interoperability/s7/Makefile b/APP_Framework/Framework/control/plc/interoperability/s7/Makefile new file mode 100644 index 000000000..cc36d59ae --- /dev/null +++ b/APP_Framework/Framework/control/plc/interoperability/s7/Makefile @@ -0,0 +1,3 @@ +SRC_FILES := s7_client.cpp s7_isotcp.cpp s7_micro_client.cpp s7_peer.cpp s7_text.cpp snap_msgsock.cpp snap_sysutils.cpp snap_threads.cpp snap_libmain.cpp + +include $(KERNEL_ROOT)/compiler.mk diff --git a/APP_Framework/Framework/control/plc/interoperability/s7/s7_client.cpp b/APP_Framework/Framework/control/plc/interoperability/s7/s7_client.cpp new file mode 100644 index 000000000..c67e50c3e --- /dev/null +++ b/APP_Framework/Framework/control/plc/interoperability/s7/s7_client.cpp @@ -0,0 +1,503 @@ +/*=============================================================================| +| PROJECT SNAP7 1.3.0 | +|==============================================================================| +| Copyright (C) 2013, 2015 Davide Nardella | +| All rights reserved. | +|==============================================================================| +| SNAP7 is free software: you can redistribute it and/or modify | +| it under the terms of the Lesser GNU General Public License as published by | +| the Free Software Foundation, either version 3 of the License, or | +| (at your option) any later version. | +| | +| It means that you can distribute your commercial software linked with | +| SNAP7 without the requirement to distribute the source code of your | +| application and without the requirement that your application be itself | +| distributed under LGPL. | +| | +| SNAP7 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 | +| Lesser GNU General Public License for more details. | +| | +| You should have received a copy of the GNU General Public License and a | +| copy of Lesser GNU General Public License along with Snap7. | +| If not, see http://www.gnu.org/licenses/ | +|=============================================================================*/ +#include "s7_client.h" + +//--------------------------------------------------------------------------- +TSnap7Client::TSnap7Client() +{ + FThread = 0; + CliCompletion = 0; + EvtJob = NULL; + EvtComplete = NULL; + FThread=NULL; + ThreadCreated = false; +} +//--------------------------------------------------------------------------- +TSnap7Client::~TSnap7Client() +{ + Destroying=true; + Disconnect(); + CliCompletion=NULL; + if (ThreadCreated) + { + CloseThread(); + delete EvtComplete; + delete EvtJob; + ThreadCreated=false; + } +} +//--------------------------------------------------------------------------- +void TSnap7Client::CloseThread() +{ + int Timeout; + + if (FThread) + { + FThread->Terminate(); + if (Job.Pending) + Timeout=3000; + else + Timeout=1000; + EvtJob->Set(); + if (FThread->WaitFor(Timeout)!=WAIT_OBJECT_0) + FThread->Kill(); + try { + delete FThread; + } + catch (...){ + } + + FThread=0; + } +} +//--------------------------------------------------------------------------- +void TSnap7Client::OpenThread() +{ + FThread = new TClientThread(this); + FThread->Start(); +} +//--------------------------------------------------------------------------- +int TSnap7Client::Reset(bool DoReconnect) +{ + bool WasConnected = Connected; + if (ThreadCreated) + { + CloseThread(); + Disconnect(); + OpenThread(); + } + else + Disconnect(); + + if (DoReconnect || WasConnected) + return Connect(); + else + return 0; +} +//--------------------------------------------------------------------------- +void TSnap7Client::DoCompletion() +{ + if ((CliCompletion!=NULL) && !Destroying) + { + try{ + CliCompletion(FUsrPtr, Job.Op, Job.Result); + }catch (...) + { + } + } +} +//--------------------------------------------------------------------------- +int TSnap7Client::SetAsCallback(pfn_CliCompletion pCompletion, void * usrPtr) +{ + CliCompletion=pCompletion; + FUsrPtr=usrPtr; + return 0; +} +//--------------------------------------------------------------------------- +int TSnap7Client::GetParam(int ParamNumber, void * pValue) +{ + // Actually there are no specific client params, maybe in future... + return TSnap7MicroClient::GetParam(ParamNumber, pValue); +} +//--------------------------------------------------------------------------- +int TSnap7Client::SetParam(int ParamNumber, void * pValue) +{ + // Actually there are no specific client params, maybe in future... + return TSnap7MicroClient::SetParam(ParamNumber, pValue); +} +//--------------------------------------------------------------------------- +bool TSnap7Client::CheckAsCompletion(int &opResult) +{ + if (!Job.Pending) + opResult=Job.Result; + else + if (!Destroying) + opResult=errCliJobPending; // don't set LastError here + else + { + opResult=errCliDestroying; + return true; + } + + return !Job.Pending; +} +//--------------------------------------------------------------------------- +int TSnap7Client::AsReadArea(int Area, int DBNumber, int Start, int Amount, int WordLen, void * pUsrData) +{ + if (!Job.Pending) + { + Job.Pending = true; + Job.Op = s7opReadArea; + Job.Area = Area; + Job.Number = DBNumber; + Job.Start = Start; + Job.Amount = Amount; + Job.WordLen = WordLen; + Job.pData = pUsrData; + JobStart = SysGetTick(); + StartAsyncJob(); + return 0; + } + else + return SetError(errCliJobPending); +} +//--------------------------------------------------------------------------- +int TSnap7Client::AsWriteArea(int Area, int DBNumber, int Start, int Amount, int WordLen, void * pUsrData) +{ + int ByteSize, TotalSize; + + if (!Job.Pending) + { + Job.Pending =true; + Job.Op =s7opWriteArea; + Job.Area =Area; + Job.Number =DBNumber; + Job.Start =Start; + // Performs some check first to copy the data + ByteSize=DataSizeByte(WordLen); + TotalSize=ByteSize*Amount; // Total size in bytes + if (ByteSize==0) + return SetError(errCliInvalidWordLen); + if ((TotalSize < 1) || (TotalSize > int(sizeof(opData)))) + return SetError(errCliInvalidParams); + Job.Amount =Amount; + Job.WordLen =WordLen; + // Doublebuffering + memcpy(&opData, pUsrData, TotalSize); + Job.pData =&opData; + JobStart =SysGetTick(); + StartAsyncJob(); + return 0; + } + else + return SetError(errCliJobPending); +} +//--------------------------------------------------------------------------- +int TSnap7Client::AsListBlocksOfType(int BlockType, PS7BlocksOfType pUsrData, int & ItemsCount) +{ + if (!Job.Pending) + { + Job.Pending =true; + Job.Op =s7opListBlocksOfType; + Job.Area =BlockType; + Job.pData =pUsrData; + Job.pAmount =&ItemsCount; + JobStart =SysGetTick(); + StartAsyncJob(); + return 0; + } + else + return SetError(errCliJobPending); +} +//--------------------------------------------------------------------------- +int TSnap7Client::AsReadSZL(int ID, int Index, PS7SZL pUsrData, int & Size) +{ + if (!Job.Pending) + { + Job.Pending =true; + Job.Op =s7opReadSZL; + Job.ID =ID; + Job.Index =Index; + Job.pData =pUsrData; + Job.pAmount =&Size; + Job.Amount =Size; + Job.IParam =1; // Data has to be copied into user buffer + JobStart =SysGetTick(); + StartAsyncJob(); + return 0; + } + else + return SetError(errCliJobPending); +} +//--------------------------------------------------------------------------- +int TSnap7Client::AsReadSZLList(PS7SZLList pUsrData, int &ItemsCount) +{ + if (!Job.Pending) + { + Job.Pending =true; + Job.Op =s7opReadSzlList; + Job.pData =pUsrData; + Job.pAmount =&ItemsCount; + Job.Amount =ItemsCount; + JobStart =SysGetTick(); + StartAsyncJob(); + return 0; + } + else + return SetError(errCliJobPending); +} +//--------------------------------------------------------------------------- +int TSnap7Client::AsUpload(int BlockType, int BlockNum, void * pUsrData, int & Size) +{ + if (!Job.Pending) + { + Job.Pending =true; + Job.Op =s7opUpload; + Job.Area =BlockType; + Job.pData =pUsrData; + Job.pAmount =&Size; + Job.Amount =Size; + Job.Number =BlockNum; + Job.IParam =0; // not full upload, only data + JobStart =SysGetTick(); + StartAsyncJob(); + return 0; + } + else + return SetError(errCliJobPending); +} +//--------------------------------------------------------------------------- +int TSnap7Client::AsFullUpload(int BlockType, int BlockNum, void * pUsrData, int & Size) +{ + if (!Job.Pending) + { + Job.Pending =true; + Job.Op =s7opUpload; + Job.Area =BlockType; + Job.pData =pUsrData; + Job.pAmount =&Size; + Job.Amount =Size; + Job.Number =BlockNum; + Job.IParam =1; // full upload + JobStart =SysGetTick(); + StartAsyncJob(); + return 0; + } + else + return SetError(errCliJobPending); +} +//--------------------------------------------------------------------------- +int TSnap7Client::AsDownload(int BlockNum, void * pUsrData, int Size) +{ + if (!Job.Pending) + { + // Checks the size : here we only need a size>0 to avoid problems during + // doublebuffering, the real test of the block size will be done in + // Checkblock. + if (Size<1) + return SetError(errCliInvalidBlockSize); + Job.Pending =true; + Job.Op =s7opDownload; + // Doublebuffering + memcpy(&opData, pUsrData, Size); + Job.Number =BlockNum; + Job.Amount =Size; + JobStart =SysGetTick(); + StartAsyncJob(); + return 0; + } + else + return SetError(errCliJobPending); +} +//--------------------------------------------------------------------------- +int TSnap7Client::AsCopyRamToRom(int Timeout) +{ + if (!Job.Pending) + { + Job.Pending =true; + Job.Op =s7opCopyRamToRom; + if (Timeout>0) + { + Job.IParam =Timeout; + JobStart =SysGetTick(); + StartAsyncJob(); + return 0; + } + else + return SetError(errCliInvalidParams); + } + else + return SetError(errCliJobPending); +} +//--------------------------------------------------------------------------- +int TSnap7Client::AsCompress(int Timeout) +{ + if (!Job.Pending) + { + Job.Pending =true; + Job.Op =s7opCompress; + if (Timeout>0) + { + Job.IParam =Timeout; + JobStart =SysGetTick(); + StartAsyncJob(); + return 0; + } + else + return SetError(errCliInvalidParams); + } + else + return SetError(errCliJobPending); +} +//--------------------------------------------------------------------------- +int TSnap7Client::AsDBRead(int DBNumber, int Start, int Size, void * pUsrData) +{ + return AsReadArea(S7AreaDB, DBNumber, Start, Size, S7WLByte, pUsrData); +} +//--------------------------------------------------------------------------- +int TSnap7Client::AsDBWrite(int DBNumber, int Start, int Size, void * pUsrData) +{ + return AsWriteArea(S7AreaDB, DBNumber, Start, Size, S7WLByte, pUsrData); +} +//--------------------------------------------------------------------------- +int TSnap7Client::AsMBRead(int Start, int Size, void * pUsrData) +{ + return AsReadArea(S7AreaMK, 0, Start, Size, S7WLByte, pUsrData); +} +//--------------------------------------------------------------------------- +int TSnap7Client::AsMBWrite(int Start, int Size, void * pUsrData) +{ + return AsWriteArea(S7AreaMK, 0, Start, Size, S7WLByte, pUsrData); +} +//--------------------------------------------------------------------------- +int TSnap7Client::AsEBRead(int Start, int Size, void * pUsrData) +{ + return AsReadArea(S7AreaPE, 0, Start, Size, S7WLByte, pUsrData); +} +//--------------------------------------------------------------------------- +int TSnap7Client::AsEBWrite(int Start, int Size, void * pUsrData) +{ + return AsWriteArea(S7AreaPE, 0, Start, Size, S7WLByte, pUsrData); +} +//--------------------------------------------------------------------------- +int TSnap7Client::AsABRead(int Start, int Size, void * pUsrData) +{ + return AsReadArea(S7AreaPA, 0, Start, Size, S7WLByte, pUsrData); +} +//--------------------------------------------------------------------------- +int TSnap7Client::AsABWrite(int Start, int Size, void * pUsrData) +{ + return AsWriteArea(S7AreaPA, 0, Start, Size, S7WLByte, pUsrData); +} +//--------------------------------------------------------------------------- +int TSnap7Client::AsTMRead(int Start, int Amount, void * pUsrData) +{ + return AsReadArea(S7AreaTM, 0, Start, Amount, S7WLTimer, pUsrData); +} +//--------------------------------------------------------------------------- +int TSnap7Client::AsTMWrite(int Start, int Amount, void * pUsrData) +{ + return AsWriteArea(S7AreaTM, 0, Start, Amount, S7WLTimer, pUsrData); +} +//--------------------------------------------------------------------------- +int TSnap7Client::AsCTRead(int Start, int Amount, void * pUsrData) +{ + return AsReadArea(S7AreaCT, 0, Start, Amount, S7WLCounter, pUsrData); +} +//--------------------------------------------------------------------------- +int TSnap7Client::AsCTWrite(int Start, int Amount, void * pUsrData) +{ + return AsWriteArea(S7AreaCT, 0, Start, Amount, S7WLCounter, pUsrData); +} +//--------------------------------------------------------------------------- +int TSnap7Client::AsDBGet(int DBNumber, void * pUsrData, int &Size) +{ + if (!Job.Pending) + { + if (Size<=0) + return SetError(errCliInvalidBlockSize); + Job.Pending =true; + Job.Op =s7opDBGet; + Job.Number =DBNumber; + Job.pData =pUsrData; + Job.pAmount =&Size; + Job.Amount =Size; + JobStart =SysGetTick(); + StartAsyncJob(); + return 0; + } + else + return SetError(errCliJobPending); +} +//--------------------------------------------------------------------------- +int TSnap7Client::AsDBFill(int DBNumber, int FillChar) +{ + if (!Job.Pending) + { + Job.Pending =true; + Job.Op =s7opDBFill; + Job.Number =DBNumber; + Job.IParam =FillChar; + JobStart =SysGetTick(); + StartAsyncJob(); + return 0; + } + else + return SetError(errCliJobPending); +} +//--------------------------------------------------------------------------- +void TSnap7Client::StartAsyncJob() +{ + ClrError(); + if (!ThreadCreated) + { + EvtJob = new TSnapEvent(false); + EvtComplete = new TSnapEvent(false); + OpenThread(); + ThreadCreated=true; + } + EvtComplete->Reset(); // reset if previously was not called WaitAsCompletion + EvtJob->Set(); +} +//--------------------------------------------------------------------------- +int TSnap7Client::WaitAsCompletion(unsigned long Timeout) +{ + if (Job.Pending) + { + if (ThreadCreated) + { + if (EvtComplete->WaitFor(Timeout)==WAIT_OBJECT_0) + return Job.Result; + else + { + if (Destroying) + return errCliDestroying; + else + return SetError(errCliJobTimeout); + } + } + else + return SetError(errCliJobTimeout); + } + else + return Job.Result; +} +//--------------------------------------------------------------------------- +void TClientThread::Execute() +{ + while (!Terminated) + { + FClient->EvtJob->WaitForever(); + if (!Terminated) + { + FClient->PerformOperation(); + FClient->EvtComplete->Set(); + // Notify the caller the end of job (if callback is set) + FClient->DoCompletion(); + } + }; +} + diff --git a/APP_Framework/Framework/control/plc/interoperability/s7/s7_client.h b/APP_Framework/Framework/control/plc/interoperability/s7/s7_client.h new file mode 100644 index 000000000..2cd4fe7a9 --- /dev/null +++ b/APP_Framework/Framework/control/plc/interoperability/s7/s7_client.h @@ -0,0 +1,104 @@ +/*=============================================================================| +| PROJECT SNAP7 1.3.0 | +|==============================================================================| +| Copyright (C) 2013, 2015 Davide Nardella | +| All rights reserved. | +|==============================================================================| +| SNAP7 is free software: you can redistribute it and/or modify | +| it under the terms of the Lesser GNU General Public License as published by | +| the Free Software Foundation, either version 3 of the License, or | +| (at your option) any later version. | +| | +| It means that you can distribute your commercial software linked with | +| SNAP7 without the requirement to distribute the source code of your | +| application and without the requirement that your application be itself | +| distributed under LGPL. | +| | +| SNAP7 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 | +| Lesser GNU General Public License for more details. | +| | +| You should have received a copy of the GNU General Public License and a | +| copy of Lesser GNU General Public License along with Snap7. | +| If not, see http://www.gnu.org/licenses/ | +|=============================================================================*/ +#ifndef s7_client_h +#define s7_client_h +//--------------------------------------------------------------------------- +#include "snap_threads.h" +#include "s7_micro_client.h" +//--------------------------------------------------------------------------- + +extern "C" { +typedef void (S7API *pfn_CliCompletion) (void * usrPtr, int opCode, int opResult); +} +class TSnap7Client; + +class TClientThread: public TSnapThread +{ +private: + TSnap7Client * FClient; +public: + TClientThread(TSnap7Client *Client) + { + FClient = Client; + } + void Execute(); +}; +//--------------------------------------------------------------------------- +class TSnap7Client: public TSnap7MicroClient +{ +private: + TClientThread *FThread; + bool ThreadCreated; + void CloseThread(); + void OpenThread(); + void StartAsyncJob(); +protected: + PSnapEvent EvtJob; + PSnapEvent EvtComplete; + pfn_CliCompletion CliCompletion; + void *FUsrPtr; + void DoCompletion(); +public: + friend class TClientThread; + TSnap7Client(); + ~TSnap7Client(); + int Reset(bool DoReconnect); + int SetAsCallback(pfn_CliCompletion pCompletion, void * usrPtr); + int GetParam(int ParamNumber, void *pValue); + int SetParam(int ParamNumber, void *pValue); + // Async functions + bool CheckAsCompletion( int & opResult); + int WaitAsCompletion(unsigned long Timeout); + int AsReadArea(int Area, int DBNumber, int Start, int Amount, int WordLen, void * pUsrData); + int AsWriteArea(int Area, int DBNumber, int Start, int Amount, int WordLen, void * pUsrData); + int AsListBlocksOfType(int BlockType, PS7BlocksOfType pUsrData, int & ItemsCount); + int AsReadSZL(int ID, int Index, PS7SZL pUsrData, int & Size); + int AsReadSZLList(PS7SZLList pUsrData, int &ItemsCount); + int AsUpload(int BlockType, int BlockNum, void * pUsrData, int & Size); + int AsFullUpload(int BlockType, int BlockNum, void * pUsrData, int & Size); + int AsDownload(int BlockNum, void * pUsrData, int Size); + int AsCopyRamToRom(int Timeout); + int AsCompress(int Timeout); + int AsDBRead(int DBNumber, int Start, int Size, void * pUsrData); + int AsDBWrite(int DBNumber, int Start, int Size, void * pUsrData); + int AsMBRead(int Start, int Size, void * pUsrData); + int AsMBWrite(int Start, int Size, void * pUsrData); + int AsEBRead(int Start, int Size, void * pUsrData); + int AsEBWrite(int Start, int Size, void * pUsrData); + int AsABRead(int Start, int Size, void * pUsrData); + int AsABWrite(int Start, int Size, void * pUsrData); + int AsTMRead(int Start, int Amount, void * pUsrData); + int AsTMWrite(int Start, int Amount, void * pUsrData); + int AsCTRead(int Start, int Amount, void * pUsrData); + int AsCTWrite(int Start, int Amount, void * pUsrData); + int AsDBGet(int DBNumber, void * pUsrData, int & Size); + int AsDBFill(int DBNumber, int FillChar); +}; + +typedef TSnap7Client *PSnap7Client; + +//--------------------------------------------------------------------------- +#endif // s7_client_h diff --git a/APP_Framework/Framework/control/plc/interoperability/s7/s7_firmware.h b/APP_Framework/Framework/control/plc/interoperability/s7/s7_firmware.h new file mode 100644 index 000000000..e1c431e64 --- /dev/null +++ b/APP_Framework/Framework/control/plc/interoperability/s7/s7_firmware.h @@ -0,0 +1,1256 @@ +/*=============================================================================| +| PROJECT SNAP7 1.3.0 | +|==============================================================================| +| Copyright (C) 2013, 2015 Davide Nardella | +| All rights reserved. | +|==============================================================================| +| SNAP7 is free software: you can redistribute it and/or modify | +| it under the terms of the Lesser GNU General Public License as published by | +| the Free Software Foundation, either version 3 of the License, or | +| (at your option) any later version. | +| | +| It means that you can distribute your commercial software linked with | +| SNAP7 without the requirement to distribute the source code of your | +| application and without the requirement that your application be itself | +| distributed under LGPL. | +| | +| SNAP7 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 | +| Lesser GNU General Public License for more details. | +| | +| You should have received a copy of the GNU General Public License and a | +| copy of Lesser GNU General Public License along with Snap7. | +| If not, see http://www.gnu.org/licenses/ | +|=============================================================================*/ +#ifndef s7_firmware_h +#define s7_firmware_h +//--------------------------------------------------------------------------- + +#include "snap_platform.h" + +//****************************************************************************** +// CPU DATABANK +//****************************************************************************** + + byte SZLNotAvail[4] = { + 0x0A,0x00,0x00,0x00 + }; + + byte SZLSysState[6] = { + 0xFF,0x09,0x00,0x02,0x02,0x00 + }; + + byte SZL_ID_0000_IDX_XXXX[236] = { + 0xFF,0x09,0x00,0xE8,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x70,0x00,0x00,0x0F,0x00,0x00,0x02,0x00, + 0x11,0x01,0x11,0x0F,0x11,0x00,0x12,0x01,0x12,0x0F,0x12,0x00,0x13,0x01,0x13,0x00,0x14,0x0F,0x14, + 0x00,0x15,0x01,0x15,0x00,0x17,0x01,0x17,0x0F,0x17,0x00,0x18,0x01,0x18,0x0F,0x18,0x00,0x19,0x0F, + 0x19,0x00,0x1A,0x0F,0x1A,0x00,0x1B,0x0F,0x1B,0x00,0x1C,0x01,0x1C,0x0F,0x1C,0x00,0x21,0x0A,0x21, + 0x0F,0x21,0x02,0x22,0x00,0x23,0x0F,0x23,0x00,0x24,0x01,0x24,0x04,0x24,0x05,0x24,0x00,0x25,0x01, + 0x25,0x02,0x25,0x0F,0x25,0x01,0x31,0x01,0x32,0x02,0x32,0x00,0x36,0x01,0x36,0x0F,0x36,0x00,0x37, + 0x01,0x37,0x0F,0x37,0x00,0x38,0x01,0x38,0x02,0x38,0x0F,0x38,0x01,0x39,0x00,0x3A,0x0F,0x3A,0x00, + 0x74,0x01,0x74,0x0F,0x74,0x05,0x91,0x0A,0x91,0x0C,0x91,0x0D,0x91,0x00,0x92,0x02,0x92,0x06,0x92, + 0x0F,0x92,0x00,0x94,0x01,0x94,0x02,0x94,0x06,0x94,0x07,0x94,0x0F,0x94,0x00,0x95,0x01,0x95,0x0F, + 0x95,0x06,0x96,0x0C,0x96,0x0C,0x97,0x0D,0x97,0x01,0x9A,0x02,0x9A,0x0F,0x9A,0x0C,0x9B,0x00,0x9C, + 0x01,0x9C,0x02,0x9C,0x03,0x9C,0x0F,0x9C,0x00,0xA0,0x01,0xA0,0x0F,0xA0,0x00,0xB1,0x00,0xB2,0x00, + 0xB3,0x00,0xB4,0x01,0xB5,0x02,0xB5,0x03,0xB5,0x04,0xB5,0x05,0xB5,0x06,0xB5,0x07,0xB5,0x08,0xB5, + 0x01,0xB6,0x02,0xB6,0x03,0xB6,0x04,0xB6 + }; + + byte SZL_ID_0F00_IDX_XXXX[12] = { + 0xFF,0x09,0x00,0x08,0x0F,0x00,0x00,0x00,0x00,0x02,0x00,0x70 + }; + + byte SZL_ID_0002_IDX_XXXX[458] = { // <--Wrapped to 458 bytes + 0xFF,0x09,0x01,0xC6,0x00,0x02,0x00,0x00,0x00,0x08,0x00,0x71,0x01,0xAC,0x00,0x01,0x00,0x28,0x00, + 0x1C,0x01,0xAC,0x24,0x00,0x00,0x24,0x00,0x00,0x01,0xAC,0x23,0x00,0x00,0x06,0x04,0xB0,0x01,0xAC, + 0x22,0x00,0x00,0x08,0x00,0x01,0x01,0xAC,0x31,0x00,0x04,0x00,0x00,0x01,0x01,0xAC,0x12,0xFF,0x00, + 0x08,0x00,0x01,0x01,0xAC,0x12,0x31,0x00,0x08,0x00,0x01,0x01,0xAD,0x00,0x00,0x80,0x00,0x00,0x01, + 0x01,0xAD,0x01,0x00,0x80,0x00,0x00,0x01,0x01,0xAD,0x02,0x00,0x80,0x00,0x00,0x01,0x01,0xAD,0x03, + 0x00,0x80,0x00,0x00,0x01,0x01,0xAD,0x04,0x00,0x80,0x00,0x00,0x01,0x01,0xAD,0x05,0x00,0x80,0x00, + 0x00,0x01,0x01,0xAD,0x06,0x00,0x80,0x00,0x00,0x01,0x01,0xAD,0x07,0x00,0x80,0x00,0x00,0x01,0x01, + 0xAD,0x00,0x01,0x80,0x00,0x00,0x01,0x01,0xAD,0x01,0x01,0x80,0x00,0x00,0x01,0x01,0xAD,0x02,0x01, + 0x80,0x00,0x00,0x01,0x01,0xAD,0x03,0x01,0x80,0x00,0x00,0x01,0x01,0xAD,0x04,0x01,0x80,0x00,0x00, + 0x01,0x01,0xAD,0x05,0x01,0x80,0x00,0x00,0x01,0x01,0xAD,0x06,0x01,0x80,0x00,0x00,0x01,0x01,0xAD, + 0x07,0x01,0x80,0x00,0x00,0x01,0x01,0xAD,0x00,0x03,0x80,0x00,0x00,0x01,0x01,0xAD,0x01,0x03,0x80, + 0x00,0x00,0x01,0x01,0xAD,0x02,0x03,0x80,0x00,0x00,0x01,0x01,0xAD,0x03,0x03,0x80,0x00,0x00,0x01, + 0x01,0xAD,0x04,0x03,0x80,0x00,0x00,0x01,0x01,0xAD,0x05,0x03,0x80,0x00,0x00,0x01,0x01,0xAD,0x06, + 0x03,0x80,0x00,0x00,0x01,0x01,0xAD,0x07,0x03,0x80,0x00,0x00,0x01,0x01,0xAD,0x00,0x04,0x80,0x00, + 0x00,0x01,0x01,0xAD,0x01,0x04,0x80,0x00,0x00,0x01,0x01,0xAD,0x02,0x04,0x80,0x00,0x00,0x01,0x01, + 0xAD,0x03,0x04,0x80,0x00,0x00,0x01,0x01,0xAD,0x04,0x04,0x80,0x00,0x00,0x01,0x01,0xAD,0x05,0x04, + 0x80,0x00,0x00,0x01,0x01,0xAD,0x06,0x04,0x80,0x00,0x00,0x01,0x01,0xAD,0x07,0x04,0x80,0x00,0x00, + 0x01,0x01,0xAD,0x00,0x05,0x80,0x00,0x00,0x01,0x01,0xAD,0x01,0x05,0x80,0x00,0x00,0x01,0x01,0xAD, + 0x02,0x05,0x80,0x00,0x00,0x01,0x01,0xAD,0x03,0x05,0x80,0x00,0x00,0x01,0x01,0xAD,0x04,0x05,0x80, + 0x00,0x00,0x01,0x01,0xAD,0x05,0x05,0x80,0x00,0x00,0x01,0x01,0xAD,0x06,0x05,0x80,0x00,0x00,0x01, + 0x01,0xAD,0x07,0x05,0x80,0x00,0x00,0x01,0x01,0xAD,0x00,0x06,0x80,0x00,0x00,0x01,0x01,0xAD,0x01, + 0x06,0x80,0x00,0x00,0x01,0x01,0xAD,0x02,0x06,0x80,0x00,0x00,0x01,0x01,0xAD,0x03,0x06,0x80,0x00, + 0x00,0x01,0x01,0xAD,0x04,0x06,0x80,0x00,0x00,0x01,0x01,0xAD,0x05,0x06,0x80,0x00,0x00,0x01,0x01, + 0xAD,0x06,0x06,0x80,0x00,0x00,0x01,0x01,0xAD,0x07,0x06,0x80,0x00,0x00,0x01,0x01,0xAD,0x00,0x07, + 0x80,0x00 + }; + + byte SZL_ID_0011_IDX_XXXX[124] = { + 0xFF,0x09,0x00,0x78,0x00,0x11,0x00,0x00,0x00,0x1C,0x00,0x04,0x00,0x01,0x36,0x45,0x53,0x37,0x20, + 0x33,0x31,0x35,0x2D,0x32,0x45,0x48,0x31,0x34,0x2D,0x30,0x41,0x42,0x30,0x20,0x00,0xC0,0x00,0x04, + 0x00,0x01,0x00,0x06,0x36,0x45,0x53,0x37,0x20,0x33,0x31,0x35,0x2D,0x32,0x45,0x48,0x31,0x34,0x2D, + 0x30,0x41,0x42,0x30,0x20,0x00,0xC0,0x00,0x04,0x00,0x01,0x00,0x07,0x20,0x20,0x20,0x20,0x20,0x20, + 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0xC0,0x56,0x03,0x02, + 0x06,0x00,0x81,0x42,0x6F,0x6F,0x74,0x20,0x4C,0x6F,0x61,0x64,0x65,0x72,0x20,0x20,0x20,0x20,0x20, + 0x20,0x20,0x20,0x20,0x00,0x00,0x41,0x20,0x09,0x09 + }; + + byte SZL_ID_0012_IDX_XXXX[58] = { + 0xFF,0x09,0x00,0x36,0x00,0x12,0x00,0x00,0x00,0x02,0x00,0x17,0x00,0x01,0x01,0x01,0x01,0x04,0x03, + 0x02,0x03,0x03,0x03,0x04,0x03,0x06,0x03,0x07,0x03,0x08,0x03,0x09,0x03,0x0A,0x03,0x0B,0x03,0x0C, + 0x03,0x0D,0x03,0x0E,0x03,0x0F,0x03,0x10,0x03,0x11,0x03,0x12,0x03,0x13,0x03,0x14,0x03,0x15,0x03, + 0x17 + }; + + byte SZL_ID_0013_IDX_XXXX[192] = { + 0xFF,0x09,0x00,0xBC,0x00,0x13,0x00,0x00,0x00,0x24,0x00,0x05,0x00,0x01,0x00,0x01,0x00,0x06,0x00, + 0x00,0x00,0x11,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x26,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x01,0x00,0x00,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x02,0x00,0x08,0x00,0x00,0x00,0x02,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00, + 0x0C,0x06,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x02,0x00,0x80,0x00,0x00,0x00,0x02,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x02,0x00,0x00,0x0C,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x00,0x20,0x00,0x00, + 0x00,0x00 + }; + + byte SZL_ID_0014_IDX_XXXX[84] = { + 0xFF,0x09,0x00,0x50,0x00,0x14,0x00,0x00,0x00,0x08,0x00,0x09,0x00,0x01,0x00,0x01,0x08,0x00,0x00, + 0x00,0x00,0x02,0x00,0x01,0x08,0x00,0x00,0x00,0x00,0x03,0x00,0x01,0x40,0x00,0x00,0x80,0x00,0x04, + 0x00,0x01,0x01,0x00,0x00,0x00,0x00,0x05,0x00,0x01,0x01,0x00,0x00,0x08,0x00,0x06,0x00,0x01,0x08, + 0x00,0x00,0x00,0x00,0x07,0x00,0x01,0x80,0x00,0x00,0x00,0x00,0x08,0x00,0x01,0x08,0x00,0x00,0x10, + 0x00,0x09,0x00,0x01,0x00,0x20,0x00,0x00 + }; + + byte SZL_ID_0015_IDX_XXXX[62] = { + 0xFF,0x09,0x00,0x3A,0x00,0x15,0x00,0x00,0x00,0x0A,0x00,0x05,0x08,0x00,0x00,0x16,0x03,0xD1,0x00, + 0x00,0xFF,0xFE,0x0A,0x00,0x3E,0x81,0x03,0xD1,0x00,0x00,0xFF,0xFE,0x0B,0x00,0x04,0x22,0x03,0xD1, + 0x00,0x00,0xFF,0xFE,0x0C,0x00,0x1F,0x40,0x03,0xD1,0x00,0x00,0xFF,0xFE,0x0E,0x00,0x1F,0x40,0x03, + 0xD1,0x00,0x00,0xFF,0xFE + }; + + byte SZL_ID_0F14_IDX_XXXX[12] = { + 0xFF,0x09,0x00,0x08,0x0F,0x14,0x00,0x00,0x00,0x08,0x00,0x09 + }; + + byte SZL_ID_0019_IDX_XXXX[40] = { + 0xFF,0x09,0x00,0x24,0x00,0x19,0x00,0x00,0x00,0x04,0x00,0x07,0x00,0x01,0x00,0x00,0x00,0x04,0x01, + 0x00,0x00,0x05,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x0B,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x15, + 0x00,0x00 + }; + + byte SZL_ID_0F19_IDX_XXXX[12] = { + 0xFF,0x09,0x00,0x08,0x0F,0x19,0x00,0x00,0x00,0x04,0x00,0x07 + }; + + byte SZL_ID_001C_IDX_XXXX[352] = { + 0xFF,0x09,0x01,0x5C,0x00,0x1C,0x00,0x00,0x00,0x22,0x00,0x0A,0x00,0x01,0x53,0x4E,0x41,0x50,0x37, + 0x2D,0x53,0x45,0x52,0x56,0x45,0x52,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x43,0x50,0x55,0x20,0x33,0x31,0x35,0x2D,0x32, + 0x20,0x50,0x4E,0x2F,0x44,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x04,0x4F,0x72,0x69,0x67,0x69,0x6E,0x61,0x6C,0x20,0x53,0x69,0x65,0x6D,0x65,0x6E,0x73,0x20, + 0x45,0x71,0x75,0x69,0x70,0x6D,0x65,0x6E,0x74,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x53,0x20, + 0x43,0x2D,0x43,0x32,0x55,0x52,0x32,0x38,0x39,0x32,0x32,0x30,0x31,0x32,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x43,0x50,0x55,0x20,0x33,0x31, + 0x35,0x2D,0x32,0x20,0x50,0x4E,0x2F,0x44,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x4D,0x4D,0x43,0x20,0x32,0x36,0x37,0x46,0x46,0x31, + 0x31,0x46,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x09,0x00,0x2A,0xF6,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x0A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + }; + + byte SZL_ID_0F1C_IDX_XXXX[12] = { + 0xFF,0x09,0x00,0x08,0x0F,0x1C,0x00,0x00,0x00,0x22,0x00,0x0A + }; + + byte SZL_ID_0036_IDX_XXXX[12] = { + 0xFF,0x09,0x00,0x08,0x00,0x36,0x00,0x00,0x00,0x00,0x00,0x00 + }; + + byte SZL_ID_0F36_IDX_XXXX[12] = { + 0xFF,0x09,0x00,0x08,0x0F,0x36,0x00,0x00,0x00,0x00,0x00,0x00 + }; + + byte SZL_ID_0025_IDX_XXXX[16] = { + 0xFF,0x09,0x00,0x0C,0x00,0x25,0x00,0x00,0x00,0x04,0x00,0x01,0x01,0x0C,0x3D,0x00 + }; + + byte SZL_ID_0F25_IDX_XXXX[12] = { + 0xFF,0x09,0x00,0x08,0x0F,0x25,0x00,0x00,0x00,0x04,0x00,0x01 + }; + + byte SZL_ID_0037_IDX_XXXX[60] = { + 0xFF,0x09,0x00,0x38,0x00,0x37,0x00,0x00,0x00,0x30,0x00,0x01,0x07,0xFE,0xC0,0xA8,0x01,0x0A,0xFF, + 0xFF,0xFF,0x00,0xC0,0xA8,0x01,0x0A,0x00,0x1B,0x1B,0x1D,0x1A,0x2D,0x01,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x8F,0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00 + }; + + byte SZL_ID_0F37_IDX_XXXX[12] = { + 0xFF,0x09,0x00,0x08,0x0F,0x37,0x00,0x00,0x00,0x30,0x00,0x01 + }; + + byte SZL_ID_0074_IDX_XXXX[40] = { + 0xFF,0x09,0x00,0x24,0x00,0x74,0x00,0x00,0x00,0x04,0x00,0x07,0x00,0x01,0x00,0x00,0x00,0x04,0x01, + 0x00,0x00,0x05,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x0B,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x15, + 0x00,0x00 + }; + + byte SZL_ID_0F74_IDX_XXXX[12] = { + 0xFF,0x09,0x00,0x08,0x0F,0x74,0x00,0x00,0x00,0x04,0x00,0x07 + }; + + byte SZL_ID_0591_IDX_XXXX[76] = { + 0xFF,0x09,0x00,0x48,0x05,0x91,0x00,0x00,0x00,0x10,0x00,0x04,0x00,0x00,0x02,0x01,0x07,0xFF,0xC4, + 0xC0,0xC4,0xC0,0x00,0x00,0xB4,0x02,0x00,0x11,0x00,0x00,0x02,0x02,0x07,0xFE,0xA7,0xC4,0xA7,0xC4, + 0x00,0x00,0xB4,0x02,0x00,0x11,0x00,0x00,0x02,0x03,0x07,0xFD,0x97,0xC5,0x97,0xC5,0x00,0x00,0xB4, + 0x02,0x00,0x11,0x00,0x00,0x02,0x04,0x07,0xFC,0x97,0xC5,0x97,0xC5,0x00,0x00,0xB4,0x02,0x00,0x11 + }; + + byte SZL_ID_0A91_IDX_XXXX[44] = { + 0xFF,0x09,0x00,0x28,0x0A,0x91,0x00,0x00,0x00,0x10,0x00,0x02,0x01,0x00,0x02,0x01,0x07,0xFF,0xC4, + 0xC0,0xC4,0xC0,0x00,0x01,0xFE,0x02,0x00,0x11,0x80,0x00,0x00,0x00,0x07,0xFB,0xA7,0xC4,0xA7,0xC4, + 0x00,0x01,0xFE,0x02,0x00,0x11 + }; + + byte SZL_ID_0F92_IDX_XXXX[12] = { + 0xFF,0x09,0x00,0x08,0x0F,0x92,0x00,0x00,0x00,0x10,0x00,0x01 + }; + + byte SZL_ID_0294_IDX_XXXX[270] = { + 0xFF,0x09,0x01,0x0A,0x02,0x94,0x00,0x00,0x01,0x02,0x00,0x01,0x00,0x00,0x03,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00 + }; + + byte SZL_ID_0794_IDX_XXXX[270] = { + 0xFF,0x09,0x01,0x0A,0x07,0x94,0x00,0x00,0x01,0x02,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00 + }; + + byte SZL_ID_0F94_IDX_XXXX[12] = { + 0xFF,0x09,0x00,0x08,0x0F,0x94,0x00,0x00,0x01,0x02,0x00,0x01 + }; + + byte SZL_ID_0095_IDX_XXXX[52] = { + 0xFF,0x09,0x00,0x30,0x00,0x95,0x00,0x00,0x00,0x28,0x00,0x01,0x64,0x00,0x02,0x02,0x07,0xFE,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + }; + + byte SZL_ID_0F95_IDX_XXXX[12] = { + 0xFF,0x09,0x00,0x08,0x0F,0x95,0x00,0x00,0x00,0x28,0x00,0x01 + }; + + byte SZL_ID_00A0_IDX_XXXX[212] = { + 0xFF,0x09,0x00,0xD0,0x00,0xA0,0x00,0x00,0x00,0x14,0x00,0x0A,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00, + 0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x86,0x13,0x81,0xFE,0x64,0xC7,0x72, + 0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x76,0x43,0x01,0xFF,0x46,0xC7, + 0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x29,0x66,0x43,0x04,0xFF,0x84, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x52,0x13,0x90,0x16,0x43,0x02,0xFF, + 0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x56,0x13,0x81, + 0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x46,0x43, + 0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x79,0x46, + 0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x51,0x19,0x48, + 0x26,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50,0x45, + 0x09,0x96,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50, + 0x45,0x09,0x86 + }; + + byte SZL_ID_0FA0_IDX_XXXX[12] = { + 0xFF,0x09,0x00,0x08,0x0F,0xA0,0x00,0x00,0x00,0x14,0x01,0xF4 + }; + + byte SZL_ID_0017_IDX_XXXX[458] = { // <--Wrapped to 458 bytes + 0xFF,0x09,0x01,0xC6,0x00,0x17,0x00,0x00,0x00,0x04,0x00,0x73,0x00,0x00,0x00,0x01,0x00,0x01,0x00, + 0x03,0x00,0x02,0x00,0x02,0x00,0x03,0x00,0x01,0x00,0x04,0x00,0x01,0x00,0x07,0x00,0x01,0x00,0x16, + 0x00,0x01,0x00,0x64,0x00,0x01,0x00,0x65,0x00,0x01,0x00,0x66,0x00,0x01,0x00,0x67,0x00,0x01,0x00, + 0x7A,0x00,0x01,0x00,0xC8,0x00,0x01,0x00,0xD2,0x00,0x01,0x02,0xBC,0x00,0x01,0x02,0xBD,0x00,0x01, + 0x02,0xBE,0x00,0x01,0x02,0xBF,0x00,0x01,0x02,0xC0,0x00,0x01,0x02,0xC1,0x00,0x01,0x02,0xC2,0x00, + 0x01,0x02,0xC3,0x00,0x01,0x02,0xC4,0x00,0x01,0x02,0xC5,0x00,0x01,0x02,0xC6,0x00,0x01,0x02,0xC7, + 0x00,0x01,0x02,0xC8,0x00,0x01,0x02,0xC9,0x00,0x01,0x02,0xCA,0x00,0x01,0x02,0xCB,0x00,0x01,0x02, + 0xCC,0x00,0x01,0x02,0xCD,0x00,0x01,0x02,0xCE,0x00,0x01,0x02,0xCF,0x00,0x01,0x02,0xD0,0x00,0x01, + 0x02,0xD1,0x00,0x01,0x02,0xD2,0x00,0x01,0x02,0xD3,0x00,0x01,0x02,0xD4,0x00,0x01,0x02,0xD5,0x00, + 0x01,0x02,0xD6,0x00,0x01,0x02,0xD7,0x00,0x01,0x02,0xD8,0x00,0x01,0x02,0xD9,0x00,0x01,0x02,0xDA, + 0x00,0x01,0x02,0xDB,0x00,0x01,0x02,0xDC,0x00,0x01,0x02,0xDD,0x00,0x01,0x02,0xDE,0x00,0x01,0x02, + 0xDF,0x00,0x01,0x02,0xE0,0x00,0x01,0x02,0xE1,0x00,0x01,0x02,0xE2,0x00,0x01,0x02,0xE3,0x00,0x01, + 0x02,0xE4,0x00,0x01,0x02,0xE5,0x00,0x01,0x02,0xE6,0x00,0x01,0x02,0xE7,0x00,0x01,0x02,0xE8,0x00, + 0x01,0x02,0xE9,0x00,0x01,0x02,0xEA,0x00,0x01,0x02,0xEB,0x00,0x01,0x02,0xEC,0x00,0x01,0x02,0xED, + 0x00,0x01,0x02,0xEE,0x00,0x01,0x02,0xEF,0x00,0x01,0x02,0xF0,0x00,0x01,0x02,0xF1,0x00,0x01,0x02, + 0xF2,0x00,0x01,0x02,0xF3,0x00,0x01,0x02,0xF4,0x00,0x01,0x02,0xF5,0x00,0x01,0x02,0xF6,0x00,0x01, + 0x02,0xF7,0x00,0x01,0x02,0xF8,0x00,0x01,0x02,0xF9,0x00,0x01,0x02,0xFA,0x00,0x01,0x02,0xFB,0x00, + 0x01,0x02,0xFC,0x00,0x01,0x02,0xFD,0x00,0x01,0x02,0xFE,0x00,0x01,0x02,0xFF,0x00,0x01,0x03,0x00, + 0x00,0x01,0x03,0x01,0x00,0x01,0x03,0x02,0x00,0x01,0x03,0x03,0x00,0x01,0x03,0x04,0x00,0x01,0x03, + 0x05,0x00,0x01,0x03,0x06,0x00,0x01,0x03,0x07,0x00,0x01,0x03,0x08,0x00,0x01,0x03,0x09,0x00,0x01, + 0x03,0x0A,0x00,0x01,0x03,0x0B,0x00,0x01,0x03,0x0C,0x00,0x01,0x03,0x0D,0x00,0x01,0x03,0x0E,0x00, + 0x01,0x03,0x0F,0x00,0x01,0x03,0x10,0x00,0x01,0x03,0x11,0x00,0x01,0x03,0x12,0x00,0x01,0x03,0x13, + 0x00,0x01,0x03,0x14,0x00,0x01,0x03,0x15,0x00,0x01,0x03,0x16,0x00,0x01,0x03,0x17,0x00,0x01,0x03, + 0x18,0x00,0x01,0x03,0x19,0x00,0x01,0x03,0x1A,0x00,0x01,0x03,0x1B,0x00,0x01,0x03,0x1C,0x00,0x01, + 0x03,0x1D + }; + + byte SZL_ID_0F17_IDX_XXXX[12] = { + 0xFF,0x09,0x00,0x08,0x0F,0x17,0x00,0x00,0x00,0x04,0x00,0x73 + }; + + byte SZL_ID_0018_IDX_XXXX[28] = { + 0xFF,0x09,0x00,0x18,0x00,0x18,0x00,0x00,0x00,0x04,0x00,0x04,0x00,0x00,0x00,0x08,0x00,0x01,0x00, + 0x08,0x00,0x02,0x00,0x08,0x00,0x03,0x00,0x08 + }; + + byte SZL_ID_0F18_IDX_XXXX[12] = { + 0xFF,0x09,0x00,0x08,0x0F,0x18,0x00,0x00,0x00,0x04,0x00,0x04 + }; + + byte SZL_ID_001A_IDX_XXXX[48] = { + 0xFF,0x09,0x00,0x2C,0x00,0x1A,0x00,0x00,0x00,0x0C,0x00,0x03,0x09,0x01,0x01,0x05,0x00,0x08,0x00, + 0x00,0x00,0x80,0x00,0x00,0x12,0x01,0x00,0x02,0x00,0x06,0x00,0x00,0x00,0x06,0x00,0x00,0x18,0x01, + 0x00,0x02,0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x00 + }; + + byte SZL_ID_0F1A_IDX_XXXX[12] = { + 0xFF,0x09,0x00,0x08,0x0F,0x1A,0x00,0x00,0x00,0x0C,0x00,0x03 + }; + + byte SZL_ID_001B_IDX_XXXX[132] = { + 0xFF,0x09,0x00,0x80,0x00,0x1B,0x00,0x00,0x00,0x14,0x00,0x06,0x09,0x00,0x00,0x00,0x00,0x02,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x06,0x00,0x00,0x00,0x00,0x09,0x00,0x00,0x70,0x00,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xF3,0xFA,0x00,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x26,0x00,0x00,0x00,0x00,0x12,0x00,0x00,0x70, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0xFF,0xDA,0x00,0x00,0x00,0x00,0x18,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00, + 0x00,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00 + }; + + byte SZL_ID_0F1B_IDX_XXXX[12] = { + 0xFF,0x09,0x00,0x08,0x0F,0x1B,0x00,0x00,0x00,0x14,0x00,0x06 + }; + + byte SZL_ID_0021_IDX_XXXX[100] = { + 0xFF,0x09,0x00,0x60,0x00,0x21,0x00,0x00,0x00,0x04,0x00,0x16,0x01,0x01,0x01,0x01,0x01,0x11,0xFE, + 0x0A,0x01,0x21,0xFE,0x14,0x01,0x22,0xFE,0x15,0x01,0x33,0xFE,0x20,0x01,0x34,0xFE,0x21,0x01,0x35, + 0xFE,0x22,0x01,0x36,0xFE,0x23,0x01,0x41,0xFE,0x28,0x01,0x55,0xFE,0x37,0x01,0x56,0xFE,0x38,0x01, + 0x57,0xFE,0x39,0x01,0x64,0xFE,0x3D,0x00,0x01,0xFE,0x50,0x00,0x42,0xFE,0x52,0x00,0x61,0xFE,0x53, + 0x00,0xA1,0xFE,0x55,0x00,0xC1,0xFE,0x56,0x00,0xD2,0xFE,0x57,0x00,0x81,0xFE,0x64,0x00,0x21,0xFE, + 0x79,0x00,0x42,0xFE,0x7A + }; + + byte SZL_ID_0A21_IDX_XXXX[16] = { + 0xFF,0x09,0x00,0x0C,0x0A,0x21,0x00,0x00,0x00,0x04,0x00,0x01,0x01,0x01,0x01,0x01 + }; + + byte SZL_ID_0F21_IDX_XXXX[12] = { + 0xFF,0x09,0x00,0x08,0x0F,0x21,0x00,0x00,0x00,0x04,0x00,0x16 + }; + + byte SZL_ID_0023_IDX_XXXX[228] = { + 0xFF,0x09,0x00,0xE0,0x00,0x23,0x00,0x00,0x00,0x12,0x00,0x0C,0x1A,0x00,0x00,0x00,0x10,0xBE,0x00, + 0x00,0x08,0x00,0x0B,0xC0,0xFC,0x01,0xFF,0xFF,0xFF,0xF3,0x19,0x00,0x00,0x00,0x10,0x01,0x00,0x00, + 0x08,0x00,0x0B,0xC0,0xFC,0x01,0xFF,0xFF,0xFF,0xF3,0x10,0x00,0x00,0x00,0x10,0x26,0x00,0x00,0x08, + 0x00,0x0B,0xC0,0xFC,0x01,0xFF,0xFF,0xFF,0xF3,0x0C,0x00,0x00,0x00,0x10,0x01,0x00,0x00,0x08,0x00, + 0x0B,0xC0,0xFC,0x01,0xFF,0xFF,0xFF,0xF3,0x0B,0x00,0x00,0x00,0x10,0x01,0x00,0x00,0x08,0x00,0x0B, + 0xC0,0xFC,0x01,0xFF,0xFF,0xFF,0xF3,0x0A,0x00,0x00,0x00,0x10,0x01,0x00,0x00,0x08,0x00,0x0B,0xC0, + 0xFC,0x01,0xFF,0xFF,0xFF,0xF3,0x09,0x00,0x00,0x00,0x10,0x01,0x00,0x00,0x08,0x00,0x0B,0xC0,0xFC, + 0x01,0xFF,0xFF,0xFF,0xF3,0x04,0x00,0x00,0x00,0x10,0x01,0x00,0x00,0x08,0x00,0x0B,0xC0,0xFC,0x01, + 0xFF,0xFF,0xFF,0xF3,0x03,0x00,0x00,0x00,0x10,0x01,0x00,0x00,0x08,0x00,0x0B,0xC0,0xFC,0x01,0xFF, + 0xFF,0xFF,0xF3,0x02,0x00,0x00,0x00,0x10,0x16,0x00,0x00,0x08,0x00,0x0B,0xC0,0xFC,0x01,0xFF,0xFF, + 0xFF,0xF3,0x01,0x00,0x00,0x00,0x10,0x01,0x00,0x00,0x08,0x00,0x0B,0xC0,0xFC,0x01,0xFF,0xFF,0xFF, + 0xF3,0x1B,0x00,0x00,0x00,0x10,0x01,0x00,0x00,0x08,0x00,0x0B,0xC0,0xFC,0x01,0xFF,0xFF,0xFF,0xF3 + }; + + byte SZL_ID_0F23_IDX_XXXX[12] = { + 0xFF,0x09,0x00,0x08,0x0F,0x23,0x00,0x00,0x00,0x12,0x00,0x0C + }; + + byte SZL_ID_0024_IDX_XXXX[92] = { + 0xFF,0x09,0x00,0x58,0x00,0x24,0x00,0x00,0x00,0x14,0x00,0x04,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00, + 0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x86,0x43,0x01,0xFF,0x46,0xC7,0x72, + 0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x29,0x66,0x43,0x04,0xFF,0x84,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x52,0x13,0x90,0x16,0x43,0x02,0xFF,0x68, + 0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x56 + }; + + byte SZL_ID_0124_IDX_XXXX[32] = { + 0xFF,0x09,0x00,0x1C,0x01,0x24,0x00,0x00,0x00,0x14,0x00,0x01,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00, + 0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x86 + }; + + byte SZL_ID_0424_IDX_XXXX[32] = { + 0xFF,0x09,0x00,0x1C,0x04,0x24,0x00,0x00,0x00,0x14,0x00,0x01,0x51,0x44,0xFF, + 0x08, // <-- CPU Status + 0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x05,0x02,0x01,0x55,0x90,0x67 + }; + + byte SZL_ID_0038_IDX_XXXX[78] = { + 0xFF,0x09,0x00,0x4A,0x00,0x38,0x00,0x00,0x00,0x42,0x00,0x01,0x00,0x01,0x07,0xFE,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xAB,0xE3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0xEE,0x49,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00 + }; + + byte SZL_ID_0F38_IDX_XXXX[12] = { + 0xFF,0x09,0x00,0x08,0x0F,0x38,0x00,0x00,0x00,0x42,0x00,0x01 + }; + + byte SZL_ID_003A_IDX_XXXX[12] = { + 0xFF,0x09,0x00,0x08,0x00,0x3A,0x00,0x00,0x00,0x94,0x00,0x00 + }; + + byte SZL_ID_0F3A_IDX_XXXX[12] = { + 0xFF,0x09,0x00,0x08,0x0F,0x3A,0x00,0x00,0x00,0x94,0x00,0x08 + }; + + byte SZL_ID_0F9A_IDX_XXXX[12] = { + 0xFF,0x09,0x00,0x08,0x0F,0x9A,0x00,0x00,0x01,0x1C,0x00,0x01 + }; + + byte SZL_ID_0D91_IDX_0000[28] = { + 0xFF,0x09,0x00,0x18,0x0D,0x91,0x00,0x00,0x00,0x10,0x00,0x01,0x00,0x00,0x02,0x00,0x7F,0xFF,0x00, + 0xC0,0x00,0xC0,0x00,0x00,0xB4,0x02,0x00,0x11 + }; + + byte SZL_ID_0092_IDX_0000[28] = { + 0xFF,0x09,0x00,0x18,0x00,0x92,0x00,0x00,0x00,0x10,0x00,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + }; + + byte SZL_ID_0292_IDX_0000[28] = { + 0xFF,0x09,0x00,0x18,0x02,0x92,0x00,0x00,0x00,0x10,0x00,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + }; + + byte SZL_ID_0692_IDX_0000[28] = { + 0xFF,0x09,0x00,0x18,0x06,0x92,0x00,0x00,0x00,0x10,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + }; + + byte SZL_ID_0094_IDX_0000[270] = { + 0xFF,0x09,0x01,0x0A,0x00,0x94,0x00,0x00,0x01,0x02,0x00,0x01,0x00,0x00,0x03,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00 + }; + + byte SZL_ID_0D97_IDX_0000[60] = { + 0xFF,0x09,0x00,0x38,0x0D,0x97,0x00,0x00,0x00,0x30,0x00,0x01,0x7F,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x02,0x00,0x04,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00 + }; + + byte SZL_ID_0111_IDX_0001[40] = { + 0xFF,0x09,0x00,0x24,0x01,0x11,0x00,0x01,0x00,0x1C,0x00,0x01,0x00,0x01,0x36,0x45,0x53,0x37,0x20, + 0x33,0x31,0x35,0x2D,0x32,0x45,0x48,0x31,0x34,0x2D,0x30,0x41,0x42,0x30,0x20,0x00,0xC0,0x00,0x04, + 0x00,0x01 + }; + + byte SZL_ID_0111_IDX_0006[40] = { + 0xFF,0x09,0x00,0x24,0x01,0x11,0x00,0x06,0x00,0x1C,0x00,0x01,0x00,0x06,0x36,0x45,0x53,0x37,0x20, + 0x33,0x31,0x35,0x2D,0x32,0x45,0x48,0x31,0x34,0x2D,0x30,0x41,0x42,0x30,0x20,0x00,0xC0,0x00,0x04, + 0x00,0x01 + }; + + byte SZL_ID_0111_IDX_0007[40] = { + 0xFF,0x09,0x00,0x24,0x01,0x11,0x00,0x07,0x00,0x1C,0x00,0x01,0x00,0x07,0x20,0x20,0x20,0x20,0x20, + 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0xC0,0x56,0x03, + 0x02,0x06 + }; + + byte SZL_ID_0F11_IDX_0001[12] = { + 0xFF,0x09,0x00,0x08,0x0F,0x11,0x00,0x00,0x00,0x1C,0x00,0x04 + }; + + byte SZL_ID_0F11_IDX_0006[12] = { + 0xFF,0x09,0x00,0x08,0x0F,0x11,0x00,0x00,0x00,0x1C,0x00,0x04 + }; + + byte SZL_ID_0F11_IDX_0007[12] = { + 0xFF,0x09,0x00,0x08,0x0F,0x11,0x00,0x00,0x00,0x1C,0x00,0x04 + }; + + byte SZL_ID_0112_IDX_0000[14] = { + 0xFF,0x09,0x00,0x0A,0x01,0x12,0x00,0x00,0x00,0x02,0x00,0x01,0x00,0x01 + }; + + byte SZL_ID_0112_IDX_0100[16] = { + 0xFF,0x09,0x00,0x0C,0x01,0x12,0x01,0x00,0x00,0x02,0x00,0x02,0x01,0x01,0x01,0x04 + }; + + byte SZL_ID_0112_IDX_0200[12] = { + 0xFF,0x09,0x00,0x08,0x01,0x12,0x02,0x00,0x00,0x00,0x00,0x00 + }; + + byte SZL_ID_0112_IDX_0400[12] = { + 0xFF,0x09,0x00,0x08,0x01,0x12,0x04,0x00,0x00,0x00,0x00,0x00 + }; + + byte SZL_ID_0F12_IDX_0000[12] = { + 0xFF,0x09,0x00,0x08,0x0F,0x12,0x00,0x00,0x00,0x02,0x00,0x17 + }; + + byte SZL_ID_0F12_IDX_0100[12] = { + 0xFF,0x09,0x00,0x08,0x0F,0x12,0x00,0x00,0x00,0x02,0x00,0x17 + }; + + byte SZL_ID_0F12_IDX_0200[12] = { + 0xFF,0x09,0x00,0x08,0x0F,0x12,0x00,0x00,0x00,0x02,0x00,0x17 + }; + + byte SZL_ID_0F12_IDX_0400[12] = { + 0xFF,0x09,0x00,0x08,0x0F,0x12,0x00,0x00,0x00,0x02,0x00,0x17 + }; + + byte SZL_ID_0113_IDX_0001[48] = { + 0xFF,0x09,0x00,0x2C,0x01,0x13,0x00,0x01,0x00,0x24,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x06,0x00, + 0x00,0x00,0x11,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x26,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + }; + + byte SZL_ID_0115_IDX_0800[22] = { + 0xFF,0x09,0x00,0x12,0x01,0x15,0x08,0x00,0x00,0x0A,0x00,0x01,0x08,0x00,0x00,0x16,0x03,0xD1,0x00, + 0x00,0xFF,0xFE + }; + + byte SZL_ID_011C_IDX_0001[46] = { + 0xFF,0x09,0x00,0x2A,0x01,0x1C,0x00,0x01,0x00,0x22,0x00,0x01,0x00,0x01,0x53,0x4D,0x41,0x52,0x54, + 0x37,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + }; + + byte SZL_ID_011C_IDX_0002[46] = { + 0xFF,0x09,0x00,0x2A,0x01,0x1C,0x00,0x02,0x00,0x22,0x00,0x01,0x00,0x02,0x43,0x50,0x55,0x20,0x33, + 0x31,0x35,0x2D,0x32,0x20,0x50,0x4E,0x2F,0x44,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + }; + + byte SZL_ID_011C_IDX_0003[46] = { + 0xFF,0x09,0x00,0x2A,0x01,0x1C,0x00,0x03,0x00,0x22,0x00,0x01,0x00,0x03,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + }; + + byte SZL_ID_011C_IDX_0004[46] = { + 0xFF,0x09,0x00,0x2A,0x01,0x1C,0x00,0x04,0x00,0x22,0x00,0x01,0x00,0x04,0x4F,0x72,0x69,0x67,0x69, + 0x6E,0x61,0x6C,0x20,0x53,0x69,0x65,0x6D,0x65,0x6E,0x73,0x20,0x45,0x71,0x75,0x69,0x70,0x6D,0x65, + 0x6E,0x74,0x00,0x00,0x00,0x00,0x00,0x00 + }; + + byte SZL_ID_011C_IDX_0005[46] = { + 0xFF,0x09,0x00,0x2A,0x01,0x1C,0x00,0x05,0x00,0x22,0x00,0x01,0x00,0x05,0x53,0x20,0x43,0x2D,0x43, + 0x32,0x55,0x52,0x32,0x38,0x39,0x32,0x32,0x30,0x31,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + }; + + byte SZL_ID_011C_IDX_0007[46] = { + 0xFF,0x09,0x00,0x2A,0x01,0x1C,0x00,0x07,0x00,0x22,0x00,0x01,0x00,0x07,0x43,0x50,0x55,0x20,0x33, + 0x31,0x35,0x2D,0x32,0x20,0x50,0x4E,0x2F,0x44,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + }; + + byte SZL_ID_011C_IDX_0008[46] = { + 0xFF,0x09,0x00,0x2A,0x01,0x1C,0x00,0x08,0x00,0x22,0x00,0x01,0x00,0x08,0x4D,0x4D,0x43,0x20,0x32, + 0x36,0x37,0x46,0x46,0x31,0x31,0x46,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + }; + + byte SZL_ID_011C_IDX_0009[46] = { + 0xFF,0x09,0x00,0x2A,0x01,0x1C,0x00,0x09,0x00,0x22,0x00,0x01,0x00,0x09,0x00,0x2A,0xF6,0x00,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + }; + + byte SZL_ID_011C_IDX_000A[46] = { + 0xFF,0x09,0x00,0x2A,0x01,0x1C,0x00,0x0A,0x00,0x22,0x00,0x01,0x00,0x0A,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + }; + + byte SZL_ID_011C_IDX_000B[46] = { + 0xFF,0x09,0x00,0x2A,0x01,0x1C,0x00,0x0B,0x00,0x22,0x00,0x01,0x00,0x0B,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + }; + + byte SZL_ID_0222_IDX_0001[40] = { + 0xFF,0x09,0x00,0x24,0x02,0x22,0x00,0x01,0x00,0x1C,0x00,0x01,0x11,0x03,0x01,0x01,0xC8,0x58,0x00, + 0x00,0x00,0x00,0x00,0x01,0x94,0x02,0x05,0x02,0x01,0x56,0x64,0x77,0x00,0x10,0x00,0x08,0x00,0x00, + 0x00,0x00 + }; + + byte SZL_ID_0222_IDX_000A[40] = { + 0xFF,0x09,0x00,0x24,0x02,0x22,0x00,0x0A,0x00,0x1C,0x00,0x01,0x10,0x11,0x02,0x0A,0x00,0x50,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00 + }; + + byte SZL_ID_0222_IDX_0014[40] = { + 0xFF,0x09,0x00,0x24,0x02,0x22,0x00,0x14,0x00,0x1C,0x00,0x01,0x10,0x21,0x03,0x14,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00 + }; + + byte SZL_ID_0222_IDX_0028[40] = { + 0xFF,0x09,0x00,0x24,0x02,0x22,0x00,0x28,0x00,0x1C,0x00,0x01,0x10,0x41,0x10,0x28,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00 + }; + + byte SZL_ID_0222_IDX_0050[40] = { + 0xFF,0x09,0x00,0x24,0x02,0x22,0x00,0x50,0x00,0x1C,0x00,0x01,0x35,0x01,0xFE,0x50,0xC8,0x58,0x00, + 0x00,0x00,0x00,0x00,0x96,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00, + 0x00,0x00 + }; + + byte SZL_ID_0222_IDX_0064[40] = { + 0xFF,0x09,0x00,0x24,0x02,0x22,0x00,0x64,0x00,0x1C,0x00,0x01,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43, + 0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x76,0x00,0x00,0x00,0x08,0x00,0x00, + 0x00,0x00 + }; + + byte SZL_ID_0125_IDX_0000[16] = { + 0xFF,0x09,0x00,0x0C,0x01,0x25,0x00,0x00,0x00,0x04,0x00,0x01,0x00,0x03,0x01,0x00 + }; + + byte SZL_ID_0125_IDX_0001[16] = { + 0xFF,0x09,0x00,0x0C,0x01,0x25,0x00,0x01,0x00,0x04,0x00,0x01,0x01,0x0C,0x3D,0x00 + }; + + byte SZL_ID_0225_IDX_0001[16] = { + 0xFF,0x09,0x00,0x0C,0x02,0x25,0x00,0x01,0x00,0x04,0x00,0x01,0x00,0x03,0x01,0x00 + }; + + byte SZL_ID_0132_IDX_0001[52] = { + 0xFF,0x09,0x00,0x30,0x01,0x32,0x00,0x01,0x00,0x28,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03 + }; + + byte SZL_ID_0132_IDX_0002[52] = { + 0xFF,0x09,0x00,0x30,0x01,0x32,0x00,0x02,0x00,0x28,0x00,0x01,0x00,0x02,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x0E,0x00,0x00,0x00,0x00,0x06,0x01,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + }; + + byte SZL_ID_0132_IDX_0003[52] = { + 0xFF,0x09,0x00,0x30,0x01,0x32,0x00,0x03,0x00,0x28,0x00,0x01,0x00,0x03,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + }; + + byte SZL_ID_0132_IDX_0004[52] = { + 0xFF,0x09,0x00,0x30,0x01,0x32,0x00,0x04,0x00,0x28,0x00,0x01,0x00,0x04,0x00,0x01,0x00,0x00,0x00, + 0x01,0x00,0x02,0x00,0x00,0x00,0x00,0x56,0x56,0x10,0x01,0x33,0x7B,0x02,0x00,0x75,0xF4,0x02,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + }; + + byte SZL_ID_0132_IDX_0005[52] = { + 0xFF,0x09,0x00,0x30,0x01,0x32,0x00,0x05,0x00,0x28,0x00,0x01,0x00,0x05,0x00,0x00,0x00,0x01,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + }; + + byte SZL_ID_0132_IDX_0006[52] = { + 0xFF,0x09,0x00,0x30,0x01,0x32,0x00,0x06,0x00,0x28,0x00,0x01,0x00,0x06,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + }; + + byte SZL_ID_0132_IDX_0007[52] = { + 0xFF,0x09,0x00,0x30,0x01,0x32,0x00,0x07,0x00,0x28,0x00,0x01,0x00,0x07,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + }; + + byte SZL_ID_0132_IDX_0008[52] = { + 0xFF,0x09,0x00,0x30,0x01,0x32,0x00,0x08,0x00,0x28,0x00,0x01,0x00,0x08,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x05,0x02, + 0x01,0x56,0x94,0x57,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + }; + + byte SZL_ID_0132_IDX_0009[52] = { + 0xFF,0x09,0x00,0x30,0x01,0x32,0x00,0x09,0x00,0x28,0x00,0x01,0x00,0x09,0x00,0x02,0xDC,0x6C,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + }; + + byte SZL_ID_0132_IDX_000A[52] = { + 0xFF,0x09,0x00,0x30,0x01,0x32,0x00,0x0A,0x00,0x28,0x00,0x01,0x00,0x0A,0x00,0x02,0xDC,0x6C,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + }; + + byte SZL_ID_0132_IDX_000B[52] = { + 0xFF,0x09,0x00,0x30,0x01,0x32,0x00,0x0B,0x00,0x28,0x00,0x01,0x00,0x0B,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + }; + + byte SZL_ID_0132_IDX_000C[52] = { + 0xFF,0x09,0x00,0x30,0x01,0x32,0x00,0x0C,0x00,0x28,0x00,0x01,0x00,0x0C,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + }; + + byte SZL_ID_0232_IDX_0001[52] = { + 0xFF,0x09,0x00,0x30,0x02,0x32,0x00,0x01,0x00,0x28,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03 + }; + + byte SZL_ID_0232_IDX_0004[52] = { + 0xFF,0x09,0x00,0x30,0x02,0x32,0x00,0x04,0x00,0x28,0x00,0x01,0x00,0x04,0x00,0x01,0x00,0x00,0x00, + 0x01,0x00,0x02,0x00,0x00,0x00,0x00,0x56,0x56,0x10,0x01,0x33,0x7B,0x02,0x00,0x75,0xF4,0x02,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + }; + + byte SZL_ID_0137_IDX_07FE[60] = { + 0xFF,0x09,0x00,0x38,0x01,0x37,0x07,0xFE,0x00,0x30,0x00,0x01,0x07,0xFE,0xC0,0xA8,0x01,0x0A,0xFF, + 0xFF,0xFF,0x00,0xC0,0xA8,0x01,0x0A,0x00,0x1B,0x1B,0x1D,0x1A,0x2D,0x01,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x8F,0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00 + }; + + byte SZL_ID_0174_IDX_0001[16] = { + 0xFF,0x09,0x00,0x0C,0x01,0x74,0x00,0x01,0x00,0x04,0x00,0x01,0x00,0x01,0x00,0x00 + }; + + byte SZL_ID_0174_IDX_0004[16] = { + 0xFF,0x09,0x00,0x0C,0x01,0x74,0x00,0x04,0x00,0x04,0x00,0x01,0x00,0x04,0x01,0x00 + }; + + byte SZL_ID_0174_IDX_0005[16] = { + 0xFF,0x09,0x00,0x0C,0x01,0x74,0x00,0x05,0x00,0x04,0x00,0x01,0x00,0x05,0x00,0x00 + }; + + byte SZL_ID_0174_IDX_0006[16] = { + 0xFF,0x09,0x00,0x0C,0x01,0x74,0x00,0x06,0x00,0x04,0x00,0x01,0x00,0x06,0x00,0x00 + }; + + byte SZL_ID_0174_IDX_000B[16] = { + 0xFF,0x09,0x00,0x0C,0x01,0x74,0x00,0x0B,0x00,0x04,0x00,0x01,0x00,0x0B,0x00,0x00 + }; + + byte SZL_ID_0174_IDX_000C[16] = { + 0xFF,0x09,0x00,0x0C,0x01,0x74,0x00,0x0C,0x00,0x04,0x00,0x01,0x00,0x0C,0x00,0x00 + }; + + byte SZL_ID_0194_IDX_0064[270] = { + 0xFF,0x09,0x01,0x0A,0x01,0x94,0x00,0x64,0x01,0x02,0x00,0x01,0x00,0x64,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00 + }; + + byte SZL_ID_0694_IDX_0064[270] = { + 0xFF,0x09,0x01,0x0A,0x06,0x94,0x00,0x64,0x01,0x02,0x00,0x01,0x00,0x64,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00 + }; + + byte SZL_ID_01A0_IDX_0000[12] = { + 0xFF,0x09,0x00,0x08,0x01,0xA0,0x00,0x00,0x00,0x14,0x00,0x00 + }; + + byte SZL_ID_01A0_IDX_0001[32] = { + 0xFF,0x09,0x00,0x1C,0x01,0xA0,0x00,0x00,0x00,0x14,0x00,0x01,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00, + 0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x86 + }; + + byte SZL_ID_01A0_IDX_0002[52] = { + 0xFF,0x09,0x00,0x30,0x01,0xA0,0x00,0x00,0x00,0x14,0x00,0x02,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00, + 0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x86,0x13,0x81,0xFE,0x64,0xC7,0x72, + 0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x76 + }; + + byte SZL_ID_01A0_IDX_0003[72] = { + 0xFF,0x09,0x00,0x44,0x01,0xA0,0x00,0x00,0x00,0x14,0x00,0x03,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00, + 0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x86,0x13,0x81,0xFE,0x64,0xC7,0x72, + 0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x76,0x43,0x01,0xFF,0x46,0xC7, + 0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x29,0x66 + }; + + byte SZL_ID_01A0_IDX_0004[92] = { + 0xFF,0x09,0x00,0x58,0x01,0xA0,0x00,0x00,0x00,0x14,0x00,0x04,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00, + 0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x86,0x13,0x81,0xFE,0x64,0xC7,0x72, + 0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x76,0x43,0x01,0xFF,0x46,0xC7, + 0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x29,0x66,0x43,0x04,0xFF,0x84, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x52,0x13,0x90,0x16 + }; + + byte SZL_ID_01A0_IDX_0005[112] = { + 0xFF,0x09,0x00,0x6C,0x01,0xA0,0x00,0x00,0x00,0x14,0x00,0x05,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00, + 0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x86,0x13,0x81,0xFE,0x64,0xC7,0x72, + 0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x76,0x43,0x01,0xFF,0x46,0xC7, + 0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x29,0x66,0x43,0x04,0xFF,0x84, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x52,0x13,0x90,0x16,0x43,0x02,0xFF, + 0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x56 + }; + + byte SZL_ID_01A0_IDX_0006[132] = { + 0xFF,0x09,0x00,0x80,0x01,0xA0,0x00,0x00,0x00,0x14,0x00,0x06,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00, + 0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x86,0x13,0x81,0xFE,0x64,0xC7,0x72, + 0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x76,0x43,0x01,0xFF,0x46,0xC7, + 0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x29,0x66,0x43,0x04,0xFF,0x84, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x52,0x13,0x90,0x16,0x43,0x02,0xFF, + 0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x56,0x13,0x81, + 0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x46 + }; + + byte SZL_ID_01A0_IDX_0007[152] = { + 0xFF,0x09,0x00,0x94,0x01,0xA0,0x00,0x00,0x00,0x14,0x00,0x07,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00, + 0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x86,0x13,0x81,0xFE,0x64,0xC7,0x72, + 0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x76,0x43,0x01,0xFF,0x46,0xC7, + 0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x29,0x66,0x43,0x04,0xFF,0x84, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x52,0x13,0x90,0x16,0x43,0x02,0xFF, + 0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x56,0x13,0x81, + 0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x46,0x43, + 0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x79,0x46 + }; + + byte SZL_ID_01A0_IDX_0008[172] = { + 0xFF,0x09,0x00,0xA8,0x01,0xA0,0x00,0x00,0x00,0x14,0x00,0x08,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00, + 0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x86,0x13,0x81,0xFE,0x64,0xC7,0x72, + 0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x76,0x43,0x01,0xFF,0x46,0xC7, + 0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x29,0x66,0x43,0x04,0xFF,0x84, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x52,0x13,0x90,0x16,0x43,0x02,0xFF, + 0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x56,0x13,0x81, + 0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x46,0x43, + 0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x79,0x46, + 0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x51,0x19,0x48, + 0x26 + }; + + byte SZL_ID_01A0_IDX_0009[192] = { + 0xFF,0x09,0x00,0xBC,0x01,0xA0,0x00,0x00,0x00,0x14,0x00,0x09,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00, + 0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x86,0x13,0x81,0xFE,0x64,0xC7,0x72, + 0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x76,0x43,0x01,0xFF,0x46,0xC7, + 0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x29,0x66,0x43,0x04,0xFF,0x84, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x52,0x13,0x90,0x16,0x43,0x02,0xFF, + 0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x56,0x13,0x81, + 0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x46,0x43, + 0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x79,0x46, + 0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x51,0x19,0x48, + 0x26,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50,0x45, + 0x09,0x96 + }; + + byte SZL_ID_01A0_IDX_000A[212] = { + 0xFF,0x09,0x00,0xD0,0x01,0xA0,0x00,0x00,0x00,0x14,0x00,0x0A,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00, + 0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x86,0x13,0x81,0xFE,0x64,0xC7,0x72, + 0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x76,0x43,0x01,0xFF,0x46,0xC7, + 0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x29,0x66,0x43,0x04,0xFF,0x84, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x52,0x13,0x90,0x16,0x43,0x02,0xFF, + 0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x56,0x13,0x81, + 0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x46,0x43, + 0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x79,0x46, + 0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x51,0x19,0x48, + 0x26,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50,0x45, + 0x09,0x96,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50, + 0x45,0x09,0x86 + }; + + byte SZL_ID_01A0_IDX_000B[232] = { + 0xFF,0x09,0x00,0xE4,0x01,0xA0,0x00,0x00,0x00,0x14,0x00,0x0B,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00, + 0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x86,0x13,0x81,0xFE,0x64,0xC7,0x72, + 0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x76,0x43,0x01,0xFF,0x46,0xC7, + 0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x29,0x66,0x43,0x04,0xFF,0x84, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x52,0x13,0x90,0x16,0x43,0x02,0xFF, + 0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x56,0x13,0x81, + 0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x46,0x43, + 0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x79,0x46, + 0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x51,0x19,0x48, + 0x26,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50,0x45, + 0x09,0x96,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50, + 0x45,0x09,0x86,0x43,0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23, + 0x50,0x45,0x00,0x96 + }; + + byte SZL_ID_01A0_IDX_000C[252] = { + 0xFF,0x09,0x00,0xF8,0x01,0xA0,0x00,0x00,0x00,0x14,0x00,0x0C,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00, + 0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x86,0x13,0x81,0xFE,0x64,0xC7,0x72, + 0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x76,0x43,0x01,0xFF,0x46,0xC7, + 0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x29,0x66,0x43,0x04,0xFF,0x84, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x52,0x13,0x90,0x16,0x43,0x02,0xFF, + 0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x56,0x13,0x81, + 0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x46,0x43, + 0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x79,0x46, + 0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x51,0x19,0x48, + 0x26,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50,0x45, + 0x09,0x96,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50, + 0x45,0x09,0x86,0x43,0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23, + 0x50,0x45,0x00,0x96,0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04, + 0x23,0x50,0x42,0x54,0x66 + }; + + byte SZL_ID_01A0_IDX_000D[272] = { + 0xFF,0x09,0x01,0x0C,0x01,0xA0,0x00,0x00,0x00,0x14,0x00,0x0D,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00, + 0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x86,0x13,0x81,0xFE,0x64,0xC7,0x72, + 0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x76,0x43,0x01,0xFF,0x46,0xC7, + 0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x29,0x66,0x43,0x04,0xFF,0x84, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x52,0x13,0x90,0x16,0x43,0x02,0xFF, + 0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x56,0x13,0x81, + 0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x46,0x43, + 0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x79,0x46, + 0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x51,0x19,0x48, + 0x26,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50,0x45, + 0x09,0x96,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50, + 0x45,0x09,0x86,0x43,0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23, + 0x50,0x45,0x00,0x96,0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04, + 0x23,0x50,0x42,0x54,0x66,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02, + 0x04,0x23,0x50,0x32,0x40,0x46 + }; + + byte SZL_ID_01A0_IDX_000E[292] = { + 0xFF,0x09,0x01,0x20,0x01,0xA0,0x00,0x00,0x00,0x14,0x00,0x0E,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00, + 0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x86,0x13,0x81,0xFE,0x64,0xC7,0x72, + 0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x76,0x43,0x01,0xFF,0x46,0xC7, + 0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x29,0x66,0x43,0x04,0xFF,0x84, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x52,0x13,0x90,0x16,0x43,0x02,0xFF, + 0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x56,0x13,0x81, + 0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x46,0x43, + 0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x79,0x46, + 0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x51,0x19,0x48, + 0x26,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50,0x45, + 0x09,0x96,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50, + 0x45,0x09,0x86,0x43,0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23, + 0x50,0x45,0x00,0x96,0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04, + 0x23,0x50,0x42,0x54,0x66,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02, + 0x04,0x23,0x50,0x32,0x40,0x46,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94, + 0x02,0x04,0x23,0x50,0x32,0x40,0x36 + }; + + byte SZL_ID_01A0_IDX_000F[312] = { + 0xFF,0x09,0x01,0x34,0x01,0xA0,0x00,0x00,0x00,0x14,0x00,0x0F,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00, + 0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x86,0x13,0x81,0xFE,0x64,0xC7,0x72, + 0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x76,0x43,0x01,0xFF,0x46,0xC7, + 0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x29,0x66,0x43,0x04,0xFF,0x84, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x52,0x13,0x90,0x16,0x43,0x02,0xFF, + 0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x56,0x13,0x81, + 0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x46,0x43, + 0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x79,0x46, + 0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x51,0x19,0x48, + 0x26,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50,0x45, + 0x09,0x96,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50, + 0x45,0x09,0x86,0x43,0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23, + 0x50,0x45,0x00,0x96,0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04, + 0x23,0x50,0x42,0x54,0x66,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02, + 0x04,0x23,0x50,0x32,0x40,0x46,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94, + 0x02,0x04,0x23,0x50,0x32,0x40,0x36,0x43,0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14, + 0x94,0x02,0x04,0x23,0x50,0x32,0x31,0x46 + }; + + byte SZL_ID_01A0_IDX_0010[332] = { + 0xFF,0x09,0x01,0x48,0x01,0xA0,0x00,0x00,0x00,0x14,0x00,0x10,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00, + 0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x86,0x13,0x81,0xFE,0x64,0xC7,0x72, + 0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x76,0x43,0x01,0xFF,0x46,0xC7, + 0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x29,0x66,0x43,0x04,0xFF,0x84, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x52,0x13,0x90,0x16,0x43,0x02,0xFF, + 0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x56,0x13,0x81, + 0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x46,0x43, + 0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x79,0x46, + 0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x51,0x19,0x48, + 0x26,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50,0x45, + 0x09,0x96,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50, + 0x45,0x09,0x86,0x43,0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23, + 0x50,0x45,0x00,0x96,0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04, + 0x23,0x50,0x42,0x54,0x66,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02, + 0x04,0x23,0x50,0x32,0x40,0x46,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94, + 0x02,0x04,0x23,0x50,0x32,0x40,0x36,0x43,0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14, + 0x94,0x02,0x04,0x23,0x50,0x32,0x31,0x46,0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x94,0x02,0x04,0x23,0x50,0x29,0x92,0x26 + }; + + byte SZL_ID_01A0_IDX_0011[352] = { + 0xFF,0x09,0x01,0x5C,0x01,0xA0,0x00,0x00,0x00,0x14,0x00,0x11,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00, + 0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x86,0x13,0x81,0xFE,0x64,0xC7,0x72, + 0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x76,0x43,0x01,0xFF,0x46,0xC7, + 0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x29,0x66,0x43,0x04,0xFF,0x84, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x52,0x13,0x90,0x16,0x43,0x02,0xFF, + 0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x56,0x13,0x81, + 0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x46,0x43, + 0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x79,0x46, + 0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x51,0x19,0x48, + 0x26,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50,0x45, + 0x09,0x96,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50, + 0x45,0x09,0x86,0x43,0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23, + 0x50,0x45,0x00,0x96,0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04, + 0x23,0x50,0x42,0x54,0x66,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02, + 0x04,0x23,0x50,0x32,0x40,0x46,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94, + 0x02,0x04,0x23,0x50,0x32,0x40,0x36,0x43,0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14, + 0x94,0x02,0x04,0x23,0x50,0x32,0x31,0x46,0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x94,0x02,0x04,0x23,0x50,0x29,0x92,0x26,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14, + 0x77,0x14,0x94,0x02,0x04,0x23,0x49,0x22,0x26,0x66 + }; + + byte SZL_ID_01A0_IDX_0012[372] = { + 0xFF,0x09,0x01,0x70,0x01,0xA0,0x00,0x00,0x00,0x14,0x00,0x12,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00, + 0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x86,0x13,0x81,0xFE,0x64,0xC7,0x72, + 0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x76,0x43,0x01,0xFF,0x46,0xC7, + 0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x29,0x66,0x43,0x04,0xFF,0x84, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x52,0x13,0x90,0x16,0x43,0x02,0xFF, + 0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x56,0x13,0x81, + 0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x46,0x43, + 0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x79,0x46, + 0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x51,0x19,0x48, + 0x26,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50,0x45, + 0x09,0x96,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50, + 0x45,0x09,0x86,0x43,0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23, + 0x50,0x45,0x00,0x96,0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04, + 0x23,0x50,0x42,0x54,0x66,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02, + 0x04,0x23,0x50,0x32,0x40,0x46,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94, + 0x02,0x04,0x23,0x50,0x32,0x40,0x36,0x43,0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14, + 0x94,0x02,0x04,0x23,0x50,0x32,0x31,0x46,0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x94,0x02,0x04,0x23,0x50,0x29,0x92,0x26,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14, + 0x77,0x14,0x94,0x02,0x04,0x23,0x49,0x22,0x26,0x66,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43,0x04,0x08, + 0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x49,0x22,0x26,0x56 + }; + + byte SZL_ID_01A0_IDX_0013[392] = { + 0xFF,0x09,0x01,0x84,0x01,0xA0,0x00,0x00,0x00,0x14,0x00,0x13,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00, + 0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x86,0x13,0x81,0xFE,0x64,0xC7,0x72, + 0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x76,0x43,0x01,0xFF,0x46,0xC7, + 0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x29,0x66,0x43,0x04,0xFF,0x84, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x52,0x13,0x90,0x16,0x43,0x02,0xFF, + 0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x56,0x13,0x81, + 0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x46,0x43, + 0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x79,0x46, + 0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x51,0x19,0x48, + 0x26,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50,0x45, + 0x09,0x96,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50, + 0x45,0x09,0x86,0x43,0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23, + 0x50,0x45,0x00,0x96,0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04, + 0x23,0x50,0x42,0x54,0x66,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02, + 0x04,0x23,0x50,0x32,0x40,0x46,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94, + 0x02,0x04,0x23,0x50,0x32,0x40,0x36,0x43,0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14, + 0x94,0x02,0x04,0x23,0x50,0x32,0x31,0x46,0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x94,0x02,0x04,0x23,0x50,0x29,0x92,0x26,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14, + 0x77,0x14,0x94,0x02,0x04,0x23,0x49,0x22,0x26,0x66,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43,0x04,0x08, + 0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x49,0x22,0x26,0x56,0x43,0x01,0xFF,0x46,0xC7,0x72,0x43,0x04, + 0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x49,0x22,0x17,0x66 + }; + + byte SZL_ID_01A0_IDX_0014[412] = { + 0xFF,0x09,0x01,0x98,0x01,0xA0,0x00,0x00,0x00,0x14,0x00,0x14,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00, + 0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x86,0x13,0x81,0xFE,0x64,0xC7,0x72, + 0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x76,0x43,0x01,0xFF,0x46,0xC7, + 0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x29,0x66,0x43,0x04,0xFF,0x84, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x52,0x13,0x90,0x16,0x43,0x02,0xFF, + 0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x56,0x13,0x81, + 0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x46,0x43, + 0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x79,0x46, + 0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x51,0x19,0x48, + 0x26,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50,0x45, + 0x09,0x96,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50, + 0x45,0x09,0x86,0x43,0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23, + 0x50,0x45,0x00,0x96,0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04, + 0x23,0x50,0x42,0x54,0x66,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02, + 0x04,0x23,0x50,0x32,0x40,0x46,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94, + 0x02,0x04,0x23,0x50,0x32,0x40,0x36,0x43,0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14, + 0x94,0x02,0x04,0x23,0x50,0x32,0x31,0x46,0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x94,0x02,0x04,0x23,0x50,0x29,0x92,0x26,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14, + 0x77,0x14,0x94,0x02,0x04,0x23,0x49,0x22,0x26,0x66,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43,0x04,0x08, + 0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x49,0x22,0x26,0x56,0x43,0x01,0xFF,0x46,0xC7,0x72,0x43,0x04, + 0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x49,0x22,0x17,0x66,0x43,0x04,0xFF,0x84,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x49,0x19,0x75,0x46 + }; + + byte SZL_ID_01A0_IDX_0015[432] = { + 0xFF,0x09,0x01,0xAC,0x01,0xA0,0x00,0x00,0x00,0x14,0x00,0x15,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00, + 0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x86,0x13,0x81,0xFE,0x64,0xC7,0x72, + 0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x76,0x43,0x01,0xFF,0x46,0xC7, + 0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x29,0x66,0x43,0x04,0xFF,0x84, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x52,0x13,0x90,0x16,0x43,0x02,0xFF, + 0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x56,0x13,0x81, + 0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x46,0x43, + 0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x79,0x46, + 0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x51,0x19,0x48, + 0x26,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50,0x45, + 0x09,0x96,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50, + 0x45,0x09,0x86,0x43,0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23, + 0x50,0x45,0x00,0x96,0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04, + 0x23,0x50,0x42,0x54,0x66,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02, + 0x04,0x23,0x50,0x32,0x40,0x46,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94, + 0x02,0x04,0x23,0x50,0x32,0x40,0x36,0x43,0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14, + 0x94,0x02,0x04,0x23,0x50,0x32,0x31,0x46,0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x94,0x02,0x04,0x23,0x50,0x29,0x92,0x26,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14, + 0x77,0x14,0x94,0x02,0x04,0x23,0x49,0x22,0x26,0x66,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43,0x04,0x08, + 0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x49,0x22,0x26,0x56,0x43,0x01,0xFF,0x46,0xC7,0x72,0x43,0x04, + 0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x49,0x22,0x17,0x66,0x43,0x04,0xFF,0x84,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x49,0x19,0x75,0x46,0x43,0x02,0xFF,0x68,0xC7,0x00, + 0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x48,0x32,0x21,0x16 + }; + + byte SZL_ID_0117_IDX_0000[16] = { + 0xFF,0x09,0x00,0x0C,0x01,0x17,0x00,0x00,0x00,0x04,0x00,0x01,0x00,0x00,0x00,0x01 + }; + + byte SZL_ID_0117_IDX_0001[16] = { + 0xFF,0x09,0x00,0x0C,0x01,0x17,0x00,0x01,0x00,0x04,0x00,0x01,0x00,0x01,0x00,0x03 + }; + + byte SZL_ID_0117_IDX_0002[16] = { + 0xFF,0x09,0x00,0x0C,0x01,0x17,0x00,0x02,0x00,0x04,0x00,0x01,0x00,0x02,0x00,0x02 + }; + + byte SZL_ID_0117_IDX_0003[16] = { + 0xFF,0x09,0x00,0x0C,0x01,0x17,0x00,0x03,0x00,0x04,0x00,0x01,0x00,0x03,0x00,0x01 + }; + + byte SZL_ID_0117_IDX_0004[16] = { + 0xFF,0x09,0x00,0x0C,0x01,0x17,0x00,0x04,0x00,0x04,0x00,0x01,0x00,0x04,0x00,0x01 + }; + + byte SZL_ID_0118_IDX_0000[16] = { + 0xFF,0x09,0x00,0x0C,0x01,0x18,0x00,0x00,0x00,0x04,0x00,0x01,0x00,0x00,0x00,0x08 + }; + + byte SZL_ID_0118_IDX_0001[16] = { + 0xFF,0x09,0x00,0x0C,0x01,0x18,0x00,0x01,0x00,0x04,0x00,0x01,0x00,0x01,0x00,0x08 + }; + + byte SZL_ID_0118_IDX_0002[16] = { + 0xFF,0x09,0x00,0x0C,0x01,0x18,0x00,0x02,0x00,0x04,0x00,0x01,0x00,0x02,0x00,0x08 + }; + + byte SZL_ID_0118_IDX_0003[16] = { + 0xFF,0x09,0x00,0x0C,0x01,0x18,0x00,0x03,0x00,0x04,0x00,0x01,0x00,0x03,0x00,0x08 + }; + + byte SZL_ID_0131_IDX_0001[52] = { + 0xFF,0x09,0x00,0x30,0x01,0x31,0x00,0x01,0x00,0x28,0x00,0x01,0x00,0x01, + 0x08,0x00, // PDU SIZE : We expose 2048 00F0 + 0x04,0x00, // Max Commections : We expose 1024 0010 + 0x00,0xB7,0x1B,0x00,0x00,0x02,0xDC,0x6C,0x05,0xF5,0xE1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + }; + + byte SZL_ID_0131_IDX_0002[52] = { + 0xFF,0x09,0x00,0x30,0x01,0x31,0x00,0x02,0x00,0x28,0x00,0x01,0x00,0x02,0xBE,0xFD,0x4F,0x00,0x00, + 0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x3C,0x01,0x08,0x00,0x00,0x00,0x7D,0x00,0x00,0x05,0x03,0x0F, + 0x00,0x00,0x08,0x00,0x00,0x0C,0x00,0x0A,0x00,0x00,0x00,0x01,0x00,0x00 + }; + + byte SZL_ID_0131_IDX_0003[52] = { + 0xFF,0x09,0x00,0x30,0x01,0x31,0x00,0x03,0x00,0x28,0x00,0x01,0x00,0x03,0x7F,0xFC,0x83,0x01, + 0x00,0xF0, // Max size of consistently readable data (will be set = PDU size) + 0x00,0x10,0x00,0x01,0x02,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + }; + + byte SZL_ID_0131_IDX_0004[52] = { + 0xFF,0x09,0x00,0x30,0x01,0x31,0x00,0x04,0x00,0x28,0x00,0x01,0x00,0x04,0xFE,0x01,0x62,0x41,0x63, + 0x00,0x1E,0x00,0x10,0x10,0x10,0x04,0x02,0x00,0x00,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + }; + + byte SZL_ID_0131_IDX_0005[52] = { + 0xFF,0x09,0x00,0x30,0x01,0x31,0x00,0x05,0x00,0x28,0x00,0x01,0x00,0x05,0x3E,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x10,0x01,0xF4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + }; + + byte SZL_ID_0131_IDX_0006[52] = { + 0xFF,0x09,0x00,0x30,0x01,0x31,0x00,0x06,0x00,0x28,0x00,0x01,0x00,0x06,0xF3,0x00,0x00,0xF8,0x01, + 0xF0,0xFF,0x4E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x20, + 0x01,0x00,0x00,0x0E,0x00,0x4C,0xFF,0xFF,0x05,0xC0,0x00,0x00,0x00,0x00 + }; + + byte SZL_ID_0131_IDX_0007[52] = { + 0xFF,0x09,0x00,0x30,0x01,0x31,0x00,0x07,0x00,0x28,0x00,0x01,0x00,0x07,0x01,0x00,0x3F,0x00,0x20, + 0x01,0x01,0x00,0x00,0x00,0x01,0x08,0x01,0x08,0x01,0x08,0x20,0x08,0x02,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + }; + + byte SZL_ID_0131_IDX_0008[52] = { + 0xFF,0x09,0x00,0x30,0x01,0x31,0x00,0x08,0x00,0x28,0x00,0x01,0x00,0x08,0x70,0x03,0x70,0x02,0x70, + 0x02,0x40,0x32,0x40,0x32,0x40,0x32,0x40,0x64,0x40,0x32,0x40,0x32,0x40,0x64,0x40,0x64,0x40,0x64, + 0x40,0x64,0x40,0x64,0x40,0x64,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + }; + + byte SZL_ID_0131_IDX_0009[52] = { + 0xFF,0x09,0x00,0x30,0x01,0x31,0x00,0x09,0x00,0x28,0x00,0x01,0x00,0x09,0x04,0x06,0x01,0x00,0x01, + 0xF7,0x01,0xF7,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + }; + + byte SZL_ID_0C91_IDX_07FE[28] = { + 0xFF,0x09,0x00,0x18,0x0C,0x91,0x07,0xFE,0x00,0x10,0x00,0x01,0x00,0x00,0x02,0x02,0x07,0xFE,0xA7, + 0xC4,0xA7,0xC4,0x00,0x00,0xB4,0x02,0x00,0x11 + }; + + +#endif + diff --git a/APP_Framework/Framework/control/plc/interoperability/s7/s7_isotcp.cpp b/APP_Framework/Framework/control/plc/interoperability/s7/s7_isotcp.cpp new file mode 100644 index 000000000..f0390bfe3 --- /dev/null +++ b/APP_Framework/Framework/control/plc/interoperability/s7/s7_isotcp.cpp @@ -0,0 +1,549 @@ +/*=============================================================================| +| PROJECT SNAP7 1.3.0 | +|==============================================================================| +| Copyright (C) 2013, 2015 Davide Nardella | +| All rights reserved. | +|==============================================================================| +| SNAP7 is free software: you can redistribute it and/or modify | +| it under the terms of the Lesser GNU General Public License as published by | +| the Free Software Foundation, either version 3 of the License, or | +| (at your option) any later version. | +| | +| It means that you can distribute your commercial software linked with | +| SNAP7 without the requirement to distribute the source code of your | +| application and without the requirement that your application be itself | +| distributed under LGPL. | +| | +| SNAP7 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 | +| Lesser GNU General Public License for more details. | +| | +| You should have received a copy of the GNU General Public License and a | +| copy of Lesser GNU General Public License along with Snap7. | +| If not, see http://www.gnu.org/licenses/ | +|=============================================================================*/ +#include "s7_isotcp.h" +#include +//--------------------------------------------------------------------------- +TIsoTcpSocket::TIsoTcpSocket() +{ + RecvTimeout = 10000; // Some old equipments are a bit slow to answer.... + RemotePort = isoTcpPort; + // These fields should be $0000 and in any case RFC says that they are not considered. + // But some equipment...need a non zero value for the source reference. + DstRef = 0x0000; + SrcRef = 0x0100; + // PDU size requested + IsoPDUSize =1024; + IsoMaxFragments=MaxIsoFragments; + LastIsoError=0; +} +//--------------------------------------------------------------------------- +TIsoTcpSocket::~TIsoTcpSocket() +{ +} +//--------------------------------------------------------------------------- +int TIsoTcpSocket::CheckPDU(void *pPDU, u_char PduTypeExpected) +{ + PIsoHeaderInfo Info; + int Size; + ClrIsoError(); + if (pPDU!=0) + { + Info = PIsoHeaderInfo(pPDU); + Size = PDUSize(pPDU); + // Performs check + if (( Size<7 ) || ( Size>IsoPayload_Size ) || // Checks RFC 1006 header length + ( Info->HLengthPDUType!=PduTypeExpected)) // Checks PDU Type + return SetIsoError(errIsoInvalidPDU); + else + return noError; + } + else + return SetIsoError(errIsoNullPointer); +} +//--------------------------------------------------------------------------- +int TIsoTcpSocket::SetIsoError(int Error) +{ + LastIsoError = Error | LastTcpError; + return LastIsoError; +} +//--------------------------------------------------------------------------- +void TIsoTcpSocket::ClrIsoError() +{ + LastIsoError=0; + LastTcpError=0; +} +//--------------------------------------------------------------------------- +int TIsoTcpSocket::BuildControlPDU() +{ + int ParLen, IsoLen; + + ClrIsoError(); + FControlPDU.COTP.Params.PduSizeCode=0xC0; // code that identifies TPDU size + FControlPDU.COTP.Params.PduSizeLen =0x01; // 1 byte this field + switch(IsoPDUSize) + { + case 128: + FControlPDU.COTP.Params.PduSizeVal =0x07; + break; + case 256: + FControlPDU.COTP.Params.PduSizeVal =0x08; + break; + case 512: + FControlPDU.COTP.Params.PduSizeVal =0x09; + break; + case 1024: + FControlPDU.COTP.Params.PduSizeVal =0x0A; + break; + case 2048: + FControlPDU.COTP.Params.PduSizeVal =0x0B; + break; + case 4096: + FControlPDU.COTP.Params.PduSizeVal =0x0C; + break; + case 8192: + FControlPDU.COTP.Params.PduSizeVal =0x0D; + break; + default: + FControlPDU.COTP.Params.PduSizeVal =0x0B; // Our Default + }; + // Build TSAPs + FControlPDU.COTP.Params.TSAP[0]=0xC1; // code that identifies source TSAP + FControlPDU.COTP.Params.TSAP[1]=2; // source TSAP Len + FControlPDU.COTP.Params.TSAP[2]=(SrcTSap>>8) & 0xFF; // HI part + FControlPDU.COTP.Params.TSAP[3]=SrcTSap & 0xFF; // LO part + + FControlPDU.COTP.Params.TSAP[4]=0xC2; // code that identifies dest TSAP + FControlPDU.COTP.Params.TSAP[5]=2; // dest TSAP Len + FControlPDU.COTP.Params.TSAP[6]=(DstTSap>>8) & 0xFF; // HI part + FControlPDU.COTP.Params.TSAP[7]=DstTSap & 0xFF; // LO part + + // Params length + ParLen=11; // 2 Src TSAP (Code+field Len) + + // 2 Src TSAP len + + // 2 Dst TSAP (Code+field Len) + + // 2 Src TSAP len + + // 3 PDU size (Code+field Len+Val) = 11 + // Telegram length + IsoLen=sizeof(TTPKT)+ // TPKT Header + 7 + // COTP Header Size without params + ParLen; // COTP params + + FControlPDU.TPKT.Version =isoTcpVersion; + FControlPDU.TPKT.Reserved =0; + FControlPDU.TPKT.HI_Lenght=0; // Connection Telegram size cannot exced 255 bytes, so + // this field is always 0 + FControlPDU.TPKT.LO_Lenght=IsoLen; + + FControlPDU.COTP.HLength =ParLen + 6; // <-- 6 = 7 - 1 (COTP Header size - 1) + FControlPDU.COTP.PDUType =pdu_type_CR; // Connection Request + FControlPDU.COTP.DstRef =DstRef; // Destination reference + FControlPDU.COTP.SrcRef =SrcRef; // Source reference + FControlPDU.COTP.CO_R =0x00; // Class + Option : RFC0983 states that it must be always 0x40 + // but for some equipment (S7) must be 0 in disaccord of specifications !!! + return noError; +} +//--------------------------------------------------------------------------- +int TIsoTcpSocket::PDUSize(void *pPDU) +{ + return PIsoHeaderInfo(pPDU)->TPKT.HI_Lenght*256+PIsoHeaderInfo( pPDU )->TPKT.LO_Lenght; +} +//--------------------------------------------------------------------------- +void TIsoTcpSocket::IsoParsePDU(TIsoControlPDU pdu) +{ +// Currently we accept a connection with any kind of src/dst tsap +// Override to implement special filters. +} +//--------------------------------------------------------------------------- +int TIsoTcpSocket::IsoConfirmConnection(u_char PDUType) +{ + PIsoControlPDU CPDU = PIsoControlPDU(&PDU); + u_short TempRef; + + ClrIsoError(); + PDU.COTP.PDUType=PDUType; + // Exchange SrcRef<->DstRef, not strictly needed by COTP 8073 but S7PLC as client needs it. + TempRef=CPDU->COTP.DstRef; + CPDU->COTP.DstRef=CPDU->COTP.SrcRef; + CPDU->COTP.SrcRef=0x0100;//TempRef; + + return SendPacket(&PDU,PDUSize(&PDU)); +} +//--------------------------------------------------------------------------- +void TIsoTcpSocket::FragmentSkipped(int Size) +{ +// override for log purpose +} +//--------------------------------------------------------------------------- +int TIsoTcpSocket::isoConnect() +{ + pbyte TmpControlPDU; + PIsoControlPDU ControlPDU; + u_int Length; + int Result; + + // Build the default connection telegram + BuildControlPDU(); + ControlPDU =&FControlPDU; + + // Checks the format + Result =CheckPDU(ControlPDU, pdu_type_CR); + if (Result!=0) + return Result; + printf("Checked PDU\n"); + + Result =SckConnect(); + printf("Socket build with Result=%d!\n", Result); + if (Result==noError) + { + // Calcs the length + Length =PDUSize(ControlPDU); + // Send connection telegram + SendPacket(ControlPDU, Length); + printf("Sent packet with LastTcpError=%d\n",LastTcpError); + if (LastTcpError==0) + { + TmpControlPDU = pbyte(ControlPDU); + // Receives TPKT header (4 bytes) + RecvPacket(TmpControlPDU, sizeof(TTPKT)); + printf("Received packet with LastTcpError=%d\n",LastTcpError); + if (LastTcpError==0) + { + // Calc the packet length + Length =PDUSize(TmpControlPDU); + printf("PDU size=%d\n",Length); + // Check if it fits in the buffer and if it's greater then TTPKT size + if ((Length<=sizeof(TIsoControlPDU)) && (Length>sizeof(TTPKT))) + { + // Points to COTP + TmpControlPDU+=sizeof(TTPKT); + Length -= sizeof(TTPKT); + // Receives remainin bytes 4 bytes after + RecvPacket(TmpControlPDU, Length); + printf("Received packet again with LastTcpError=%d\n",LastTcpError); + if (LastTcpError==0) + { + // Finally checks the Connection Confirm telegram + Result =CheckPDU(ControlPDU, pdu_type_CC); + printf("Checked PDU with Result=%d\n",Result); + if (Result!=0) + LastIsoError=Result; + } + else + Result =SetIsoError(errIsoRecvPacket); + } + else + Result =SetIsoError(errIsoInvalidPDU); + } + else + Result =SetIsoError(errIsoRecvPacket); + // Flush buffer + if (Result!=0) + Purge(); + } + else + Result =SetIsoError(errIsoSendPacket); + + if (Result!=0) + SckDisconnect(); + } + return Result; +} +//--------------------------------------------------------------------------- +int TIsoTcpSocket::isoSendBuffer(void *Data, int Size) +{ + int Result; + u_int IsoSize; + + ClrIsoError(); + // Total Size = Size + Header Size + IsoSize =Size+DataHeaderSize; + // Checks the length + if ((IsoSize>0) && (IsoSize<=IsoFrameSize)) + { + // Builds the header + Result =0; + // TPKT + PDU.TPKT.Version = isoTcpVersion; + PDU.TPKT.Reserved = 0; + PDU.TPKT.HI_Lenght= (u_short(IsoSize)>> 8) & 0xFF; + PDU.TPKT.LO_Lenght= u_short(IsoSize) & 0xFF; + // COPT + PDU.COTP.HLength =sizeof(TCOTP_DT)-1; + PDU.COTP.PDUType =pdu_type_DT; + PDU.COTP.EoT_Num =pdu_EoT; + // Fill payload + if (Data!=0) // Data=null ==> use internal buffer PDU.Payload + memcpy(&PDU.Payload, Data, Size); + // Send over TCP/IP + SendPacket(&PDU, IsoSize); + + if (LastTcpError!=0) + Result =SetIsoError(errIsoSendPacket); + } + else + Result =SetIsoError(errIsoInvalidDataSize ); + return Result; +} +//--------------------------------------------------------------------------- +int TIsoTcpSocket::isoRecvBuffer(void *Data, int & Size) +{ + int Result; + + ClrIsoError(); + Size =0; + Result =isoRecvPDU(&PDU); + if (Result==0) + { + Size =PDUSize( &PDU )-DataHeaderSize; + if (Data!=0) // Data=NULL ==> a child will consume directly PDY.Payload + memcpy(Data, &PDU.Payload, Size); + } + return Result; +} +//--------------------------------------------------------------------------- +int TIsoTcpSocket::isoExchangeBuffer(void *Data, int &Size) +{ + int Result; + + ClrIsoError(); + Result =isoSendBuffer(Data, Size); + if (Result==0) + Result =isoRecvBuffer(Data, Size); + return Result; +} +//--------------------------------------------------------------------------- +bool TIsoTcpSocket::IsoPDUReady() +{ + ClrIsoError(); + return PacketReady(sizeof(TCOTP_DT)); +} +//--------------------------------------------------------------------------- +int TIsoTcpSocket::isoDisconnect(bool OnlyTCP) +{ + int Result; + + ClrIsoError(); + if (Connected) + Purge(); // Flush pending + LastIsoError=0; + // OnlyTCP true -> Disconnect Request telegram is not required : only TCP disconnection + if (!OnlyTCP) + { + // if we are connected -> we have a valid connection telegram + if (Connected) + FControlPDU.COTP.PDUType =pdu_type_DR; + // Checks the format + Result =CheckPDU(&FControlPDU, pdu_type_DR); + if (Result!=0) + return Result; + // Sends Disconnect request + SendPacket(&FControlPDU, PDUSize(&FControlPDU)); + if (LastTcpError!=0) + { + Result =SetIsoError(errIsoSendPacket); + return Result; + } + } + // TCP disconnect + SckDisconnect(); + if (LastTcpError!=0) + Result =SetIsoError(errIsoDisconnect); + else + Result =0; + + return Result; +} +//--------------------------------------------------------------------------- +int TIsoTcpSocket::isoSendPDU(PIsoDataPDU Data) +{ + int Result; + + ClrIsoError(); + Result=CheckPDU(Data,pdu_type_DT); + if (Result==0) + { + SendPacket(Data,PDUSize(Data)); + if (LastTcpError!=0) + Result=SetIsoError(errIsoSendPacket); + } + return Result; +} +//------------------------------------------------------------------------------ +int TIsoTcpSocket::isoRecvFragment(void *From, int Max, int &Size, bool &EoT) +{ + int DataLength; + + Size =0; + EoT =false; + byte PDUType; + ClrIsoError(); + // header is received always from beginning + RecvPacket(&PDU, DataHeaderSize); // TPKT + COPT_DT + if (LastTcpError==0) + { + PDUType=PDU.COTP.PDUType; + switch (PDUType) + { + case pdu_type_CR: + case pdu_type_DR: + EoT=true; + break; + case pdu_type_DT: + EoT = (PDU.COTP.EoT_Num & 0x80) == 0x80; // EoT flag + break; + default: + return SetIsoError(errIsoInvalidPDU); + } + + DataLength = PDUSize(&PDU) - DataHeaderSize; + if (CheckPDU(&PDU, PDUType)!=0) + return LastIsoError; + // Checks for data presence + if (DataLength>0) // payload present + { + // Check if the data fits in the buffer + if(DataLength<=Max) + { + RecvPacket(From, DataLength); + if (LastTcpError!=0) + return SetIsoError(errIsoRecvPacket); + else + Size =DataLength; + } + else + return SetIsoError(errIsoPduOverflow); + } + } + else + return SetIsoError(errIsoRecvPacket); + + return LastIsoError; +} +//--------------------------------------------------------------------------- +// Fragments Recv schema +//------------------------------------------------------------------------------ +// +// packet 1 packet 2 packet 3 +// +--------+------------+ +--------+------------+ +--------+------------+ +// | HEADER | FRAGMENT 1 | | HEADER | FRAGMENT 2 | | HEADER | FRAGMENT 3 | +// +--------+------------+ +--------+------------+ +--------+------------+ +// | | | +// | +-----------+ | +// | | | +// | | +------------------------+ +// | | | (Packet 3 has EoT Flag set) +// V V V +// +--------+------------+------------+------------+ +// | HEADER | FRAGMENT 1 : FRAGMENT 2 : FRAGMENT 3 | +// +--------+------------+------------+------------+ +// ^ +// | +// +-- A new header is built with updated info +// +//------------------------------------------------------------------------------ +int TIsoTcpSocket::isoRecvPDU(PIsoDataPDU Data) +{ + int Result; + int Size; + pbyte pData; + int max; + int Offset; + int Received; + int NumParts; + bool Complete; + + NumParts =1; + Offset =0; + Complete =false; + ClrIsoError(); + pData = pbyte(&PDU.Payload); + do { + pData=pData+Offset; + max =IsoPayload_Size-Offset; // Maximum packet allowed + if (max>0) + { + Result =isoRecvFragment(pData, max, Received, Complete); + if((Result==0) && !Complete) + { + ++NumParts; + Offset += Received; + if (NumParts>IsoMaxFragments) + Result =SetIsoError(errIsoTooManyFragments); + } + } + else + Result =SetIsoError(errIsoTooManyFragments); + } while ((!Complete) && (Result==0)); + + + if (Result==0) + { + // Add to offset the header size + Size =Offset+Received+DataHeaderSize; + // Adjust header + PDU.TPKT.HI_Lenght =(u_short(Size)>>8) & 0xFF; + PDU.TPKT.LO_Lenght =u_short(Size) & 0xFF; + // Copies data if target is not the local PDU + if (Data!=&PDU) + memcpy(Data, &PDU, Size); + } + else + if (LastTcpError!=WSAECONNRESET) + Purge(); + return Result; +} +//--------------------------------------------------------------------------- +int TIsoTcpSocket::isoExchangePDU(PIsoDataPDU Data) +{ + int Result; + ClrIsoError(); + Result=isoSendPDU(Data); + if (Result==0) + Result=isoRecvPDU(Data); + return Result; +} +//--------------------------------------------------------------------------- +void TIsoTcpSocket::IsoPeek(void *pPDU, TPDUKind &PduKind) +{ + PIsoHeaderInfo Info; + u_int IsoLen; + + Info=PIsoHeaderInfo(pPDU); + IsoLen=PDUSize(Info); + + // Check for empty fragment : size of PDU = size of header and nothing else + if (IsoLen==DataHeaderSize ) + { + // We don't need to check the EoT flag since the PDU is empty.... + PduKind=pkEmptyFragment; + return; + }; + // Check for invalid packet : size of PDU < size of header + if (IsoLenDataHeaderSize : check the PDUType + switch (Info->PDUType) + { + case pdu_type_CR: + PduKind=pkConnectionRequest; + break; + case pdu_type_DR: + PduKind=pkDisconnectRequest; + break; + case pdu_type_DT: + PduKind=pkValidData; + break; + default: + PduKind=pkUnrecognizedType; + }; +} + + + diff --git a/APP_Framework/Framework/control/plc/interoperability/s7/s7_isotcp.h b/APP_Framework/Framework/control/plc/interoperability/s7/s7_isotcp.h new file mode 100644 index 000000000..e02a365d2 --- /dev/null +++ b/APP_Framework/Framework/control/plc/interoperability/s7/s7_isotcp.h @@ -0,0 +1,271 @@ +/*=============================================================================| +| PROJECT SNAP7 1.3.0 | +|==============================================================================| +| Copyright (C) 2013, 2015 Davide Nardella | +| All rights reserved. | +|==============================================================================| +| SNAP7 is free software: you can redistribute it and/or modify | +| it under the terms of the Lesser GNU General Public License as published by | +| the Free Software Foundation, either version 3 of the License, or | +| (at your option) any later version. | +| | +| It means that you can distribute your commercial software linked with | +| SNAP7 without the requirement to distribute the source code of your | +| application and without the requirement that your application be itself | +| distributed under LGPL. | +| | +| SNAP7 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 | +| Lesser GNU General Public License for more details. | +| | +| You should have received a copy of the GNU General Public License and a | +| copy of Lesser GNU General Public License along with Snap7. | +| If not, see http://www.gnu.org/licenses/ | +|=============================================================================*/ +#ifndef s7_isotcp_h +#define s7_isotcp_h +//--------------------------------------------------------------------------- +#include "snap_msgsock.h" +//--------------------------------------------------------------------------- +#pragma pack(1) + +#define isoTcpVersion 3 // RFC 1006 +#define isoTcpPort 102 // RFC 1006 +#define isoInvalidHandle 0 +#define MaxTSAPLength 16 // Max Lenght for Src and Dst TSAP +#define MaxIsoFragments 64 // Max fragments +#define IsoPayload_Size 4096 // Iso telegram Buffer size + +#define noError 0 + +const longword errIsoMask = 0x000F0000; +const longword errIsoBase = 0x0000FFFF; + +const longword errIsoConnect = 0x00010000; // Connection error +const longword errIsoDisconnect = 0x00020000; // Disconnect error +const longword errIsoInvalidPDU = 0x00030000; // Bad format +const longword errIsoInvalidDataSize = 0x00040000; // Bad Datasize passed to send/recv : buffer is invalid +const longword errIsoNullPointer = 0x00050000; // Null passed as pointer +const longword errIsoShortPacket = 0x00060000; // A short packet received +const longword errIsoTooManyFragments = 0x00070000; // Too many packets without EoT flag +const longword errIsoPduOverflow = 0x00080000; // The sum of fragments data exceded maximum packet size +const longword errIsoSendPacket = 0x00090000; // An error occurred during send +const longword errIsoRecvPacket = 0x000A0000; // An error occurred during recv +const longword errIsoInvalidParams = 0x000B0000; // Invalid TSAP params +const longword errIsoResvd_1 = 0x000C0000; // Unassigned +const longword errIsoResvd_2 = 0x000D0000; // Unassigned +const longword errIsoResvd_3 = 0x000E0000; // Unassigned +const longword errIsoResvd_4 = 0x000F0000; // Unassigned + +const longword ISO_OPT_TCP_NODELAY = 0x00000001; // Disable Nagle algorithm +const longword ISO_OPT_INSIDE_MTU = 0x00000002; // Max packet size < MTU ethernet card + +// TPKT Header - ISO on TCP - RFC 1006 (4 bytes) +typedef struct{ + u_char Version; // Always 3 for RFC 1006 + u_char Reserved; // 0 + u_char HI_Lenght; // High part of packet lenght (entire frame, payload and TPDU included) + u_char LO_Lenght; // Low part of packet lenght (entire frame, payload and TPDU included) +} TTPKT; // Packet length : min 7 max 65535 + +typedef struct { + u_char PduSizeCode; + u_char PduSizeLen; + u_char PduSizeVal; + u_char TSAP[245]; // We don't know in advance these fields.... +} TCOPT_Params ; + +// PDU Type constants - ISO 8073, not all are mentioned in RFC 1006 +// For our purposes we use only those labeled with ** +// These constants contains 4 low bit order 0 (credit nibble) +// +// $10 ED : Expedited Data +// $20 EA : Expedited Data Ack +// $40 UD : CLTP UD +// $50 RJ : Reject +// $70 AK : Ack data +// ** $80 DR : Disconnect request (note : S7 doesn't use it) +// ** $C0 DC : Disconnect confirm (note : S7 doesn't use it) +// ** $D0 CC : Connection confirm +// ** $E0 CR : Connection request +// ** $F0 DT : Data +// + +// COTP Header for CONNECTION REQUEST/CONFIRM - DISCONNECT REQUEST/CONFIRM +typedef struct { + u_char HLength; // Header length : initialized to 6 (length without params - 1) + // descending classes that add values in params field must update it. + u_char PDUType; // 0xE0 Connection request + // 0xD0 Connection confirm + // 0x80 Disconnect request + // 0xDC Disconnect confirm + u_short DstRef; // Destination reference : Always 0x0000 + u_short SrcRef; // Source reference : Always 0x0000 + u_char CO_R; // If the telegram is used for Connection request/Confirm, + // the meaning of this field is CLASS+OPTION : + // Class (High 4 bits) + Option (Low 4 bits) + // Class : Always 4 (0100) but is ignored in input (RFC States this) + // Option : Always 0, also this in ignored. + // If the telegram is used for Disconnect request, + // the meaning of this field is REASON : + // 1 Congestion at TSAP + // 2 Session entity not attached to TSAP + // 3 Address unknown (at TCP connect time) + // 128+0 Normal disconnect initiated by the session + // entity. + // 128+1 Remote transport entity congestion at connect + // request time + // 128+3 Connection negotiation failed + // 128+5 Protocol Error + // 128+8 Connection request refused on this network + // connection + // Parameter data : depending on the protocol implementation. + // ISO 8073 define several type of parameters, but RFC 1006 recognizes only + // TSAP related parameters and PDU size. See RFC 0983 for more details. + TCOPT_Params Params; + /* Other params not used here, list only for completeness + ACK_TIME = 0x85, 1000 0101 Acknowledge Time + RES_ERROR = 0x86, 1000 0110 Residual Error Rate + PRIORITY = 0x87, 1000 0111 Priority + TRANSIT_DEL = 0x88, 1000 1000 Transit Delay + THROUGHPUT = 0x89, 1000 1001 Throughput + SEQ_NR = 0x8A, 1000 1010 Subsequence Number (in AK) + REASSIGNMENT = 0x8B, 1000 1011 Reassignment Time + FLOW_CNTL = 0x8C, 1000 1100 Flow Control Confirmation (in AK) + TPDU_SIZE = 0xC0, 1100 0000 TPDU Size + SRC_TSAP = 0xC1, 1100 0001 TSAP-ID / calling TSAP ( in CR/CC ) + DST_TSAP = 0xC2, 1100 0010 TSAP-ID / called TSAP + CHECKSUM = 0xC3, 1100 0011 Checksum + VERSION_NR = 0xC4, 1100 0100 Version Number + PROTECTION = 0xC5, 1100 0101 Protection Parameters (user defined) + OPT_SEL = 0xC6, 1100 0110 Additional Option Selection + PROTO_CLASS = 0xC7, 1100 0111 Alternative Protocol Classes + PREF_MAX_TPDU_SIZE = 0xF0, 1111 0000 + INACTIVITY_TIMER = 0xF2, 1111 0010 + ADDICC = 0xe0 1110 0000 Additional Information on Connection Clearing + */ +} TCOTP_CO ; +typedef TCOTP_CO *PCOTP_CO; + +// COTP Header for DATA EXCHANGE +typedef struct { + u_char HLength; // Header length : 3 for this header + u_char PDUType; // 0xF0 for this header + u_char EoT_Num; // EOT (bit 7) + PDU Number (bits 0..6) + // EOT = 1 -> End of Trasmission Packet (This packet is complete) + // PDU Number : Always 0 +} TCOTP_DT; +typedef TCOTP_DT *PCOTP_DT; + +// Info part of a PDU, only common parts. We use it to check the consistence +// of a telegram regardless of it's nature (control or data). +typedef struct { + TTPKT TPKT; // TPKT Header + // Common part of any COTP + u_char HLength; // Header length : 3 for this header + u_char PDUType; // Pdu type +} TIsoHeaderInfo ; +typedef TIsoHeaderInfo *PIsoHeaderInfo; + +// PDU Type consts (Code + Credit) +const byte pdu_type_CR = 0xE0; // Connection request +const byte pdu_type_CC = 0xD0; // Connection confirm +const byte pdu_type_DR = 0x80; // Disconnect request +const byte pdu_type_DC = 0xC0; // Disconnect confirm +const byte pdu_type_DT = 0xF0; // Data transfer + +const byte pdu_EoT = 0x80; // End of Trasmission Packet (This packet is complete) + +const longword DataHeaderSize = sizeof(TTPKT)+sizeof(TCOTP_DT); +const longword IsoFrameSize = IsoPayload_Size+DataHeaderSize; + +typedef struct { + TTPKT TPKT; // TPKT Header + TCOTP_CO COTP; // COPT Header for CONNECTION stuffs +} TIsoControlPDU; +typedef TIsoControlPDU *PIsoControlPDU; + +typedef u_char TIsoPayload[IsoPayload_Size]; + +typedef struct { + TTPKT TPKT; // TPKT Header + TCOTP_DT COTP; // COPT Header for DATA EXCHANGE + TIsoPayload Payload; // Payload +} TIsoDataPDU ; + +typedef TIsoDataPDU *PIsoDataPDU; +typedef TIsoPayload *PIsoPayload; + +typedef enum { + pkConnectionRequest, + pkDisconnectRequest, + pkEmptyFragment, + pkInvalidPDU, + pkUnrecognizedType, + pkValidData +} TPDUKind ; + +#pragma pack() + +void ErrIsoText(int Error, char *Msg, int len); + +class TIsoTcpSocket : public TMsgSocket +{ +private: + + TIsoControlPDU FControlPDU; + int IsoMaxFragments; // max fragments allowed for an ISO telegram + // Checks the PDU format + int CheckPDU(void *pPDU, u_char PduTypeExpected); + // Receives the next fragment + int isoRecvFragment(void *From, int Max, int &Size, bool &EoT); +protected: + TIsoDataPDU PDU; + int SetIsoError(int Error); + // Builds the control PDU starting from address properties + virtual int BuildControlPDU(); + // Calcs the PDU size + int PDUSize(void *pPDU); + // Parses the connection request PDU to extract TSAP and PDU size info + virtual void IsoParsePDU(TIsoControlPDU PDU); + // Confirms the connection, override this method for special pourpose + // By default it checks the PDU format and resend it changing the pdu type + int IsoConfirmConnection(u_char PDUType); + void ClrIsoError(); + virtual void FragmentSkipped(int Size); +public: + word SrcTSap; // Source TSAP + word DstTSap; // Destination TSAP + word SrcRef; // Source Reference + word DstRef; // Destination Reference + int IsoPDUSize; + int LastIsoError; + //-------------------------------------------------------------------------- + TIsoTcpSocket(); + ~TIsoTcpSocket(); + // HIGH Level functions (work on payload hiding the underlying protocol) + // Connects with a peer, the connection PDU is automatically built starting from address scheme (see below) + int isoConnect(); + // Disconnects from a peer, if OnlyTCP = true, only a TCP disconnect is performed, + // otherwise a disconnect PDU is built and send. + int isoDisconnect(bool OnlyTCP); + // Sends a buffer, a valid header is created + int isoSendBuffer(void *Data, int Size); + // Receives a buffer + int isoRecvBuffer(void *Data, int & Size); + // Exchange cycle send->receive + int isoExchangeBuffer(void *Data, int & Size); + // A PDU is ready (at least its header) to be read + bool IsoPDUReady(); + // Same as isoSendBuffer, but the entire PDU has to be provided (in any case a check is performed) + int isoSendPDU(PIsoDataPDU Data); + // Same as isoRecvBuffer, but it returns the entire PDU, automatically enques the fragments + int isoRecvPDU(PIsoDataPDU Data); + // Same as isoExchangeBuffer, but the entire PDU has to be provided (in any case a check is performed) + int isoExchangePDU(PIsoDataPDU Data); + // Peeks an header info to know which kind of telegram is incoming + void IsoPeek(void *pPDU, TPDUKind &PduKind); +}; + +#endif // s7_isotcp_h diff --git a/APP_Framework/Framework/control/plc/interoperability/s7/s7_micro_client.cpp b/APP_Framework/Framework/control/plc/interoperability/s7/s7_micro_client.cpp new file mode 100644 index 000000000..7c3b5213f --- /dev/null +++ b/APP_Framework/Framework/control/plc/interoperability/s7/s7_micro_client.cpp @@ -0,0 +1,3328 @@ +/*=============================================================================| +| PROJECT SNAP7 1.3.0 | +|==============================================================================| +| Copyright (C) 2013, 2015 Davide Nardella | +| All rights reserved. | +|==============================================================================| +| SNAP7 is free software: you can redistribute it and/or modify | +| it under the terms of the Lesser GNU General Public License as published by | +| the Free Software Foundation, either version 3 of the License, or | +| (at your option) any later version. | +| | +| It means that you can distribute your commercial software linked with | +| SNAP7 without the requirement to distribute the source code of your | +| application and without the requirement that your application be itself | +| distributed under LGPL. | +| | +| SNAP7 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 | +| Lesser GNU General Public License for more details. | +| | +| You should have received a copy of the GNU General Public License and a | +| copy of Lesser GNU General Public License along with Snap7. | +| If not, see http://www.gnu.org/licenses/ | +|=============================================================================*/ +#include "s7_micro_client.h" +//--------------------------------------------------------------------------- + +TSnap7MicroClient::TSnap7MicroClient() +{ + SrcRef =0x0100; // RFC0983 states that SrcRef and DetRef should be 0 + // and, in any case, they are ignored. + // S7 instead requires a number != 0 + // Libnodave uses 0x0100 + // S7Manager uses 0x0D00 + // TIA Portal V12 uses 0x1D00 + // WinCC uses 0x0300 + // Seems that every non zero value is good enough... + DstRef =0x0000; + SrcTSap =0x0100; + DstTSap =0x0000; // It's filled by connection functions + ConnectionType = CONNTYPE_PG; // Default connection type + memset(&Job,0,sizeof(TSnap7Job)); +} +//--------------------------------------------------------------------------- +TSnap7MicroClient::~TSnap7MicroClient() +{ + Destroying = true; +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::opReadArea() +{ + PReqFunReadParams ReqParams; + PResFunReadParams ResParams; + PS7ResHeader23 Answer; + PResFunReadItem ResData; + word RPSize; // ReqParams size + int WordSize; + uintptr_t Offset; + pbyte Target; + int Address; + int IsoSize; + int Start; + int MaxElements; // Max elements that we can transfer in a PDU + word NumElements; // Num of elements that we are asking for this telegram + int TotElements; // Total elements requested + int Size; + int Result; + + WordSize=DataSizeByte(Job.WordLen); // The size in bytes of an element that we are asking for + if (WordSize==0) + return errCliInvalidWordLen; + // First check : params bounds + if ((Job.Number<0) || (Job.Number>65535) || (Job.Start<0) || (Job.Amount<1)) + return errCliInvalidParams; + // Second check : transport size + if ((Job.WordLen==S7WLBit) && (Job.Amount>1)) + return errCliInvalidTransportSize; + // Request Params size + RPSize =sizeof(TReqFunReadItem)+2; // 1 item + FunRead + ItemsCount + // Setup pointers (note : PDUH_out and PDU.Payload are the same pointer) + ReqParams =PReqFunReadParams(pbyte(PDUH_out)+sizeof(TS7ReqHeader)); + Answer =PS7ResHeader23(&PDU.Payload); + ResParams =PResFunReadParams(pbyte(Answer)+ResHeaderSize23); + ResData =PResFunReadItem(pbyte(ResParams)+sizeof(TResFunReadParams)); + // Each packet cannot exceed the PDU length (in bytes) negotiated, and moreover + // we must ensure to transfer a "finite" number of item per PDU + MaxElements=(PDULength-sizeof(TS7ResHeader23)-sizeof(TResFunReadParams)-4) / WordSize; + TotElements=Job.Amount; + Start =Job.Start; + Offset =0; + Result =0; + while ((TotElements>0) && (Result==0)) + { + NumElements=TotElements; + if (NumElements>MaxElements) + NumElements=MaxElements; + + Target=pbyte(Job.pData)+Offset; + //----------------------------------------------- Read next slice----- + PDUH_out->P = 0x32; // Always 0x32 + PDUH_out->PDUType = PduType_request; // 0x01 + PDUH_out->AB_EX = 0x0000; // Always 0x0000 + PDUH_out->Sequence = GetNextWord(); // AutoInc + PDUH_out->ParLen = SwapWord(RPSize); // 14 bytes params + PDUH_out->DataLen = 0x0000; // No data + + ReqParams->FunRead = pduFuncRead; // 0x04 + ReqParams->ItemsCount = 1; + ReqParams->Items[0].ItemHead[0] = 0x12; + ReqParams->Items[0].ItemHead[1] = 0x0A; + ReqParams->Items[0].ItemHead[2] = 0x10; + ReqParams->Items[0].TransportSize = Job.WordLen; + ReqParams->Items[0].Length = SwapWord(NumElements); + ReqParams->Items[0].Area = Job.Area; + if (Job.Area==S7AreaDB) + ReqParams->Items[0].DBNumber = SwapWord(Job.Number); + else + ReqParams->Items[0].DBNumber = 0x0000; + // Adjusts the offset + if ((Job.WordLen==S7WLBit) || (Job.WordLen==S7WLCounter) || (Job.WordLen==S7WLTimer)) + Address = Start; + else + Address = Start*8; + + ReqParams->Items[0].Address[2] = Address & 0x000000FF; + Address = Address >> 8; + ReqParams->Items[0].Address[1] = Address & 0x000000FF; + Address = Address >> 8; + ReqParams->Items[0].Address[0] = Address & 0x000000FF; + + IsoSize = sizeof(TS7ReqHeader)+RPSize; + Result = isoExchangeBuffer(0,IsoSize); + // Get Data + if (Result==0) // 1St level Iso + { + Size = 0; + // Item level error + if (ResData->ReturnCode==0xFF) // <-- 0xFF means Result OK + { + // Calcs data size in bytes + Size = SwapWord(ResData->DataLength); + // Adjust Size in accord of TransportSize + if ((ResData->TransportSize != TS_ResOctet) && (ResData->TransportSize != TS_ResReal) && (ResData->TransportSize != TS_ResBit)) + Size = Size >> 3; + memcpy(Target, &ResData->Data[0], Size); + } + else + Result = CpuError(ResData->ReturnCode); + Offset+=Size; + }; + //-------------------------------------------------------------------- + TotElements -= NumElements; + Start += NumElements*WordSize; + } + return Result; +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::opWriteArea() +{ + PReqFunWriteParams ReqParams; + PReqFunWriteDataItem ReqData; // only 1 item for WriteArea Function + PResFunWrite ResParams; + PS7ResHeader23 Answer; + word RPSize; // ReqParams size + word RHSize; // Request headers size + bool First = true; + int WordSize; + uintptr_t Offset = 0; + pbyte Source; + pbyte Target; + int Address; + int IsoSize; + int Start; // where we are starting from for this telegram + int MaxElements; // Max elements that we can transfer in a PDU + word NumElements; // Num of elements that we are asking for this telegram + int TotElements; // Total elements requested + word Size; + int Result = 0; + + WordSize=DataSizeByte(Job.WordLen); // The size in bytes of an element that we are pushing + if (WordSize==0) + return errCliInvalidWordLen; + // First check : params bounds + if ((Job.Number<0) || (Job.Number>65535) || (Job.Start<0) || (Job.Amount<1)) + return errCliInvalidParams; + // Second check : transport size + if ((Job.WordLen==S7WLBit) && (Job.Amount>1)) + return errCliInvalidTransportSize; + + RHSize =sizeof(TS7ReqHeader)+ // Request header + 2+ // FunWrite+ItemCount (of TReqFunWriteParams) + sizeof(TReqFunWriteItem)+// 1 item reference + 4; // ReturnCode+TransportSize+DataLength + RPSize =sizeof(TReqFunWriteItem)+2; + + // Setup pointers (note : PDUH_out and PDU.Payload are the same pointer) + ReqParams=PReqFunWriteParams(pbyte(PDUH_out)+sizeof(TS7ReqHeader)); + ReqData =PReqFunWriteDataItem(pbyte(ReqParams)+sizeof(TReqFunWriteItem)+2); // 2 = FunWrite+ItemsCount + Target =pbyte(ReqData)+4; // 4 = ReturnCode+TransportSize+DataLength + Answer =PS7ResHeader23(&PDU.Payload); + ResParams=PResFunWrite(pbyte(Answer)+ResHeaderSize23); + + // Each packet cannot exceed the PDU length (in bytes) negotiated, and moreover + // we must ensure to transfer a "finite" number of item per PDU + MaxElements=(PDULength-RHSize) / WordSize; + TotElements=Job.Amount; + Start =Job.Start; + while ((TotElements>0) && (Result==0)) + { + NumElements=TotElements; + if (NumElements>MaxElements) + NumElements=MaxElements; + Source=pbyte(Job.pData)+Offset; + + Size=NumElements * WordSize; + PDUH_out->P=0x32; // Always 0x32 + PDUH_out->PDUType=PduType_request; // 0x01 + PDUH_out->AB_EX=0x0000; // Always 0x0000 + PDUH_out->Sequence=GetNextWord(); // AutoInc + PDUH_out->ParLen =SwapWord(RPSize); // 14 bytes params + PDUH_out->DataLen =SwapWord(Size+4); + + ReqParams->FunWrite=pduFuncWrite; // 0x05 + ReqParams->ItemsCount=1; + ReqParams->Items[0].ItemHead[0]=0x12; + ReqParams->Items[0].ItemHead[1]=0x0A; + ReqParams->Items[0].ItemHead[2]=0x10; + ReqParams->Items[0].TransportSize=Job.WordLen; + ReqParams->Items[0].Length=SwapWord(NumElements); + ReqParams->Items[0].Area=Job.Area; + if (Job.Area==S7AreaDB) + ReqParams->Items[0].DBNumber=SwapWord(Job.Number); + else + ReqParams->Items[0].DBNumber=0x0000; + + // Adjusts the offset + if ((Job.WordLen==S7WLBit) || (Job.WordLen==S7WLCounter) || (Job.WordLen==S7WLTimer)) + Address=Start; + else + Address=Start*8; + + ReqParams->Items[0].Address[2]=Address & 0x000000FF; + Address=Address >> 8; + ReqParams->Items[0].Address[1]=Address & 0x000000FF; + Address=Address >> 8; + ReqParams->Items[0].Address[0]=Address & 0x000000FF; + + ReqData->ReturnCode=0x00; + + switch(Job.WordLen) + { + case S7WLBit: + ReqData->TransportSize=TS_ResBit; + break; + case S7WLInt: + case S7WLDInt: + ReqData->TransportSize=TS_ResInt; + break; + case S7WLReal: + ReqData->TransportSize=TS_ResReal; + break; + case S7WLChar : + case S7WLCounter: + case S7WLTimer: + ReqData->TransportSize=TS_ResOctet; + break; + default: + ReqData->TransportSize=TS_ResByte; + break; + }; + + if ((ReqData->TransportSize!=TS_ResOctet) && (ReqData->TransportSize!=TS_ResReal) && (ReqData->TransportSize!=TS_ResBit)) + ReqData->DataLength=SwapWord(Size*8); + else + ReqData->DataLength=SwapWord(Size); + + memcpy(Target, Source, Size); + IsoSize=RHSize + Size; + Result=isoExchangeBuffer(0,IsoSize); + + if (Result==0) // 1St check : Iso result + { + Result=CpuError(SwapWord(Answer->Error)); // 2nd level global error + if (Result==0) + { // 2th check : item error + if (ResParams->Data[0] == 0xFF) // <-- 0xFF means Result OK + Result=0; + else + // Now we check the error : if it's the first part we report the cpu error + // otherwise we warn that the function failed but some data were written + if (First) + Result=CpuError(ResParams->Data[0]); + else + Result=errCliPartialDataWritten; + }; + Offset+=Size; + }; + First=false; + + TotElements-=NumElements; + Start+=(NumElements*WordSize); + } + return Result; +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::opReadMultiVars() +{ + PS7DataItem Item; + PReqFunReadParams ReqParams; + PS7ResHeader23 Answer; + PResFunReadParams ResParams; + TResFunReadData ResData; + + word RPSize; // ReqParams size + uintptr_t Offset =0 ; + word Slice; + longword Address; + int IsoSize; + pbyte P; + int ItemsCount, c, Result; + + Item = PS7DataItem(Job.pData); + ItemsCount = Job.Amount; + + // Some useful initial check to detail the errors (Since S7 CPU always answers + // with $05 if (something is wrong in params) + if (ItemsCount>MaxVars) + return errCliTooManyItems; + + // Adjusts Word Length in case of timers and counters and clears results + for (c = 0; c < ItemsCount; c++) + { + Item->Result=0; + if (Item->Area==S7AreaCT) + Item->WordLen=S7WLCounter; + if (Item->Area==S7AreaTM) + Item->WordLen=S7WLTimer; + Item++; + }; + + // Let's build the PDU + RPSize = word(2 + ItemsCount * sizeof(TReqFunReadItem)); + ReqParams = PReqFunReadParams(pbyte(PDUH_out)+sizeof(TS7ReqHeader)); + Answer = PS7ResHeader23(&PDU.Payload); + ResParams = PResFunReadParams(pbyte(Answer)+ResHeaderSize23); + // Fill Header + PDUH_out->P=0x32; // Always 0x32 + PDUH_out->PDUType=PduType_request; // 0x01 + PDUH_out->AB_EX=0x0000; // Always 0x0000 + PDUH_out->Sequence=GetNextWord(); // AutoInc + PDUH_out->ParLen=SwapWord(RPSize); // Request params size + PDUH_out->DataLen=0x0000; // No data in output + + // Fill Params + ReqParams->FunRead=pduFuncRead; // 0x04 + ReqParams->ItemsCount=ItemsCount; + + Item = PS7DataItem(Job.pData); + for (c = 0; c < ItemsCount; c++) + { + ReqParams->Items[c].ItemHead[0]=0x12; + ReqParams->Items[c].ItemHead[1]=0x0A; + ReqParams->Items[c].ItemHead[2]=0x10; + + ReqParams->Items[c].TransportSize=Item->WordLen; + ReqParams->Items[c].Length=SwapWord(Item->Amount); + ReqParams->Items[c].Area=Item->Area; + // Automatically drops DBNumber if (Area is not DB + if (Item->Area==S7AreaDB) + ReqParams->Items[c].DBNumber=SwapWord(Item->DBNumber); + else + ReqParams->Items[c].DBNumber=0x0000; + // Adjusts the offset + if ((Item->WordLen==S7WLBit) || (Item->WordLen==S7WLCounter) || (Item->WordLen==S7WLTimer)) + Address=Item->Start; + else + Address=Item->Start*8; + // Builds the offset + ReqParams->Items[c].Address[2]=Address & 0x000000FF; + Address=Address >> 8; + ReqParams->Items[c].Address[1]=Address & 0x000000FF; + Address=Address >> 8; + ReqParams->Items[c].Address[0]=Address & 0x000000FF; + Item++; + }; + + IsoSize=RPSize+sizeof(TS7ReqHeader); + if (IsoSize>PDULength) + return errCliSizeOverPDU; + Result=isoExchangeBuffer(0,IsoSize); + + if (Result!=0) + return Result; + + // Function level error + if (Answer->Error!=0) + return CpuError(SwapWord(Answer->Error)); + + if (ResParams->ItemCount!=ItemsCount) + return errCliInvalidPlcAnswer; + + P=pbyte(ResParams)+sizeof(TResFunReadParams); + Item = PS7DataItem(Job.pData); + for (c = 0; c < ItemsCount; c++) + { + ResData[c] =PResFunReadItem(pbyte(P)+Offset); + Slice=0; + // Item level error + if (ResData[c]->ReturnCode==0xFF) // <-- 0xFF means Result OK + { + // Calcs data size in bytes + Slice=SwapWord(ResData[c]->DataLength); + // Adjust Size in accord of TransportSize + if ((ResData[c]->TransportSize != TS_ResOctet) && (ResData[c]->TransportSize != TS_ResReal) && (ResData[c]->TransportSize != TS_ResBit)) + Slice=Slice >> 3; + + memcpy(Item->pdata, ResData[c]->Data, Slice); + Item->Result=0; + } + else + Item->Result=CpuError(ResData[c]->ReturnCode); + + if ((Slice % 2)!=0) + Slice++; // Skip fill byte for Odd frame + + Offset+=(4+Slice); + Item++; + }; + return Result; +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::opWriteMultiVars() +{ + PS7DataItem Item; + PReqFunWriteParams ReqParams; + PResFunWrite ResParams; + TReqFunWriteData ReqData; + PS7ResHeader23 Answer; + pbyte P; + uintptr_t Offset; + longword Address; + int ItemsCount, c, IsoSize; + word RPSize; // ReqParams size + word Size; // Write data size + int WordSize, Result; + + Item = PS7DataItem(Job.pData); + ItemsCount = Job.Amount; + + // Some useful initial check to detail the errors (Since S7 CPU always answers + // with $05 if (something is wrong in params) + if (ItemsCount>MaxVars) + return errCliTooManyItems; + + // Adjusts Word Length in case of timers and counters and clears results + for (c = 0; c < ItemsCount; c++) + { + Item->Result=0; + if (Item->Area==S7AreaCT) + Item->WordLen=S7WLCounter; + if (Item->Area==S7AreaTM) + Item->WordLen=S7WLTimer; + Item++; + }; + + // Let's build the PDU : setup pointers + RPSize = word(2 + ItemsCount * sizeof(TReqFunWriteItem)); + ReqParams = PReqFunWriteParams(pbyte(PDUH_out)+sizeof(TS7ReqHeader)); + Answer = PS7ResHeader23(&PDU.Payload); + ResParams = PResFunWrite(pbyte(Answer)+ResHeaderSize23); + P=pbyte(ReqParams)+RPSize; + + // Fill Header + PDUH_out->P=0x32; // Always 0x32 + PDUH_out->PDUType=PduType_request; // 0x01 + PDUH_out->AB_EX=0x0000; // Always 0x0000 + PDUH_out->Sequence=GetNextWord(); // AutoInc + PDUH_out->ParLen=SwapWord(RPSize); // Request params size + + // Fill Params + ReqParams->FunWrite=pduFuncWrite; // 0x05 + ReqParams->ItemsCount=ItemsCount; + + Offset=0; + Item = PS7DataItem(Job.pData); + for (c = 0; c < ItemsCount; c++) + { + // Items Params + ReqParams->Items[c].ItemHead[0]=0x12; + ReqParams->Items[c].ItemHead[1]=0x0A; + ReqParams->Items[c].ItemHead[2]=0x10; + + ReqParams->Items[c].TransportSize=Item->WordLen; + ReqParams->Items[c].Length=SwapWord(Item->Amount); + ReqParams->Items[c].Area=Item->Area; + + if (Item->Area==S7AreaDB) + ReqParams->Items[c].DBNumber=SwapWord(Item->DBNumber); + else + ReqParams->Items[c].DBNumber=0x0000; + + // Adjusts the offset + if ((Item->WordLen==S7WLBit) || (Item->WordLen==S7WLCounter) || (Item->WordLen==S7WLTimer)) + Address=Item->Start; + else + Address=Item->Start*8; + // Builds the offset + ReqParams->Items[c].Address[2]=Address & 0x000000FF; + Address=Address >> 8; + ReqParams->Items[c].Address[1]=Address & 0x000000FF; + Address=Address >> 8; + ReqParams->Items[c].Address[0]=Address & 0x000000FF; + + // Items Data + ReqData[c]=PReqFunWriteDataItem(pbyte(P)+Offset); + ReqData[c]->ReturnCode=0x00; + + switch (Item->WordLen) + { + case S7WLBit : + ReqData[c]->TransportSize=TS_ResBit; + break; + case S7WLInt : + case S7WLDInt : + ReqData[c]->TransportSize=TS_ResInt; + break; + case S7WLReal : + ReqData[c]->TransportSize=TS_ResReal; + break; + case S7WLChar : + case S7WLCounter : + case S7WLTimer : ReqData[c]->TransportSize=TS_ResOctet; + break; + default : + ReqData[c]->TransportSize=TS_ResByte; // byte/word/dword etc. + break; + }; + + WordSize=DataSizeByte(Item->WordLen); + Size=Item->Amount * WordSize; + + if ((ReqData[c]->TransportSize!=TS_ResOctet) && (ReqData[c]->TransportSize!=TS_ResReal) && (ReqData[c]->TransportSize!=TS_ResBit)) + ReqData[c]->DataLength=SwapWord(Size*8); + else + ReqData[c]->DataLength=SwapWord(Size); + + memcpy(ReqData[c]->Data, Item->pdata, Size); + + if ((Size % 2) != 0 && (ItemsCount - c != 1)) + Size++; // Skip fill byte for Odd frame (except for the last one) + + Offset+=(4+Size); // next item + Item++; + }; + + PDUH_out->DataLen=SwapWord(word(Offset)); + + IsoSize=RPSize+sizeof(TS7ReqHeader)+int(Offset); + if (IsoSize>PDULength) + return errCliSizeOverPDU; + Result=isoExchangeBuffer(0,IsoSize); + + if (Result!=0) + return Result; + + // Function level error + if (Answer->Error!=0) + return CpuError(SwapWord(Answer->Error)); + + if (ResParams->ItemCount!=ItemsCount) + return errCliInvalidPlcAnswer; + + Item = PS7DataItem(Job.pData); + for (c = 0; c < ItemsCount; c++) + { + // Item level error + if (ResParams->Data[c]==0xFF) // <-- 0xFF means Result OK + Item->Result=0; + else + Item->Result=CpuError(ResParams->Data[c]); + Item++; + }; + return Result; +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::opListBlocks() +{ + PReqFunGetBlockInfo ReqParams; + PReqDataFunBlocks ReqData; + PResFunGetBlockInfo ResParams; + PDataFunListAll ResData; + PS7ResHeader17 Answer; + PS7BlocksList List; + int IsoSize, Result; + + // Setup pointers (note : PDUH_out and PDU.Payload are the same pointer) + ReqParams=PReqFunGetBlockInfo(pbyte(PDUH_out)+sizeof(TS7ReqHeader)); + ReqData =PReqDataFunBlocks(pbyte(ReqParams)+sizeof(TReqFunGetBlockInfo)); + Answer =PS7ResHeader17(&PDU.Payload); + ResParams=PResFunGetBlockInfo(pbyte(Answer)+ResHeaderSize17); + ResData =PDataFunListAll(pbyte(ResParams)+sizeof(TResFunGetBlockInfo)); + List =PS7BlocksList(Job.pData); + // Fill Header + PDUH_out->P=0x32; // Always 0x32 + PDUH_out->PDUType=PduType_userdata; // 0x07 + PDUH_out->AB_EX=0x0000; // Always 0x0000 + PDUH_out->Sequence=GetNextWord(); // AutoInc + PDUH_out->ParLen=SwapWord(sizeof(TReqFunGetBlockInfo)); // 8 bytes params + PDUH_out->DataLen=SwapWord(sizeof(TReqDataFunBlocks)); // 4 bytes data + // Fill params (mostly constants) + ReqParams->Head[0]=0x00; + ReqParams->Head[1]=0x01; + ReqParams->Head[2]=0x12; + ReqParams->Plen =0x04; + ReqParams->Uk =0x11; + ReqParams->Tg =grBlocksInfo; + ReqParams->SubFun =SFun_ListAll; + ReqParams->Seq =0x00; + // Fill data + ReqData[0] =0x0A; + ReqData[1] =0x00; + ReqData[2] =0x00; + ReqData[3] =0x00; + + IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqFunGetBlockInfo)+sizeof(TReqDataFunBlocks); + Result=isoExchangeBuffer(0,IsoSize); + // Get Data + if (Result==0) + { + if (ResParams->ErrNo==0) + { + if (SwapWord(ResData->Length)!=28) + return errCliInvalidPlcAnswer; + + for (int c = 0; c < 7; c++) + { + switch (ResData->Blocks[c].BType) + { + case Block_OB: + List->OBCount=SwapWord(ResData->Blocks[c].BCount); + break; + case Block_DB: + List->DBCount=SwapWord(ResData->Blocks[c].BCount); + break; + case Block_SDB: + List->SDBCount=SwapWord(ResData->Blocks[c].BCount); + break; + case Block_FC: + List->FCCount=SwapWord(ResData->Blocks[c].BCount); + break; + case Block_SFC: + List->SFCCount=SwapWord(ResData->Blocks[c].BCount); + break; + case Block_FB: + List->FBCount=SwapWord(ResData->Blocks[c].BCount); + break; + case Block_SFB: + List->SFBCount=SwapWord(ResData->Blocks[c].BCount); + break; + } + } + } + else + Result=CpuError(SwapWord(ResParams->ErrNo)); + } + return Result; +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::opListBlocksOfType() +{ + PReqFunGetBlockInfo ReqParams; + PReqDataBlockOfType ReqData; + + PS7ResHeader17 Answer; + PResFunGetBlockInfo ResParams; + PDataFunGetBot ResData; + longword *PadData; + word *List; + bool First; + bool Done = false; + byte BlockType, In_Seq; + int Count, Last, IsoSize, Result; + int c, CThis; + word DataLength; + bool RoomError = false; + + BlockType=Job.Area; + List=(word*)(&opData); + // Setup pointers (note : PDUH_out and PDU.Payload are the same pointer) + ReqParams=PReqFunGetBlockInfo(pbyte(PDUH_out)+sizeof(TS7ReqHeader)); + Answer =PS7ResHeader17(&PDU.Payload); + ResParams=PResFunGetBlockInfo(pbyte(Answer)+ResHeaderSize17); + ResData =PDataFunGetBot(pbyte(ResParams)+sizeof(TResFunGetBlockInfo)); + // Get Data + First =true; + In_Seq=0x00; // first group sequence, next will come from PLC + Count =0; + Last =0; + do + { + //<--------------------------------------------------------- Get next slice + // Fill Header + PDUH_out->P=0x32; // Always 0x32 + PDUH_out->PDUType=PduType_userdata; // 0x07 + PDUH_out->AB_EX=0x0000; // Always 0x0000 + PDUH_out->Sequence=GetNextWord(); // AutoInc + if (First) + { + PDUH_out->ParLen=SwapWord(8); // 8 bytes params + PDUH_out->DataLen=SwapWord(6); // 6 bytes data + DataLength=14; + } + else + { + PDUH_out->ParLen=SwapWord(12); // 12 bytes params + PDUH_out->DataLen=SwapWord(4); // 4 bytes data + DataLength=16; + } + + // Fill params (mostly constants) + ReqParams->Head[0]=0x00; + ReqParams->Head[1]=0x01; + ReqParams->Head[2]=0x12; + + if (First) + ReqParams->Plen =0x04; + else + ReqParams->Plen =0x08; + + if (First) + ReqParams->Uk = 0x11; + else + ReqParams->Uk = 0x12; + + ReqParams->Tg =grBlocksInfo; + ReqParams->SubFun =SFun_ListBoT; + ReqParams->Seq =In_Seq; + + // Fill data + if (First) + { + // overlap resvd and error to avoid another struct... + ReqData =PReqDataBlockOfType(pbyte(ReqParams)+sizeof(TReqFunGetBlockInfo)); + ReqData->RetVal =0xFF; + ReqData->TSize =TS_ResOctet; + ReqData->Length =SwapWord(0x0002); + ReqData->Zero =0x30; // zero ascii '0' + ReqData->BlkType =BlockType; + } + else + { + PadData =(longword*)(pbyte(ReqParams)+sizeof(TReqFunGetBlockInfo)); + ReqData =PReqDataBlockOfType(pbyte(ReqParams)+sizeof(TReqFunGetBlockInfo)+4); + *PadData =0x00000000; + ReqData->RetVal =0x0A; + ReqData->TSize =0x00; + ReqData->Length =0x0000; + ReqData->Zero =0x00; + ReqData->BlkType =0x00; + }; + + IsoSize=sizeof(TS7ReqHeader)+DataLength; + Result=isoExchangeBuffer(0,IsoSize); + + if (Result==0) + { + if (ResParams->ErrNo==0) + { + if (ResData->RetVal==0xFF) + { + Done=((ResParams->Rsvd & 0xFF00) == 0); // Low order byte = 0x00 => the sequence is done + In_Seq=ResParams->Seq; // every next telegram must have this number + CThis=((SwapWord(ResData->DataLen) - 4 ) / 4) + 1; // Partial counter + for (c=0; c < CThis+1; c++) + { + *List=SwapWord(ResData->Items[c].BlockNum); + Last++; + List++; + if (Last==0x8000) + { + Done=true; + break; + }; + }; + Count+=CThis; // Total counter + List--; + } + else + Result=errCliItemNotAvailable; + } + else + Result=errCliItemNotAvailable; + }; + First=false; + //---------------------------------------------------------> Get next slice + } + while ((!Done) && (Result==0)); + + *Job.pAmount=0; + if (Result==0) + { + if (Count>Job.Amount) + { + Count=Job.Amount; + RoomError=true; + } + memcpy(Job.pData, &opData, Count*2); + *Job.pAmount=Count; + + if (RoomError) // Result==0 -> override if romerror + Result=errCliPartialDataRead; + }; + + return Result; +} +//--------------------------------------------------------------------------- +void TSnap7MicroClient::FillTime(word SiemensTime, char *PTime) +{ + // SiemensTime -> number of seconds after 1/1/1984 + // This is not S7 date and time but is used only internally for block info + time_t TheDate = (SiemensTime * 86400)+ DeltaSecs; + struct tm * timeinfo = localtime (&TheDate); + if (timeinfo!=NULL) { + strftime(PTime,11,"%Y/%m/%d",timeinfo); + } + else + *PTime='\0'; +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::opAgBlockInfo() +{ + PS7BlockInfo BlockInfo; + PReqFunGetBlockInfo ReqParams; + PReqDataBlockInfo ReqData; + PS7ResHeader17 Answer; + PResFunGetBlockInfo ResParams; + PResDataBlockInfo ResData; + byte BlockType; + int BlockNum, IsoSize, Result; + + BlockType=Job.Area; + BlockNum =Job.Number; + BlockInfo=PS7BlockInfo(Job.pData); + memset(BlockInfo,0,sizeof(TS7BlockInfo)); + // Setup pointers (note : PDUH_out and PDU.Payload are the same pointer) + ReqParams=PReqFunGetBlockInfo(pbyte(PDUH_out)+sizeof(TS7ReqHeader)); + ReqData =PReqDataBlockInfo(pbyte(ReqParams)+sizeof(TReqFunGetBlockInfo)); + Answer =PS7ResHeader17(&PDU.Payload); + ResParams=PResFunGetBlockInfo(pbyte(Answer)+ResHeaderSize17); + ResData =PResDataBlockInfo(pbyte(ResParams)+sizeof(TResFunGetBlockInfo)); + // Fill Header + PDUH_out->P=0x32; // Always 0x32 + PDUH_out->PDUType=PduType_userdata; // 0x07 + PDUH_out->AB_EX=0x0000; // Always 0x0000 + PDUH_out->Sequence=GetNextWord(); // AutoInc + PDUH_out->ParLen=SwapWord(sizeof(TReqFunGetBlockInfo)); // 8 bytes params + PDUH_out->DataLen=SwapWord(sizeof(TReqDataBlockInfo)); // 4 bytes data + // Fill params (mostly constants) + ReqParams->Head[0]=0x00; + ReqParams->Head[1]=0x01; + ReqParams->Head[2]=0x12; + ReqParams->Plen =0x04; + ReqParams->Uk =0x11; + ReqParams->Tg =grBlocksInfo; + ReqParams->SubFun =SFun_BlkInfo; + ReqParams->Seq =0x00; + // Fill data + ReqData->RetVal =0xFF; + ReqData->TSize =TS_ResOctet; + ReqData->DataLen =SwapWord(0x0008); + ReqData->BlkPrfx =0x30; + ReqData->BlkType =BlockType; + ReqData->A =0x41; + + ReqData->AsciiBlk[0]=(BlockNum / 10000)+0x30; + BlockNum=BlockNum % 10000; + ReqData->AsciiBlk[1]=(BlockNum / 1000)+0x30; + BlockNum=BlockNum % 1000; + ReqData->AsciiBlk[2]=(BlockNum / 100)+0x30; + BlockNum=BlockNum % 100; + ReqData->AsciiBlk[3]=(BlockNum / 10)+0x30; + BlockNum=BlockNum % 10; + ReqData->AsciiBlk[4]=(BlockNum / 1)+0x30; + + IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqFunGetBlockInfo)+sizeof(TReqDataBlockInfo); + Result=isoExchangeBuffer(0,IsoSize); + + // Get Data + if (Result==0) + { + if (ResParams->ErrNo==0) + { + if (SwapWord(ResData->Length)<40) // 78 + return errCliInvalidPlcAnswer; + if (ResData->RetVal==0xFF) // <-- 0xFF means Result OK + { + //<----------------------------------------------Fill block info + BlockInfo->BlkType=ResData->SubBlkType; + BlockInfo->BlkNumber=SwapWord(ResData->BlkNumber); + BlockInfo->BlkLang=ResData->BlkLang; + BlockInfo->BlkFlags=ResData->BlkFlags; + BlockInfo->MC7Size=SwapWord(ResData->MC7Len); + BlockInfo->LoadSize=SwapDWord(ResData->LenLoadMem); + BlockInfo->LocalData=SwapWord(ResData->LocDataLen); + BlockInfo->SBBLength=SwapWord(ResData->SbbLen); + BlockInfo->CheckSum=SwapWord(ResData->BlkChksum); + BlockInfo->Version=ResData->Version; + memcpy(BlockInfo->Author, ResData->Author, 8); + memcpy(BlockInfo->Family,ResData->Family,8); + memcpy(BlockInfo->Header,ResData->Header,8); + FillTime(SwapWord(ResData->CodeTime_dy),BlockInfo->CodeDate); + FillTime(SwapWord(ResData->IntfTime_dy),BlockInfo->IntfDate); + //---------------------------------------------->Fill block info + } + else + Result=CpuError(ResData->RetVal); + } + else + Result=CpuError(SwapWord(ResParams->ErrNo)); + }; + return Result; +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::opDBGet() +{ + TS7BlockInfo BI; + void * usrPData; + int * usrPSize; + int Result, Room; + bool RoomError = false; + + // Stores user pointer + usrPData=Job.pData; + usrPSize=Job.pAmount; + Room =Job.Amount; + + // 1 Pass : Get block info + Job.Area=Block_DB; + Job.pData=&BI; + Result=opAgBlockInfo(); + + // 2 Pass : Read the whole (MC7Size bytes) DB. + if (Result==0) + { + // Check user space + if (BI.MC7Size>Room) + { + Job.Amount=Room; + RoomError=true; + } + else + Job.Amount =BI.MC7Size; + // The data is read even if the buffer is small (the error is reported). + // Imagine that we want to read only a small amount of data at the + // beginning of a DB regardless it's size.... + Job.Area =S7AreaDB; + Job.WordLen=S7WLByte; + Job.Start =0; + Job.pData =usrPData; + Result =opReadArea(); + if (Result==0) + *usrPSize=Job.Amount; + } + + if ((Result==0) && RoomError) + return errCliBufferTooSmall; + else + return Result; +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::opDBFill() +{ + TS7BlockInfo BI; + int Result; + // new op : get block info + Job.Op =s7opAgBlockInfo; + Job.Area =Block_DB; + Job.pData=&BI; + Result =opAgBlockInfo(); + // Restore original op + Job.Op =s7opDBFill; + // Fill internal buffer then write it + if (Result==0) + { + Job.Amount =BI.MC7Size; + Job.Area =S7AreaDB; + Job.WordLen=S7WLByte; + Job.Start =0; + memset(&opData, byte(Job.IParam), Job.Amount); + Job.pData =&opData; + Result =opWriteArea(); + } + return Result; +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::opUpload() +{ + PS7ResHeader23 Answer; + int IsoSize; + byte Upload_ID = 0; // not strictly needed, only to avoid warning + byte BlockType; + int BlockNum, BlockLength, Result; + bool Done, Full; // if full==true, the data will be compatible to full download function + uintptr_t Offset; + bool RoomError = false; + + BlockType=Job.Area; + BlockNum =Job.Number; + Full =Job.IParam==1; + // Setup Answer (is the same for all Upload pdus) + Answer= PS7ResHeader23(&PDU.Payload); + // Init sequence + Done =false; + Offset=0; + //<-------------------------------------------------------------StartUpload + PReqFunStartUploadParams ReqParams; + PResFunStartUploadParams ResParams; + // Setup pointers (note : PDUH_out and PDU.Payload are the same pointer) + ReqParams=PReqFunStartUploadParams(pbyte(PDUH_out)+sizeof(TS7ReqHeader)); + ResParams=PResFunStartUploadParams(pbyte(Answer)+ResHeaderSize23); + // Init Header + PDUH_out->P=0x32; // Always 0x32 + PDUH_out->PDUType=PduType_request; // 0x01 + PDUH_out->AB_EX=0x0000; // Always 0x0000 + PDUH_out->Sequence=GetNextWord(); // AutoInc + PDUH_out->ParLen=SwapWord(sizeof(TReqFunStartUploadParams));// params size + PDUH_out->DataLen=0x0000; // No data + // Init Params + ReqParams->FunSUpld=pduStartUpload; + ReqParams->Uk6[0]=0x00; + ReqParams->Uk6[1]=0x00; + ReqParams->Uk6[2]=0x00; + ReqParams->Uk6[3]=0x00; + ReqParams->Uk6[4]=0x00; + ReqParams->Uk6[5]=0x00; + ReqParams->Upload_ID=Upload_ID; // At begining is 0) we will put upload id incoming from plc + ReqParams->Len_1 =0x09; // 9 bytes from here + ReqParams->Prefix=0x5F; + ReqParams->BlkPrfx=0x30; // '0' + ReqParams->BlkType=BlockType; + // Block number + ReqParams->AsciiBlk[0]=(BlockNum / 10000)+0x30; + BlockNum=BlockNum % 10000; + ReqParams->AsciiBlk[1]=(BlockNum / 1000)+0x30; + BlockNum=BlockNum % 1000; + ReqParams->AsciiBlk[2]=(BlockNum / 100)+0x30; + BlockNum=BlockNum % 100; + ReqParams->AsciiBlk[3]=(BlockNum / 10)+0x30; + BlockNum=BlockNum % 10; + ReqParams->AsciiBlk[4]=(BlockNum / 1)+0x30; + ReqParams->A=0x41; // 'A' + + IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqFunStartUploadParams); + Result=isoExchangeBuffer(0,IsoSize); + // Get Upload Infos (only ID now) + if (Result==0) + { + if (Answer->Error==0) + Upload_ID=ResParams->Upload_ID; + else + Result=CpuError(SwapWord(Answer->Error)); + }; + //------------------------------------------------------------->StartUpload + if (Result==0) + { + //<--------------------------------------------------------FirstUpload + PReqFunUploadParams ReqParams; + PResFunUploadParams ResParams; + PResFunUploadDataHeaderFirst ResDataHeader; + pbyte Source; + pbyte Target; + int Size; + + // Setup pointers (note : PDUH_out and PDU.Payload are the same pointer) + ReqParams=PReqFunUploadParams(pbyte(PDUH_out)+sizeof(TS7ReqHeader)); + // First upload pdu consists of params, block info header, data. + ResParams=PResFunUploadParams(pbyte(Answer)+ResHeaderSize23); + ResDataHeader=PResFunUploadDataHeaderFirst(pbyte(ResParams)+sizeof(TResFunUploadParams)); + if (Full) + Source=pbyte(ResDataHeader)+4; // skip only the mini header + else + Source=pbyte(ResDataHeader)+sizeof(TResFunUploadDataHeaderFirst); // not full : skip the data header + // Init Header + PDUH_out->P=0x32; // Always 0x32 + PDUH_out->PDUType=PduType_request; // 0x01 + PDUH_out->AB_EX=0x0000; // Always 0x0000 + PDUH_out->Sequence=GetNextWord(); // AutoInc + PDUH_out->ParLen=SwapWord(sizeof(TReqFunUploadParams));// params size + PDUH_out->DataLen=0x0000; // No data + // Init Params + ReqParams->FunUpld=pduUpload; + ReqParams->Uk6[0]=0x00; + ReqParams->Uk6[1]=0x00; + ReqParams->Uk6[2]=0x00; + ReqParams->Uk6[3]=0x00; + ReqParams->Uk6[4]=0x00; + ReqParams->Uk6[5]=0x00; + ReqParams->Upload_ID=Upload_ID; // At begining is 0) we will put upload id incoming from plc + + IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqFunUploadParams); + Result=isoExchangeBuffer(0,IsoSize); + // Get Upload Infos (only ID now) + if (Result==0) + { + if (Answer->Error==0) + { + Done=ResParams->EoU==0; + if (Full) + Size=SwapWord(Answer->DataLen)-4; // Full data Size + else + Size=SwapWord(Answer->DataLen)-sizeof(TResFunUploadDataHeaderFirst); // Size of this data slice + + BlockLength=SwapWord(ResDataHeader->MC7Len); // Full block size in byte + Target=pbyte(&opData)+Offset; + memcpy(Target, Source, Size); + Offset+=Size; + } + else + Result=errCliUploadSequenceFailed; + }; + //-------------------------------------------------------->FirstUpload + while (!Done && (Result==0)) + { + //<----------------------------------------------------NextUpload + PReqFunUploadParams ReqParams; + PResFunUploadParams ResParams; + PResFunUploadDataHeaderNext ResDataHeader; + pbyte Source; + pbyte Target; + int Size; + + // Setup pointers (note : PDUH_out and PDU.Payload are the same pointer) + ReqParams=PReqFunUploadParams(pbyte(PDUH_out)+sizeof(TS7ReqHeader)); + // Next upload pdu consists of params, small info header, data. + ResParams=PResFunUploadParams(pbyte(Answer)+ResHeaderSize23); + ResDataHeader=PResFunUploadDataHeaderNext(pbyte(ResParams)+sizeof(TResFunUploadParams)); + Source=pbyte(ResDataHeader)+sizeof(TResFunUploadDataHeaderNext); + // Init Header + PDUH_out->P=0x32; // Always 0x32 + PDUH_out->PDUType=PduType_request; // 0x01 + PDUH_out->AB_EX=0x0000; // Always 0x0000 + PDUH_out->Sequence=GetNextWord(); // AutoInc + PDUH_out->ParLen=SwapWord(sizeof(TReqFunUploadParams));// params size + PDUH_out->DataLen=0x0000; // No data + // Init Params + ReqParams->FunUpld=pduUpload; + ReqParams->Uk6[0]=0x00; + ReqParams->Uk6[1]=0x00; + ReqParams->Uk6[2]=0x00; + ReqParams->Uk6[3]=0x00; + ReqParams->Uk6[4]=0x00; + ReqParams->Uk6[5]=0x00; + ReqParams->Upload_ID=Upload_ID; // At begining is 0) we will put upload id incoming from plc + + IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqFunUploadParams); + Result=isoExchangeBuffer(0,IsoSize); + // Get Upload Infos (only ID now) + if (Result==0) + { + if (Answer->Error==0) + { + Done=ResParams->EoU==0; + Size=SwapWord(Answer->DataLen)-sizeof(TResFunUploadDataHeaderNext); // Size of this data slice + Target=pbyte(&opData)+Offset; + memcpy(Target, Source, Size); + Offset+=Size; + } + else + Result=errCliUploadSequenceFailed; + }; + //---------------------------------------------------->NextUpload + } + if (Result==0) + { + //<----------------------------------------------------EndUpload; + PReqFunEndUploadParams ReqParams; + PResFunEndUploadParams ResParams; + + // Setup pointers (note : PDUH_out and PDU.Payload are the same pointer) + ReqParams=PReqFunEndUploadParams(pbyte(PDUH_out)+sizeof(TS7ReqHeader)); + ResParams=PResFunEndUploadParams(pbyte(Answer)+ResHeaderSize23); + // Init Header + PDUH_out->P=0x32; // Always 0x32 + PDUH_out->PDUType=PduType_request; // 0x01 + PDUH_out->AB_EX=0x0000; // Always 0x0000 + PDUH_out->Sequence=GetNextWord(); // AutoInc + PDUH_out->ParLen=SwapWord(sizeof(TReqFunEndUploadParams));// params size + PDUH_out->DataLen=0x0000; // No data + // Init Params + ReqParams->FunEUpld=pduEndUpload; + ReqParams->Uk6[0]=0x00; + ReqParams->Uk6[1]=0x00; + ReqParams->Uk6[2]=0x00; + ReqParams->Uk6[3]=0x00; + ReqParams->Uk6[4]=0x00; + ReqParams->Uk6[5]=0x00; + ReqParams->Upload_ID=Upload_ID; // At begining is 0) we will put upload id incoming from plc + + IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqFunEndUploadParams); + Result=isoExchangeBuffer(0,IsoSize); + + // Get EndUpload Result + if (Result==0) + { + if ((Answer->Error!=0) || (ResParams->FunEUpld!=pduEndUpload)) + Result=errCliUploadSequenceFailed; + }; + //---------------------------------------------------->EndUpload; + } + }; + + *Job.pAmount=0; + if (Result==0) + { + if (Full) + { + opSize=int(Offset); + if (opSize<78) + Result=errCliInvalidDataSizeRecvd; + } + else + { + opSize=BlockLength; + if (opSize<1) + Result=errCliInvalidDataSizeRecvd; + }; + if (Result==0) + { + // Checks user space + if (Job.Amount override if romerror + Result=errCliPartialDataRead; + }; + }; + return Result; +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::opDownload() +{ + PS7CompactBlockInfo Info; + PS7BlockFooter Footer; + int BlockNum, StoreBlockNum, BlockAmount; + int BlockSize, BlockSizeLd; + int BlockType, Remainder; + int Result, IsoSize; + bool Done = false; + uintptr_t Offset; + + BlockAmount=Job.Amount; + BlockNum =Job.Number; + Result=CheckBlock(-1,-1,&opData,BlockAmount); + if (Result==0) + { + Info=PS7CompactBlockInfo(&opData); + // Gets blocktype + BlockType=SubBlockToBlock(Info->SubBlkType); + + if (BlockNum>=0) + Info->BlkNum=SwapWord(BlockNum); // change the number + else + BlockNum=SwapWord(Info->BlkNum); // use the header's number + + BlockSizeLd=BlockAmount; // load mem needed for this block + BlockSize =SwapWord(Info->MC7Len); // net size + Footer=PS7BlockFooter(pbyte(&opData)+BlockSizeLd-sizeof(TS7BlockFooter)); + Footer->Chksum=0x0000; + + Offset=0; + Remainder=BlockAmount; + //<---------------------------------------------- Start Download request + PReqStartDownloadParams ReqParams; + PResStartDownloadParams ResParams; + PS7ResHeader23 Answer; + + // Setup pointers (note : PDUH_out and PDU.Payload are the same pointer) + ReqParams=PReqStartDownloadParams(pbyte(PDUH_out)+sizeof(TS7ReqHeader)); + Answer =PS7ResHeader23(&PDU.Payload); + ResParams=PResStartDownloadParams(pbyte(Answer)+ResHeaderSize23); + // Init Header + PDUH_out->P=0x32; // Always 0x32 + PDUH_out->PDUType=PduType_request; // 0x01 + PDUH_out->AB_EX=0x0000; // Always 0x0000 + PDUH_out->Sequence=GetNextWord(); // AutoInc + PDUH_out->ParLen=SwapWord(sizeof(TReqStartDownloadParams)); + PDUH_out->DataLen=0x0000; // No data + // Init Params + ReqParams->FunSDwnld = pduReqDownload; + ReqParams->Uk6[0]=0x00; + ReqParams->Uk6[1]=0x01; + ReqParams->Uk6[2]=0x00; + ReqParams->Uk6[3]=0x00; + ReqParams->Uk6[4]=0x00; + ReqParams->Uk6[5]=0x00; + ReqParams->Dwnld_ID=0x00; + ReqParams->Len_1 =0x09; + ReqParams->Prefix=0x5F; + ReqParams->BlkPrfx=0x30; + ReqParams->BlkType=BlockType; + StoreBlockNum=BlockNum; + ReqParams->AsciiBlk[0]=(BlockNum / 10000)+0x30; + BlockNum=BlockNum % 10000; + ReqParams->AsciiBlk[1]=(BlockNum / 1000)+0x30; + BlockNum=BlockNum % 1000; + ReqParams->AsciiBlk[2]=(BlockNum / 100)+0x30; + BlockNum=BlockNum % 100; + ReqParams->AsciiBlk[3]=(BlockNum / 10)+0x30; + BlockNum=BlockNum % 10; + ReqParams->AsciiBlk[4]=(BlockNum / 1)+0x30; + ReqParams->P =0x50; + ReqParams->Len_2=0x0D; + ReqParams->Uk1 =0x31; // '1' + BlockNum=StoreBlockNum; + // Load memory + ReqParams->AsciiLoad[0]=(BlockSizeLd / 100000)+0x30; + BlockSizeLd=BlockSizeLd % 100000; + ReqParams->AsciiLoad[1]=(BlockSizeLd / 10000)+0x30; + BlockSizeLd=BlockSizeLd % 10000; + ReqParams->AsciiLoad[2]=(BlockSizeLd / 1000)+0x30; + BlockSizeLd=BlockSizeLd % 1000; + ReqParams->AsciiLoad[3]=(BlockSizeLd / 100)+0x30; + BlockSizeLd=BlockSizeLd % 100; + ReqParams->AsciiLoad[4]=(BlockSizeLd / 10)+0x30; + BlockSizeLd=BlockSizeLd % 10; + ReqParams->AsciiLoad[5]=(BlockSizeLd / 1)+0x30; + // MC7 memory + ReqParams->AsciiMC7[0]=(BlockSize / 100000)+0x30; + BlockSize=BlockSize % 100000; + ReqParams->AsciiMC7[1]=(BlockSize / 10000)+0x30; + BlockSize=BlockSize % 10000; + ReqParams->AsciiMC7[2]=(BlockSize / 1000)+0x30; + BlockSize=BlockSize % 1000; + ReqParams->AsciiMC7[3]=(BlockSize / 100)+0x30; + BlockSize=BlockSize % 100; + ReqParams->AsciiMC7[4]=(BlockSize / 10)+0x30; + BlockSize=BlockSize % 10; + ReqParams->AsciiMC7[5]=(BlockSize / 1)+0x30; + + IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqStartDownloadParams); + Result=isoExchangeBuffer(0,IsoSize); + + // Get Result + if (Result==0) + { + if (SwapWord(Answer->Error)!=Code7NeedPassword) + { + if ((Answer->Error!=0) || (*ResParams!=pduReqDownload)) + Result=errCliDownloadSequenceFailed; + } + else + Result=errCliNeedPassword; + } + //----------------------------------------------> Start Download request + if (Result==0) + { + do + { + //<-------------------------------- Download sequence (PLC requests) + PReqDownloadParams ReqParams; + PS7ResHeader23 Answer; + PResDownloadParams ResParams; + PResDownloadDataHeader ResData; + int Slice, Size, MaxSlice; + word Sequence; + pbyte Source; + pbyte Target; + + ReqParams=PReqDownloadParams(pbyte(PDUH_out)+sizeof(TS7ReqHeader)); + Answer =PS7ResHeader23(&PDU.Payload); + ResParams=PResDownloadParams(pbyte(Answer)+ResHeaderSize23); + ResData =PResDownloadDataHeader(pbyte(ResParams)+sizeof(TResDownloadParams)); + Target =pbyte(ResData)+sizeof(TResDownloadDataHeader); + Source =pbyte(&opData)+Offset; + + Result=isoRecvBuffer(0,Size); + if (Result==0) + { + if ((u_int(Size)>sizeof(TS7ReqHeader)) && (ReqParams->Fun==pduDownload)) + { + Sequence=PDUH_out->Sequence; + // Max data slice that we can fit in this pdu + MaxSlice=PDULength-ResHeaderSize23-sizeof(TResDownloadParams)-sizeof(TResDownloadDataHeader); + Slice=Remainder; + if (Slice>MaxSlice) + Slice=MaxSlice; + Remainder-=Slice; + Offset+=Slice; + Done=Remainder<=0; + // Init Answer + Answer->P=0x32; + Answer->PDUType=PduType_response; + Answer->AB_EX=0x0000; + Answer->Sequence=Sequence; + Answer->ParLen =SwapWord(sizeof(TResDownloadParams)); + Answer->DataLen=SwapWord(word(sizeof(TResDownloadDataHeader))+Slice); + Answer->Error =0x0000; + + // Init Params + ResParams->FunDwnld=pduDownload; + if (Remainder>0) + ResParams->EoS=0x01; + else + ResParams->EoS=0x00; + + // Init Data + ResData->DataLen=SwapWord(Slice); + ResData->FB_00=0xFB00; + memcpy(Target, Source, Slice); + + // Send the slice + IsoSize=ResHeaderSize23+sizeof(TResDownloadParams)+sizeof(TResDownloadDataHeader)+Slice; + Result=isoSendBuffer(0,IsoSize); + } + else + Result=errCliDownloadSequenceFailed; + }; + //--------------------------------> Download sequence (PLC requests) + } + while (!Done && (Result==0)); + + if (Result==0) + { + //<-------------------------------------------Perform Download Ended + PReqDownloadParams ReqParams; + PS7ResHeader23 Answer; + PResEndDownloadParams ResParams; + int Size; + word Sequence; + + ReqParams=PReqDownloadParams(pbyte(PDUH_out)+sizeof(TS7ReqHeader)); + Answer =PS7ResHeader23(&PDU.Payload); + ResParams=PResEndDownloadParams(pbyte(Answer)+ResHeaderSize23); + + Result=isoRecvBuffer(0,Size); + if (Result==0) + { + if ((u_int(Size)>sizeof(TS7ReqHeader)) && (ReqParams->Fun==pduDownloadEnded)) + { + Sequence=PDUH_out->Sequence; + // Init Answer + Answer->P=0x32; + Answer->PDUType=PduType_response; + Answer->AB_EX=0x0000; + Answer->Sequence=Sequence; + Answer->ParLen =SwapWord(sizeof(TResEndDownloadParams)); + Answer->DataLen=0x0000; + Answer->Error =0x0000; + + // Init Params + *ResParams=pduDownloadEnded; + IsoSize=ResHeaderSize23+sizeof(TResEndDownloadParams); + Result=isoSendBuffer(0,IsoSize); + } + else + Result=errCliDownloadSequenceFailed; + }; + //------------------------------------------->Perform Download Ended + if (Result==0) + { + //<----------------------------------- Insert block into the unit + PReqControlBlockParams ReqParams; + PS7ResHeader23 Answer; + pbyte ResParams; + + // Setup pointers (note : PDUH_out and PDU.Payload are the same pointer) + ReqParams=PReqControlBlockParams(pbyte(PDUH_out)+sizeof(TS7ReqHeader)); + Answer=PS7ResHeader23(&PDU.Payload); + ResParams=pbyte(Answer)+ResHeaderSize23; + // Init Header + PDUH_out->P=0x32; // Always 0x32 + PDUH_out->PDUType=PduType_request; // 0x01 + PDUH_out->AB_EX=0x0000; // Always 0x0000 + PDUH_out->Sequence=GetNextWord(); // AutoInc + PDUH_out->ParLen=SwapWord(sizeof(TReqControlBlockParams)); + PDUH_out->DataLen=0x0000; // No data + // Init Params + ReqParams->Fun = pduControl; + ReqParams->Uk7[0]=0x00; + ReqParams->Uk7[1]=0x00; + ReqParams->Uk7[2]=0x00; + ReqParams->Uk7[3]=0x00; + ReqParams->Uk7[4]=0x00; + ReqParams->Uk7[5]=0x00; + ReqParams->Uk7[6]=0xFD; + ReqParams->Len_1 =SwapWord(0x0A); + ReqParams->NumOfBlocks=0x01; + ReqParams->ByteZero =0x00; + ReqParams->AsciiZero =0x30; + ReqParams->BlkType=BlockType; + ReqParams->AsciiBlk[0]=(BlockNum / 10000)+0x30; + BlockNum=BlockNum % 10000; + ReqParams->AsciiBlk[1]=(BlockNum / 1000)+0x30; + BlockNum=BlockNum % 1000; + ReqParams->AsciiBlk[2]=(BlockNum / 100)+0x30; + BlockNum=BlockNum % 100; + ReqParams->AsciiBlk[3]=(BlockNum / 10)+0x30; + BlockNum=BlockNum % 10; + ReqParams->AsciiBlk[4]=(BlockNum / 1)+0x30; + ReqParams->SFun =SFun_Insert; + ReqParams->Len_2=0x05; + ReqParams->Cmd[0]='_'; + ReqParams->Cmd[1]='I'; + ReqParams->Cmd[2]='N'; + ReqParams->Cmd[3]='S'; + ReqParams->Cmd[4]='E'; + + IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqControlBlockParams); + Result=isoExchangeBuffer(0,IsoSize); + + if (Result==0) + { + if ((Answer->Error!=0) || (*ResParams!=pduControl)) + Result=errCliInsertRefused; + }; + //-----------------------------------> Insert block into the unit + } + }; + }; + }; + return Result; +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::opDelete() +{ + PReqControlBlockParams ReqParams; + PS7ResHeader23 Answer; + pbyte ResParams; + int IsoSize, BlockType, BlockNum, Result; + + BlockType=Job.Area; + BlockNum =Job.Number; + // Setup pointers (note : PDUH_out and PDU.Payload are the same pointer) + ReqParams=PReqControlBlockParams(pbyte(PDUH_out)+sizeof(TS7ReqHeader)); + Answer =PS7ResHeader23(&PDU.Payload); + ResParams=pbyte(Answer)+ResHeaderSize23; + // Init Header + PDUH_out->P=0x32; // Always 0x32 + PDUH_out->PDUType=PduType_request; // 0x01 + PDUH_out->AB_EX=0x0000; // Always 0x0000 + PDUH_out->Sequence=GetNextWord(); // AutoInc + PDUH_out->ParLen=SwapWord(sizeof(TReqControlBlockParams)); + PDUH_out->DataLen=0x0000; // No data + // Init Params + ReqParams->Fun = pduControl; + ReqParams->Uk7[0]=0x00; + ReqParams->Uk7[1]=0x00; + ReqParams->Uk7[2]=0x00; + ReqParams->Uk7[3]=0x00; + ReqParams->Uk7[4]=0x00; + ReqParams->Uk7[5]=0x00; + ReqParams->Uk7[6]=0xFD; + ReqParams->Len_1 =SwapWord(0x0A); + ReqParams->NumOfBlocks=0x01; + ReqParams->ByteZero =0x00; + ReqParams->AsciiZero =0x30; + ReqParams->BlkType=BlockType; + ReqParams->AsciiBlk[0]=(BlockNum / 10000)+0x30; + BlockNum=BlockNum % 10000; + ReqParams->AsciiBlk[1]=(BlockNum / 1000)+0x30; + BlockNum=BlockNum % 1000; + ReqParams->AsciiBlk[2]=(BlockNum / 100)+0x30; + BlockNum=BlockNum % 100; + ReqParams->AsciiBlk[3]=(BlockNum / 10)+0x30; + BlockNum=BlockNum % 10; + ReqParams->AsciiBlk[4]=(BlockNum / 1)+0x30; + ReqParams->SFun =SFun_Delete; + ReqParams->Len_2=0x05; + ReqParams->Cmd[0]='_'; + ReqParams->Cmd[1]='D'; + ReqParams->Cmd[2]='E'; + ReqParams->Cmd[3]='L'; + ReqParams->Cmd[4]='E'; + + IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqControlBlockParams); + Result=isoExchangeBuffer(0,IsoSize); + + if (Result==0) + { + if (SwapWord(Answer->Error)!=Code7NeedPassword) + { + if ((Answer->Error!=0) || (*ResParams!=pduControl)) + Result=errCliDeleteRefused; + } + else + Result=errCliNeedPassword; + } + return Result; +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::opReadSZL() +{ + PS7Answer17 Answer; + PReqFunReadSZLFirst ReqParamsFirst; + PReqFunReadSZLNext ReqParamsNext; + PS7ReqSZLData ReqDataFirst; + PS7ReqSZLData ReqDataNext; + PS7ResParams7 ResParams; + PS7ResSZLDataFirst ResDataFirst; + PS7ResSZLDataNext ResDataNext; + PSZL_HEADER Header; + PS7SZLList Target; + pbyte PDataFirst; + pbyte PDataNext; + word ID, Index; + int IsoSize, DataSize, DataSZL, Result; + bool First, Done; + bool NoRoom = false; + uintptr_t Offset =0; + byte Seq_in =0x00; + + ID=Job.ID; + Index=Job.Index; + opSize=0; + // Setup pointers (note : PDUH_out and PDU.Payload are the same pointer) + ReqParamsFirst=PReqFunReadSZLFirst(pbyte(PDUH_out)+sizeof(TS7ReqHeader)); + ReqParamsNext =PReqFunReadSZLNext(pbyte(PDUH_out)+sizeof(TS7ReqHeader)); + ReqDataFirst =PS7ReqSZLData(pbyte(ReqParamsFirst)+sizeof(TReqFunReadSZLFirst)); + ReqDataNext =PS7ReqSZLData(pbyte(ReqParamsNext)+sizeof(TReqFunReadSZLNext)); + + Answer =PS7Answer17(&PDU.Payload); + ResParams =PS7ResParams7(pbyte(Answer)+ResHeaderSize17); + ResDataFirst =PS7ResSZLDataFirst(pbyte(ResParams)+sizeof(TS7Params7)); + ResDataNext =PS7ResSZLDataNext(pbyte(ResParams)+sizeof(TS7Params7)); + PDataFirst =pbyte(ResDataFirst)+8; // skip header + PDataNext =pbyte(ResDataNext)+4; // skip header + Header =PSZL_HEADER(&opData); + First=true; + Done =false; + do + { + //<------------------------------------------------------- read slices + if (First) + { + //<-------------------------------------------------- prepare first + DataSize=sizeof(TS7ReqSZLData); + // Fill Header + PDUH_out->P=0x32; // Always 0x32 + PDUH_out->PDUType=PduType_userdata; // 0x07 + PDUH_out->AB_EX=0x0000; // Always 0x0000 + PDUH_out->Sequence=GetNextWord(); // AutoInc + PDUH_out->ParLen=SwapWord(sizeof(TReqFunReadSZLFirst)); // 8 bytes params + PDUH_out->DataLen=SwapWord(DataSize); // 8/4 bytes data + // Fill Params + ReqParamsFirst->Head[0]=0x00; + ReqParamsFirst->Head[1]=0x01; + ReqParamsFirst->Head[2]=0x12; + ReqParamsFirst->Plen =0x04; + ReqParamsFirst->Uk =0x11; + ReqParamsFirst->Tg =grSZL; + ReqParamsFirst->SubFun =SFun_ReadSZL; //0x03 + ReqParamsFirst->Seq =Seq_in; + // Fill Data + ReqDataFirst->Ret =0xFF; + ReqDataFirst->TS =TS_ResOctet; + ReqDataFirst->DLen =SwapWord(0x0004); + ReqDataFirst->ID =SwapWord(ID); + ReqDataFirst->Index =SwapWord(Index); + IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqFunReadSZLFirst)+DataSize; + //--------------------------------------------------> prepare first + } + else + { + //<-------------------------------------------------- prepare next + DataSize=sizeof(TS7ReqSZLData)-4; + // Fill Header + PDUH_out->P=0x32; // Always 0x32 + PDUH_out->PDUType=PduType_userdata; // 0x07 + PDUH_out->AB_EX=0x0000; // Always 0x0000 + PDUH_out->Sequence=GetNextWord(); // AutoInc + PDUH_out->ParLen=SwapWord(sizeof(TReqFunReadSZLNext)); // 8 bytes params + PDUH_out->DataLen=SwapWord(DataSize);// 8/4 bytes data + // Fill Params + ReqParamsNext->Head[0]=0x00; + ReqParamsNext->Head[1]=0x01; + ReqParamsNext->Head[2]=0x12; + ReqParamsNext->Plen =0x08; + ReqParamsNext->Uk =0x12; + ReqParamsNext->Tg =grSZL; + ReqParamsNext->SubFun =SFun_ReadSZL; + ReqParamsNext->Seq =Seq_in; + ReqParamsNext->Rsvd =0x0000; + ReqParamsNext->ErrNo =0x0000; + // Fill Data + ReqDataNext->Ret =0x0A; + ReqDataNext->TS =0x00; + ReqDataNext->DLen =0x0000; + ReqDataNext->ID =0x0000; + ReqDataNext->Index =0x0000; + IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqFunReadSZLNext)+DataSize; + //--------------------------------------------------> prepare next + } + Result=isoExchangeBuffer(0,IsoSize); + // Get Data + if (Result==0) + { + if (First) + { + //<------------------------------------------ get data first + if (ResParams->Err==0) + { + if (ResDataFirst->Ret==0xFF) // <-- 0xFF means Result OK + { + // Gets Amount of this slice + DataSZL=SwapWord(ResDataFirst->DLen)-4;// Skips extra params (ID, Index ...) + // Gets end of Sequence Flag + Done=(ResParams->resvd & 0xFF00) == 0; // Low order byte = 0x00 => the sequence is done + // Gets Unit's function sequence + Seq_in=ResParams->Seq; + Target=PS7SZLList(pbyte(&opData)+Offset); + memcpy(Target, PDataFirst, DataSZL); + Offset+=DataSZL; + } + else + Result=CpuError(ResDataFirst->Ret); + } + else + Result=CpuError(ResDataFirst->Ret); + //------------------------------------------> get data first + } + else + { + //<------------------------------------------ get data next + if (ResParams->Err==0) + { + if (ResDataNext->Ret==0xFF) // <-- 0xFF means Result OK + { + // Gets Amount of this slice + DataSZL=SwapWord(ResDataNext->DLen); + // Gets end of Sequence Flag + Done=(ResParams->resvd & 0xFF00) == 0; // Low order byte = 0x00 => the sequence is done + // Gets Unit's function sequence + Seq_in=ResParams->Seq; + Target=PS7SZLList(pbyte(&opData)+Offset); + memcpy(Target, PDataNext, DataSZL); + Offset+=DataSZL; + } + else + Result=CpuError(ResDataNext->Ret); + } + else + Result=CpuError(ResDataNext->Ret); + //------------------------------------------> get data next + } + First=false; + } + //-------------------------------------------------------> read slices + } + while ((!Done) && (Result==0)); + + // Check errors and adjust header + if (Result==0) + { + // Adjust big endian header + Header->LENTHDR=SwapWord(Header->LENTHDR); + Header->N_DR =SwapWord(Header->N_DR); + opSize=int(Offset); + + if (Job.IParam==1) // if 1 data has to be copied into user buffer + { + // Check buffer size + if (opSize>Job.Amount) + { + opSize=Job.Amount; + NoRoom=true; + } + memcpy(Job.pData, &opData, opSize); + *Job.pAmount=opSize; + }; + }; + if ((Result==0)&& NoRoom) + Result=errCliBufferTooSmall; + + return Result; +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::opReadSZLList() +{ + PS7SZLList usrSZLList, opDataList; + int ItemsCount, ItemsCount_in, c, Result; + bool NoRoom = false; + + Job.ID =0x0000; + Job.Index =0x0000; + Job.IParam =0; + ItemsCount_in=Job.Amount; // stores the room + Job.Amount =sizeof(opData); // read into the internal buffer + + Result =opReadSZL(); + if (Result==0) + { + opDataList=PS7SZLList(&opData); // Source + usrSZLList=PS7SZLList(Job.pData); // Target + + ItemsCount=(opSize-sizeof(SZL_HEADER)) / 2; + // Check input size + if (ItemsCount>ItemsCount_in) + { + ItemsCount=ItemsCount_in; // Trim itemscount + NoRoom=true; + } + for (c = 0; c < ItemsCount; c++) + usrSZLList->List[c]=SwapWord(opDataList->List[c]); + *Job.pAmount=ItemsCount; + } + else + *Job.pAmount=0; + + if ((Result==0) && NoRoom) + Result=errCliBufferTooSmall; + + return Result; +} +//--------------------------------------------------------------------------- +byte TSnap7MicroClient::BCDtoByte(byte B) +{ + return ((B >> 4) * 10) + (B & 0x0F); +} +//--------------------------------------------------------------------------- +byte TSnap7MicroClient::WordToBCD(word Value) +{ + return ((Value / 10) << 4) | (Value % 10); +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::opGetDateTime() +{ + PTimeStruct DateTime; + PReqFunDateTime ReqParams; + PReqDataGetDateTime ReqData; + PS7ResParams7 ResParams; + PResDataGetTime ResData; + PS7ResHeader17 Answer; + int IsoSize, Result; + word AYear; + + // Setup pointers (note : PDUH_out and PDU.Payload are the same pointer) + ReqParams=PReqFunDateTime(pbyte(PDUH_out)+sizeof(TS7ReqHeader)); + ReqData =PReqDataGetDateTime(pbyte(ReqParams)+sizeof(TReqFunDateTime)); + Answer =PS7ResHeader17(&PDU.Payload); + ResParams=PS7ResParams7(pbyte(Answer)+ResHeaderSize17); + ResData =PResDataGetTime(pbyte(ResParams)+sizeof(TS7Params7)); + DateTime =PTimeStruct(Job.pData); + // Fill Header + PDUH_out->P=0x32; // Always 0x32 + PDUH_out->PDUType=PduType_userdata; // 0x07 + PDUH_out->AB_EX=0x0000; // Always 0x0000 + PDUH_out->Sequence=GetNextWord(); // AutoInc + PDUH_out->ParLen=SwapWord(sizeof(TReqFunDateTime)); // 8 bytes params + PDUH_out->DataLen=SwapWord(sizeof(TReqDataGetDateTime)); // 4 bytes data + // Fill params (mostly constants) + ReqParams->Head[0]=0x00; + ReqParams->Head[1]=0x01; + ReqParams->Head[2]=0x12; + ReqParams->Plen =0x04; + ReqParams->Uk =0x11; + ReqParams->Tg =grClock; + ReqParams->SubFun =SFun_ReadClock; + ReqParams->Seq =0x00; + // Fill Data + *ReqData =0x0000000A; + + IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqFunDateTime)+sizeof(TReqDataGetDateTime); + Result=isoExchangeBuffer(0,IsoSize); + + // Get Data + if (Result==0) + { + if (ResParams->Err==0) + { + if (ResData->RetVal==0xFF) // <-- 0xFF means Result OK + { + // Decode Plc Date and Time + AYear=BCDtoByte(ResData->Time[0]); + if (AYear<90) + AYear=AYear+100; + DateTime->tm_year=AYear; + DateTime->tm_mon =BCDtoByte(ResData->Time[1])-1; + DateTime->tm_mday=BCDtoByte(ResData->Time[2]); + DateTime->tm_hour=BCDtoByte(ResData->Time[3]); + DateTime->tm_min =BCDtoByte(ResData->Time[4]); + DateTime->tm_sec =BCDtoByte(ResData->Time[5]); + DateTime->tm_wday=(ResData->Time[7] & 0x0F)-1; + } + else + Result=CpuError(ResData->RetVal); + } + else + Result=CpuError(ResData->RetVal); + } + return Result; +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::opSetDateTime() +{ + PTimeStruct DateTime; + PReqFunDateTime ReqParams; + PReqDataSetTime ReqData; + PS7ResParams7 ResParams; + PS7ResHeader17 Answer; + word AYear; + int IsoSize, Result; + + // Setup pointers (note : PDUH_out and PDU.Payload are the same pointer) + ReqParams=PReqFunDateTime(pbyte(PDUH_out)+sizeof(TS7ReqHeader)); + ReqData =PReqDataSetTime(pbyte(ReqParams)+sizeof(TReqFunDateTime)); + Answer =PS7ResHeader17(&PDU.Payload); + ResParams=PS7ResParams7(pbyte(Answer)+ResHeaderSize17); + DateTime =PTimeStruct(Job.pData); + // Fill Header + PDUH_out->P=0x32; // Always 0x32 + PDUH_out->PDUType=PduType_userdata; // 0x07 + PDUH_out->AB_EX=0x0000; // Always 0x0000 + PDUH_out->Sequence=GetNextWord(); // AutoInc + PDUH_out->ParLen=SwapWord(sizeof(TReqFunDateTime)); // 8 bytes params + PDUH_out->DataLen=SwapWord(sizeof(TReqDataSetTime)); // 4 bytes data + // Fill params (mostly constants) + ReqParams->Head[0]=0x00; + ReqParams->Head[1]=0x01; + ReqParams->Head[2]=0x12; + ReqParams->Plen =0x04; + ReqParams->Uk =0x11; + ReqParams->Tg =grClock; + ReqParams->SubFun =SFun_SetClock; + ReqParams->Seq =0x00; + // EncodeSiemensDateTime; + if (DateTime->tm_year<100) + AYear=DateTime->tm_year; + else + AYear=DateTime->tm_year-100; + + ReqData->RetVal=0xFF; + ReqData->TSize =TS_ResOctet; + ReqData->Length=SwapWord(0x000A); + ReqData->Rsvd =0x00; + ReqData->HiYear=0x19; // *must* be 19 tough it's not the Hi part of the year... + + ReqData->Time[0]=WordToBCD(AYear); + ReqData->Time[1]=WordToBCD(DateTime->tm_mon+1); + ReqData->Time[2]=WordToBCD(DateTime->tm_mday); + ReqData->Time[3]=WordToBCD(DateTime->tm_hour); + ReqData->Time[4]=WordToBCD(DateTime->tm_min); + ReqData->Time[5]=WordToBCD(DateTime->tm_sec); + ReqData->Time[6]=0; + ReqData->Time[7]=DateTime->tm_wday+1; + + IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqFunDateTime)+sizeof(TReqDataSetTime); + Result=isoExchangeBuffer(0,IsoSize); + + // Get Result + if (Result==0) + { + if (ResParams->Err!=0) + Result=CpuError(SwapWord(ResParams->Err)); + }; + return Result; +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::opGetOrderCode() +{ + PS7OrderCode OC; + int Result; + + Job.ID =0x0011; + Job.Index =0x0000; + Job.IParam =0; + Result =opReadSZL(); + if (Result==0) + { + OC=PS7OrderCode(Job.pData); + memset(OC,0,sizeof(TS7OrderCode)); + memcpy(OC->Code,&opData[6],20); + OC->V1=opData[opSize-3]; + OC->V2=opData[opSize-2]; + OC->V3=opData[opSize-1]; + }; + return Result; +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::opGetCpuInfo() +{ + PS7CpuInfo Info; + int Result; + + // Store Pointer + Info=PS7CpuInfo(Job.pData); + // Clear data in order to have the end of strings (\0) correctly setted + memset(Info, 0, sizeof(TS7CpuInfo)); + + Job.ID =0x001C; + Job.Index =0x0000; + Job.IParam=0; + Result =opReadSZL(); + if (Result==0) + { + memcpy(Info->ModuleTypeName,&opData[176],32); + memcpy(Info->SerialNumber,&opData[142],24); + memcpy(Info->ASName,&opData[6],24); + memcpy(Info->Copyright,&opData[108],26); + memcpy(Info->ModuleName,&opData[40],24); + } + return Result; +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::opGetCpInfo() +{ + PS7CpInfo Info; + int Result; + // Store Pointer + Info=PS7CpInfo(Job.pData); + memset(Info,0,sizeof(TS7CpInfo)); + Job.ID =0x0131; + Job.Index =0x0001; + Job.IParam=0; + Result =opReadSZL(); + if (Result==0) + { + Info->MaxPduLengt=opData[6]*256+opData[7]; + Info->MaxConnections=opData[8]*256+opData[9]; + Info->MaxMpiRate=DWordAt(&opData[10]); + Info->MaxBusRate=DWordAt(&opData[14]); + }; + return Result; +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::opGetPlcStatus() +{ + int *Status; + int Result; + + Status =(int*)Job.pData; + Job.ID =0x0424; + Job.Index =0x0000; + Job.IParam =0; + Result =opReadSZL(); + if (Result==0) + { + switch (opData[7]) + { + case S7CpuStatusUnknown : + case S7CpuStatusRun : + case S7CpuStatusStop : *Status=opData[7]; + break; + default : + // Since RUN status is always $08 for all CPUs and CPs, STOP status + // sometime can be coded as $03 (especially for old cpu...) + *Status=S7CpuStatusStop; + } + } + else + *Status=0; + return Result; +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::opPlcStop() +{ + PReqFunPlcStop ReqParams; + PResFunCtrl ResParams; + PS7ResHeader23 Answer; + int IsoSize, Result; + + char p_program[] = {'P','_','P','R','O','G','R','A','M'}; + + // Setup pointers (note : PDUH_out and PDU.Payload are the same pointer) + ReqParams=PReqFunPlcStop(pbyte(PDUH_out)+sizeof(TS7ReqHeader)); + Answer =PS7ResHeader23(&PDU.Payload); + ResParams=PResFunCtrl(pbyte(Answer)+ResHeaderSize23); + // Fill Header + PDUH_out->P=0x32; // Always 0x32 + PDUH_out->PDUType=PduType_request; // 0x01 + PDUH_out->AB_EX=0x0000; // Always 0x0000 + PDUH_out->Sequence=GetNextWord(); // AutoInc + PDUH_out->ParLen=SwapWord(sizeof(TReqFunPlcStop)); + PDUH_out->DataLen=0x0000; // No Data + // Fill Params + ReqParams->Fun=pduStop; + memset(ReqParams->Uk_5,0,5); + ReqParams->Len_2=0x09; + memcpy(ReqParams->Cmd,&p_program,9); + + IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqFunPlcStop); + Result=isoExchangeBuffer(0,IsoSize); + + if (Result==0) + { + if (Answer->Error!=0) + { + if (ResParams->ResFun!=pduStop) + Result=errCliCannotStopPLC; + else + if (ResParams->para ==0x07) + Result=errCliAlreadyStop; + else + Result=errCliCannotStopPLC; + }; + }; + return Result; +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::opPlcHotStart() +{ + PReqFunPlcHotStart ReqParams; + PResFunCtrl ResParams; + PS7ResHeader23 Answer; + int IsoSize, Result; + + char p_program[] = {'P','_','P','R','O','G','R','A','M'}; + + // Setup pointers (note : PDUH_out and PDU.Payload are the same pointer) + ReqParams=PReqFunPlcHotStart(pbyte(PDUH_out)+sizeof(TS7ReqHeader)); + Answer =PS7ResHeader23(&PDU.Payload); + ResParams=PResFunCtrl(pbyte(Answer)+ResHeaderSize23); + // Fill Header + PDUH_out->P=0x32; // Always 0x32 + PDUH_out->PDUType=PduType_request; // 0x01 + PDUH_out->AB_EX=0x0000; // Always 0x0000 + PDUH_out->Sequence=GetNextWord(); // AutoInc + PDUH_out->ParLen=SwapWord(sizeof(TReqFunPlcHotStart)); // 16 bytes params + PDUH_out->DataLen=0x0000; // No Data + // Fill Params + ReqParams->Fun=pduStart; + ReqParams->Uk_7[0]=0x00; + ReqParams->Uk_7[1]=0x00; + ReqParams->Uk_7[2]=0x00; + ReqParams->Uk_7[3]=0x00; + ReqParams->Uk_7[4]=0x00; + ReqParams->Uk_7[5]=0x00; + ReqParams->Uk_7[6]=0xFD; + + ReqParams->Len_1=0x0000; + ReqParams->Len_2=0x09; + memcpy(ReqParams->Cmd,&p_program,9); + + IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqFunPlcHotStart); + Result=isoExchangeBuffer(0,IsoSize); + + if (Result==0) + { + if ((Answer->Error!=0)) + { + if ((ResParams->ResFun!=pduStart)) + Result=errCliCannotStartPLC; + else + { + if (ResParams->para==0x03) + Result=errCliAlreadyRun; + else + if (ResParams->para==0x02) + Result=errCliCannotStartPLC; + else + Result=errCliCannotStartPLC; + } + } + }; + return Result; +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::opPlcColdStart() +{ + PReqFunPlcColdStart ReqParams; + PResFunCtrl ResParams; + PS7ResHeader23 Answer; + int IsoSize, Result; + char p_program[] = {'P','_','P','R','O','G','R','A','M'}; + + // Setup pointers (note : PDUH_out and PDU.Payload are the same pointer) + ReqParams=PReqFunPlcColdStart(pbyte(PDUH_out)+sizeof(TS7ReqHeader)); + Answer =PS7ResHeader23(&PDU.Payload); + ResParams=PResFunCtrl(pbyte(Answer)+ResHeaderSize23); + // Fill Header + PDUH_out->P=0x32; // Always 0x32 + PDUH_out->PDUType=PduType_request; // 0x01 + PDUH_out->AB_EX=0x0000; // Always 0x0000 + PDUH_out->Sequence=GetNextWord(); // AutoInc + PDUH_out->ParLen=SwapWord(sizeof(TReqFunPlcColdStart)); // 22 bytes params + PDUH_out->DataLen=0x0000; // No Data + // Fill Params + ReqParams->Fun=pduStart; + ReqParams->Uk_7[0]=0x00; + ReqParams->Uk_7[1]=0x00; + ReqParams->Uk_7[2]=0x00; + ReqParams->Uk_7[3]=0x00; + ReqParams->Uk_7[4]=0x00; + ReqParams->Uk_7[5]=0x00; + ReqParams->Uk_7[6]=0xFD; + + ReqParams->Len_1=SwapWord(0x0002); + ReqParams->SFun =SwapWord(0x4320); // Cold start + ReqParams->Len_2=0x09; + memcpy(ReqParams->Cmd,&p_program,9); + + IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqFunPlcColdStart); + Result=isoExchangeBuffer(0,IsoSize); + + if (Result==0) + { + if ((Answer->Error!=0)) + { + if ((ResParams->ResFun!=pduStart)) + Result=errCliCannotStartPLC; + else + { + if (ResParams->para==0x03) + Result=errCliAlreadyRun; + else + if (ResParams->para==0x02) + Result=errCliCannotStartPLC; + else + Result=errCliCannotStartPLC; + } + } + }; + return Result; +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::opCopyRamToRom() +{ + PReqFunCopyRamToRom ReqParams; + PResFunCtrl ResParams; + PS7ResHeader23 Answer; + int IsoSize, CurTimeout, Result; + char _modu[] = {'_','M','O','D','U'}; + + // Setup pointers (note : PDUH_out and PDU.Payload are the same pointer) + ReqParams=PReqFunCopyRamToRom(pbyte(PDUH_out)+sizeof(TS7ReqHeader)); + Answer =PS7ResHeader23(&PDU.Payload); + ResParams=PResFunCtrl(pbyte(Answer)+ResHeaderSize23); + // Fill Header + PDUH_out->P=0x32; // Always 0x32 + PDUH_out->PDUType=PduType_request; // 0x01 + PDUH_out->AB_EX=0x0000; // Always 0x0000 + PDUH_out->Sequence=GetNextWord(); // AutoInc + PDUH_out->ParLen=SwapWord(sizeof(TReqFunCopyRamToRom)); + PDUH_out->DataLen=0x0000; // No Data + // Fill Params + ReqParams->Fun=pduControl; + ReqParams->Uk_7[0]=0x00; + ReqParams->Uk_7[1]=0x00; + ReqParams->Uk_7[2]=0x00; + ReqParams->Uk_7[3]=0x00; + ReqParams->Uk_7[4]=0x00; + ReqParams->Uk_7[5]=0x00; + ReqParams->Uk_7[6]=0xFD; + + ReqParams->Len_1=SwapWord(0x0002); + ReqParams->SFun =SwapWord(0x4550); + ReqParams->Len_2=0x05; + memcpy(ReqParams->Cmd,&_modu,5); + + IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqFunCopyRamToRom); + // Changes the timeout + CurTimeout=RecvTimeout; + RecvTimeout=Job.IParam; + Result=isoExchangeBuffer(0,IsoSize); + // Restores the timeout + RecvTimeout=CurTimeout; + + if (Result==0) + { + if ((Answer->Error!=0) || (ResParams->ResFun!=pduControl)) + Result=errCliCannotCopyRamToRom; + } + return Result; +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::opCompress() +{ + PReqFunCompress ReqParams; + PResFunCtrl ResParams; + PS7ResHeader23 Answer; + int IsoSize, CurTimeout, Result; + char _garb[] = {'_','G','A','R','B'}; + + // Setup pointers (note : PDUH_out and PDU.Payload are the same pointer) + ReqParams=PReqFunCompress(pbyte(PDUH_out)+sizeof(TS7ReqHeader)); + Answer =PS7ResHeader23(&PDU.Payload); + ResParams=PResFunCtrl(pbyte(Answer)+ResHeaderSize23); + // Fill Header + PDUH_out->P=0x32; // Always 0x32 + PDUH_out->PDUType=PduType_request; // 0x01 + PDUH_out->AB_EX=0x0000; // Always 0x0000 + PDUH_out->Sequence=GetNextWord(); // AutoInc + PDUH_out->ParLen=SwapWord(sizeof(TReqFunCompress)); + PDUH_out->DataLen=0x0000; // No Data + // Fill Params + ReqParams->Fun=pduControl; + ReqParams->Uk_7[0]=0x00; + ReqParams->Uk_7[1]=0x00; + ReqParams->Uk_7[2]=0x00; + ReqParams->Uk_7[3]=0x00; + ReqParams->Uk_7[4]=0x00; + ReqParams->Uk_7[5]=0x00; + ReqParams->Uk_7[6]=0xFD; + + ReqParams->Len_1=0x0000; + ReqParams->Len_2=0x05; + memcpy(ReqParams->Cmd,&_garb,5); + + IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqFunCompress); + // Changes the timeout + CurTimeout=RecvTimeout; + RecvTimeout=Job.IParam; + Result=isoExchangeBuffer(0,IsoSize); + // Restores the timeout + RecvTimeout=CurTimeout; + + if (Result==0) + { + if (((Answer->Error!=0) || (ResParams->ResFun!=pduControl))) + Result=errCliCannotCompress; + } + return Result; +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::opGetProtection() +{ + PS7Protection Info, usrInfo; + int Result; + + // Store Pointer + usrInfo=PS7Protection(Job.pData); + memset(usrInfo, 0, sizeof(TS7Protection)); + + Job.ID =0x0232; + Job.Index =0x0004; + Job.IParam=0; // No copy in Usr Data pointed by Job.pData + Result =opReadSZL(); + if (Result==0) + { + Info=PS7Protection(pbyte(&opData)+6); + usrInfo->sch_schal=SwapWord(Info->sch_schal); + usrInfo->sch_par =SwapWord(Info->sch_par); + usrInfo->sch_rel =SwapWord(Info->sch_rel); + usrInfo->bart_sch =SwapWord(Info->bart_sch); + usrInfo->anl_sch =SwapWord(Info->anl_sch); + } + return Result; +} +//****************************************************************************** +// NOTE +// PASSWORD HACKING IS VERY FAR FROM THE AIM OF THIS PROJECT +// NEXT FUNCTION ONLY ENCODES THE ASCII PASSWORD TO BE DOWNLOADED IN THE PLC. +// +// MOREOVER **YOU NEED TO KNOW** THE CORRECT PASSWORD TO MEET THE CPU +// SECURITY LEVEL +//****************************************************************************** +int TSnap7MicroClient::opSetPassword() +{ + PReqFunSecurity ReqParams; + PReqDataSecurity ReqData; + PResParamsSecurity ResParams; + PS7ResHeader23 Answer; + int c, IsoSize, Result; + + // Setup pointers (note : PDUH_out and PDU.Payload are the same pointer) + ReqParams=PReqFunSecurity(pbyte(PDUH_out)+sizeof(TS7ReqHeader)); + ReqData =PReqDataSecurity(pbyte(ReqParams)+sizeof(TReqFunSecurity)); + Answer =PS7ResHeader23(&PDU.Payload); + ResParams=PResParamsSecurity(pbyte(Answer)+ResHeaderSize17); + // Fill Header + PDUH_out->P=0x32; // Always 0x32 + PDUH_out->PDUType=PduType_userdata; // 0x07 + PDUH_out->AB_EX=0x0000; // Always 0x0000 + PDUH_out->Sequence=GetNextWord(); // AutoInc + PDUH_out->ParLen =SwapWord(sizeof(TReqFunSecurity)); + PDUH_out->DataLen=SwapWord(sizeof(TReqDataSecurity)); + // Fill params (mostly constants) + ReqParams->Head[0]=0x00; + ReqParams->Head[1]=0x01; + ReqParams->Head[2]=0x12; + ReqParams->Plen =0x04; + ReqParams->Uk =0x11; + ReqParams->Tg =grSecurity; + ReqParams->SubFun =SFun_EnterPwd; + ReqParams->Seq =0x00; + // Fill Data + ReqData->Ret =0xFF; + ReqData->TS =TS_ResOctet; + ReqData->DLen =SwapWord(0x0008); // 8 bytes data : password + // Encode the password + ReqData->Pwd[0]=opData[0] ^ 0x55; + ReqData->Pwd[1]=opData[1] ^ 0x55; + for (c = 2; c < 8; c++){ + ReqData->Pwd[c]=opData[c] ^ 0x55 ^ ReqData->Pwd[c-2]; + }; + + IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqFunSecurity)+sizeof(TReqDataSecurity); + Result=isoExchangeBuffer(0,IsoSize); + + // Get Return + if (Result==0) + { + if (ResParams->Err!=0) + Result=CpuError(SwapWord(ResParams->Err)); + }; + + return Result; +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::opClearPassword() +{ + PReqFunSecurity ReqParams; + PReqDataSecurity ReqData; + PResParamsSecurity ResParams; + PS7ResHeader23 Answer; + int IsoSize, Result; + + // Setup pointers (note : PDUH_out and PDU.Payload are the same pointer) + ReqParams=PReqFunSecurity(pbyte(PDUH_out)+sizeof(TS7ReqHeader)); + ReqData =PReqDataSecurity(pbyte(ReqParams)+sizeof(TReqFunSecurity)); + Answer =PS7ResHeader23(&PDU.Payload); + ResParams=PResParamsSecurity(pbyte(Answer)+ResHeaderSize17); + // Fill Header + PDUH_out->P=0x32; // Always 0x32 + PDUH_out->PDUType=PduType_userdata; // 0x07 + PDUH_out->AB_EX=0x0000; // Always 0x0000 + PDUH_out->Sequence=GetNextWord(); // AutoInc + PDUH_out->ParLen =SwapWord(sizeof(TReqFunSecurity)); + PDUH_out->DataLen=SwapWord(0x0004); // We need only 4 bytes + // Fill params (mostly constants) + ReqParams->Head[0]=0x00; + ReqParams->Head[1]=0x01; + ReqParams->Head[2]=0x12; + ReqParams->Plen =0x04; + ReqParams->Uk =0x11; + ReqParams->Tg =grSecurity; + ReqParams->SubFun =SFun_CancelPwd; + ReqParams->Seq =0x00; + // Fill Data + ReqData->Ret =0x0A; + ReqData->TS =0x00; + ReqData->DLen =0x0000; + + IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqFunSecurity)+4; + Result=isoExchangeBuffer(0,IsoSize); + + // Get Return + if (Result==0) + { + if (ResParams->Err!=0) + Result=CpuError(SwapWord(ResParams->Err)); + }; + return Result; +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::CpuError(int Error) +{ + switch(Error) + { + case 0 : return 0; + case Code7AddressOutOfRange : return errCliAddressOutOfRange; + case Code7InvalidTransportSize : return errCliInvalidTransportSize; + case Code7WriteDataSizeMismatch : return errCliWriteDataSizeMismatch; + case Code7ResItemNotAvailable : + case Code7ResItemNotAvailable1 : return errCliItemNotAvailable; + case Code7DataOverPDU : return errCliSizeOverPDU; + case Code7InvalidValue : return errCliInvalidValue; + case Code7FunNotAvailable : return errCliFunNotAvailable; + case Code7NeedPassword : return errCliNeedPassword; + case Code7InvalidPassword : return errCliInvalidPassword; + case Code7NoPasswordToSet : + case Code7NoPasswordToClear : return errCliNoPasswordToSetOrClear; + default: + return errCliFunctionRefused; + }; +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::DataSizeByte(int WordLength) +{ + switch (WordLength){ + case S7WLBit : return 1; // S7 sends 1 byte per bit + case S7WLByte : return 1; + case S7WLChar : return 1; + case S7WLWord : return 2; + case S7WLDWord : return 4; + case S7WLInt : return 2; + case S7WLDInt : return 4; + case S7WLReal : return 4; + case S7WLCounter : return 2; + case S7WLTimer : return 2; + default : return 0; + } +} +//--------------------------------------------------------------------------- +longword TSnap7MicroClient::DWordAt(void * P) +{ + longword DW; + DW=*(longword*)P; + return SwapDWord(DW); +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::CheckBlock(int BlockType, int BlockNum, void * pBlock, int Size) +{ + PS7CompactBlockInfo Info = PS7CompactBlockInfo(pBlock); + + if (BlockType>=0) // if (BlockType<0 the test is skipped + { + if ((BlockType!=Block_OB)&&(BlockType!=Block_DB)&&(BlockType!=Block_FB)&& + (BlockType!=Block_FC)&&(BlockType!=Block_SDB)&&(BlockType!=Block_SFC)&& + (BlockType!=Block_SFB)) + return errCliInvalidBlockType; + } + + if (BlockNum>=0) // if (BlockNum<0 the test is skipped + { + if (BlockNum>0xFFFF) + return errCliInvalidBlockNumber; + }; + + if (SwapDWord(Info->LenLoadMem)!=longword(Size)) + return errCliInvalidBlockSize; + + // Check the presence of the footer + if (SwapWord(Info->MC7Len)+sizeof(TS7CompactBlockInfo)>=u_int(Size)) + return errCliInvalidBlockSize; + + return 0; +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::SubBlockToBlock(int SBB) +{ + switch (SBB) + { + case SubBlk_OB : return Block_OB; + case SubBlk_DB : return Block_DB; + case SubBlk_SDB : return Block_SDB; + case SubBlk_FC : return Block_FC; + case SubBlk_SFC : return Block_SFC; + case SubBlk_FB : return Block_FB; + case SubBlk_SFB : return Block_SFB; + default : return 0; + }; +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::PerformOperation() +{ + ClrError(); + int Operation=Job.Op; + switch(Operation) + { + case s7opNone: + Job.Result=errCliInvalidParams; + break; + case s7opReadArea: + Job.Result=opReadArea(); + break; + case s7opWriteArea: + Job.Result=opWriteArea(); + break; + case s7opReadMultiVars: + Job.Result=opReadMultiVars(); + break; + case s7opWriteMultiVars: + Job.Result=opWriteMultiVars(); + break; + case s7opDBGet: + Job.Result=opDBGet(); + break; + case s7opDBFill: + Job.Result=opDBFill(); + break; + case s7opUpload: + Job.Result=opUpload(); + break; + case s7opDownload: + Job.Result=opDownload(); + break; + case s7opDelete: + Job.Result=opDelete(); + break; + case s7opListBlocks: + Job.Result=opListBlocks(); + break; + case s7opAgBlockInfo: + Job.Result=opAgBlockInfo(); + break; + case s7opListBlocksOfType: + Job.Result=opListBlocksOfType(); + break; + case s7opReadSzlList: + Job.Result=opReadSZLList(); + break; + case s7opReadSZL: + Job.Result=opReadSZL(); + break; + case s7opGetDateTime: + Job.Result=opGetDateTime(); + break; + case s7opSetDateTime: + Job.Result=opSetDateTime(); + break; + case s7opGetOrderCode: + Job.Result=opGetOrderCode(); + break; + case s7opGetCpuInfo: + Job.Result=opGetCpuInfo(); + break; + case s7opGetCpInfo: + Job.Result=opGetCpInfo(); + break; + case s7opGetPlcStatus: + Job.Result=opGetPlcStatus(); + break; + case s7opPlcHotStart: + Job.Result=opPlcHotStart(); + break; + case s7opPlcColdStart: + Job.Result=opPlcColdStart(); + break; + case s7opCopyRamToRom: + Job.Result=opCopyRamToRom(); + break; + case s7opCompress: + Job.Result=opCompress(); + break; + case s7opPlcStop: + Job.Result=opPlcStop(); + break; + case s7opGetProtection: + Job.Result=opGetProtection(); + break; + case s7opSetPassword: + Job.Result=opSetPassword(); + break; + case s7opClearPassword: + Job.Result=opClearPassword(); + break; + } + Job.Time =SysGetTick()-JobStart; + Job.Pending=false; + return SetError(Job.Result); +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::Disconnect() +{ + JobStart=SysGetTick(); + PeerDisconnect(); + Job.Time=SysGetTick()-JobStart; + Job.Pending=false; + return 0; +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::Reset(bool DoReconnect) +{ + Job.Pending=false; + if (DoReconnect) { + Disconnect(); + return Connect(); + } + else + return 0; +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::Connect() +{ + int Result; + JobStart=SysGetTick(); + Result =PeerConnect(); + Job.Time=SysGetTick()-JobStart; + return Result; +} +//--------------------------------------------------------------------------- +void TSnap7MicroClient::SetConnectionType(word ConnType) +{ + ConnectionType=ConnType; +} +//--------------------------------------------------------------------------- +void TSnap7MicroClient::SetConnectionParams(const char *RemAddress, word LocalTSAP, word RemoteTSAP) +{ + SrcTSap = LocalTSAP; + DstTSap = RemoteTSAP; + strncpy(RemoteAddress, RemAddress, 16); +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::ConnectTo(const char *RemAddress, int Rack, int Slot) +{ + word RemoteTSAP = (ConnectionType<<8)+(Rack*0x20)+Slot; + SetConnectionParams(RemAddress, SrcTSap, RemoteTSAP); + return Connect(); +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::GetParam(int ParamNumber, void *pValue) +{ + switch (ParamNumber) + { + case p_u16_RemotePort: + *Puint16_t(pValue)=RemotePort; + break; + case p_i32_PingTimeout: + *Pint32_t(pValue)=PingTimeout; + break; + case p_i32_SendTimeout: + *Pint32_t(pValue)=SendTimeout; + break; + case p_i32_RecvTimeout: + *Pint32_t(pValue)=RecvTimeout; + break; + case p_i32_WorkInterval: + *Pint32_t(pValue)=WorkInterval; + break; + case p_u16_SrcRef: + *Puint16_t(pValue)=SrcRef; + break; + case p_u16_DstRef: + *Puint16_t(pValue)=DstRef; + break; + case p_u16_SrcTSap: + *Puint16_t(pValue)=SrcTSap; + break; + case p_i32_PDURequest: + *Pint32_t(pValue)=PDURequest; + break; + default: return errCliInvalidParamNumber; + } + return 0; +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::SetParam(int ParamNumber, void *pValue) +{ + switch (ParamNumber) + { + case p_u16_RemotePort: + if (!Connected) + RemotePort=*Puint16_t(pValue); + else + return errCliCannotChangeParam; + break; + case p_i32_PingTimeout: + PingTimeout=*Pint32_t(pValue); + break; + case p_i32_SendTimeout: + SendTimeout=*Pint32_t(pValue); + break; + case p_i32_RecvTimeout: + RecvTimeout=*Pint32_t(pValue); + break; + case p_i32_WorkInterval: + WorkInterval=*Pint32_t(pValue); + break; + case p_u16_SrcRef: + SrcRef=*Puint16_t(pValue); + break; + case p_u16_DstRef: + DstRef=*Puint16_t(pValue); + break; + case p_u16_SrcTSap: + SrcTSap=*Puint16_t(pValue); + break; + case p_i32_PDURequest: + PDURequest=*Pint32_t(pValue); + break; + default: return errCliInvalidParamNumber; + } + return 0; +} +//--------------------------------------------------------------------------- +// Data I/O functions +int TSnap7MicroClient::ReadArea(int Area, int DBNumber, int Start, int Amount, int WordLen, void * pUsrData) +{ + if (!Job.Pending) + { + Job.Pending = true; + Job.Op = s7opReadArea; + Job.Area = Area; + Job.Number = DBNumber; + Job.Start = Start; + Job.Amount = Amount; + Job.WordLen = WordLen; + Job.pData = pUsrData; + JobStart = SysGetTick(); + return PerformOperation(); + } + else + return SetError(errCliJobPending); +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::WriteArea(int Area, int DBNumber, int Start, int Amount, int WordLen, void * pUsrData) +{ + if (!Job.Pending) + { + Job.Pending = true; + Job.Op = s7opWriteArea; + Job.Area = Area; + Job.Number = DBNumber; + Job.Start = Start; + Job.Amount = Amount; + Job.WordLen = WordLen; + Job.pData = pUsrData; + JobStart = SysGetTick(); + return PerformOperation(); + } + else + return SetError(errCliJobPending); +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::ReadMultiVars(PS7DataItem Item, int ItemsCount) +{ + if (!Job.Pending) + { + Job.Pending =true; + Job.Op =s7opReadMultiVars; + Job.Amount =ItemsCount; + Job.pData =Item; + JobStart =SysGetTick(); + return PerformOperation(); + } + else + return SetError(errCliJobPending); +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::WriteMultiVars(PS7DataItem Item, int ItemsCount) +{ + if (!Job.Pending) + { + Job.Pending =true; + Job.Op =s7opWriteMultiVars; + Job.Amount =ItemsCount; + Job.pData =Item; + JobStart =SysGetTick(); + return PerformOperation(); + } + else + return SetError(errCliJobPending); +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::DBRead(int DBNumber, int Start, int Size, void * pUsrData) +{ + return ReadArea(S7AreaDB, DBNumber, Start, Size, S7WLByte, pUsrData); +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::DBWrite(int DBNumber, int Start, int Size, void * pUsrData) +{ + return WriteArea(S7AreaDB, DBNumber, Start, Size, S7WLByte, pUsrData); +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::MBRead(int Start, int Size, void * pUsrData) +{ + return ReadArea(S7AreaMK, 0, Start, Size, S7WLByte, pUsrData); +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::MBWrite(int Start, int Size, void * pUsrData) +{ + return WriteArea(S7AreaMK, 0, Start, Size, S7WLByte, pUsrData); +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::EBRead(int Start, int Size, void * pUsrData) +{ + return ReadArea(S7AreaPE, 0, Start, Size, S7WLByte, pUsrData); +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::EBWrite(int Start, int Size, void * pUsrData) +{ + return WriteArea(S7AreaPE, 0, Start, Size, S7WLByte, pUsrData); +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::ABRead(int Start, int Size, void * pUsrData) +{ + return ReadArea(S7AreaPA, 0, Start, Size, S7WLByte, pUsrData); +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::ABWrite(int Start, int Size, void * pUsrData) +{ + return WriteArea(S7AreaPA, 0, Start, Size, S7WLByte, pUsrData); +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::TMRead(int Start, int Amount, void * pUsrData) +{ + return ReadArea(S7AreaTM, 0, Start, Amount, S7WLTimer, pUsrData); +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::TMWrite(int Start, int Amount, void * pUsrData) +{ + return WriteArea(S7AreaTM, 0, Start, Amount, S7WLTimer, pUsrData); +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::CTRead(int Start, int Amount, void * pUsrData) +{ + return ReadArea(S7AreaCT, 0, Start, Amount, S7WLCounter, pUsrData); +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::CTWrite(int Start, int Amount, void * pUsrData) +{ + return WriteArea(S7AreaCT, 0, Start, Amount, S7WLCounter, pUsrData); +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::ListBlocks(PS7BlocksList pUsrData) +{ + if (!Job.Pending) + { + Job.Pending =true; + Job.Op =s7opListBlocks; + Job.pData =pUsrData; + JobStart =SysGetTick(); + return PerformOperation(); + } + else + return SetError(errCliJobPending); +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::GetAgBlockInfo(int BlockType, int BlockNum, PS7BlockInfo pUsrData) +{ + if (!Job.Pending) + { + Job.Pending =true; + Job.Op =s7opAgBlockInfo; + Job.Area =BlockType; + Job.Number =BlockNum; + Job.pData =pUsrData; + JobStart =SysGetTick(); + return PerformOperation(); + } + else + return SetError(errCliJobPending); +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::GetPgBlockInfo(void * pBlock, PS7BlockInfo pUsrData, int Size) +{ + PS7CompactBlockInfo Info; + PS7BlockFooter Footer; + + int Result=CheckBlock(-1,-1,pBlock,Size); + if (Result==0) + { + Info=PS7CompactBlockInfo(pBlock); + pUsrData->BlkType =Info->SubBlkType; + pUsrData->BlkNumber=SwapWord(Info->BlkNum); + pUsrData->BlkLang =Info->BlkLang; + pUsrData->BlkFlags =Info->BlkFlags; + pUsrData->MC7Size =SwapWord(Info->MC7Len); + pUsrData->LoadSize =SwapDWord(Info->LenLoadMem); + pUsrData->LocalData=SwapDWord(Info->LocDataLen); + pUsrData->SBBLength=SwapDWord(Info->SbbLen); + pUsrData->CheckSum =0; // this info is not available + pUsrData->Version =0; // this info is not available + FillTime(SwapWord(Info->CodeTime_dy),pUsrData->CodeDate); + FillTime(SwapWord(Info->IntfTime_dy),pUsrData->IntfDate); + + Footer=PS7BlockFooter(pbyte(Info)+pUsrData->LoadSize-sizeof(TS7BlockFooter)); + + memcpy(pUsrData->Author,Footer->Author,8); + memcpy(pUsrData->Family,Footer->Family,8); + memcpy(pUsrData->Header,Footer->Header,8); + }; + return SetError(Result); +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::ListBlocksOfType(int BlockType, TS7BlocksOfType *pUsrData, int &ItemsCount) +{ + if (!Job.Pending) + { + if (ItemsCount<1) + return SetError(errCliInvalidBlockSize); + Job.Pending =true; + Job.Op =s7opListBlocksOfType; + Job.Area =BlockType; + Job.pData =pUsrData; + Job.pAmount =&ItemsCount; + Job.Amount =ItemsCount; + JobStart =SysGetTick(); + return PerformOperation(); + } + else + return SetError(errCliJobPending); +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::Upload(int BlockType, int BlockNum, void * pUsrData, int & Size) +{ + if (!Job.Pending) + { + if (Size<=0) + return SetError(errCliInvalidBlockSize); + Job.Pending =true; + Job.Op =s7opUpload; + Job.Area =BlockType; + Job.pData =pUsrData; + Job.pAmount =&Size; + Job.Amount =Size; + Job.Number =BlockNum; + Job.IParam =0; // not full upload, only data + JobStart =SysGetTick(); + return PerformOperation(); + } + else + return SetError(errCliJobPending); +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::FullUpload(int BlockType, int BlockNum, void * pUsrData, int & Size) +{ + if (!Job.Pending) + { + if (Size<=0) + return SetError(errCliInvalidBlockSize); + Job.Pending =true; + Job.Op =s7opUpload; + Job.Area =BlockType; + Job.pData =pUsrData; + Job.pAmount =&Size; + Job.Amount =Size; + Job.Number =BlockNum; + Job.IParam =1; // header + data + footer + JobStart =SysGetTick(); + return PerformOperation(); + } + else + return SetError(errCliJobPending); +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::Download(int BlockNum, void * pUsrData, int Size) +{ + if (!Job.Pending) + { + Job.Pending =true; + Job.Op =s7opDownload; + memcpy(&opData, pUsrData, Size); + Job.Number =BlockNum; + Job.Amount =Size; + JobStart =SysGetTick(); + return PerformOperation(); + } + else + return SetError(errCliJobPending); +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::Delete(int BlockType, int BlockNum) +{ + if (!Job.Pending) + { + Job.Pending =true; + Job.Op =s7opDelete; + Job.Area =BlockType; + Job.Number =BlockNum; + JobStart =SysGetTick(); + return PerformOperation(); + } + else + return SetError(errCliJobPending); +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::DBGet(int DBNumber, void * pUsrData, int & Size) +{ + if (!Job.Pending) + { + if (Size<=0) + return SetError(errCliInvalidBlockSize); + Job.Pending =true; + Job.Op =s7opDBGet; + Job.Number =DBNumber; + Job.pData =pUsrData; + Job.pAmount =&Size; + Job.Amount =Size; + JobStart =SysGetTick(); + return PerformOperation(); + } + else + return SetError(errCliJobPending); +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::DBFill(int DBNumber, int FillChar) +{ + if (!Job.Pending) + { + Job.Pending =true; + Job.Op =s7opDBFill; + Job.Number =DBNumber; + Job.IParam =FillChar; + JobStart =SysGetTick(); + return PerformOperation(); + } + else + return SetError(errCliJobPending); +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::GetPlcDateTime(tm &DateTime) +{ + if (!Job.Pending) + { + Job.Pending =true; + Job.Op =s7opGetDateTime; + Job.pData =&DateTime; + JobStart =SysGetTick(); + return PerformOperation(); + } + else + return SetError(errCliJobPending); +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::SetPlcDateTime(tm * DateTime) +{ + if (!Job.Pending) + { + Job.Pending =true; + Job.Op =s7opSetDateTime; + Job.pData =DateTime; + JobStart =SysGetTick(); + return PerformOperation(); + } + else + return SetError(errCliJobPending); +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::SetPlcSystemDateTime() +{ + time_t Now; + time(&Now); + struct tm * DateTime = localtime (&Now); + return SetPlcDateTime(DateTime); +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::GetOrderCode(PS7OrderCode pUsrData) +{ + if (!Job.Pending) + { + Job.Pending =true; + Job.Op =s7opGetOrderCode; + Job.pData =pUsrData; + JobStart =SysGetTick(); + return PerformOperation(); + } + else + return SetError(errCliJobPending); +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::GetCpuInfo(PS7CpuInfo pUsrData) +{ + if (!Job.Pending) + { + Job.Pending =true; + Job.Op =s7opGetCpuInfo; + Job.pData =pUsrData; + JobStart =SysGetTick(); + return PerformOperation(); + } + else + return SetError(errCliJobPending); +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::GetCpInfo(PS7CpInfo pUsrData) +{ + if (!Job.Pending) + { + Job.Pending =true; + Job.Op =s7opGetCpInfo; + Job.pData =pUsrData; + JobStart =SysGetTick(); + return PerformOperation(); + } + else + return SetError(errCliJobPending); +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::ReadSZL(int ID, int Index, PS7SZL pUsrData, int &Size) +{ + if (!Job.Pending) + { + Job.Pending =true; + Job.Op =s7opReadSZL; + Job.ID =ID; + Job.Index =Index; + Job.pData =pUsrData; + Job.pAmount =&Size; + Job.Amount =Size; + Job.IParam =1; // Data has to be copied into user buffer + JobStart =SysGetTick(); + return PerformOperation(); + } + else + return SetError(errCliJobPending); +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::ReadSZLList(PS7SZLList pUsrData, int &ItemsCount) +{ + if (!Job.Pending) + { + Job.Pending =true; + Job.Op =s7opReadSzlList; + Job.pData =pUsrData; + Job.pAmount =&ItemsCount; + Job.Amount =ItemsCount; + JobStart =SysGetTick(); + return PerformOperation(); + } + else + return SetError(errCliJobPending); +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::PlcHotStart() +{ + if (!Job.Pending) + { + Job.Pending =true; + Job.Op =s7opPlcHotStart; + JobStart =SysGetTick(); + return PerformOperation(); + } + else + return SetError(errCliJobPending); +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::PlcColdStart() +{ + if (!Job.Pending) + { + Job.Pending =true; + Job.Op =s7opPlcColdStart; + JobStart =SysGetTick(); + return PerformOperation(); + } + else + return SetError(errCliJobPending); +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::PlcStop() +{ + if (!Job.Pending) + { + Job.Pending =true; + Job.Op =s7opPlcStop; + JobStart =SysGetTick(); + return PerformOperation(); + } + else + return SetError(errCliJobPending); +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::CopyRamToRom(int Timeout) +{ + if (!Job.Pending) + { + if (Timeout>0) + { + Job.Pending =true; + Job.Op =s7opCopyRamToRom; + Job.IParam =Timeout; + JobStart =SysGetTick(); + return PerformOperation(); + } + else + return SetError(errCliInvalidParams); + } + else + return SetError(errCliJobPending); +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::Compress(int Timeout) +{ + if (!Job.Pending) + { + if (Timeout>0) + { + Job.Pending =true; + Job.Op =s7opCompress; + Job.IParam =Timeout; + JobStart =SysGetTick(); + return PerformOperation(); + } + else + return SetError(errCliInvalidParams); + } + else + return SetError(errCliJobPending); +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::GetPlcStatus(int & Status) +{ + if (!Job.Pending) + { + Job.Pending =true; + Job.Op =s7opGetPlcStatus; + Job.pData =&Status; + JobStart =SysGetTick(); + return PerformOperation(); + } + else + return SetError(errCliJobPending); +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::GetProtection(PS7Protection pUsrData) +{ + if (!Job.Pending) + { + Job.Pending =true; + Job.Op =s7opGetProtection; + Job.pData =pUsrData; + JobStart =SysGetTick(); + return PerformOperation(); + } + else + return SetError(errCliJobPending); +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::SetSessionPassword(char *Password) +{ + if (!Job.Pending) + { + size_t L = strlen(Password); + // checks the len + if ((L<1) || (L>8)) + return SetError(errCliInvalidParams); + Job.Pending =true; + // prepares an 8 char string filled with spaces + memset(&opData,0x20,8); + // copies + strncpy((char*)&opData,Password,L); + Job.Op =s7opSetPassword; + JobStart =SysGetTick(); + return PerformOperation(); + } + else + return SetError(errCliJobPending); +} +//--------------------------------------------------------------------------- +int TSnap7MicroClient::ClearSessionPassword() +{ + if (!Job.Pending) + { + Job.Pending =true; + Job.Op =s7opClearPassword; + JobStart =SysGetTick(); + return PerformOperation(); + } + else + return SetError(errCliJobPending); +} +//--------------------------------------------------------------------------- + diff --git a/APP_Framework/Framework/control/plc/interoperability/s7/s7_micro_client.h b/APP_Framework/Framework/control/plc/interoperability/s7/s7_micro_client.h new file mode 100644 index 000000000..2394a61ff --- /dev/null +++ b/APP_Framework/Framework/control/plc/interoperability/s7/s7_micro_client.h @@ -0,0 +1,364 @@ +/*=============================================================================| +| PROJECT SNAP7 1.3.0 | +|==============================================================================| +| Copyright (C) 2013, 2015 Davide Nardella | +| All rights reserved. | +|==============================================================================| +| SNAP7 is free software: you can redistribute it and/or modify | +| it under the terms of the Lesser GNU General Public License as published by | +| the Free Software Foundation, either version 3 of the License, or | +| (at your option) any later version. | +| | +| It means that you can distribute your commercial software linked with | +| SNAP7 without the requirement to distribute the source code of your | +| application and without the requirement that your application be itself | +| distributed under LGPL. | +| | +| SNAP7 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 | +| Lesser GNU General Public License for more details. | +| | +| You should have received a copy of the GNU General Public License and a | +| copy of Lesser GNU General Public License along with Snap7. | +| If not, see http://www.gnu.org/licenses/ | +|=============================================================================*/ +#ifndef s7_micro_client_h +#define s7_micro_client_h +//--------------------------------------------------------------------------- +#include "s7_peer.h" +//--------------------------------------------------------------------------- + +const longword errCliMask = 0xFFF00000; +const longword errCliBase = 0x000FFFFF; + +const longword errCliInvalidParams = 0x00200000; +const longword errCliJobPending = 0x00300000; +const longword errCliTooManyItems = 0x00400000; +const longword errCliInvalidWordLen = 0x00500000; +const longword errCliPartialDataWritten = 0x00600000; +const longword errCliSizeOverPDU = 0x00700000; +const longword errCliInvalidPlcAnswer = 0x00800000; +const longword errCliAddressOutOfRange = 0x00900000; +const longword errCliInvalidTransportSize = 0x00A00000; +const longword errCliWriteDataSizeMismatch = 0x00B00000; +const longword errCliItemNotAvailable = 0x00C00000; +const longword errCliInvalidValue = 0x00D00000; +const longword errCliCannotStartPLC = 0x00E00000; +const longword errCliAlreadyRun = 0x00F00000; +const longword errCliCannotStopPLC = 0x01000000; +const longword errCliCannotCopyRamToRom = 0x01100000; +const longword errCliCannotCompress = 0x01200000; +const longword errCliAlreadyStop = 0x01300000; +const longword errCliFunNotAvailable = 0x01400000; +const longword errCliUploadSequenceFailed = 0x01500000; +const longword errCliInvalidDataSizeRecvd = 0x01600000; +const longword errCliInvalidBlockType = 0x01700000; +const longword errCliInvalidBlockNumber = 0x01800000; +const longword errCliInvalidBlockSize = 0x01900000; +const longword errCliDownloadSequenceFailed = 0x01A00000; +const longword errCliInsertRefused = 0x01B00000; +const longword errCliDeleteRefused = 0x01C00000; +const longword errCliNeedPassword = 0x01D00000; +const longword errCliInvalidPassword = 0x01E00000; +const longword errCliNoPasswordToSetOrClear = 0x01F00000; +const longword errCliJobTimeout = 0x02000000; +const longword errCliPartialDataRead = 0x02100000; +const longword errCliBufferTooSmall = 0x02200000; +const longword errCliFunctionRefused = 0x02300000; +const longword errCliDestroying = 0x02400000; +const longword errCliInvalidParamNumber = 0x02500000; +const longword errCliCannotChangeParam = 0x02600000; + +const time_t DeltaSecs = 441763200; // Seconds between 1970/1/1 (C time base) and 1984/1/1 (Siemens base) + +#pragma pack(1) + +// Read/Write Multivars +typedef struct{ + int Area; + int WordLen; + int Result; + int DBNumber; + int Start; + int Amount; + void *pdata; +} TS7DataItem, *PS7DataItem; + +typedef int TS7ResultItems[MaxVars]; +typedef TS7ResultItems *PS7ResultItems; + +typedef struct { + int OBCount; + int FBCount; + int FCCount; + int SFBCount; + int SFCCount; + int DBCount; + int SDBCount; +} TS7BlocksList, *PS7BlocksList; + +typedef struct { + int BlkType; + int BlkNumber; + int BlkLang; + int BlkFlags; + int MC7Size; // The real size in bytes + int LoadSize; + int LocalData; + int SBBLength; + int CheckSum; + int Version; + // Chars info + char CodeDate[11]; + char IntfDate[11]; + char Author[9]; + char Family[9]; + char Header[9]; +} TS7BlockInfo, *PS7BlockInfo ; + +typedef word TS7BlocksOfType[0x2000]; +typedef TS7BlocksOfType *PS7BlocksOfType; + +typedef struct { + char Code[21]; // Order Code + byte V1; // Version V1.V2.V3 + byte V2; + byte V3; +} TS7OrderCode, *PS7OrderCode; + +typedef struct { + char ModuleTypeName[33]; + char SerialNumber[25]; + char ASName[25]; + char Copyright[27]; + char ModuleName[25]; +} TS7CpuInfo, *PS7CpuInfo; + +typedef struct { + int MaxPduLengt; + int MaxConnections; + int MaxMpiRate; + int MaxBusRate; +} TS7CpInfo, *PS7CpInfo; + +// See §33.1 of "System Software for S7-300/400 System and Standard Functions" +// and see SFC51 description too +typedef struct { + word LENTHDR; + word N_DR; +} SZL_HEADER, *PSZL_HEADER; + +typedef struct { + SZL_HEADER Header; + byte Data[0x4000-4]; +} TS7SZL, *PS7SZL; + +// SZL List of available SZL IDs : same as SZL but List items are big-endian adjusted +typedef struct { + SZL_HEADER Header; + word List[0x2000-2]; +} TS7SZLList, *PS7SZLList; + +// See §33.19 of "System Software for S7-300/400 System and Standard Functions" +typedef struct { + word sch_schal; + word sch_par; + word sch_rel; + word bart_sch; + word anl_sch; +} TS7Protection, *PS7Protection; + +#define s7opNone 0 +#define s7opReadArea 1 +#define s7opWriteArea 2 +#define s7opReadMultiVars 3 +#define s7opWriteMultiVars 4 +#define s7opDBGet 5 +#define s7opUpload 6 +#define s7opDownload 7 +#define s7opDelete 8 +#define s7opListBlocks 9 +#define s7opAgBlockInfo 10 +#define s7opListBlocksOfType 11 +#define s7opReadSzlList 12 +#define s7opReadSZL 13 +#define s7opGetDateTime 14 +#define s7opSetDateTime 15 +#define s7opGetOrderCode 16 +#define s7opGetCpuInfo 17 +#define s7opGetCpInfo 18 +#define s7opGetPlcStatus 19 +#define s7opPlcHotStart 20 +#define s7opPlcColdStart 21 +#define s7opCopyRamToRom 22 +#define s7opCompress 23 +#define s7opPlcStop 24 +#define s7opGetProtection 25 +#define s7opSetPassword 26 +#define s7opClearPassword 27 +#define s7opDBFill 28 + +// Param Number (to use with setparam) + +// Low level : change them to experiment new connections, their defaults normally work well +const int pc_iso_SendTimeout = 6; +const int pc_iso_RecvTimeout = 7; +const int pc_iso_ConnTimeout = 8; +const int pc_iso_SrcRef = 1; +const int pc_iso_DstRef = 2; +const int pc_iso_SrcTSAP = 3; +const int pc_iso_DstTSAP = 4; +const int pc_iso_IsoPduSize = 5; + +// Client Connection Type +const word CONNTYPE_PG = 0x01; // Connect to the PLC as a PG +const word CONNTYPE_OP = 0x02; // Connect to the PLC as an OP +const word CONNTYPE_BASIC = 0x03; // Basic connection + +#pragma pack() + +// Internal struct for operations +// Commands are not executed directly in the function such as "DBRead(...", +// but this struct is filled and then PerformOperation() is called. +// This allow us to implement async function very easily. + +struct TSnap7Job +{ + int Op; // Operation Code + int Result; // Operation result + bool Pending; // A Job is pending + longword Time; // Job Execution time + // Read/Write + int Area; // Also used for Block type and Block of type + int Number; // Used for DB Number, Block number + int Start; // Offset start + int WordLen; // Word length + // SZL + int ID; // SZL ID + int Index; // SZL Index + // ptr info + void * pData; // User data pointer + int Amount; // Items amount/Size in input + int *pAmount; // Items amount/Size in output + // Generic + int IParam; // Used for full upload and CopyRamToRom extended timeout +}; + +class TSnap7MicroClient: public TSnap7Peer +{ +private: + void FillTime(word SiemensTime, char *PTime); + byte BCDtoByte(byte B); + byte WordToBCD(word Value); + int opReadArea(); + int opWriteArea(); + int opReadMultiVars(); + int opWriteMultiVars(); + int opListBlocks(); + int opListBlocksOfType(); + int opAgBlockInfo(); + int opDBGet(); + int opDBFill(); + int opUpload(); + int opDownload(); + int opDelete(); + int opReadSZL(); + int opReadSZLList(); + int opGetDateTime(); + int opSetDateTime(); + int opGetOrderCode(); + int opGetCpuInfo(); + int opGetCpInfo(); + int opGetPlcStatus(); + int opPlcStop(); + int opPlcHotStart(); + int opPlcColdStart(); + int opCopyRamToRom(); + int opCompress(); + int opGetProtection(); + int opSetPassword(); + int opClearPassword(); + int CpuError(int Error); + longword DWordAt(void * P); + int CheckBlock(int BlockType, int BlockNum, void *pBlock, int Size); + int SubBlockToBlock(int SBB); +protected: + word ConnectionType; + longword JobStart; + TSnap7Job Job; + int DataSizeByte(int WordLength); + int opSize; // last operation size + int PerformOperation(); +public: + TS7Buffer opData; + TSnap7MicroClient(); + ~TSnap7MicroClient(); + int Reset(bool DoReconnect); + void SetConnectionParams(const char *RemAddress, word LocalTSAP, word RemoteTsap); + void SetConnectionType(word ConnType); + int ConnectTo(const char *RemAddress, int Rack, int Slot); + int Connect(); + int Disconnect(); + int GetParam(int ParamNumber, void *pValue); + int SetParam(int ParamNumber, void *pValue); + // Fundamental Data I/O functions + int ReadArea(int Area, int DBNumber, int Start, int Amount, int WordLen, void * pUsrData); + int WriteArea(int Area, int DBNumber, int Start, int Amount, int WordLen, void * pUsrData); + int ReadMultiVars(PS7DataItem Item, int ItemsCount); + int WriteMultiVars(PS7DataItem Item, int ItemsCount); + // Data I/O Helper functions + int DBRead(int DBNumber, int Start, int Size, void * pUsrData); + int DBWrite(int DBNumber, int Start, int Size, void * pUsrData); + int MBRead(int Start, int Size, void * pUsrData); + int MBWrite(int Start, int Size, void * pUsrData); + int EBRead(int Start, int Size, void * pUsrData); + int EBWrite(int Start, int Size, void * pUsrData); + int ABRead(int Start, int Size, void * pUsrData); + int ABWrite(int Start, int Size, void * pUsrData); + int TMRead(int Start, int Amount, void * pUsrData); + int TMWrite(int Start, int Amount, void * pUsrData); + int CTRead(int Start, int Amount, void * pUsrData); + int CTWrite(int Start, int Amount, void * pUsrData); + // Directory functions + int ListBlocks(PS7BlocksList pUsrData); + int GetAgBlockInfo(int BlockType, int BlockNum, PS7BlockInfo pUsrData); + int GetPgBlockInfo(void * pBlock, PS7BlockInfo pUsrData, int Size); + int ListBlocksOfType(int BlockType, TS7BlocksOfType *pUsrData, int & ItemsCount); + // Blocks functions + int Upload(int BlockType, int BlockNum, void * pUsrData, int & Size); + int FullUpload(int BlockType, int BlockNum, void * pUsrData, int & Size); + int Download(int BlockNum, void * pUsrData, int Size); + int Delete(int BlockType, int BlockNum); + int DBGet(int DBNumber, void * pUsrData, int & Size); + int DBFill(int DBNumber, int FillChar); + // Date/Time functions + int GetPlcDateTime(tm &DateTime); + int SetPlcDateTime(tm * DateTime); + int SetPlcSystemDateTime(); + // System Info functions + int GetOrderCode(PS7OrderCode pUsrData); + int GetCpuInfo(PS7CpuInfo pUsrData); + int GetCpInfo(PS7CpInfo pUsrData); + int ReadSZL(int ID, int Index, PS7SZL pUsrData, int &Size); + int ReadSZLList(PS7SZLList pUsrData, int &ItemsCount); + // Control functions + int PlcHotStart(); + int PlcColdStart(); + int PlcStop(); + int CopyRamToRom(int Timeout); + int Compress(int Timeout); + int GetPlcStatus(int &Status); + // Security functions + int GetProtection(PS7Protection pUsrData); + int SetSessionPassword(char *Password); + int ClearSessionPassword(); + // Properties + bool Busy(){ return Job.Pending; }; + int Time(){ return int(Job.Time);} // record the job running time +}; + +typedef TSnap7MicroClient *PSnap7MicroClient; + +//--------------------------------------------------------------------------- +#endif // s7_micro_client_h diff --git a/APP_Framework/Framework/control/plc/interoperability/s7/s7_peer.cpp b/APP_Framework/Framework/control/plc/interoperability/s7/s7_peer.cpp new file mode 100644 index 000000000..3e51f90af --- /dev/null +++ b/APP_Framework/Framework/control/plc/interoperability/s7/s7_peer.cpp @@ -0,0 +1,122 @@ +/*=============================================================================| +| PROJECT SNAP7 1.3.0 | +|==============================================================================| +| Copyright (C) 2013, 2015 Davide Nardella | +| All rights reserved. | +|==============================================================================| +| SNAP7 is free software: you can redistribute it and/or modify | +| it under the terms of the Lesser GNU General Public License as published by | +| the Free Software Foundation, either version 3 of the License, or | +| (at your option) any later version. | +| | +| It means that you can distribute your commercial software linked with | +| SNAP7 without the requirement to distribute the source code of your | +| application and without the requirement that your application be itself | +| distributed under LGPL. | +| | +| SNAP7 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 | +| Lesser GNU General Public License for more details. | +| | +| You should have received a copy of the GNU General Public License and a | +| copy of Lesser GNU General Public License along with Snap7. | +| If not, see http://www.gnu.org/licenses/ | +|=============================================================================*/ +#include "s7_peer.h" +//--------------------------------------------------------------------------- + +TSnap7Peer::TSnap7Peer() +{ + PDUH_out=PS7ReqHeader(&PDU.Payload); + PDURequest=480; // Our request, FPDULength will contain the CPU answer + LastError=0; + cntword = 0; + Destroying = false; +} +//--------------------------------------------------------------------------- +TSnap7Peer::~TSnap7Peer() +{ + Destroying = true; +} +//--------------------------------------------------------------------------- +int TSnap7Peer::SetError(int Error) +{ + if (Error==0) + ClrError(); + else + LastError=Error | LastIsoError | LastTcpError; + return Error; +} +//--------------------------------------------------------------------------- +void TSnap7Peer::ClrError() +{ + LastError=0; + LastIsoError=0; + LastTcpError=0; +} +//--------------------------------------------------------------------------- +word TSnap7Peer::GetNextWord() +{ + if (cntword==0xFFFF) + cntword=0; + return cntword++; +} +//--------------------------------------------------------------------------- +int TSnap7Peer::NegotiatePDULength( ) +{ + int Result, IsoSize = 0; + PReqFunNegotiateParams ReqNegotiate; + PResFunNegotiateParams ResNegotiate; + PS7ResHeader23 Answer; + ClrError(); + // Setup Pointers + ReqNegotiate = PReqFunNegotiateParams(pbyte(PDUH_out) + sizeof(TS7ReqHeader)); + // Header + PDUH_out->P = 0x32; // Always $32 + PDUH_out->PDUType = PduType_request; // $01 + PDUH_out->AB_EX = 0x0000; // Always $0000 + PDUH_out->Sequence = GetNextWord(); // AutoInc + PDUH_out->ParLen = SwapWord(sizeof(TReqFunNegotiateParams)); // 8 bytes + PDUH_out->DataLen = 0x0000; + // Params + ReqNegotiate->FunNegotiate = pduNegotiate; + ReqNegotiate->Unknown = 0x00; + ReqNegotiate->ParallelJobs_1 = 0x0100; + ReqNegotiate->ParallelJobs_2 = 0x0100; + ReqNegotiate->PDULength = SwapWord(PDURequest); + IsoSize = sizeof( TS7ReqHeader ) + sizeof( TReqFunNegotiateParams ); + Result = isoExchangeBuffer(NULL, IsoSize); + if ((Result == 0) && (IsoSize == int(sizeof(TS7ResHeader23) + sizeof(TResFunNegotiateParams)))) + { + // Setup pointers + Answer = PS7ResHeader23(&PDU.Payload); + ResNegotiate = PResFunNegotiateParams(pbyte(Answer) + sizeof(TS7ResHeader23)); + if ( Answer->Error != 0 ) + Result = SetError(errNegotiatingPDU); + if ( Result == 0 ) + PDULength = SwapWord(ResNegotiate->PDULength); + } + return Result; +} +//--------------------------------------------------------------------------- +void TSnap7Peer::PeerDisconnect( ) +{ + ClrError(); + isoDisconnect(true); +} +//--------------------------------------------------------------------------- +int TSnap7Peer::PeerConnect( ) +{ + int Result; + + ClrError(); + Result = isoConnect(); + if (Result == 0) + { + Result = NegotiatePDULength(); + if (Result != 0) + PeerDisconnect(); + } + return Result; +} diff --git a/APP_Framework/Framework/control/plc/interoperability/s7/s7_peer.h b/APP_Framework/Framework/control/plc/interoperability/s7/s7_peer.h new file mode 100644 index 000000000..b86f6c3a3 --- /dev/null +++ b/APP_Framework/Framework/control/plc/interoperability/s7/s7_peer.h @@ -0,0 +1,58 @@ +/*=============================================================================| +| PROJECT SNAP7 1.3.0 | +|==============================================================================| +| Copyright (C) 2013, 2015 Davide Nardella | +| All rights reserved. | +|==============================================================================| +| SNAP7 is free software: you can redistribute it and/or modify | +| it under the terms of the Lesser GNU General Public License as published by | +| the Free Software Foundation, either version 3 of the License, or | +| (at your option) any later version. | +| | +| It means that you can distribute your commercial software linked with | +| SNAP7 without the requirement to distribute the source code of your | +| application and without the requirement that your application be itself | +| distributed under LGPL. | +| | +| SNAP7 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 | +| Lesser GNU General Public License for more details. | +| | +| You should have received a copy of the GNU General Public License and a | +| copy of Lesser GNU General Public License along with Snap7. | +| If not, see http://www.gnu.org/licenses/ | +|=============================================================================*/ +#ifndef s7_peer_h +#define s7_peer_h +//--------------------------------------------------------------------------- +#include "s7_types.h" +#include "s7_isotcp.h" +//--------------------------------------------------------------------------- + +const longword errPeerMask = 0xFFF00000; +const longword errPeerBase = 0x000FFFFF; +const longword errNegotiatingPDU = 0x00100000; + +class TSnap7Peer: public TIsoTcpSocket +{ +private: + word cntword; +protected: + bool Destroying; + PS7ReqHeader PDUH_out; + word GetNextWord(); + int SetError(int Error); + int NegotiatePDULength(); + void ClrError(); +public: + int LastError; + int PDULength; + int PDURequest; + TSnap7Peer(); + ~TSnap7Peer(); + void PeerDisconnect(); + int PeerConnect(); +}; +//--------------------------------------------------------------------------- +#endif diff --git a/APP_Framework/Framework/control/plc/interoperability/s7/s7_text.cpp b/APP_Framework/Framework/control/plc/interoperability/s7/s7_text.cpp new file mode 100644 index 000000000..73f0664c5 --- /dev/null +++ b/APP_Framework/Framework/control/plc/interoperability/s7/s7_text.cpp @@ -0,0 +1,279 @@ +/*=============================================================================| +| PROJECT SNAP7 1.3.0 | +|==============================================================================| +| Copyright (C) 2013, 2015 Davide Nardella | +| All rights reserved. | +|==============================================================================| +| SNAP7 is free software: you can redistribute it and/or modify | +| it under the terms of the Lesser GNU General Public License as published by | +| the Free Software Foundation, either version 3 of the License, or | +| (at your option) any later version. | +| | +| It means that you can distribute your commercial software linked with | +| SNAP7 without the requirement to distribute the source code of your | +| application and without the requirement that your application be itself | +| distributed under LGPL. | +| | +| SNAP7 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 | +| Lesser GNU General Public License for more details. | +| | +| You should have received a copy of the GNU General Public License and a | +| copy of Lesser GNU General Public License along with Snap7. | +| If not, see http://www.gnu.org/licenses/ | +|=============================================================================*/ +#include "s7_text.h" +//--------------------------------------------------------------------------- +static char* itoa(int value, char* result, int base) { + // check that the base if valid + if (base < 2 || base > 36){ + *result = '\0'; return result; + + } + char* ptr = result, *ptr1 = result, tmp_char; + int tmp_value; + + do { + tmp_value = value; + value /= base; + *ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz" [35 + (tmp_value - value * base)]; + } while ( value ); + + // Apply negative sign + if (tmp_value < 0) *ptr++ = '-'; + *ptr-- = '\0'; + while(ptr1 < ptr) { + tmp_char = *ptr; + *ptr--= *ptr1; + *ptr1++ = tmp_char; + } + return result; +} +//--------------------------------------------------------------------------- +char* NumToString(int Value, int Base, int Len, char* Result) +{ + char CNumber[64]; + char Pad[65] = "0000000000000000000000000000000000000000000000000000000000000000"; + itoa(Value, CNumber, Base); + + if (Len > 0) + { + int Delta = Len - strlen(CNumber); // Len is max 8 in this program + if (Delta > 0) + { + strncpy(Result, Pad, Delta); + Result[Delta] = '\0'; + strcat(Result, CNumber); + } + else + strcpy(Result, CNumber); + } + else + strcpy(Result, CNumber); + + return Result; +} +//--------------------------------------------------------------------------- +char* IntToString(int Value, char* Result) +{ + return NumToString(Value, 10, 0, Result); +} +//--------------------------------------------------------------------------- +char* TimeToString(time_t dt, char* Result) +{ + struct tm * DateTime = localtime(&dt); + if (DateTime != NULL) + strftime(Result, 50, "%Y-%m-%d %H:%M:%S", DateTime); + else + *Result = '\0'; + return Result; +} + +//--------------------------------------------------------------------------- +char* IpAddressToString(int IP, char* Result) +{ + in_addr Addr; + Addr.s_addr = IP; + strcpy(Result, inet_ntoa(Addr)); + return Result; +} +//--------------------------------------------------------------------------- +#define WSAEINVALIDADDRESS 12001 + +char* TcpTextOf(int Error, char* Result) +{ + switch (Error) + { + case 0: *Result='\0';break; + case WSAEINTR: strcpy(Result," TCP : Interrupted system call\0");break; + case WSAEBADF: strcpy(Result," TCP : Bad file number\0");break; + case WSAEACCES: strcpy(Result," TCP : Permission denied\0");break; + case WSAEFAULT: strcpy(Result," TCP : Bad address\0");break; + case WSAEINVAL: strcpy(Result," TCP : Invalid argument\0");break; + case WSAEMFILE: strcpy(Result," TCP : Too many open files\0");break; + case WSAEWOULDBLOCK: strcpy(Result," TCP : Operation would block\0");break; + case WSAEINPROGRESS: strcpy(Result," TCP : Operation now in progress\0");break; + case WSAEALREADY: strcpy(Result," TCP : Operation already in progress\0");break; + case WSAENOTSOCK: strcpy(Result," TCP : Socket operation on non socket\0");break; + case WSAEDESTADDRREQ: strcpy(Result," TCP : Destination address required\0");break; + case WSAEMSGSIZE: strcpy(Result," TCP : Message too long\0");break; + case WSAEPROTOTYPE: strcpy(Result," TCP : Protocol wrong type for Socket\0");break; + case WSAENOPROTOOPT: strcpy(Result," TCP : Protocol not available\0");break; + case WSAEPROTONOSUPPORT: strcpy(Result," TCP : Protocol not supported\0");break; + case WSAESOCKTNOSUPPORT: strcpy(Result," TCP : Socket not supported\0");break; + case WSAEOPNOTSUPP: strcpy(Result," TCP : Operation not supported on Socket\0");break; + case WSAEPFNOSUPPORT: strcpy(Result," TCP : Protocol family not supported\0");break; + case WSAEAFNOSUPPORT: strcpy(Result," TCP : Address family not supported\0");break; + case WSAEADDRINUSE: strcpy(Result," TCP : Address already in use\0");break; + case WSAEADDRNOTAVAIL: strcpy(Result," TCP : Can't assign requested address\0");break; + case WSAENETDOWN: strcpy(Result," TCP : Network is down\0");break; + case WSAENETUNREACH: strcpy(Result," TCP : Network is unreachable\0");break; + case WSAENETRESET: strcpy(Result," TCP : Network dropped connection on reset\0");break; + case WSAECONNABORTED: strcpy(Result," TCP : Software caused connection abort\0");break; + case WSAECONNRESET: strcpy(Result," TCP : Connection reset by peer\0");break; + case WSAENOBUFS: strcpy(Result," TCP : No Buffer space available\0");break; + case WSAEISCONN: strcpy(Result," TCP : Socket is already connected\0");break; + case WSAENOTCONN: strcpy(Result," TCP : Socket is not connected\0");break; + case WSAESHUTDOWN: strcpy(Result," TCP : Can't send after Socket shutdown\0");break; + case WSAETOOMANYREFS: strcpy(Result," TCP : Too many references:can't splice\0");break; + case WSAETIMEDOUT: strcpy(Result," TCP : Connection timed out\0");break; + case WSAECONNREFUSED: strcpy(Result," TCP : Connection refused\0");break; + case WSAELOOP: strcpy(Result," TCP : Too many levels of symbolic links\0");break; + case WSAENAMETOOLONG: strcpy(Result," TCP : File name is too long\0");break; + case WSAEHOSTDOWN: strcpy(Result," TCP : Host is down\0");break; + case WSAEHOSTUNREACH: strcpy(Result," TCP : Unreachable peer\0");break; + case WSAENOTEMPTY: strcpy(Result," TCP : Directory is not empty\0");break; + case WSAEUSERS: strcpy(Result," TCP : Too many users\0");break; + case WSAEDQUOT: strcpy(Result," TCP : Disk quota exceeded\0");break; + case WSAESTALE: strcpy(Result," TCP : Stale NFS file handle\0");break; + case WSAEREMOTE: strcpy(Result," TCP : Too many levels of remote in path\0");break; + case WSAEINVALIDADDRESS: strcpy(Result," TCP : Invalid address\0");break; + default: + { + char CNumber[16]; + strcpy(Result, " TCP : Other Socket error ("); + strcat(Result, IntToString(Error, CNumber)); + strcat(Result, ")"); + break; + } + } + return Result; +} +//--------------------------------------------------------------------------- +char* IsoTextOf(int Error, char* Result) +{ + switch (Error) + { + case 0 : *Result='\0';break; + case errIsoConnect: strcpy(Result," ISO : Connection error\0");break; + case errIsoDisconnect: strcpy(Result," ISO : Disconnect error\0");break; + case errIsoInvalidPDU: strcpy(Result," ISO : Bad PDU format\0");break; + case errIsoInvalidDataSize: strcpy(Result," ISO : Datasize passed to send/recv buffer is invalid\0");break; + case errIsoNullPointer: strcpy(Result," ISO : Null passed as pointer\0");break; + case errIsoShortPacket: strcpy(Result," ISO : A short packet received\0");break; + case errIsoTooManyFragments: strcpy(Result," ISO : Too many packets without EoT flag\0");break; + case errIsoPduOverflow: strcpy(Result," ISO : The sum of fragments data exceded maximum packet size\0");break; + case errIsoSendPacket: strcpy(Result," ISO : An error occurred during send\0");break; + case errIsoRecvPacket: strcpy(Result," ISO : An error occurred during recv\0");break; + case errIsoInvalidParams: strcpy(Result," ISO : Invalid connection params (wrong TSAPs)\0");break; + default: + { + char CNumber[16]; + strcpy(Result, " ISO : Unknown error (0x"); + strcat(Result, NumToString(Error, 16, 8, CNumber)); + strcat(Result, ")"); + break; + } + } + return Result; +} +//--------------------------------------------------------------------------- +char* CliTextOf(int Error, char* Result) +{ + switch (Error) + { + case 0 : *Result='\0';break; + case errNegotiatingPDU : strcpy(Result,"CPU : Error in PDU negotiation\0");break; + case errCliInvalidParams : strcpy(Result,"CLI : invalid param(s) supplied\0");break; + case errCliJobPending : strcpy(Result,"CLI : Job pending\0");break; + case errCliTooManyItems : strcpy(Result,"CLI : too may items (>20) in multi read/write\0");break; + case errCliInvalidWordLen : strcpy(Result,"CLI : invalid WordLength\0");break; + case errCliPartialDataWritten : strcpy(Result,"CLI : Partial data written\0");break; + case errCliSizeOverPDU : strcpy(Result,"CPU : total data exceeds the PDU size\0");break; + case errCliInvalidPlcAnswer : strcpy(Result,"CLI : invalid CPU answer\0");break; + case errCliAddressOutOfRange : strcpy(Result,"CPU : Address out of range\0");break; + case errCliInvalidTransportSize : strcpy(Result,"CPU : Invalid Transport size\0");break; + case errCliWriteDataSizeMismatch : strcpy(Result,"CPU : Data size mismatch\0");break; + case errCliItemNotAvailable : strcpy(Result,"CPU : Item not available\0");break; + case errCliInvalidValue : strcpy(Result,"CPU : Invalid value supplied\0");break; + case errCliCannotStartPLC : strcpy(Result,"CPU : Cannot start PLC\0");break; + case errCliAlreadyRun : strcpy(Result,"CPU : PLC already RUN\0");break; + case errCliCannotStopPLC : strcpy(Result,"CPU : Cannot stop PLC\0");break; + case errCliCannotCopyRamToRom : strcpy(Result,"CPU : Cannot copy RAM to ROM\0");break; + case errCliCannotCompress : strcpy(Result,"CPU : Cannot compress\0");break; + case errCliAlreadyStop : strcpy(Result,"CPU : PLC already STOP\0");break; + case errCliFunNotAvailable : strcpy(Result,"CPU : Function not available\0");break; + case errCliUploadSequenceFailed : strcpy(Result,"CPU : Upload sequence failed\0");break; + case errCliInvalidDataSizeRecvd : strcpy(Result,"CLI : Invalid data size received\0");break; + case errCliInvalidBlockType : strcpy(Result,"CLI : Invalid block type\0");break; + case errCliInvalidBlockNumber : strcpy(Result,"CLI : Invalid block number\0");break; + case errCliInvalidBlockSize : strcpy(Result,"CLI : Invalid block size\0");break; + case errCliDownloadSequenceFailed : strcpy(Result,"CPU : Download sequence failed\0");break; + case errCliInsertRefused : strcpy(Result,"CPU : block insert refused\0");break; + case errCliDeleteRefused : strcpy(Result,"CPU : block delete refused\0");break; + case errCliNeedPassword : strcpy(Result,"CPU : Function not authorized for current protection level\0");break; + case errCliInvalidPassword : strcpy(Result,"CPU : Invalid password\0");break; + case errCliNoPasswordToSetOrClear : strcpy(Result,"CPU : No password to set or clear\0");break; + case errCliJobTimeout : strcpy(Result,"CLI : Job Timeout\0");break; + case errCliFunctionRefused : strcpy(Result,"CLI : function refused by CPU (Unknown error)\0");break; + case errCliPartialDataRead : strcpy(Result,"CLI : Partial data read\0");break; + case errCliBufferTooSmall : strcpy(Result,"CLI : The buffer supplied is too small to accomplish the operation\0");break; + case errCliDestroying : strcpy(Result,"CLI : Cannot perform (destroying)\0");break; + case errCliInvalidParamNumber : strcpy(Result,"CLI : Invalid Param Number\0");break; + case errCliCannotChangeParam : strcpy(Result,"CLI : Cannot change this param now\0");break; + default : + { + char CNumber[16]; + strcpy(Result, "CLI : Unknown error (0x"); + strcat(Result, NumToString(Error, 16, 8, CNumber)); + strcat(Result, ")"); + break; + } + }; + return Result; +} +//--------------------------------------------------------------------------- +char* ErrCliText(int Error, char * Result, int TextLen) +{ + char TcpError[128]; + char IsoError[128]; + char CliError[256]; + if (Error != 0) + { + switch (Error) + { + case errLibInvalidParam : strncpy(Result,"LIB : Invalid param supplied\0",TextLen);break; + case errLibInvalidObject: strncpy(Result, "LIB : Invalid object supplied\0", TextLen); break; + default : + { + CliTextOf(Error & ErrS7Mask, CliError); + strcat(CliError, IsoTextOf(Error & ErrIsoMask, IsoError)); + strcat(CliError, TcpTextOf(Error & ErrTcpMask, TcpError)); + strncpy(Result, CliError, TextLen); + } + } + } + else + strncpy(Result, "OK\0", TextLen); + return Result; +} +//--------------------------------------------------------------------------- +char* ClockText(word Code, char* Result) +{ + if (Code==evsGetClock) + strcpy(Result,"System clock read requested"); + else + strcpy(Result, "System clock write requested"); + return Result; +} diff --git a/APP_Framework/Framework/control/plc/interoperability/s7/s7_text.h b/APP_Framework/Framework/control/plc/interoperability/s7/s7_text.h new file mode 100644 index 000000000..98b5c3870 --- /dev/null +++ b/APP_Framework/Framework/control/plc/interoperability/s7/s7_text.h @@ -0,0 +1,44 @@ +/*=============================================================================| +| PROJECT SNAP7 1.3.0 | +|==============================================================================| +| Copyright (C) 2013, 2015 Davide Nardella | +| All rights reserved. | +|==============================================================================| +| SNAP7 is free software: you can redistribute it and/or modify | +| it under the terms of the Lesser GNU General Public License as published by | +| the Free Software Foundation, either version 3 of the License, or | +| (at your option) any later version. | +| | +| It means that you can distribute your commercial software linked with | +| SNAP7 without the requirement to distribute the source code of your | +| application and without the requirement that your application be itself | +| distributed under LGPL. | +| | +| SNAP7 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 | +| Lesser GNU General Public License for more details. | +| | +| You should have received a copy of the GNU General Public License and a | +| copy of Lesser GNU General Public License along with Snap7. | +| If not, see http://www.gnu.org/licenses/ | +|=============================================================================*/ +#ifndef s7_text_h +#define s7_text_h +//--------------------------------------------------------------------------- +#include "s7_micro_client.h" +//--------------------------------------------------------------------------- + +const int errLibInvalidParam = -1; +const int errLibInvalidObject = -2; +// Errors areas definition +const longword ErrTcpMask = 0x0000FFFF; +const longword ErrIsoMask = 0x000F0000; +const longword ErrS7Mask = 0xFFF00000; + +char* ErrCliText(int Error, char* Result, int TextLen); + + +#endif + + diff --git a/APP_Framework/Framework/control/plc/interoperability/s7/s7_types.h b/APP_Framework/Framework/control/plc/interoperability/s7/s7_types.h new file mode 100644 index 000000000..6dd8e4ebe --- /dev/null +++ b/APP_Framework/Framework/control/plc/interoperability/s7/s7_types.h @@ -0,0 +1,1062 @@ +/*=============================================================================| +| PROJECT SNAP7 1.3.0 | +|==============================================================================| +| Copyright (C) 2013, 2015 Davide Nardella | +| All rights reserved. | +|==============================================================================| +| SNAP7 is free software: you can redistribute it and/or modify | +| it under the terms of the Lesser GNU General Public License as published by | +| the Free Software Foundation, either version 3 of the License, or | +| (at your option) any later version. | +| | +| It means that you can distribute your commercial software linked with | +| SNAP7 without the requirement to distribute the source code of your | +| application and without the requirement that your application be itself | +| distributed under LGPL. | +| | +| SNAP7 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 | +| Lesser GNU General Public License for more details. | +| | +| You should have received a copy of the GNU General Public License and a | +| copy of Lesser GNU General Public License along with Snap7. | +| If not, see http://www.gnu.org/licenses/ | +|=============================================================================*/ +#ifndef s7_types_h +#define s7_types_h +//------------------------------------------------------------------------------ +#include "s7_isotcp.h" +//------------------------------------------------------------------------------ +// EXPORT CONSTANTS +// Everything added in this section has to be copied into wrappers interface +//------------------------------------------------------------------------------ + +#define SM7API + + // Area ID +const byte S7AreaPE = 0x81; +const byte S7AreaPA = 0x82; +const byte S7AreaMK = 0x83; +const byte S7AreaDB = 0x84; +const byte S7AreaCT = 0x1C; +const byte S7AreaTM = 0x1D; + +const int MaxVars = 20; + +const int S7WLBit = 0x01; +const int S7WLByte = 0x02; +const int S7WLChar = 0x03; +const int S7WLWord = 0x04; +const int S7WLInt = 0x05; +const int S7WLDWord = 0x06; +const int S7WLDInt = 0x07; +const int S7WLReal = 0x08; +const int S7WLCounter = 0x1C; +const int S7WLTimer = 0x1D; + + // Block type +const byte Block_OB = 0x38; +const byte Block_DB = 0x41; +const byte Block_SDB = 0x42; +const byte Block_FC = 0x43; +const byte Block_SFC = 0x44; +const byte Block_FB = 0x45; +const byte Block_SFB = 0x46; + + // Sub Block Type +const byte SubBlk_OB = 0x08; +const byte SubBlk_DB = 0x0A; +const byte SubBlk_SDB = 0x0B; +const byte SubBlk_FC = 0x0C; +const byte SubBlk_SFC = 0x0D; +const byte SubBlk_FB = 0x0E; +const byte SubBlk_SFB = 0x0F; + + // Block languages +const byte BlockLangAWL = 0x01; +const byte BlockLangKOP = 0x02; +const byte BlockLangFUP = 0x03; +const byte BlockLangSCL = 0x04; +const byte BlockLangDB = 0x05; +const byte BlockLangGRAPH = 0x06; + + // CPU status +const byte S7CpuStatusUnknown = 0x00; +const byte S7CpuStatusRun = 0x08; +const byte S7CpuStatusStop = 0x04; + +const longword evcSnap7Base = 0x00008000; +// S7 Server Event Code +const longword evcPDUincoming = 0x00010000; +const longword evcDataRead = 0x00020000; +const longword evcDataWrite = 0x00040000; +const longword evcNegotiatePDU = 0x00080000; +const longword evcReadSZL = 0x00100000; +const longword evcClock = 0x00200000; +const longword evcUpload = 0x00400000; +const longword evcDownload = 0x00800000; +const longword evcDirectory = 0x01000000; +const longword evcSecurity = 0x02000000; +const longword evcControl = 0x04000000; +const longword evcReserved_08000000 = 0x08000000; +const longword evcReserved_10000000 = 0x10000000; +const longword evcReserved_20000000 = 0x20000000; +const longword evcReserved_40000000 = 0x40000000; +const longword evcReserved_80000000 = 0x80000000; +// Event SubCodes +const word evsUnknown = 0x0000; +const word evsStartUpload = 0x0001; +const word evsStartDownload = 0x0001; +const word evsGetBlockList = 0x0001; +const word evsStartListBoT = 0x0002; +const word evsListBoT = 0x0003; +const word evsGetBlockInfo = 0x0004; +const word evsGetClock = 0x0001; +const word evsSetClock = 0x0002; +const word evsSetPassword = 0x0001; +const word evsClrPassword = 0x0002; +// Event Result +const word evrNoError = 0; +const word evrFragmentRejected = 0x0001; +const word evrMalformedPDU = 0x0002; +const word evrSparseBytes = 0x0003; +const word evrCannotHandlePDU = 0x0004; +const word evrNotImplemented = 0x0005; +const word evrErrException = 0x0006; +const word evrErrAreaNotFound = 0x0007; +const word evrErrOutOfRange = 0x0008; +const word evrErrOverPDU = 0x0009; +const word evrErrTransportSize = 0x000A; +const word evrInvalidGroupUData = 0x000B; +const word evrInvalidSZL = 0x000C; +const word evrDataSizeMismatch = 0x000D; +const word evrCannotUpload = 0x000E; +const word evrCannotDownload = 0x000F; +const word evrUploadInvalidID = 0x0010; +const word evrResNotFound = 0x0011; + + // Async mode +const int amPolling = 0; +const int amEvent = 1; +const int amCallBack = 2; + +//------------------------------------------------------------------------------ +// PARAMS LIST +// Notes for Local/Remote Port +// If the local port for a server and remote port for a client is != 102 they +// will be *no more compatible with S7 IsoTCP* +// A good reason to change them could be inside a debug session under Unix. +// Increasing the port over 1024 avoids the need of be root. +// Obviously you need to work with the couple Snap7Client/Snap7Server and change +// both, or, use iptable and nat the port. +//------------------------------------------------------------------------------ +const int p_u16_LocalPort = 1; +const int p_u16_RemotePort = 2; +const int p_i32_PingTimeout = 3; +const int p_i32_SendTimeout = 4; +const int p_i32_RecvTimeout = 5; +const int p_i32_WorkInterval = 6; +const int p_u16_SrcRef = 7; +const int p_u16_DstRef = 8; +const int p_u16_SrcTSap = 9; +const int p_i32_PDURequest = 10; +const int p_i32_MaxClients = 11; +const int p_i32_BSendTimeout = 12; +const int p_i32_BRecvTimeout = 13; +const int p_u32_RecoveryTime = 14; +const int p_u32_KeepAliveTime = 15; + +// Bool param is passed as int32_t : 0->false, 1->true +// String param (only set) is passed as pointer + +typedef int16_t *Pint16_t; +typedef uint16_t *Puint16_t; +typedef int32_t *Pint32_t; +typedef uint32_t *Puint32_t; +typedef int64_t *Pint64_t; +typedef uint64_t *Puint64_t; +typedef uintptr_t *Puintptr_t; +//----------------------------------------------------------------------------- +// INTERNALS CONSTANTS +//------------------------------------------------------------------------------ + +const word DBMaxName = 0xFFFF; // max number (name) of DB + +const longword errS7Mask = 0xFFF00000; +const longword errS7Base = 0x000FFFFF; +const longword errS7notConnected = errS7Base+0x0001; // Client not connected +const longword errS7InvalidMode = errS7Base+0x0002; // Requested a connection to... +const longword errS7InvalidPDUin = errS7Base+0x0003; // Malformed input PDU + +// S7 outcoming Error code +const word Code7Ok = 0x0000; +const word Code7AddressOutOfRange = 0x0005; +const word Code7InvalidTransportSize = 0x0006; +const word Code7WriteDataSizeMismatch = 0x0007; +const word Code7ResItemNotAvailable = 0x000A; +const word Code7ResItemNotAvailable1 = 0xD209; +const word Code7InvalidValue = 0xDC01; +const word Code7NeedPassword = 0xD241; +const word Code7InvalidPassword = 0xD602; +const word Code7NoPasswordToClear = 0xD604; +const word Code7NoPasswordToSet = 0xD605; +const word Code7FunNotAvailable = 0x8104; +const word Code7DataOverPDU = 0x8500; + +// Result transport size +const byte TS_ResBit = 0x03; +const byte TS_ResByte = 0x04; +const byte TS_ResInt = 0x05; +const byte TS_ResReal = 0x07; +const byte TS_ResOctet = 0x09; + +// Client Job status (lib internals, not S7) +const int JobComplete = 0; +const int JobPending = 1; + +// Control codes +const word CodeControlUnknown = 0; +const word CodeControlColdStart = 1; // Cold start +const word CodeControlWarmStart = 2; // Warm start +const word CodeControlStop = 3; // Stop +const word CodeControlCompress = 4; // Compress +const word CodeControlCpyRamRom = 5; // Copy Ram to Rom +const word CodeControlInsDel = 6; // Insert in working ram the block downloaded + // Delete from working ram the block selected +// PDU Type +const byte PduType_request = 1; // family request +const byte PduType_response = 3; // family response +const byte PduType_userdata = 7; // family user data + +// PDU Functions +const byte pduResponse = 0x02; // Response (when error) +const byte pduFuncRead = 0x04; // Read area +const byte pduFuncWrite = 0x05; // Write area +const byte pduNegotiate = 0xF0; // Negotiate PDU length +const byte pduStart = 0x28; // CPU start +const byte pduStop = 0x29; // CPU stop +const byte pduStartUpload = 0x1D; // Start Upload +const byte pduUpload = 0x1E; // Upload +const byte pduEndUpload = 0x1F; // EndUpload +const byte pduReqDownload = 0x1A; // Start Download request +const byte pduDownload = 0x1B; // Download request +const byte pduDownloadEnded = 0x1C; // Download end request +const byte pduControl = 0x28; // Control (insert/delete..) + +// PDU SubFunctions +const byte SFun_ListAll = 0x01; // List all blocks +const byte SFun_ListBoT = 0x02; // List Blocks of type +const byte SFun_BlkInfo = 0x03; // Get Block info +const byte SFun_ReadSZL = 0x01; // Read SZL +const byte SFun_ReadClock = 0x01; // Read Clock (Date and Time) +const byte SFun_SetClock = 0x02; // Set Clock (Date and Time) +const byte SFun_EnterPwd = 0x01; // Enter password for this session +const byte SFun_CancelPwd = 0x02; // Cancel password for this session +const byte SFun_Insert = 0x50; // Insert block +const byte SFun_Delete = 0x42; // Delete block + +typedef tm *PTimeStruct; + +//============================================================================== +// HEADERS +//============================================================================== +#pragma pack(1) + +// Tag Struct +typedef struct{ + int Area; + int DBNumber; + int Start; + int Size; + int WordLen; +}TS7Tag, *PS7Tag; + +// Incoming header, it will be mapped onto IsoPDU payload +typedef struct { + byte P; // Telegram ID, always 32 + byte PDUType; // Header type 1 or 7 + word AB_EX; // AB currently unknown, maybe it can be used for long numbers. + word Sequence; // Message ID. This can be used to make sure a received answer + word ParLen; // Length of parameters which follow this header + word DataLen; // Length of data which follow the parameters +}TS7ReqHeader; + +typedef TS7ReqHeader* PS7ReqHeader; + +// Outcoming 12 bytes header , response for Request type 1 +typedef struct{ + byte P; // Telegram ID, always 32 + byte PDUType; // Header type 2 or 3 + word AB_EX; // AB currently unknown, maybe it can be used for long numbers. + word Sequence; // Message ID. This can be used to make sure a received answer + word ParLen; // Length of parameters which follow this header + word DataLen; // Length of data which follow the parameters + word Error; // Error code +} TS7ResHeader23; + +typedef TS7ResHeader23* PS7ResHeader23; + +// Outcoming 10 bytes header , response for Request type 7 +typedef struct{ + byte P; // Telegram ID, always 32 + byte PDUType; // Header type 1 or 7 + word AB_EX; // AB currently unknown, maybe it can be used for long numbers. + word Sequence; // Message ID. This can be used to make sure a received answer + word ParLen; // Length of parameters which follow this header + word DataLen; // Length of data which follow the parameters +}TS7ResHeader17; + +typedef TS7ResHeader17* PS7ResHeader17; + +// Outcoming 10 bytes header , response for Request type 8 (server control) +typedef struct { + byte P; // Telegram ID, always 32 + byte PDUType; // Header type 8 + word AB_EX; // Zero + word Sequence; // Message ID. This can be used to make sure a received answer + word DataLen; // Length of data which follow this header + word Error; // Error code +} TS7ResHeader8; + +typedef TS7ResHeader8* PS7ResHeader8; + +// Outcoming answer buffer header type 2 or header type 3 +typedef struct{ + TS7ResHeader23 Header; + byte ResData [IsoPayload_Size - sizeof(TS7ResHeader23)]; +} TS7Answer23; + +typedef TS7Answer23* PS7Answer23; + +// Outcoming buffer header type 1 or header type 7 +typedef struct { + TS7ResHeader17 Header; + byte ResData [IsoPayload_Size - sizeof(TS7ResHeader17)]; +} TS7Answer17; + +typedef TS7Answer17* PS7Answer17; + +typedef byte TTimeBuffer[8]; +typedef byte *PTimeBuffer[8]; + +typedef struct{ + byte bcd_year; + byte bcd_mon; + byte bcd_day; + byte bcd_hour; + byte bcd_min; + byte bcd_sec; + byte bcd_himsec; + byte bcd_dow; +}TS7Time, *PS7Time; + +typedef byte TS7Buffer[65536]; +typedef byte *PS7Buffer; + +const int ReqHeaderSize = sizeof(TS7ReqHeader); +const int ResHeaderSize23 = sizeof(TS7ResHeader23); +const int ResHeaderSize17 = sizeof(TS7ResHeader17); + +// Most used request type parameters record +typedef struct { + byte Head[3];// 0x00 0x01 0x12 + byte Plen; // par len 0x04 + byte Uk; // unknown + byte Tg; // type and group (4 bits type and 4 bits group) + byte SubFun; // subfunction + byte Seq; // sequence +}TReqFunTypedParams; + +//============================================================================== +// FUNCTION NEGOTIATE +//============================================================================== +typedef struct { + byte FunNegotiate; + byte Unknown; + word ParallelJobs_1; + word ParallelJobs_2; + word PDULength; +}TReqFunNegotiateParams; + +typedef TReqFunNegotiateParams* PReqFunNegotiateParams; + +typedef struct { + byte FunNegotiate; + byte Unknown; + word ParallelJobs_1; + word ParallelJobs_2; + word PDULength; +}TResFunNegotiateParams; + +typedef TResFunNegotiateParams* PResFunNegotiateParams; + +//============================================================================== +// FUNCTION READ +//============================================================================== +typedef struct { + byte ItemHead[3]; + byte TransportSize; + word Length; + word DBNumber; + byte Area; + byte Address[3]; +}TReqFunReadItem, * PReqFunReadItem; + +//typedef TReqFunReadItem; + +typedef struct { + byte FunRead; + byte ItemsCount; + TReqFunReadItem Items[MaxVars]; +}TReqFunReadParams; + +typedef TReqFunReadParams* PReqFunReadParams; + +typedef struct { + byte FunRead; + byte ItemCount; +}TResFunReadParams; + +typedef TResFunReadParams* PResFunReadParams; + +typedef struct { + byte ReturnCode; + byte TransportSize; + word DataLength; + byte Data[IsoPayload_Size - 17]; // 17 = header + params + data header - 1 +}TResFunReadItem, *PResFunReadItem; + +typedef PResFunReadItem TResFunReadData[MaxVars]; + +//============================================================================== +// FUNCTION WRITE +//============================================================================== +typedef struct { + byte ItemHead[3]; + byte TransportSize; + word Length; + word DBNumber; + byte Area; + byte Address[3]; +}TReqFunWriteItem, * PReqFunWriteItem; + +typedef struct { + byte FunWrite; + byte ItemsCount; + TReqFunWriteItem Items[MaxVars]; +}TReqFunWriteParams; + +typedef TReqFunWriteParams* PReqFunWriteParams; + +typedef struct { + byte ReturnCode; + byte TransportSize; + word DataLength; + byte Data [IsoPayload_Size - 17]; // 17 = header + params + data header -1 +}TReqFunWriteDataItem, *PReqFunWriteDataItem; + +typedef PReqFunWriteDataItem TReqFunWriteData[MaxVars]; + +typedef struct { + byte FunWrite; + byte ItemCount; + byte Data[MaxVars]; +}TResFunWrite; + +typedef TResFunWrite* PResFunWrite; + +//============================================================================== +// GROUP UPLOAD +//============================================================================== +typedef struct { + byte FunSUpld; // function start upload 0x1D + byte Uk6 [6]; // Unknown 6 bytes + byte Upload_ID; + byte Len_1; + byte Prefix; + byte BlkPrfx; // always 0x30 + byte BlkType; + byte AsciiBlk[5]; // BlockNum in ascii + byte A; // always 0x41 ('A') +}TReqFunStartUploadParams; + +typedef TReqFunStartUploadParams* PReqFunStartUploadParams; + +typedef struct { + byte FunSUpld; // function start upload 0x1D + byte Data_1[6]; + byte Upload_ID; + byte Uk[3]; + byte LenLoad[5]; +}TResFunStartUploadParams; + +typedef TResFunStartUploadParams* PResFunStartUploadParams; + +typedef struct { + byte FunUpld; // function upload 0x1E + byte Uk6[6]; // Unknown 6 bytes + byte Upload_ID; +}TReqFunUploadParams; + +typedef TReqFunUploadParams* PReqFunUploadParams; + +typedef struct { + byte FunUpld; // function upload 0x1E + byte EoU; // 0 = End Of Upload, 1 = Upload in progress +}TResFunUploadParams; + +typedef TResFunUploadParams* PResFunUploadParams; + +typedef struct { + word Length; // Payload length - 4 + byte Uk_00; // Unknown 0x00 + byte Uk_FB; // Unknown 0xFB + // from here is the same of TS7CompactBlockInfo + word Cst_pp; + byte Uk_01; // Unknown 0x01 + byte BlkFlags; + byte BlkLang; + byte SubBlkType; + word BlkNum; + u_int LenLoadMem; + u_int BlkSec; + u_int CodeTime_ms; + word CodeTime_dy; + u_int IntfTime_ms; + word IntfTime_dy; + word SbbLen; + word AddLen; + word LocDataLen; + word MC7Len; +}TResFunUploadDataHeaderFirst; + +typedef TResFunUploadDataHeaderFirst* PResFunUploadDataHeaderFirst; + +typedef struct { + word Length;// Payload length - 4 + byte Uk_00; // Unknown 0x00 + byte Uk_FB; // Unknown 0xFB +}TResFunUploadDataHeaderNext; + +typedef TResFunUploadDataHeaderNext* PResFunUploadDataHeaderNext; + +typedef struct { + word Length;// Payload length - 4 + byte Uk_00; // Unknown 0x00 + byte Uk_FB; // Unknown 0xFB +}TResFunUploadDataHeader; + +typedef TResFunUploadDataHeader* PResFunUploadDataHeader; + +typedef struct { + byte ID; // 0x65 + word Seq; // Sequence + byte Const_1[10]; + word Lo_bound; + word Hi_Bound; + byte u_shortLen;// 0x02 byte + // 0x04 word + // 0x05 int + // 0x06 dword + // 0x07 dint + // 0x08 real + byte c1, c2; + char Author[8]; + char Family[8]; + char Header[8]; + byte B1; // 0x11 + byte B2; // 0x00 + word Chksum; + byte Uk_8[8]; +}TArrayUpldFooter; + +typedef TArrayUpldFooter* PArrayUpldFooter; + +typedef struct { + byte FunEUpld; // function end upload 0x1F + byte Uk6[6]; // Unknown 6 bytes + byte Upload_ID; +}TReqFunEndUploadParams; + +typedef TReqFunEndUploadParams* PReqFunEndUploadParams; + +typedef struct { + byte FunEUpld; // function end upload 0x1F +}TResFunEndUploadParams; + +typedef TResFunEndUploadParams* PResFunEndUploadParams; + +//============================================================================== +// GROUP DOWNLOAD +//============================================================================== +typedef struct { + byte FunSDwnld; // function start Download 0x1A + byte Uk6[6]; // Unknown 6 bytes + byte Dwnld_ID; + byte Len_1; // 0x09 + byte Prefix; // 0x5F + byte BlkPrfx; // always 0x30 + byte BlkType; + byte AsciiBlk[5]; // BlockNum in ascii + byte P; // 0x50 ('P') + byte Len_2; // 0x0D + byte Uk1; // 0x01 + byte AsciiLoad[6];// load memory size (MC7 size + 92) + byte AsciiMC7[6]; // Block size in bytes +}TReqStartDownloadParams; + +typedef TReqStartDownloadParams* PReqStartDownloadParams; +typedef byte TResStartDownloadParams; +typedef TResStartDownloadParams* PResStartDownloadParams; + +typedef struct { + byte Fun; // pduDownload or pduDownloadEnded + byte Uk7[7]; + byte Len_1; // 0x09 + byte Prefix; // 0x5F + byte BlkPrfx; // always 0x30 + byte BlkType; + byte AsciiBlk[5]; // BlockNum in ascii + byte P; // 0x50 ('P') +}TReqDownloadParams; + +typedef TReqDownloadParams* PReqDownloadParams; + +typedef struct { + byte FunDwnld; // 0x1B + byte EoS; // End of sequence : 0x00 - Sequence in progress : 0x01 +}TResDownloadParams; + +typedef TResDownloadParams* PResDownloadParams; + +typedef struct { + word DataLen; + word FB_00; // 0x00 0xFB +}TResDownloadDataHeader; + +typedef TResDownloadDataHeader* PResDownloadDataHeader; +typedef byte TResEndDownloadParams; +typedef TResEndDownloadParams* PResEndDownloadParams; + +typedef struct { + word Cst_pp; + byte Uk_01; // Unknown 0x01 + byte BlkFlags; + byte BlkLang; + byte SubBlkType; + word BlkNum; + u_int LenLoadMem; + u_int BlkSec; + u_int CodeTime_ms; + word CodeTime_dy; + u_int IntfTime_ms; + word IntfTime_dy; + word SbbLen; + word AddLen; + word LocDataLen; + word MC7Len; +}TS7CompactBlockInfo; + +typedef TS7CompactBlockInfo* PS7CompactBlockInfo; + +typedef struct { + byte Uk_20[20]; + byte Author[8]; + byte Family[8]; + byte Header[8]; + byte B1; // 0x11 + byte B2; // 0x00 + word Chksum; + byte Uk_12[8]; +}TS7BlockFooter; + +typedef TS7BlockFooter* PS7BlockFooter; + +//============================================================================== +// FUNCTION INSERT/DELETE +//============================================================================== +typedef struct { + byte Fun; // plc control 0x28 + byte Uk7[7]; // unknown 7 + word Len_1; // Length part 1 : 10 + byte NumOfBlocks; // number of blocks to insert + byte ByteZero; // 0x00 + byte AsciiZero; // 0x30 '0' + byte BlkType; + byte AsciiBlk[5]; // BlockNum in ascii + byte SFun; // 0x50 or 0x42 + byte Len_2; // Length part 2 : 0x05 bytes + char Cmd[5]; // ascii '_INSE' or '_DELE' +}TReqControlBlockParams; + +typedef TReqControlBlockParams* PReqControlBlockParams; + +//============================================================================== +// FUNCTIONS START/STOP/COPY RAM TO ROM/COMPRESS +//============================================================================== +typedef struct { + byte Fun; // stop 0x29 + byte Uk_5[5]; // unknown 5 bytes 0x00 + byte Len_2; // Length part 2 : 0x09 + char Cmd[9]; // ascii 'P_PROGRAM' +}TReqFunPlcStop; + +typedef TReqFunPlcStop* PReqFunPlcStop; + +typedef struct { + byte Fun; // start 0x28 + byte Uk_7[7]; // unknown 7 + word Len_1; // Length part 1 : 0x0000 + byte Len_2; // Length part 2 : 0x09 + char Cmd [9]; // ascii 'P_PROGRAM' +}TReqFunPlcHotStart; + +typedef TReqFunPlcHotStart* PReqFunPlcHotStart; + +typedef struct { + byte Fun; // start 0x28 + byte Uk_7[7]; // unknown 7 + word Len_1; // Length part 1 : 0x0002 + word SFun; // 'C ' 0x4320 + byte Len_2; // Length part 2 : 0x09 + char Cmd[9]; // ascii 'P_PROGRAM' +}TReqFunPlcColdStart; + +typedef TReqFunPlcColdStart* PReqFunPlcColdStart; + +typedef struct { + byte Fun; // pduControl 0x28 + byte Uk_7[7]; // unknown 7 + word Len_1; // Length part 1 : 0x0002 + word SFun; // 'EP' 0x4550 + byte Len_2; // Length part 2 : 0x05 + char Cmd[5]; // ascii '_MODU' +}TReqFunCopyRamToRom; + +typedef TReqFunCopyRamToRom* PReqFunCopyRamToRom; + +typedef struct { + byte Fun; // pduControl 0x28 + byte Uk_7[7]; // unknown 7 + word Len_1; // Length part 1 : 0x00 + byte Len_2; // Length part 2 : 0x05 + char Cmd[5]; // ascii '_GARB' +}TReqFunCompress; + +typedef TReqFunCompress* PReqFunCompress; + +typedef struct { + byte ResFun; + byte para; +}TResFunCtrl; + +typedef TResFunCtrl* PResFunCtrl; + +//============================================================================== +// FUNCTIONS USERDATA +//============================================================================== +typedef struct { + byte Head[3]; // Always 0x00 0x01 0x12 + byte Plen; // par len 0x04 or 0x08 + byte Uk; // unknown + byte Tg; // type and group (4 bits type and 4 bits group) + byte SubFun; // subfunction + byte Seq; // sequence + word resvd; // present if plen=0x08 (S7 manager online functions) + word Err; // present if plen=0x08 (S7 manager online functions) +}TS7Params7; + +typedef TS7Params7* PS7ReqParams7; +typedef TS7Params7* PS7ResParams7; + +// for convenience Hi order bit of type are included (0x4X) +const byte grProgrammer = 0x41; +const byte grCyclicData = 0x42; +const byte grBlocksInfo = 0x43; +const byte grSZL = 0x44; +const byte grPassword = 0x45; +const byte grBSend = 0x46; +const byte grClock = 0x47; +const byte grSecurity = 0x45; + +//============================================================================== +// GROUP SECURITY +//============================================================================== +typedef TReqFunTypedParams TReqFunSecurity; +typedef TReqFunSecurity* PReqFunSecurity; + +typedef char TS7Password[8]; + +typedef struct { + byte Ret; // 0xFF for request + byte TS; // 0x09 Transport size + word DLen; // Data len : 8 bytes + byte Pwd[8]; // Password encoded into "AG" format +}TReqDataSecurity; + +typedef TReqDataSecurity* PReqDataSecurity; +typedef TS7Params7 TResParamsSecurity; +typedef TResParamsSecurity* PResParamsSecurity; + +typedef struct { + byte Ret; + byte TS; + word DLen; +}TResDataSecurity; + +typedef TResDataSecurity* PResDataSecurity; + +//============================================================================== +// GROUP BLOCKS SZL +//============================================================================== +typedef TReqFunTypedParams TReqFunReadSZLFirst; +typedef TReqFunReadSZLFirst* PReqFunReadSZLFirst; + +typedef struct { + byte Head[3]; // 0x00 0x01 0x12 + byte Plen; // par len 0x04 + byte Uk; // unknown + byte Tg; // type and group (4 bits type and 4 bits group) + byte SubFun; // subfunction + byte Seq; // sequence + word Rsvd; // Reserved 0x0000 + word ErrNo; // Error Code +}TReqFunReadSZLNext; + +typedef TReqFunReadSZLNext* PReqFunReadSZLNext; + +typedef struct { + byte Ret; // 0xFF for request + byte TS; // 0x09 Transport size + word DLen; // Data len + word ID; // SZL-ID + word Index;// SZL-Index +}TS7ReqSZLData; + +typedef TS7ReqSZLData* PS7ReqSZLData; + +typedef struct { + byte Ret; + byte TS; + word DLen; + word ID; + word Index; + word ListLen; + word ListCount; + word Data[32747]; +}TS7ResSZLDataFirst; + +typedef TS7ResSZLDataFirst* PS7ResSZLDataFirst; + +typedef struct { + byte Ret; + byte TS; + word DLen; + word Data[32751]; +}TS7ResSZLDataNext; + +typedef TS7ResSZLDataNext* PS7ResSZLDataNext; + +typedef struct { + byte Ret; + byte OtherInfo[9]; + word Count; + word Items[32747]; +}TS7ResSZLData_0; + +typedef TS7ResSZLData_0* PS7ResSZLData_0; + +//============================================================================== +// GROUP CLOCK +//============================================================================== +typedef TReqFunTypedParams TReqFunDateTime; +typedef TReqFunDateTime* PReqFunDateTime; + +typedef byte TReqDataGetDateTime[4]; + +typedef longword *PReqDataGetDateTime; + +typedef struct { + byte RetVal; + byte TSize; + word Length; + byte Rsvd; + byte HiYear; + TTimeBuffer Time; +}TResDataGetTime; + +typedef TResDataGetTime* PResDataGetTime; +typedef TResDataGetTime TReqDataSetTime; +typedef TReqDataSetTime* PReqDataSetTime; + +typedef struct { + byte RetVal; + byte TSize; + word Length; +}TResDataSetTime; + +typedef TResDataSetTime* PResDataSetTime; + +//============================================================================== +// GROUP BLOCKS INFO +//============================================================================== +typedef TReqFunTypedParams TReqFunGetBlockInfo; +typedef TReqFunGetBlockInfo* PReqFunGetBlockInfo; + +typedef byte TReqDataFunBlocks[4]; +typedef u_char* PReqDataFunBlocks; + +typedef struct { + byte Head[3]; // 0x00 0x01 0x12 + byte Plen; // par len 0x04 + byte Uk; // unknown + byte Tg; // type and group (4 bits type and 4 bits group) + byte SubFun; // subfunction + byte Seq; // sequence + word Rsvd; // Reserved 0x0000 + word ErrNo; // Error Code +}TResFunGetBlockInfo; + +typedef TResFunGetBlockInfo* PResFunGetBlockInfo; + +typedef struct { + byte Zero; // always 0x30 -> Ascii 0 + byte BType; // Block Type + word BCount; // Block count +}TResFunGetBlockItem; + +typedef struct { + byte RetVal; + byte TRSize; + word Length; + TResFunGetBlockItem Blocks[7]; +}TDataFunListAll; + +typedef TDataFunListAll* PDataFunListAll; + +typedef struct { + word BlockNum; + byte Unknown; + byte BlockLang; +}TDataFunGetBotItem; + +typedef struct { + byte RetVal; + byte TSize; + word DataLen; + TDataFunGetBotItem Items[(IsoPayload_Size - 29 ) / 4]; +}TDataFunGetBot; +// Note : 29 is the size of headers iso, COPT, S7 header, params, data + +typedef TDataFunGetBot* PDataFunGetBot; + +typedef struct { + byte RetVal; // 0xFF + byte TSize; // Octet (0x09) + word Length; // 0x0002 + byte Zero; // Ascii '0' (0x30) + byte BlkType; +}TReqDataBlockOfType; + +typedef TReqDataBlockOfType* PReqDataBlockOfType; + +typedef struct { + byte RetVal; + byte TSize; + word DataLen; + byte BlkPrfx; // always 0x30 + byte BlkType; + byte AsciiBlk[5]; // BlockNum in ascii + byte A; // always 0x41 ('A') +}TReqDataBlockInfo; + +typedef TReqDataBlockInfo* PReqDataBlockInfo; + +typedef struct { + byte RetVal; + byte TSize; + word Length; + byte Cst_b; + byte BlkType; + word Cst_w1; + word Cst_w2; + word Cst_pp; + byte Unknown_1; + byte BlkFlags; + byte BlkLang; + byte SubBlkType; + word BlkNumber; + u_int LenLoadMem; + byte BlkSec[4]; + u_int CodeTime_ms; + word CodeTime_dy; + u_int IntfTime_ms; + word IntfTime_dy; + word SbbLen; + word AddLen; + word LocDataLen; + word MC7Len; + byte Author[8]; + byte Family[8]; + byte Header[8]; + byte Version; + byte Unknown_2; + word BlkChksum; + byte Resvd1[4]; + byte Resvd2[4]; +}TResDataBlockInfo; + +typedef TResDataBlockInfo* PResDataBlockInfo; + +//============================================================================== +// BSEND / BRECV +//============================================================================== +typedef struct { + int Size; + longword R_ID; + byte Data[65536]; +}TPendingBuffer; + +typedef struct { + TTPKT TPKT; + TCOTP_DT COTP; + byte P; + byte PDUType; +}TPacketInfo; + +typedef struct { + byte Head[3];// Always 0x00 0x01 0x12 + byte Plen; // par len 0x04 or 0x08 + byte Uk; // unknown (0x12) + byte Tg; // type and group, 4 bits type and 4 bits group (0x46) + byte SubFun; // subfunction (0x01) + byte Seq; // sequence + byte IDSeq; // ID Sequence (come from partner) + byte EoS; // End of Sequence = 0x00 Sequence in progress = 0x01; + word Err; // +}TBSendParams; + +typedef TBSendParams* PBSendReqParams; +typedef TBSendParams* PBSendResParams; + +// Data frame + +typedef struct { + byte FF; // 0xFF + byte TRSize; // Transport Size 0x09 (octet) + word Len; // This Telegram Length + byte DHead[4];// sequence 0x12 0x06 0x13 0x00 + u_int R_ID; // R_ID +}TBsendRequestData; + +typedef TBsendRequestData* PBsendRequestData; + +typedef struct { + byte DHead[4]; // sequence 0x0A 0x00 0x00 0x00 +}TBSendResData; + +typedef TBSendResData* PBSendResData; + +#pragma pack() +#endif // s7_types_h diff --git a/APP_Framework/Framework/control/plc/interoperability/s7/snap7_libmain.cpp b/APP_Framework/Framework/control/plc/interoperability/s7/snap7_libmain.cpp new file mode 100644 index 000000000..f782d4cb7 --- /dev/null +++ b/APP_Framework/Framework/control/plc/interoperability/s7/snap7_libmain.cpp @@ -0,0 +1,917 @@ +/*=============================================================================| +| PROJECT SNAP7 1.4.1 | +|==============================================================================| +| Copyright (C) 2013, 2015 Davide Nardella | +| All rights reserved. | +|==============================================================================| +| SNAP7 is free software: you can redistribute it and/or modify | +| it under the terms of the Lesser GNU General Public License as published by | +| the Free Software Foundation, either version 3 of the License, or | +| (at your option) any later version. | +| | +| It means that you can distribute your commercial software linked with | +| SNAP7 without the requirement to distribute the source code of your | +| application and without the requirement that your application be itself | +| distributed under LGPL. | +| | +| SNAP7 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 | +| Lesser GNU General Public License for more details. | +| | +| You should have received a copy of the GNU General Public License and a | +| copy of Lesser GNU General Public License along with Snap7. | +| If not, see http://www.gnu.org/licenses/ | +|=============================================================================*/ +#include "snap7_libmain.h" + +#ifndef OS_WINDOWS +void libinit(void) __attribute__((constructor)); +void libdone(void) __attribute__((destructor)); +#endif + +static bool libresult = true; + +void libinit(void) +{ + // in future expansions here can be inserted some initialization code + libresult=true; +} + +void libdone(void) +{ + // in future expansions here can be inserted some destruction code +} + +#ifdef OS_WINDOWS +BOOL APIENTRY DllMain (HINSTANCE hInst, + DWORD reason, + LPVOID reserved) +{ + switch (reason) + { + case DLL_PROCESS_ATTACH: + libinit(); + break; + case DLL_PROCESS_DETACH: + libdone(); + break; + case DLL_THREAD_ATTACH: + break; + case DLL_THREAD_DETACH: + break; + } + return libresult; +} +#endif + +//*************************************************************************** +// CLIENT +//*************************************************************************** +S7Object S7API Cli_Create() +{ + return S7Object(new TSnap7Client()); +} +//--------------------------------------------------------------------------- +void S7API Cli_Destroy(S7Object &Client) +{ + if (Client) + { + delete PSnap7Client(Client); + Client=0; + } +} +//--------------------------------------------------------------------------- +int S7API Cli_SetConnectionParams(S7Object Client, const char *Address, word LocalTSAP, word RemoteTSAP) +{ + if (Client) + { + PSnap7Client(Client)->SetConnectionParams(Address, LocalTSAP, RemoteTSAP); + return 0; + } + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_SetConnectionType(S7Object Client, word ConnectionType) +{ + if (Client) + { + PSnap7Client(Client)->SetConnectionType(ConnectionType); + return 0; + } + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_ConnectTo(S7Object Client, const char *Address, int Rack, int Slot) +{ + if (Client) + return PSnap7Client(Client)->ConnectTo(Address, Rack, Slot); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_Connect(S7Object Client) +{ + if (Client) + return PSnap7Client(Client)->Connect(); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_Disconnect(S7Object Client) +{ + if (Client) + return PSnap7Client(Client)->Disconnect(); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_GetParam(S7Object Client, int ParamNumber, void *pValue) +{ + if (Client) + return PSnap7Client(Client)->GetParam(ParamNumber, pValue); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_SetParam(S7Object Client, int ParamNumber, void *pValue) +{ + if (Client) + return PSnap7Client(Client)->SetParam(ParamNumber, pValue); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_SetAsCallback(S7Object Client, pfn_CliCompletion pCompletion, void *usrPtr) +{ + if (Client) + return PSnap7Client(Client)->SetAsCallback(pCompletion, usrPtr); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_ReadArea(S7Object Client, int Area, int DBNumber, int Start, int Amount, int WordLen, void *pUsrData) +{ + if (Client) + return PSnap7Client(Client)->ReadArea(Area, DBNumber, Start, Amount, WordLen, pUsrData); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_WriteArea(S7Object Client, int Area, int DBNumber, int Start, int Amount, int WordLen, void *pUsrData) +{ + if (Client) + return PSnap7Client(Client)->WriteArea(Area, DBNumber, Start, Amount, WordLen, pUsrData); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_ReadMultiVars(S7Object Client, PS7DataItem Item, int ItemsCount) +{ + if (Client) + return PSnap7Client(Client)->ReadMultiVars(Item, ItemsCount); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_WriteMultiVars(S7Object Client, PS7DataItem Item, int ItemsCount) +{ + if (Client) + return PSnap7Client(Client)->WriteMultiVars(Item, ItemsCount); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_DBRead(S7Object Client, int DBNumber, int Start, int Size, void *pUsrData) +{ + if (Client) + return PSnap7Client(Client)->DBRead(DBNumber, Start, Size, pUsrData); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_DBWrite(S7Object Client, int DBNumber, int Start, int Size, void *pUsrData) +{ + if (Client) + return PSnap7Client(Client)->DBWrite(DBNumber, Start, Size, pUsrData); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_MBRead(S7Object Client, int Start, int Size, void *pUsrData) +{ + if (Client) + return PSnap7Client(Client)->MBRead(Start, Size, pUsrData); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_MBWrite(S7Object Client, int Start, int Size, void *pUsrData) +{ + if (Client) + return PSnap7Client(Client)->MBWrite(Start, Size, pUsrData); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_EBRead(S7Object Client, int Start, int Size, void *pUsrData) +{ + if (Client) + return PSnap7Client(Client)->EBRead(Start, Size, pUsrData); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_EBWrite(S7Object Client, int Start, int Size, void *pUsrData) +{ + if (Client) + return PSnap7Client(Client)->EBWrite(Start, Size, pUsrData); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_ABRead(S7Object Client, int Start, int Size, void *pUsrData) +{ + if (Client) + return PSnap7Client(Client)->ABRead(Start, Size, pUsrData); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_ABWrite(S7Object Client, int Start, int Size, void *pUsrData) +{ + if (Client) + return PSnap7Client(Client)->ABWrite(Start, Size, pUsrData); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_TMRead(S7Object Client, int Start, int Amount, void *pUsrData) +{ + if (Client) + return PSnap7Client(Client)->TMRead(Start, Amount, pUsrData); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_TMWrite(S7Object Client, int Start, int Amount, void *pUsrData) +{ + if (Client) + return PSnap7Client(Client)->TMWrite(Start, Amount, pUsrData); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_CTRead(S7Object Client, int Start, int Amount, void *pUsrData) +{ + if (Client) + return PSnap7Client(Client)->CTRead(Start, Amount, pUsrData); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_CTWrite(S7Object Client, int Start, int Amount, void *pUsrData) +{ + if (Client) + return PSnap7Client(Client)->CTWrite(Start, Amount, pUsrData); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_ListBlocks(S7Object Client, TS7BlocksList *pUsrData) +{ + if (Client) + return PSnap7Client(Client)->ListBlocks(pUsrData); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_GetAgBlockInfo(S7Object Client, int BlockType, int BlockNum, TS7BlockInfo *pUsrData) +{ + if (Client) + return PSnap7Client(Client)->GetAgBlockInfo(BlockType, BlockNum, pUsrData); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_GetPgBlockInfo(S7Object Client, void *pBlock, TS7BlockInfo *pUsrData, int Size) +{ + if (Client) + return PSnap7Client(Client)->GetPgBlockInfo(pBlock, pUsrData, Size); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_ListBlocksOfType(S7Object Client, int BlockType, TS7BlocksOfType *pUsrData, int &ItemsCount) +{ + if (Client) + return PSnap7Client(Client)->ListBlocksOfType(BlockType, pUsrData, ItemsCount); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_Upload(S7Object Client, int BlockType, int BlockNum, void *pUsrData, int &Size) +{ + if (Client) + return PSnap7Client(Client)->Upload(BlockType, BlockNum, pUsrData, Size); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_FullUpload(S7Object Client, int BlockType, int BlockNum, void *pUsrData, int &Size) +{ + if (Client) + return PSnap7Client(Client)->FullUpload(BlockType, BlockNum, pUsrData, Size); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_Download(S7Object Client, int BlockNum, void *pUsrData, int Size) +{ + if (Client) + return PSnap7Client(Client)->Download(BlockNum, pUsrData, Size); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_Delete(S7Object Client, int BlockType, int BlockNum) +{ + if (Client) + return PSnap7Client(Client)->Delete(BlockType, BlockNum); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_DBGet(S7Object Client, int DBNumber, void *pUsrData, int &Size) +{ + if (Client) + return PSnap7Client(Client)->DBGet(DBNumber, pUsrData, Size); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_DBFill(S7Object Client, int DBNumber, int FillChar) +{ + if (Client) + return PSnap7Client(Client)->DBFill(DBNumber, FillChar); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_GetPlcDateTime(S7Object Client, tm &DateTime) +{ + if (Client) + return PSnap7Client(Client)->GetPlcDateTime(DateTime); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_SetPlcDateTime(S7Object Client, tm *DateTime) +{ + if (Client) + return PSnap7Client(Client)->SetPlcDateTime(DateTime); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_SetPlcSystemDateTime(S7Object Client) +{ + if (Client) + return PSnap7Client(Client)->SetPlcSystemDateTime(); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_GetOrderCode(S7Object Client, TS7OrderCode *pUsrData) +{ + if (Client) + return PSnap7Client(Client)->GetOrderCode(pUsrData); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_GetCpuInfo(S7Object Client, TS7CpuInfo *pUsrData) +{ + if (Client) + return PSnap7Client(Client)->GetCpuInfo(pUsrData); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_GetCpInfo(S7Object Client, TS7CpInfo *pUsrData) +{ + if (Client) + return PSnap7Client(Client)->GetCpInfo(pUsrData); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_ReadSZL(S7Object Client, int ID, int Index, TS7SZL *pUsrData, int &Size) +{ + if (Client) + return PSnap7Client(Client)->ReadSZL(ID, Index, pUsrData, Size); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_ReadSZLList(S7Object Client, TS7SZLList *pUsrData, int &ItemsCount) +{ + if (Client) + return PSnap7Client(Client)->ReadSZLList(pUsrData, ItemsCount); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_PlcHotStart(S7Object Client) +{ + if (Client) + return PSnap7Client(Client)->PlcHotStart(); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_PlcColdStart(S7Object Client) +{ + if (Client) + return PSnap7Client(Client)->PlcColdStart(); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_PlcStop(S7Object Client) +{ + if (Client) + return PSnap7Client(Client)->PlcStop(); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_CopyRamToRom(S7Object Client, int Timeout) +{ + if (Client) + return PSnap7Client(Client)->CopyRamToRom(Timeout); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_Compress(S7Object Client, int Timeout) +{ + if (Client) + return PSnap7Client(Client)->Compress(Timeout); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_GetPlcStatus(S7Object Client, int &Status) +{ + if (Client) + return PSnap7Client(Client)->GetPlcStatus(Status); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_GetProtection(S7Object Client, TS7Protection *pUsrData) +{ + if (Client) + return PSnap7Client(Client)->GetProtection(pUsrData); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_SetSessionPassword(S7Object Client, char *Password) +{ + if (Client) + return PSnap7Client(Client)->SetSessionPassword(Password); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_ClearSessionPassword(S7Object Client) +{ + if (Client) + return PSnap7Client(Client)->ClearSessionPassword(); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_IsoExchangeBuffer(S7Object Client, void *pUsrData, int &Size) +{ + if (Client) + return PSnap7Client(Client)->isoExchangeBuffer(pUsrData, Size); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_GetExecTime(S7Object Client, int &Time) +{ + if (Client) + { + Time=PSnap7Client(Client)->Time(); + return 0; + } + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_GetLastError(S7Object Client, int &LastError) +{ + if (Client) + { + LastError=PSnap7Client(Client)->LastError; + return 0; + } + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_GetPduLength(S7Object Client, int &Requested, int &Negotiated) +{ + if (Client) + { + Negotiated=PSnap7Client(Client)->PDULength; + Requested =PSnap7Client(Client)->PDURequest; + return 0; + } + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_ErrorText(int Error, char *Text, int TextLen) +{ + try{ + ErrCliText(Error, Text, TextLen); + Text[TextLen-1] = '\0'; + } + catch (...){ + return errLibInvalidParam; + } + return 0; +} +//--------------------------------------------------------------------------- +int S7API Cli_GetConnected(S7Object Client, int &Connected) +{ + Connected=0; + if (Client) + { + Connected=PSnap7Client(Client)->Connected; + return 0; + } + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_AsReadArea(S7Object Client, int Area, int DBNumber, int Start, int Amount, int WordLen, void *pUsrData) +{ + if (Client) + return PSnap7Client(Client)->AsReadArea(Area, DBNumber, Start, Amount, WordLen, pUsrData); + else + return errLibInvalidParam; +} +//--------------------------------------------------------------------------- +int S7API Cli_AsWriteArea(S7Object Client, int Area, int DBNumber, int Start, int Amount, int WordLen, void *pUsrData) +{ + if (Client) + return PSnap7Client(Client)->AsWriteArea(Area, DBNumber, Start, Amount, WordLen, pUsrData); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_AsDBRead(S7Object Client, int DBNumber, int Start, int Size, void *pUsrData) +{ + if (Client) + return PSnap7Client(Client)->AsDBRead(DBNumber, Start, Size, pUsrData); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_AsDBWrite(S7Object Client, int DBNumber, int Start, int Size, void *pUsrData) +{ + if (Client) + return PSnap7Client(Client)->AsDBWrite(DBNumber, Start, Size, pUsrData); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_AsMBRead(S7Object Client, int Start, int Size, void *pUsrData) +{ + if (Client) + return PSnap7Client(Client)->AsMBRead(Start, Size, pUsrData); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_AsMBWrite(S7Object Client, int Start, int Size, void *pUsrData) +{ + if (Client) + return PSnap7Client(Client)->AsMBWrite(Start, Size, pUsrData); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_AsEBRead(S7Object Client, int Start, int Size, void *pUsrData) +{ + if (Client) + return PSnap7Client(Client)->AsEBRead(Start, Size, pUsrData); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_AsEBWrite(S7Object Client, int Start, int Size, void *pUsrData) +{ + if (Client) + return PSnap7Client(Client)->AsEBWrite(Start, Size, pUsrData); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_AsABRead(S7Object Client, int Start, int Size, void *pUsrData) +{ + if (Client) + return PSnap7Client(Client)->AsABRead(Start, Size, pUsrData); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_AsABWrite(S7Object Client, int Start, int Size, void *pUsrData) +{ + if (Client) + return PSnap7Client(Client)->AsABWrite(Start, Size, pUsrData); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_AsTMRead(S7Object Client, int Start, int Amount, void *pUsrData) +{ + if (Client) + return PSnap7Client(Client)->AsTMRead(Start, Amount, pUsrData); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_AsTMWrite(S7Object Client, int Start, int Amount, void *pUsrData) +{ + if (Client) + return PSnap7Client(Client)->AsTMWrite(Start, Amount, pUsrData); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_AsCTRead(S7Object Client, int Start, int Amount, void *pUsrData) +{ + if (Client) + return PSnap7Client(Client)->AsCTRead(Start, Amount, pUsrData); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_AsCTWrite(S7Object Client, int Start, int Amount, void *pUsrData) +{ + if (Client) + return PSnap7Client(Client)->AsCTWrite(Start, Amount, pUsrData); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_AsListBlocksOfType(S7Object Client, int BlockType, TS7BlocksOfType *pUsrData, int &ItemsCount) +{ + if (Client) + return PSnap7Client(Client)->AsListBlocksOfType(BlockType, pUsrData, ItemsCount); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_AsReadSZL(S7Object Client, int ID, int Index, TS7SZL *pUsrData, int &Size) +{ + if (Client) + return PSnap7Client(Client)->AsReadSZL(ID, Index, pUsrData, Size); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_AsReadSZLList(S7Object Client, TS7SZLList *pUsrData, int &ItemsCount) +{ + if (Client) + return PSnap7Client(Client)->AsReadSZLList(pUsrData, ItemsCount); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_AsUpload(S7Object Client, int BlockType, int BlockNum, void *pUsrData, int &Size) +{ + if (Client) + return PSnap7Client(Client)->AsUpload(BlockType, BlockNum, pUsrData, Size); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_AsFullUpload(S7Object Client, int BlockType, int BlockNum, void *pUsrData, int &Size) +{ + if (Client) + return PSnap7Client(Client)->AsFullUpload(BlockType, BlockNum, pUsrData, Size); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_AsDownload(S7Object Client, int BlockNum, void *pUsrData, int Size) +{ + if (Client) + return PSnap7Client(Client)->AsDownload(BlockNum, pUsrData, Size); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_AsCopyRamToRom(S7Object Client, int Timeout) +{ + if (Client) + return PSnap7Client(Client)->AsCopyRamToRom(Timeout); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_AsCompress(S7Object Client, int Timeout) +{ + if (Client) + return PSnap7Client(Client)->Compress(Timeout); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_AsDBGet(S7Object Client, int DBNumber, void *pUsrData, int &Size) +{ + if (Client) + return PSnap7Client(Client)->AsDBGet(DBNumber, pUsrData, Size); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_AsDBFill(S7Object Client, int DBNumber, int FillChar) +{ + if (Client) + return PSnap7Client(Client)->AsDBFill(DBNumber, FillChar); + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_CheckAsCompletion(S7Object Client, int &opResult) +{ + if (Client) + { + if (PSnap7Client(Client)->CheckAsCompletion(opResult)) + return JobComplete; + else + return JobPending; + } + else + return errLibInvalidObject; +} +//--------------------------------------------------------------------------- +int S7API Cli_WaitAsCompletion(S7Object Client, int Timeout) +{ + if (Client) + return PSnap7Client(Client)->WaitAsCompletion(Timeout); + else + return errLibInvalidObject; +} + +void hexdump(void *mem, unsigned int len) +{ + unsigned int i, j; + + for (i = 0; i < len + ((len % HEXDUMP_COLS) ? (HEXDUMP_COLS - len % HEXDUMP_COLS) : 0); i++) + { + /* print offset */ + if (i % HEXDUMP_COLS == 0) + { + printf("0x%04x: ", i); + } + + /* print hex data */ + if (i < len) + { + printf("%02x ", 0xFF & ((char *)mem)[i]); + } + else /* end of block, just aligning for ASCII dump */ + { + printf(" "); + } + + /* print ASCII dump */ + if (i % HEXDUMP_COLS == (HEXDUMP_COLS - 1)) + { + for (j = i - (HEXDUMP_COLS - 1); j <= i; j++) + { + if (j >= len) /* end of block, not really printing */ + { + putchar(' '); + } + else if (isprint((((char *)mem)[j] & 0x7F))) /* printable char */ + { + putchar(0xFF & ((char *)mem)[j]); + } + else /* other char */ + { + putchar('.'); + } + } + putchar('\n'); + } + } +} + +int WordLenToByteLen(int WordLen){ + switch (WordLen) + { + case S7WLBit: // need to dump a byte to view it + return 1; + break; + case S7WLByte: + return 1; + break; + case S7WLChar: + return 1; + break; + case S7WLWord: + return 2; + break; + case S7WLInt: + return 2; + break; + case S7WLDWord: + return 4; + break; + case S7WLDInt: + return 4; + break; + case S7WLReal: + return 4; + break; + default: + return 0; + break; + } +} + +void Usage() +{ + printf("Usage\n"); + printf(" client [Rack=0 Slot=2]\n"); + printf("Example\n"); + printf(" client 192.168.1.101 0 2\n"); + printf("or\n"); + printf(" client 192.168.1.101\n"); + getchar(); +} + +int Check(S7Object Client, int Result, char *function) +{ + int ExecTime; + char text[1024]; + printf("\n"); + printf("+-----------------------------------------------------\n"); + printf("| %s\n", function); + printf("+-----------------------------------------------------\n"); + if (Result == 0) + { + Cli_GetExecTime(Client, ExecTime); + printf("| Result : OK\n"); + printf("| Execution time : %d ms\n", ExecTime); + printf("+-----------------------------------------------------\n"); + } + else + { + printf("| ERROR !!! \n"); + if (Result < 0) + printf("| Library Error (-1)\n"); + else + { + Cli_ErrorText(Result, text, 1024); + printf("| %s\n", text); + } + printf("+-----------------------------------------------------\n"); + } + return !Result; +} + +void Cli_ReadAndDump(S7Object Client, int Area, int DBNumber, int Start, int Amount, int WordLen, byte *pUsrData, char *description){ + int len = WordLenToByteLen(WordLen); + memset(pUsrData, 0, sizeof(byte)*Amount*len); + int res = Cli_ReadArea(Client, Area, DBNumber, Start, Amount, WordLen, pUsrData); + if (Check(Client, res, description)) + { + printf("Dump (%d bit) :\n", Amount*len); + hexdump(pUsrData, Amount*len); + } +} + + +void Cli_WriteAndDump(S7Object Client, int Area, int DBNumber, int Start, int Amount, int WordLen, byte *pUsrData, char *description){ + int len = WordLenToByteLen(WordLen); + int res = Cli_WriteArea(Client, Area, DBNumber, Start, Amount, WordLen, pUsrData); + if (Check(Client, res, description)) + { + printf("Dump (%d bit) :\n", Amount*len); + hexdump(pUsrData, Amount*len); + } +} \ No newline at end of file diff --git a/APP_Framework/Framework/control/plc/interoperability/s7/snap7_libmain.h b/APP_Framework/Framework/control/plc/interoperability/s7/snap7_libmain.h new file mode 100644 index 000000000..5f23c6b8b --- /dev/null +++ b/APP_Framework/Framework/control/plc/interoperability/s7/snap7_libmain.h @@ -0,0 +1,170 @@ +/*=============================================================================| +| PROJECT SNAP7 1.3.0 | +|==============================================================================| +| Copyright (C) 2013, 2015 Davide Nardella | +| All rights reserved. | +|==============================================================================| +| SNAP7 is free software: you can redistribute it and/or modify | +| it under the terms of the Lesser GNU General Public License as published by | +| the Free Software Foundation, either version 3 of the License, or | +| (at your option) any later version. | +| | +| It means that you can distribute your commercial software linked with | +| SNAP7 without the requirement to distribute the source code of your | +| application and without the requirement that your application be itself | +| distributed under LGPL. | +| | +| SNAP7 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 | +| Lesser GNU General Public License for more details. | +| | +| You should have received a copy of the GNU General Public License and a | +| copy of Lesser GNU General Public License along with Snap7. | +| If not, see http://www.gnu.org/licenses/ | +|=============================================================================*/ +#ifndef snap7_libmain_h +#define snap7_libmain_h +//--------------------------------------------------------------------------- +#include "s7_client.h" +#include "s7_text.h" +//--------------------------------------------------------------------------- + +const int mkEvent = 0; +const int mkLog = 1; + +typedef uintptr_t S7Object; // multi platform/processor object reference + +//============================================================================== +// CLIENT EXPORT LIST - Sync functions +//============================================================================== +EXPORTSPEC S7Object S7API Cli_Create(); +EXPORTSPEC void S7API Cli_Destroy(S7Object &Client); +EXPORTSPEC int S7API Cli_Connect(S7Object Client); +EXPORTSPEC int S7API Cli_SetConnectionParams(S7Object Client, const char *Address, word LocalTSAP, word RemoteTSAP); +EXPORTSPEC int S7API Cli_SetConnectionType(S7Object Client, word ConnectionType); +EXPORTSPEC int S7API Cli_ConnectTo(S7Object Client, const char *Address, int Rack, int Slot); +EXPORTSPEC int S7API Cli_Disconnect(S7Object Client); +EXPORTSPEC int S7API Cli_GetParam(S7Object Client, int ParamNumber, void *pValue); +EXPORTSPEC int S7API Cli_SetParam(S7Object Client, int ParamNumber, void *pValue); +EXPORTSPEC int S7API Cli_SetAsCallback(S7Object Client, pfn_CliCompletion pCompletion, void *usrPtr); +// Data I/O functions +EXPORTSPEC int S7API Cli_ReadArea(S7Object Client, int Area, int DBNumber, int Start, int Amount, int WordLen, void *pUsrData); +EXPORTSPEC int S7API Cli_WriteArea(S7Object Client, int Area, int DBNumber, int Start, int Amount, int WordLen, void *pUsrData); +EXPORTSPEC int S7API Cli_ReadMultiVars(S7Object Client, PS7DataItem Item, int ItemsCount); +EXPORTSPEC int S7API Cli_WriteMultiVars(S7Object Client, PS7DataItem Item, int ItemsCount); +// Data I/O Lean functions +EXPORTSPEC int S7API Cli_DBRead(S7Object Client, int DBNumber, int Start, int Size, void *pUsrData); +EXPORTSPEC int S7API Cli_DBWrite(S7Object Client, int DBNumber, int Start, int Size, void *pUsrData); +EXPORTSPEC int S7API Cli_MBRead(S7Object Client, int Start, int Size, void *pUsrData); +EXPORTSPEC int S7API Cli_MBWrite(S7Object Client, int Start, int Size, void *pUsrData); +EXPORTSPEC int S7API Cli_EBRead(S7Object Client, int Start, int Size, void *pUsrData); +EXPORTSPEC int S7API Cli_EBWrite(S7Object Client, int Start, int Size, void *pUsrData); +EXPORTSPEC int S7API Cli_ABRead(S7Object Client, int Start, int Size, void *pUsrData); +EXPORTSPEC int S7API Cli_ABWrite(S7Object Client, int Start, int Size, void *pUsrData); +EXPORTSPEC int S7API Cli_TMRead(S7Object Client, int Start, int Amount, void *pUsrData); +EXPORTSPEC int S7API Cli_TMWrite(S7Object Client, int Start, int Amount, void *pUsrData); +EXPORTSPEC int S7API Cli_CTRead(S7Object Client, int Start, int Amount, void *pUsrData); +EXPORTSPEC int S7API Cli_CTWrite(S7Object Client, int Start, int Amount, void *pUsrData); +// Directory functions +EXPORTSPEC int S7API Cli_ListBlocks(S7Object Client, TS7BlocksList *pUsrData); +EXPORTSPEC int S7API Cli_GetAgBlockInfo(S7Object Client, int BlockType, int BlockNum, TS7BlockInfo *pUsrData); +EXPORTSPEC int S7API Cli_GetPgBlockInfo(S7Object Client, void *pBlock, TS7BlockInfo *pUsrData, int Size); +EXPORTSPEC int S7API Cli_ListBlocksOfType(S7Object Client, int BlockType, TS7BlocksOfType *pUsrData, int &ItemsCount); +// Blocks functions +EXPORTSPEC int S7API Cli_Upload(S7Object Client, int BlockType, int BlockNum, void *pUsrData, int &Size); +EXPORTSPEC int S7API Cli_FullUpload(S7Object Client, int BlockType, int BlockNum, void *pUsrData, int &Size); +EXPORTSPEC int S7API Cli_Download(S7Object Client, int BlockNum, void *pUsrData, int Size); +EXPORTSPEC int S7API Cli_Delete(S7Object Client, int BlockType, int BlockNum); +EXPORTSPEC int S7API Cli_DBGet(S7Object Client, int DBNumber, void *pUsrData, int &Size); +EXPORTSPEC int S7API Cli_DBFill(S7Object Client, int DBNumber, int FillChar); +// Date/Time functions +EXPORTSPEC int S7API Cli_GetPlcDateTime(S7Object Client, tm &DateTime); +EXPORTSPEC int S7API Cli_SetPlcDateTime(S7Object Client, tm *DateTime); +EXPORTSPEC int S7API Cli_SetPlcSystemDateTime(S7Object Client); +// System Info functions +EXPORTSPEC int S7API Cli_GetOrderCode(S7Object Client, TS7OrderCode *pUsrData); +EXPORTSPEC int S7API Cli_GetCpuInfo(S7Object Client, TS7CpuInfo *pUsrData); +EXPORTSPEC int S7API Cli_GetCpInfo(S7Object Client, TS7CpInfo *pUsrData); +EXPORTSPEC int S7API Cli_ReadSZL(S7Object Client, int ID, int Index, TS7SZL *pUsrData, int &Size); +EXPORTSPEC int S7API Cli_ReadSZLList(S7Object Client, TS7SZLList *pUsrData, int &ItemsCount); +// Control functions +EXPORTSPEC int S7API Cli_PlcHotStart(S7Object Client); +EXPORTSPEC int S7API Cli_PlcColdStart(S7Object Client); +EXPORTSPEC int S7API Cli_PlcStop(S7Object Client); +EXPORTSPEC int S7API Cli_CopyRamToRom(S7Object Client, int Timeout); +EXPORTSPEC int S7API Cli_Compress(S7Object Client, int Timeout); +EXPORTSPEC int S7API Cli_GetPlcStatus(S7Object Client, int &Status); +// Security functions +EXPORTSPEC int S7API Cli_GetProtection(S7Object Client, TS7Protection *pUsrData); +EXPORTSPEC int S7API Cli_SetSessionPassword(S7Object Client, char *Password); +EXPORTSPEC int S7API Cli_ClearSessionPassword(S7Object Client); +// Low level +EXPORTSPEC int S7API Cli_IsoExchangeBuffer(S7Object Client, void *pUsrData, int &Size); +// Misc +EXPORTSPEC int S7API Cli_GetExecTime(S7Object Client, int &Time); +EXPORTSPEC int S7API Cli_GetLastError(S7Object Client, int &LastError); +EXPORTSPEC int S7API Cli_GetPduLength(S7Object Client, int &Requested, int &Negotiated); +EXPORTSPEC int S7API Cli_ErrorText(int Error, char *Text, int TextLen); +EXPORTSPEC int S7API Cli_GetConnected(S7Object Client, int &Connected); +//============================================================================== +// CLIENT EXPORT LIST - Async functions +//============================================================================== +EXPORTSPEC int S7API Cli_AsReadArea(S7Object Client, int Area, int DBNumber, int Start, int Amount, int WordLen, void *pUsrData); +EXPORTSPEC int S7API Cli_AsWriteArea(S7Object Client, int Area, int DBNumber, int Start, int Amount, int WordLen, void *pUsrData); +EXPORTSPEC int S7API Cli_AsDBRead(S7Object Client, int DBNumber, int Start, int Size, void *pUsrData); +EXPORTSPEC int S7API Cli_AsDBWrite(S7Object Client, int DBNumber, int Start, int Size, void *pUsrData); +EXPORTSPEC int S7API Cli_AsMBRead(S7Object Client, int Start, int Size, void *pUsrData); +EXPORTSPEC int S7API Cli_AsMBWrite(S7Object Client, int Start, int Size, void *pUsrData); +EXPORTSPEC int S7API Cli_AsEBRead(S7Object Client, int Start, int Size, void *pUsrData); +EXPORTSPEC int S7API Cli_AsEBWrite(S7Object Client, int Start, int Size, void *pUsrData); +EXPORTSPEC int S7API Cli_AsABRead(S7Object Client, int Start, int Size, void *pUsrData); +EXPORTSPEC int S7API Cli_AsABWrite(S7Object Client, int Start, int Size, void *pUsrData); +EXPORTSPEC int S7API Cli_AsTMRead(S7Object Client, int Start, int Amount, void *pUsrData); +EXPORTSPEC int S7API Cli_AsTMWrite(S7Object Client, int Start, int Amount, void *pUsrData); +EXPORTSPEC int S7API Cli_AsCTRead(S7Object Client, int Start, int Amount, void *pUsrData); +EXPORTSPEC int S7API Cli_AsCTWrite(S7Object Client, int Start, int Amount, void *pUsrData); +EXPORTSPEC int S7API Cli_AsListBlocksOfType(S7Object Client, int BlockType, TS7BlocksOfType *pUsrData, int &ItemsCount); +EXPORTSPEC int S7API Cli_AsReadSZL(S7Object Client, int ID, int Index, TS7SZL *pUsrData, int &Size); +EXPORTSPEC int S7API Cli_AsReadSZLList(S7Object Client, TS7SZLList *pUsrData, int &ItemsCount); +EXPORTSPEC int S7API Cli_AsUpload(S7Object Client, int BlockType, int BlockNum, void *pUsrData, int &Size); +EXPORTSPEC int S7API Cli_AsFullUpload(S7Object Client, int BlockType, int BlockNum, void *pUsrData, int &Size); +EXPORTSPEC int S7API Cli_AsDownload(S7Object Client, int BlockNum, void *pUsrData, int Size); +EXPORTSPEC int S7API Cli_AsCopyRamToRom(S7Object Client, int Timeout); +EXPORTSPEC int S7API Cli_AsCompress(S7Object Client, int Timeout); +EXPORTSPEC int S7API Cli_AsDBGet(S7Object Client, int DBNumber, void *pUsrData, int &Size); +EXPORTSPEC int S7API Cli_AsDBFill(S7Object Client, int DBNumber, int FillChar); +EXPORTSPEC int S7API Cli_CheckAsCompletion(S7Object Client, int &opResult); +EXPORTSPEC int S7API Cli_WaitAsCompletion(S7Object Client, int Timeout); + +#include +#include +#include + +#ifndef HEXDUMP_COLS +#define HEXDUMP_COLS 16 +#endif +EXPORTSPEC void hexdump(void *mem, unsigned int len); + +// real length of the data in bytes +// S7WLBit and S7WLByte are simply enum variables +EXPORTSPEC int WordLenToByteLen(int WordLen); + +// Usage Syntax +EXPORTSPEC void Usage(); + +// Check error +EXPORTSPEC int Check(S7Object Client, int Result, char *function); + + +// Supported `Area` are S7AreaPE, S7AreaPA, S7AreaMK, S7AreaDB, S7AreaCT, S7AreaTM +// Supported `WordLen` are S7WLBit, S7WLByte, S7WLChar, S7WLWord, S7WLInt, S7WLDWord, S7WLDInt, S7WLReal, +// In fact, these types have no effect on the real data content, only identify the data length, +// You have to transform the data pointer to your desired type, +// When type is `S7WLBit`, amount must be 1, +// This function is just a wrapper of `Cli_ReadArea` +EXPORTSPEC void Cli_ReadAndDump(S7Object Client, int Area, int DBNumber, int Start, int Amount, int WordLen, byte *pUsrData, char *description); +EXPORTSPEC void Cli_WriteAndDump(S7Object Client, int Area, int DBNumber, int Start, int Amount, int WordLen, byte *pUsrData, char *description); + + +#endif // snap7_libmain_h diff --git a/APP_Framework/Framework/control/plc/interoperability/s7/snap_msgsock.cpp b/APP_Framework/Framework/control/plc/interoperability/s7/snap_msgsock.cpp new file mode 100644 index 000000000..cf94a8eba --- /dev/null +++ b/APP_Framework/Framework/control/plc/interoperability/s7/snap_msgsock.cpp @@ -0,0 +1,786 @@ +/*=============================================================================| +| PROJECT SNAP7 1.3.0 | +|==============================================================================| +| Copyright (C) 2013, 2015 Davide Nardella | +| All rights reserved. | +|==============================================================================| +| SNAP7 is free software: you can redistribute it and/or modify | +| it under the terms of the Lesser GNU General Public License as published by | +| the Free Software Foundation, either version 3 of the License, or | +| (at your option) any later version. | +| | +| It means that you can distribute your commercial software linked with | +| SNAP7 without the requirement to distribute the source code of your | +| application and without the requirement that your application be itself | +| distributed under LGPL. | +| | +| SNAP7 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 | +| Lesser GNU General Public License for more details. | +| | +| You should have received a copy of the GNU General Public License and a | +| copy of Lesser GNU General Public License along with Snap7. | +| If not, see http://www.gnu.org/licenses/ | +|=============================================================================*/ + +#include "snap_msgsock.h" + +//--------------------------------------------------------------------------- + +static SocketsLayer SocketsLayerInitializer; + +//--------------------------------------------------------------------------- +// Base class endian aware +//--------------------------------------------------------------------------- +TSnapBase::TSnapBase() +{ + int x = 1; + LittleEndian=*(char *)&x == 1; +} +//--------------------------------------------------------------------------- +word TSnapBase::SwapWord(word Value) +{ + if (LittleEndian) + return ((Value >> 8) & 0xFF) | ((Value << 8) & 0xFF00); + else + return Value; +} +//--------------------------------------------------------------------------- +longword TSnapBase::SwapDWord(longword Value) +{ + if (LittleEndian) + return (Value >> 24) | ((Value << 8) & 0x00FF0000) | ((Value >> 8) & 0x0000FF00) | (Value << 24); + else + return Value; +} +//--------------------------------------------------------------------------- +void Msg_CloseSocket(socket_t FSocket) +{ + #ifdef OS_WINDOWS + closesocket(FSocket); + #else + close(FSocket); + #endif +} +//--------------------------------------------------------------------------- +longword Msg_GetSockAddr(socket_t FSocket) +{ + sockaddr_in RemoteSin; + #ifdef OS_WINDOWS + int namelen = sizeof(RemoteSin); + #else + uint32_t namelen = sizeof(RemoteSin); + #endif + namelen=sizeof(sockaddr_in); + if (getpeername(FSocket,(struct sockaddr*)&RemoteSin, &namelen)==0) + return RemoteSin.sin_addr.s_addr; + else + return 0; +} +//--------------------------------------------------------------------------- +TMsgSocket::TMsgSocket() +{ + Pinger = new TPinger(); + // Set Defaults + strcpy(LocalAddress,"0.0.0.0"); + LocalPort=0; + strcpy(RemoteAddress,"127.0.0.1"); + RemotePort=0; + WorkInterval=100; + RecvTimeout=500; + SendTimeout=10; + PingTimeout=750; + Connected=false; + FSocket=INVALID_SOCKET; + LastTcpError=0; + LocalBind=0; +} +//--------------------------------------------------------------------------- +TMsgSocket::~TMsgSocket() +{ + DestroySocket(); + delete Pinger; +} +//--------------------------------------------------------------------------- +void TMsgSocket::SetSin(sockaddr_in &sin, char *Address, u_short Port) +{ + uint32_t in_addr; + in_addr=inet_addr(Address); + memset(&sin, 0, sizeof(sin)); + LastTcpError=0; + + if (in_addr!=INADDR_NONE) + { + sin.sin_addr.s_addr = in_addr; + sin.sin_family = AF_INET; + sin.sin_port = htons(Port); + } + else + LastTcpError=WSAEINVALIDADDRESS; +} +//--------------------------------------------------------------------------- +void TMsgSocket::GetSin(sockaddr_in sin, char *Address, u_short &Port) +{ + strcpy(Address,inet_ntoa(sin.sin_addr)); + Port=htons(sin.sin_port); +} +//--------------------------------------------------------------------------- +void TMsgSocket::GetLocal() +{ + #ifdef OS_WINDOWS + int namelen = sizeof(LocalSin); + #else + uint32_t namelen = sizeof(LocalSin); + #endif + if (getsockname(FSocket, (struct sockaddr*)&LocalSin, &namelen)==0) + GetSin(LocalSin, LocalAddress, LocalPort); +} +//--------------------------------------------------------------------------- +void TMsgSocket::GetRemote() +{ + #ifdef OS_WINDOWS + int namelen = sizeof(RemoteSin); + #else + uint32_t namelen = sizeof(RemoteSin); + #endif + if (getpeername(FSocket,(struct sockaddr*)&RemoteSin, &namelen)==0) + GetSin(RemoteSin, RemoteAddress, RemotePort); +} +//--------------------------------------------------------------------------- +int TMsgSocket::GetLastSocketError() +{ +#ifdef OS_WINDOWS + return WSAGetLastError(); +#else + return errno; +#endif +} +//--------------------------------------------------------------------------- +void TMsgSocket::Purge() +{ + // small buffer to empty the socket + char Trash[512]; + int Read; + if (LastTcpError!=WSAECONNRESET) + { + if (CanRead(0)) { + do + { + Read=recv(FSocket, Trash, 512, MSG_NOSIGNAL ); + } while(Read==512); + } + } +} +//--------------------------------------------------------------------------- +void TMsgSocket::CreateSocket() +{ + DestroySocket(); + LastTcpError=0; + FSocket =socket(AF_INET, SOCK_STREAM, IPPROTO_TCP ); + if (FSocket!=INVALID_SOCKET) + SetSocketOptions(); + else + LastTcpError =GetLastSocketError(); +} +//--------------------------------------------------------------------------- +void TMsgSocket::GotSocket() +{ + ClientHandle=RemoteSin.sin_addr.s_addr; + // could be inherited it if wee need further actions on the socket +} +//--------------------------------------------------------------------------- +void TMsgSocket::SetSocket(socket_t s) +{ + FSocket=s; + if (FSocket!=INVALID_SOCKET) + { + SetSocketOptions(); + GetLocal(); + GetRemote(); + GotSocket(); + } + Connected=FSocket!=INVALID_SOCKET; +} +//--------------------------------------------------------------------------- +void TMsgSocket::DestroySocket() +{ + if(FSocket != INVALID_SOCKET) + { + if (shutdown(FSocket, SD_SEND)==0) + Purge(); + #ifdef OS_WINDOWS + closesocket(FSocket); + #else + close(FSocket); + #endif + FSocket=INVALID_SOCKET; + } + LastTcpError=0; +} +//--------------------------------------------------------------------------- +int TMsgSocket::WaitingData() +{ + int result = 0; + u_long x = 0; +#ifdef OS_WINDOWS + if (ioctlsocket(FSocket, FIONREAD, &x) == 0) + result = x; +#else + if (ioctl(FSocket, FIONREAD, &x) == 0) + result = x; +#endif + if (result>MaxPacketSize) + result = MaxPacketSize; + return result; +} +//--------------------------------------------------------------------------- +int TMsgSocket::WaitForData(int Size, int Timeout) +{ + longword Elapsed; + + // Check for connection active + if (CanRead(0) && (WaitingData()==0)) + LastTcpError=WSAECONNRESET; + else + LastTcpError=0; + + // Enter main loop + if (LastTcpError==0) + { + Elapsed =SysGetTick(); + while((WaitingData()=(longword)(Timeout)) + LastTcpError =WSAETIMEDOUT; + else + SysSleep(1); + } + } + if(LastTcpError==WSAECONNRESET) + Connected =false; + + return LastTcpError; +} +//--------------------------------------------------------------------------- +void TMsgSocket::SetSocketOptions() +{ + int NoDelay = 1; + int KeepAlive = 1; + LastTcpError=0; + SockCheck(setsockopt(FSocket, IPPROTO_TCP, TCP_NODELAY,(char*)&NoDelay, sizeof(NoDelay))); + + if (LastTcpError==0) + SockCheck(setsockopt(FSocket, SOL_SOCKET, SO_KEEPALIVE,(char*)&KeepAlive, sizeof(KeepAlive))); +} +//--------------------------------------------------------------------------- +int TMsgSocket::SockCheck(int SockResult) +{ + if (SockResult == (int)(SOCKET_ERROR)) + LastTcpError = GetLastSocketError(); + + return LastTcpError; +} +//--------------------------------------------------------------------------- +bool TMsgSocket::CanWrite(int Timeout) +{ + timeval TimeV; + int64_t x; + fd_set FDset; + + if(FSocket == INVALID_SOCKET) + return false; + + TimeV.tv_usec = (Timeout % 1000) * 1000; + TimeV.tv_sec = Timeout / 1000; + + FD_ZERO(&FDset); + FD_SET(FSocket, &FDset); + + x = select(FSocket + 1, NULL, &FDset, NULL, &TimeV); //<-Ignore this warning in 64bit Visual Studio + if (x==(int)SOCKET_ERROR) + { + LastTcpError = GetLastSocketError(); + x=0; + } + return (x > 0); +} +//--------------------------------------------------------------------------- +bool TMsgSocket::CanRead(int Timeout) +{ + timeval TimeV; + int64_t x; + fd_set FDset; + + if(FSocket == INVALID_SOCKET) + return false; + + TimeV.tv_usec = (Timeout % 1000) * 1000; + TimeV.tv_sec = Timeout / 1000; + + FD_ZERO(&FDset); + FD_SET(FSocket, &FDset); + + x = select(FSocket + 1, &FDset, NULL, NULL, &TimeV); //<-Ignore this warning in 64bit Visual Studio + if (x==(int)SOCKET_ERROR) + { + LastTcpError = GetLastSocketError(); + x=0; + } + return (x > 0); +} +//--------------------------------------------------------------------------- + +// +// Non blocking connection (UNIX) Thanks to Rolf Stalder +// +int TMsgSocket::SckConnect() +{ + int n, flags, err; + socklen_t len; + fd_set rset, wset; + struct timeval tval; + + SetSin(RemoteSin, RemoteAddress, RemotePort); + + if (LastTcpError == 0) { + CreateSocket(); + if (LastTcpError == 0) { + flags = fcntl(FSocket, F_GETFL, 0); + if (flags >= 0) { + if (fcntl(FSocket, F_SETFL, flags | O_NONBLOCK) != -1) { + n = connect(FSocket, (struct sockaddr*)&RemoteSin, sizeof(RemoteSin)); + if (n < 0) { + if (errno != EINPROGRESS) { + LastTcpError = GetLastSocketError(); + } + else { + // still connecting ... + FD_ZERO(&rset); + FD_SET(FSocket, &rset); + wset = rset; + tval.tv_sec = PingTimeout / 1000; + tval.tv_usec = (PingTimeout % 1000) * 1000; + + n = select(FSocket+1, &rset, &wset, NULL, + (PingTimeout ? &tval : NULL)); + if (n == 0) { + // timeout + LastTcpError = WSAEHOSTUNREACH; + } + else { + if (FD_ISSET(FSocket, &rset) || FD_ISSET(FSocket, &wset)) { + err = 0; + len = sizeof(err); + if (getsockopt( + FSocket, SOL_SOCKET, SO_ERROR, &err, &len) == 0) { + if (err) { + LastTcpError = err; + } + else { + if (fcntl(FSocket, F_SETFL, flags) != -1) { + GetLocal(); + ClientHandle = LocalSin.sin_addr.s_addr; + } + else { + LastTcpError = GetLastSocketError(); + } + } + } + else { + LastTcpError = GetLastSocketError(); + } + } + else { + LastTcpError = -1; + } + } + } // still connecting + } + else if (n == 0) { + // connected immediatly + GetLocal(); + ClientHandle = LocalSin.sin_addr.s_addr; + } + } + else { + LastTcpError = GetLastSocketError(); + } // fcntl(F_SETFL) + } + else { + LastTcpError = GetLastSocketError(); + } // fcntl(F_GETFL) + } //valid socket + } // LastTcpError==0 + Connected=LastTcpError==0; + return LastTcpError; +} + +//--------------------------------------------------------------------------- +void TMsgSocket::SckDisconnect() +{ + DestroySocket(); + Connected=false; +} +//--------------------------------------------------------------------------- +void TMsgSocket::ForceClose() +{ + if(FSocket != INVALID_SOCKET) + { + try { + #ifdef OS_WINDOWS + closesocket(FSocket); + #else + close(FSocket); + #endif + } catch (...) { + } + FSocket=INVALID_SOCKET; + } + LastTcpError=0; +} +//--------------------------------------------------------------------------- +int TMsgSocket::SckBind() +{ + int Res; + int Opt=1; + SetSin(LocalSin, LocalAddress, LocalPort); + if (LastTcpError==0) + { + CreateSocket(); + if (LastTcpError==0) + { + setsockopt(FSocket ,SOL_SOCKET, SO_REUSEADDR, (const char *)&Opt, sizeof(int)); + Res =bind(FSocket, (struct sockaddr*)&LocalSin, sizeof(sockaddr_in)); + SockCheck(Res); + if (Res==0) + { + LocalBind=LocalSin.sin_addr.s_addr; + } + } + } + else + LastTcpError=WSAEINVALIDADDRESS; + + return LastTcpError; +} +//--------------------------------------------------------------------------- +int TMsgSocket::SckListen() +{ + LastTcpError=0; + SockCheck(listen(FSocket ,SOMAXCONN)); + return LastTcpError; +} +//--------------------------------------------------------------------------- +bool TMsgSocket::Ping(char *Host) +{ + return Pinger->Ping(Host, PingTimeout); +} +//--------------------------------------------------------------------------- +bool TMsgSocket::Ping(sockaddr_in Addr) +{ + if (PingTimeout == 0) + return true; + else + return Pinger->Ping(Addr.sin_addr.s_addr, PingTimeout); +} +//--------------------------------------------------------------------------- +socket_t TMsgSocket::SckAccept() +{ + socket_t result; + LastTcpError=0; + result = accept(FSocket, NULL, NULL); + if(result==INVALID_SOCKET) + LastTcpError =GetLastSocketError(); + return result; +} +//--------------------------------------------------------------------------- +int TMsgSocket::SendPacket(void *Data, int Size) +{ + int Result; + + LastTcpError=0; + if (SendTimeout>0) + { + if (!CanWrite(SendTimeout)) + { + LastTcpError = WSAETIMEDOUT; + return LastTcpError; + } + } + if (send(FSocket, (char*)Data, Size, MSG_NOSIGNAL)==Size) + return 0; + else + Result =SOCKET_ERROR; + + SockCheck(Result); + return Result; +} +//--------------------------------------------------------------------------- +bool TMsgSocket::PacketReady(int Size) +{ + return (WaitingData()>=Size); +} +//--------------------------------------------------------------------------- +int TMsgSocket::Receive(void *Data, int BufSize, int &SizeRecvd) +{ + LastTcpError=0; + if (CanRead(RecvTimeout)) + { + SizeRecvd=recv(FSocket ,(char*)Data ,BufSize ,MSG_NOSIGNAL ); + + if (SizeRecvd>0) // something read (default case) + LastTcpError=0; + else + if (SizeRecvd==0) + LastTcpError = WSAECONNRESET; // Connection reset by Peer + else + LastTcpError=GetLastSocketError(); // we need to know what happened + } + else + LastTcpError = WSAETIMEDOUT; + + if (LastTcpError==WSAECONNRESET) + Connected = false; + + return LastTcpError; +} +//--------------------------------------------------------------------------- +int TMsgSocket::RecvPacket(void *Data, int Size) +{ + int BytesRead; + WaitForData(Size, RecvTimeout); + if (LastTcpError==0) + { + BytesRead=recv(FSocket, (char*)Data, Size, MSG_NOSIGNAL); + if (BytesRead==0) + LastTcpError = WSAECONNRESET; // Connection reset by Peer + else + if (BytesRead<0) + LastTcpError = GetLastSocketError(); + } + else // After the timeout the bytes waiting were less then we expected + if (LastTcpError==WSAETIMEDOUT) + Purge(); + + if (LastTcpError==WSAECONNRESET) + Connected =false; + + return LastTcpError; +} +//--------------------------------------------------------------------------- +int TMsgSocket::PeekPacket(void *Data, int Size) +{ + int BytesRead; + WaitForData(Size, RecvTimeout); + if (LastTcpError==0) + { + BytesRead=recv(FSocket, (char*)Data, Size, MSG_PEEK | MSG_NOSIGNAL ); + if (BytesRead==0) + LastTcpError = WSAECONNRESET; // Connection reset by Peer + else + if (BytesRead<0) + LastTcpError = GetLastSocketError(); + } + else // After the timeout the bytes waiting were less then we expected + if (LastTcpError==WSAETIMEDOUT) + Purge(); + + if (LastTcpError==WSAECONNRESET) + Connected =false; + + return LastTcpError; +} +//--------------------------------------------------------------------------- +bool TMsgSocket::Execute() +{ + return true; +} +//============================================================================== +// PING +//============================================================================== + +static int PingKind; + +//--------------------------------------------------------------------------- +// RAW Socket Pinger +//--------------------------------------------------------------------------- +TRawSocketPinger::TRawSocketPinger() +{ + FSocket =socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); + FId =word(size_t(this)); + FSeq =0; +} +//--------------------------------------------------------------------------- +TRawSocketPinger::~TRawSocketPinger() +{ + if (FSocket!=INVALID_SOCKET) + { + #ifdef OS_WINDOWS + closesocket(FSocket); + #else + close(FSocket); + #endif + FSocket=INVALID_SOCKET; + }; +} +//--------------------------------------------------------------------------- +void TRawSocketPinger::InitPacket() +{ + memset(&IcmpBuffer,0,ICmpBufferSize); + FSeq++; + + SendPacket=PIcmpPacket(pbyte(&IcmpBuffer)+sizeof(TIPHeader)); + SendPacket->Header.ic_type=ICMP_ECHORQ; + SendPacket->Header.ic_code=0; + SendPacket->Header.ic_cksum=0; + SendPacket->Header.ic_id=FId; + SendPacket->Header.ic_seq=FSeq; + + memset(&SendPacket->Data,0,sizeof(SendPacket->Data)); + SendPacket->Header.ic_cksum=PacketChecksum(); +} +//--------------------------------------------------------------------------- +word TRawSocketPinger::PacketChecksum() +{ + word *P = (word*)(SendPacket); + longword Sum = 0; + int c; + for (c = 0; c < int(sizeof(TIcmpPacket) / 2); c++) { + Sum+=*P; + P++; + } + Sum=(Sum >> 16) + (Sum & 0xFFFF); + Sum=Sum+(Sum >> 16); + return word(~Sum); +} +//--------------------------------------------------------------------------- +bool TRawSocketPinger::CanRead(int Timeout) +{ + timeval TimeV; + int64_t x; + fd_set FDset; + + TimeV.tv_usec = (Timeout % 1000) * 1000; + TimeV.tv_sec = Timeout / 1000; + + FD_ZERO(&FDset); + FD_SET(FSocket, &FDset); + + x = select(FSocket + 1, &FDset, NULL, NULL, &TimeV); //<-Ignore this warning in 64bit Visual Studio + if (x==(int)(SOCKET_ERROR)) + x=0; + return (x > 0); +} +//--------------------------------------------------------------------------- +bool TRawSocketPinger::Ping(longword ip_addr, int Timeout) +{ + sockaddr_in LSockAddr; + sockaddr_in RSockAddr; + PIcmpReply Reply; + + if (FSocket==INVALID_SOCKET) + return true; + + // Init packet + InitPacket(); + Reply=PIcmpReply(&IcmpBuffer); + // Init Remote and Local Addresses struct + RSockAddr.sin_family=AF_INET; + RSockAddr.sin_port=0; + RSockAddr.sin_addr.s_addr=ip_addr; + + LSockAddr.sin_family=AF_INET; + LSockAddr.sin_port=0; + LSockAddr.sin_addr.s_addr=inet_addr("0.0.0.0"); + + // Bind to local + if (bind(FSocket, (struct sockaddr*)&LSockAddr, sizeof(sockaddr_in))!=0) + return false; + // Connect to remote (not a really TCP connection, only to setup the socket) + if (connect(FSocket, (struct sockaddr*)&RSockAddr, sizeof(sockaddr_in))!=0) + return false; + // Send ICMP packet + if (send(FSocket, (char*)SendPacket, sizeof(TIcmpPacket), MSG_NOSIGNAL)!=int(sizeof(TIcmpPacket))) + return false; + // Wait for a reply + if (!CanRead(Timeout)) + return false;// time expired + // Get the answer + if (recv(FSocket, (char*)&IcmpBuffer, ICmpBufferSize, MSG_NOSIGNAL)IPH.ip_src==RSockAddr.sin_addr.s_addr) && // the peer is what we are looking for + (Reply->ICmpReply.Header.ic_type==ICMP_ECHORP); // type = reply +} +//--------------------------------------------------------------------------- +// Pinger +//--------------------------------------------------------------------------- +TPinger::TPinger() +{ +} +//--------------------------------------------------------------------------- +TPinger::~TPinger() +{ +} +//--------------------------------------------------------------------------- +bool TPinger::RawPing(longword ip_addr, int Timeout) +{ + PRawSocketPinger RawPinger = new TRawSocketPinger(); + bool Result; + Result=RawPinger->Ping(ip_addr, Timeout); + delete RawPinger; + return Result; +} +//--------------------------------------------------------------------------- +bool TPinger::Ping(char *Host, int Timeout) +{ + longword Addr; + Addr=inet_addr(Host); + return Ping(Addr, Timeout); +} +//--------------------------------------------------------------------------- +bool TPinger::Ping(longword ip_addr, int Timeout) +{ + if (PingKind==pkRawSocket) + return RawPing(ip_addr, Timeout); + else + return true; // we still need to continue +} +//--------------------------------------------------------------------------- +// Checks if raw sockets are allowed +//--------------------------------------------------------------------------- +bool RawSocketsCheck() +{ + socket_t RawSocket; + bool Result; + RawSocket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); + + Result=RawSocket != INVALID_SOCKET; + if (Result) + #ifdef OS_WINDOWS + closesocket(RawSocket); + #else + close(RawSocket); + #endif + + return Result; +} +//--------------------------------------------------------------------------- +// Sockets init +// - Check for raw socket +//--------------------------------------------------------------------------- +SocketsLayer::SocketsLayer() +{ + if (RawSocketsCheck()) + PingKind=pkRawSocket; + else + PingKind=pkCannotPing; +} + +SocketsLayer::~SocketsLayer() +{ +} + + diff --git a/APP_Framework/Framework/control/plc/interoperability/s7/snap_msgsock.h b/APP_Framework/Framework/control/plc/interoperability/s7/snap_msgsock.h new file mode 100644 index 000000000..faf9a79de --- /dev/null +++ b/APP_Framework/Framework/control/plc/interoperability/s7/snap_msgsock.h @@ -0,0 +1,308 @@ +/*=============================================================================| +| PROJECT SNAP7 1.3.0 | +|==============================================================================| +| Copyright (C) 2013, 2015 Davide Nardella | +| All rights reserved. | +|==============================================================================| +| SNAP7 is free software: you can redistribute it and/or modify | +| it under the terms of the Lesser GNU General Public License as published by | +| the Free Software Foundation, either version 3 of the License, or | +| (at your option) any later version. | +| | +| It means that you can distribute your commercial software linked with | +| SNAP7 without the requirement to distribute the source code of your | +| application and without the requirement that your application be itself | +| distributed under LGPL. | +| | +| SNAP7 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 | +| Lesser GNU General Public License for more details. | +| | +| You should have received a copy of the GNU General Public License and a | +| copy of Lesser GNU General Public License along with Snap7. | +| If not, see http://www.gnu.org/licenses/ | +|=============================================================================*/ +#ifndef snap_msgsock_h +#define snap_msgsock_h +//--------------------------------------------------------------------------- +#include "snap_platform.h" +#include "snap_sysutils.h" +//---------------------------------------------------------------------------- + +//---------------------------------------------------------------------------- +// Non blocking connection to avoid root priviledges under UNIX +// i.e. raw socket pinger is not more used. +// Thanks to Rolf Stalder that made it ;) +//---------------------------------------------------------------------------- +#include +//---------------------------------------------------------------------------- +typedef int socket_t; + +//---------------------------------------------------------------------------- +#define SD_RECEIVE 0x00 +#define SD_SEND 0x01 +#define SD_BOTH 0x02 +#define MaxPacketSize 65536 + +//---------------------------------------------------------------------------- +// re-define next constants + +#define INVALID_SOCKET (socket_t)(~0) +#define SOCKET_ERROR (-1) + +#define WSAEINTR EINTR +#define WSAEBADF EBADF +#define WSAEACCES EACCES +#define WSAEFAULT EFAULT +#define WSAEINVAL EINVAL +#define WSAEMFILE EMFILE +#define WSAEWOULDBLOCK EWOULDBLOCK +#define WSAEINPROGRESS EINPROGRESS +#define WSAEALREADY EALREADY +#define WSAENOTSOCK ENOTSOCK +#define WSAEDESTADDRREQ EDESTADDRREQ +#define WSAEMSGSIZE EMSGSIZE +#define WSAEPROTOTYPE EPROTOTYPE +#define WSAENOPROTOOPT ENOPROTOOPT +#define WSAEPROTONOSUPPORT EPROTONOSUPPORT +#define WSAESOCKTNOSUPPORT ESOCKTNOSUPPORT +#define WSAEOPNOTSUPP EOPNOTSUPP +#define WSAEPFNOSUPPORT EPFNOSUPPORT +#define WSAEAFNOSUPPORT EAFNOSUPPORT +#define WSAEADDRINUSE EADDRINUSE +#define WSAEADDRNOTAVAIL EADDRNOTAVAIL +#define WSAENETDOWN ENETDOWN +#define WSAENETUNREACH ENETUNREACH +#define WSAENETRESET ENETRESET +#define WSAECONNABORTED ECONNABORTED +#define WSAECONNRESET ECONNRESET +#define WSAENOBUFS ENOBUFS +#define WSAEISCONN EISCONN +#define WSAENOTCONN ENOTCONN +#define WSAESHUTDOWN ESHUTDOWN +#define WSAETOOMANYREFS ETOOMANYREFS +#define WSAETIMEDOUT ETIMEDOUT +#define WSAECONNREFUSED ECONNREFUSED +#define WSAELOOP ELOOP +#define WSAENAMETOOLONG ENAMETOOLONG +#define WSAEHOSTDOWN EHOSTDOWN +#define WSAEHOSTUNREACH EHOSTUNREACH +#define WSAENOTEMPTY ENOTEMPTY +#define WSAEUSERS EUSERS +#define WSAEDQUOT EDQUOT +#define WSAESTALE ESTALE +#define WSAEREMOTE EREMOTE + +#define WSAEINVALIDADDRESS 12001 + +#define ICmpBufferSize 4096 +typedef byte TIcmpBuffer[ICmpBufferSize]; + +// Ping result +#define PR_CANNOT_PERFORM -1 // cannot ping : + // unix : no root rights or SUID flag set to + // open raw sockets + // windows : neither helper DLL found nor raw + // sockets can be opened (no administrator rights) + // In this case the execution continues whitout + // the benefit of the smart-connect. + +#define PR_SUCCESS 0 // Host found +#define PR_ERROR 1 // Ping Error, Ping was performed but ... + // - host didn't replied (not found) + // - routing error + // - TTL expired + // - ... all other icmp error that we don't need + // to know. + +// Ping Kind +#define pkCannotPing 1 // see PR_CANNOT_PERFORM comments +#define pkWinHelper 2 // use iphlpapi.dll (only windows) +#define pkRawSocket 3 // use raw sockets (unix/windows) + +const byte ICMP_ECHORP = 0; // ECHO Reply +const byte ICMP_ECHORQ = 8; // ECHO Request +//--------------------------------------------------------------------------- +// RAW SOCKET PING STRUCTS +//--------------------------------------------------------------------------- +#pragma pack(1) +typedef struct{ + byte ip_hl_v; + byte ip_tos; + word ip_len; + word ip_id ; + word ip_off; + byte ip_ttl; + byte ip_p; + word ip_sum; + longword ip_src; + longword ip_dst; +}TIPHeader; + +typedef struct{ + byte ic_type; // Type of message + byte ic_code; // Code + word ic_cksum; // 16 bit checksum + word ic_id; // ID (ic1 : ipv4) + word ic_seq; // Sequence +}TIcmpHeader; + +typedef struct{ + TIcmpHeader Header; + byte Data[32]; // use the well known default +}TIcmpPacket, *PIcmpPacket; + +typedef struct{ + TIPHeader IPH; + TIcmpPacket ICmpReply; +}TIcmpReply, *PIcmpReply; +#pragma pack() + +//--------------------------------------------------------------------------- +class TRawSocketPinger +{ +private: + socket_t FSocket; + PIcmpPacket SendPacket; + TIcmpBuffer IcmpBuffer; + word FId, FSeq; + void InitPacket(); + word PacketChecksum(); + bool CanRead(int Timeout); +public: + bool Ping(longword ip_addr, int Timeout); + TRawSocketPinger(); + ~TRawSocketPinger(); +}; +typedef TRawSocketPinger *PRawSocketPinger; +//--------------------------------------------------------------------------- +class TPinger +{ +private: + PRawSocketPinger RawPinger; + bool RawAvail; +#ifdef OS_WINDOWS + bool WinPing(longword ip_addr, int Timeout); +#endif + bool RawPing(longword ip_addr, int Timeout); +public: + TPinger(); + ~TPinger(); + bool Ping(char *Host, int Timeout); + bool Ping(longword ip_addr, int Timeout); +}; +typedef TPinger *PPinger; +//--------------------------------------------------------------------------- +class TSnapBase // base class endian-aware +{ +private: + bool LittleEndian; +protected: + longword SwapDWord(longword Value); + word SwapWord(word Value); +public: + TSnapBase(); +}; +//--------------------------------------------------------------------------- +class TMsgSocket : public TSnapBase +{ +private: + PPinger Pinger; + int GetLastSocketError(); + int SockCheck(int SockResult); + void DestroySocket(); + void SetSocketOptions(); + bool CanWrite(int Timeout); + void GetLocal(); + void GetRemote(); + void SetSin(sockaddr_in &sin, char *Address, u_short Port); + void GetSin(sockaddr_in sin, char *Address, u_short &Port); +protected: + socket_t FSocket; + sockaddr_in LocalSin; + sockaddr_in RemoteSin; + //-------------------------------------------------------------------------- + // low level socket + void CreateSocket(); + // Called when a socket is assigned externally + void GotSocket(); + // Returns how many bytes are ready to be read in the winsock buffer + int WaitingData(); + // Waits until there at least "size" bytes ready to be read or until receive timeout occurs + int WaitForData(int Size, int Timeout); + // Clear socket input buffer + void Purge(); +public: + longword ClientHandle; + longword LocalBind; + // Coordinates Address:Port + char LocalAddress[16]; + char RemoteAddress[16]; + word LocalPort; + word RemotePort; + // "speed" of the socket listener (used server-side) + int WorkInterval; + // Timeouts : 3 different values for fine tuning. + // Send timeout should be small since with work with small packets and TCP_NO_DELAY + // option, so we don't expect "time to wait". + // Recv timeout depends of equipment's processing time : we send a packet, the equipment + // processes the message, finally it sends the answer. In any case Recv timeout > Send Timeout. + // PingTimeout is the maximum time interval during which we expect that the PLC answers. + // By default is 750 ms, increase it if there are many switch/repeaters. + int PingTimeout; + int RecvTimeout; + int SendTimeout; + //int ConnTimeout; + // Output : Last operation error + int LastTcpError; + // Output : Connected to the remote Host/Peer/Client + bool Connected; + //-------------------------------------------------------------------------- + TMsgSocket(); + virtual ~TMsgSocket(); + // Returns true if "something" can be read during the Timeout interval.. + bool CanRead(int Timeout); + // Connects to a peer (using RemoteAddress and RemotePort) + int SckConnect(); // (client-side) + // Disconnects from a peer (gracefully) + void SckDisconnect(); + // Disconnects RAW + void ForceClose(); + // Binds to a local adapter (using LocalAddress and LocalPort) (server-side) + int SckBind(); + // Listens for an incoming connection (server-side) + int SckListen(); + // Set an external socket reference (tipically from a listener) + void SetSocket(socket_t s); + // Accepts an incoming connection returning a socket descriptor (server-side) + socket_t SckAccept(); + // Pings the peer before connecting + bool Ping(char *Host); + bool Ping(sockaddr_in Addr); + // Sends a packet + int SendPacket(void *Data, int Size); + // Returns true if a Packet at least of "Size" bytes is ready to be read + bool PacketReady(int Size); + // Receives everything + int Receive(void *Data, int BufSize, int & SizeRecvd); + // Receives a packet of size specified. + int RecvPacket(void *Data, int Size); + // Peeks a packet of size specified without extract it from the socket queue + int PeekPacket(void *Data, int Size); + virtual bool Execute(); +}; + +typedef TMsgSocket *PMsgSocket; +//--------------------------------------------------------------------------- +void Msg_CloseSocket(socket_t FSocket); +longword Msg_GetSockAddr(socket_t FSocket); +//--------------------------------------------------------------------------- +class SocketsLayer +{ +public: + SocketsLayer(); + ~SocketsLayer(); +}; + +#endif // snap_msgsock_h diff --git a/APP_Framework/Framework/control/plc/interoperability/s7/snap_platform.h b/APP_Framework/Framework/control/plc/interoperability/s7/snap_platform.h new file mode 100644 index 000000000..8dd3c226e --- /dev/null +++ b/APP_Framework/Framework/control/plc/interoperability/s7/snap_platform.h @@ -0,0 +1,68 @@ +/*=============================================================================| +| PROJECT SNAP7 1.4.1 | +|==============================================================================| +| Copyright (C) 2013, 2015 Davide Nardella | +| All rights reserved. | +|==============================================================================| +| SNAP7 is free software: you can redistribute it and/or modify | +| it under the terms of the Lesser GNU General Public License as published by | +| the Free Software Foundation, either version 3 of the License, or | +| (at your option) any later version. | +| | +| It means that you can distribute your commercial software linked with | +| SNAP7 without the requirement to distribute the source code of your | +| application and without the requirement that your application be itself | +| distributed under LGPL. | +| | +| SNAP7 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 | +| Lesser GNU General Public License for more details. | +| | +| You should have received a copy of the GNU General Public License and a | +| copy of Lesser GNU General Public License along with Snap7. | +| If not, see http://www.gnu.org/licenses/ | +|=============================================================================*/ +#ifndef snap_platform_h +#define snap_platform_h + +#include // XiUOS +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define PLATFORM_UNIX +#define POSIX + + +#define EXPORTSPEC extern "C" +#define S7API + + + +// Exact length types regardless of platform/processor +// We absolute need of them, all structs have an exact size that +// must be the same across the processor used 32/64 bit + +// *Use them* if you change/expand the code and avoid long, u_long and so on... + +typedef uint8_t byte; +typedef uint16_t word; +typedef uint32_t longword; +typedef byte *pbyte; +typedef word *pword; +typedef uintptr_t snap_obj; // multi platform/processor object reference + +#ifndef OS_WINDOWS +# define INFINITE 0XFFFFFFFF +#endif + + +#endif // snap_platform_h diff --git a/APP_Framework/Framework/control/plc/interoperability/s7/snap_sysutils.cpp b/APP_Framework/Framework/control/plc/interoperability/s7/snap_sysutils.cpp new file mode 100644 index 000000000..048323e5f --- /dev/null +++ b/APP_Framework/Framework/control/plc/interoperability/s7/snap_sysutils.cpp @@ -0,0 +1,48 @@ +/*=============================================================================| +| PROJECT SNAP7 1.3.0 | +|==============================================================================| +| Copyright (C) 2013, 2015 Davide Nardella | +| All rights reserved. | +|==============================================================================| +| SNAP7 is free software: you can redistribute it and/or modify | +| it under the terms of the Lesser GNU General Public License as published by | +| the Free Software Foundation, either version 3 of the License, or | +| (at your option) any later version. | +| | +| It means that you can distribute your commercial software linked with | +| SNAP7 without the requirement to distribute the source code of your | +| application and without the requirement that your application be itself | +| distributed under LGPL. | +| | +| SNAP7 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 | +| Lesser GNU General Public License for more details. | +| | +| You should have received a copy of the GNU General Public License and a | +| copy of Lesser GNU General Public License along with Snap7. | +| If not, see http://www.gnu.org/licenses/ | +|=============================================================================*/ + +#include "snap_sysutils.h" + +//--------------------------------------------------------------------------- +longword SysGetTick() +{ + return PrivGetTickTime(); +} +//--------------------------------------------------------------------------- +void SysSleep(longword Delay_ms) +{ + PrivTaskDelay(Delay_ms); +} +//--------------------------------------------------------------------------- +longword DeltaTime(longword &Elapsed) +{ + longword TheTime; + TheTime=SysGetTick(); + // Checks for rollover + if (TheTimeTerminated) + try + { + Thread->Execute(); + } catch (...) + { + }; + Thread->Closed = true; + if (Thread->FreeOnTerminate) + { + delete Thread; + }; + pthread_exit((void*)0); + return 0; // never reach, only to avoid compiler warning +} +//--------------------------------------------------------------------------- +TSnapThread::TSnapThread() +{ + Started = false; + Closed=false; + Terminated = false; + FreeOnTerminate = false; +} +//--------------------------------------------------------------------------- +TSnapThread::~TSnapThread() +{ + if (Started && !Closed) + { + Terminate(); + Join(); + }; +} +//--------------------------------------------------------------------------- +void TSnapThread::ThreadCreate() +{ + pthread_attr_t a; + pthread_attr_init(&a); + pthread_attr_setdetachstate(&a, PTHREAD_CREATE_DETACHED); + pthread_create(&th, &a, &ThreadProc, this); +} +//--------------------------------------------------------------------------- +void TSnapThread::Start() +{ + if (!Started) + { + ThreadCreate(); + Started = true; + } +} +//--------------------------------------------------------------------------- +void TSnapThread::Terminate() +{ + Terminated = true; +} +//--------------------------------------------------------------------------- +void TSnapThread::Kill() +{ + if (Started && !Closed) + { + ThreadKill(); + Closed = true; + } +} +//--------------------------------------------------------------------------- +void TSnapThread::Join() +{ + if (Started && !Closed) + { + ThreadJoin(); + Closed = true; + } +} +//--------------------------------------------------------------------------- +longword TSnapThread::WaitFor(uint64_t Timeout) +{ + if (Started) + { + if (!Closed) + return ThreadWait(Timeout); + else + return WAIT_OBJECT_0; + } + else + return WAIT_OBJECT_0; +} +//--------------------------------------------------------------------------- + diff --git a/APP_Framework/Framework/control/plc/interoperability/s7/snap_threads.h b/APP_Framework/Framework/control/plc/interoperability/s7/snap_threads.h new file mode 100644 index 000000000..34545485d --- /dev/null +++ b/APP_Framework/Framework/control/plc/interoperability/s7/snap_threads.h @@ -0,0 +1,222 @@ +/*=============================================================================| +| PROJECT SNAP7 1.3.0 | +|==============================================================================| +| Copyright (C) 2013, 2015 Davide Nardella | +| All rights reserved. | +|==============================================================================| +| SNAP7 is free software: you can redistribute it and/or modify | +| it under the terms of the Lesser GNU General Public License as published by | +| the Free Software Foundation, either version 3 of the License, or | +| (at your option) any later version. | +| | +| It means that you can distribute your commercial software linked with | +| SNAP7 without the requirement to distribute the source code of your | +| application and without the requirement that your application be itself | +| distributed under LGPL. | +| | +| SNAP7 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 | +| Lesser GNU General Public License for more details. | +| | +| You should have received a copy of the GNU General Public License and a | +| copy of Lesser GNU General Public License along with Snap7. | +| If not, see http://www.gnu.org/licenses/ | +|=============================================================================*/ +#ifndef snap_threads_h +#define snap_threads_h +//--------------------------------------------------------------------------- +#include "snap_platform.h" +#include "snap_sysutils.h" +//--------------------------------------------------------------------------- + +class TSnapCriticalSection +{ +private: + pthread_mutex_t mx; +// int result; +public: + + TSnapCriticalSection() + { + /* + + This would be the best code, but very often it causes a segmentation fault in many + unix systems (the problem seems to be pthread_mutexattr_destroy()). + So, to avoid problems in future kernel/libc release, we use the "safe" default. + + pthread_mutexattr_t mxAttr; + pthread_mutexattr_settype(&mxAttr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&mx, &mxAttr); + pthread_mutexattr_destroy(&mxAttr); + + */ + pthread_mutex_init(&mx, 0); + }; + + ~TSnapCriticalSection() + { + pthread_mutex_destroy(&mx); + }; + + void Enter() + { + pthread_mutex_lock(&mx); + }; + + void Leave() + { + pthread_mutex_unlock(&mx); + }; + + bool TryEnter() + { + return pthread_mutex_trylock(&mx) == 0; + }; +}; +typedef TSnapCriticalSection *PSnapCriticalSection; + +//--------------------------------------------------------------------------- +const longword WAIT_OBJECT_0 = 0x00000000L; +const longword WAIT_ABANDONED = 0x00000080L; +const longword WAIT_TIMEOUT = 0x00000102L; +const longword WAIT_FAILED = 0xFFFFFFFFL; + +class TSnapEvent +{ +private: + pthread_cond_t CVariable; + pthread_mutex_t Mutex; + bool AutoReset; + bool State; +public: + + TSnapEvent(bool ManualReset) + { + AutoReset = !ManualReset; + if (pthread_cond_init(&CVariable, 0) == 0) + pthread_mutex_init(&Mutex, 0); + State = false; + } + + ~TSnapEvent() + { + pthread_cond_destroy(&CVariable); + pthread_mutex_destroy(&Mutex); + }; + + void Set() + { + pthread_mutex_lock(&Mutex); + State = true; + if (AutoReset) + pthread_cond_signal(&CVariable); + else + pthread_cond_broadcast(&CVariable); + pthread_mutex_unlock(&Mutex); + }; + + void Reset() + { + pthread_mutex_lock(&Mutex); + State = false; + pthread_mutex_unlock(&Mutex); + } + + longword WaitForever() + { + pthread_mutex_lock(&Mutex); + while (!State) // <-- to avoid spurious wakeups + pthread_cond_wait(&CVariable, &Mutex); + if (AutoReset) + State = false; + pthread_mutex_unlock(&Mutex); + return WAIT_OBJECT_0; + }; + + longword WaitFor(int64_t Timeout) + { + longword Result = WAIT_OBJECT_0; + if (Timeout == 0) + Timeout = 1; // 0 is not allowed + + if (Timeout > 0) + { + pthread_mutex_lock(&Mutex); + if (!State) + { + timespec ts; + timeval tv; + gettimeofday(&tv, NULL); + uint64_t nsecs = ((uint64_t) tv.tv_sec) * 1000000000 + + Timeout * 1000000 + + ((uint64_t) tv.tv_usec) * 1000; + ts.tv_sec = nsecs / 1000000000; + ts.tv_nsec = (nsecs - ((uint64_t) ts.tv_sec) * 1000000000); + do { + Result = pthread_cond_timedwait(&CVariable, &Mutex, &ts); + if (Result == ETIMEDOUT) + Result = WAIT_TIMEOUT; + } while (Result == 0 && !State); + } + else + if (AutoReset) // take the ownership + State = false; + pthread_mutex_unlock(&Mutex); + return Result; + } + else // Timeout<0 + return WaitForever(); + }; +}; +typedef TSnapEvent *PSnapEvent; +//--------------------------------------------------------------------------- +class TSnapThread +{ +private: + pthread_t th; + bool FCreateSuspended; + void ThreadCreate(); + + void ThreadJoin() + { + pthread_join(th, 0); + }; + + void ThreadKill() + { + pthread_cancel(th); + }; + + longword ThreadWait(uint64_t Timeout) + { + longword Elapsed = SysGetTick(); + while (!Closed && !(DeltaTime(Elapsed) > Timeout)) + SysSleep(100); + if (Closed) + return WAIT_OBJECT_0; + else + return WAIT_TIMEOUT; + }; +protected: + bool Started; +public: + bool Terminated; + bool Closed; + bool FreeOnTerminate; + TSnapThread(); + virtual ~TSnapThread(); + + virtual void Execute() + { + }; + void Start(); + void Terminate(); + void Kill(); + void Join(); + longword WaitFor(uint64_t Timeout); +}; +typedef TSnapThread *PSnapThread; + +//--------------------------------------------------------------------------- +#endif // snap_threads_h \ No newline at end of file diff --git a/APP_Framework/Framework/transform_layer/rtthread/transform.c b/APP_Framework/Framework/transform_layer/rtthread/transform.c index 15226a9d7..c3d41ce12 100644 --- a/APP_Framework/Framework/transform_layer/rtthread/transform.c +++ b/APP_Framework/Framework/transform_layer/rtthread/transform.c @@ -101,6 +101,11 @@ int PrivTaskDelay(int32_t ms) rt_thread_mdelay(ms); } +uint32_t PrivGetTickTime() +{ + return rt_tick_get_millisecond(); +} + /*********************fs**************************/ /************************Driver Posix Transform***********************/ diff --git a/APP_Framework/Framework/transform_layer/rtthread/transform.h b/APP_Framework/Framework/transform_layer/rtthread/transform.h index a6db34732..1210976dc 100644 --- a/APP_Framework/Framework/transform_layer/rtthread/transform.h +++ b/APP_Framework/Framework/transform_layer/rtthread/transform.h @@ -179,6 +179,7 @@ int PrivTaskStartup(pthread_t *thread); int PrivTaskDelete(pthread_t thread, int sig); void PrivTaskQuit(void *value_ptr); int PrivTaskDelay(int32_t ms); +uint32_t PrivGetTickTime(); /*********************driver*************************/ diff --git a/APP_Framework/Framework/transform_layer/xiuos/transform.c b/APP_Framework/Framework/transform_layer/xiuos/transform.c index e80102a65..ab4206d8c 100644 --- a/APP_Framework/Framework/transform_layer/xiuos/transform.c +++ b/APP_Framework/Framework/transform_layer/xiuos/transform.c @@ -102,6 +102,11 @@ int PrivTaskDelay(int32_t ms) UserTaskDelay(ms); } +uint32_t PrivGetTickTime() +{ + return CalculteTimeMsFromTick(CurrentTicksGain()); +} + /*********************fs**************************/ #ifdef FS_VFS /************************Driver Posix Transform***********************/ diff --git a/APP_Framework/Framework/transform_layer/xiuos/transform.h b/APP_Framework/Framework/transform_layer/xiuos/transform.h index b2996fd44..36ec20774 100644 --- a/APP_Framework/Framework/transform_layer/xiuos/transform.h +++ b/APP_Framework/Framework/transform_layer/xiuos/transform.h @@ -172,6 +172,7 @@ int PrivTaskDelete(pthread_t thread, int sig); void PrivTaskQuit(void *value_ptr); int PrivTaskDelay(int32_t ms); int PrivUserTaskSearch(void); +uint32_t PrivGetTickTime(); /*********************driver*************************/ diff --git a/Ubiquitous/XiUOS/resources/ethernet/LwIP/include/lwip/sockets.h b/Ubiquitous/XiUOS/resources/ethernet/LwIP/include/lwip/sockets.h index a07937e3c..9492e78ef 100644 --- a/Ubiquitous/XiUOS/resources/ethernet/LwIP/include/lwip/sockets.h +++ b/Ubiquitous/XiUOS/resources/ethernet/LwIP/include/lwip/sockets.h @@ -55,6 +55,8 @@ extern "C" { #endif +#define SOMAXCONN 8 + /* If your port already typedef's sa_family_t, define SA_FAMILY_T_DEFINED to prevent this code from redefining it. */ #if !defined(sa_family_t) && !defined(SA_FAMILY_T_DEFINED)