migrate s7
This commit is contained in:
parent
3a35bee743
commit
bc91dc1ae2
|
@ -6,6 +6,10 @@ ifeq ($(CONFIG_USING_CONTROL_PLC_OPCUA), y)
|
||||||
SRC_DIR += opcua_demo
|
SRC_DIR += opcua_demo
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_USING_CONTROL_PLC_S7), y)
|
||||||
|
SRC_DIR += s7_demo
|
||||||
|
endif
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
include $(KERNEL_ROOT)/compiler.mk
|
include $(KERNEL_ROOT)/compiler.mk
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
SRC_FILES :=s7_demo.c
|
||||||
|
|
||||||
|
include $(KERNEL_ROOT)/compiler.mk
|
|
@ -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);
|
||||||
|
}
|
|
@ -4,3 +4,7 @@ menuconfig USING_CONTROL_PLC_OPCUA
|
||||||
default y
|
default y
|
||||||
depends on RESOURCES_LWIP
|
depends on RESOURCES_LWIP
|
||||||
|
|
||||||
|
menuconfig CONFIG_USING_CONTROL_PLC_S7
|
||||||
|
bool "PLC support S7"
|
||||||
|
default y
|
||||||
|
depends on RESOURCES_LWIP
|
|
@ -6,6 +6,10 @@ ifeq ($(CONFIG_USING_CONTROL_PLC_OPCUA), y)
|
||||||
SRC_DIR += opcua
|
SRC_DIR += opcua
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_USING_CONTROL_PLC_S7), y)
|
||||||
|
SRC_DIR += s7
|
||||||
|
endif
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
SRC_FILES += interoperability.c
|
SRC_FILES += interoperability.c
|
||||||
|
|
|
@ -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
|
|
@ -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();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -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 <stdio.h>
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
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->HLength<sizeof( TCOTP_DT )-1 ) || // Checks ISO 8073 header length
|
||||||
|
( Info->PDUType!=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 (IsoLen<DataHeaderSize )
|
||||||
|
{
|
||||||
|
PduKind=pkInvalidPDU;
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
// Here IsoLen>DataHeaderSize : 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;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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;
|
||||||
|
}
|
|
@ -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
|
|
@ -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;
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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 <IP> [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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#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
|
|
@ -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()<Size) && (LastTcpError==0))
|
||||||
|
{
|
||||||
|
// Checks timeout
|
||||||
|
if (DeltaTime(Elapsed)>=(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)<int(sizeof(TIcmpReply)))
|
||||||
|
return false;
|
||||||
|
// Check the answer
|
||||||
|
return (Reply->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()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 <fcntl.h>
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
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
|
|
@ -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 <transform.h> // XiUOS
|
||||||
|
#include <lwip/tcp.h>
|
||||||
|
#include <lwip/errno.h>
|
||||||
|
#include <lwip/sockets.h>
|
||||||
|
#include <lwip/inet.h>
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#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
|
|
@ -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 (TheTime<Elapsed)
|
||||||
|
Elapsed=0;
|
||||||
|
return TheTime-Elapsed;
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*=============================================================================|
|
||||||
|
| 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_sysutils_h
|
||||||
|
#define snap_sysutils_h
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
#include "snap_platform.h"
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
longword SysGetTick();
|
||||||
|
void SysSleep(longword Delay_ms);
|
||||||
|
longword DeltaTime(longword &Elapsed);
|
||||||
|
|
||||||
|
#endif // snap_sysutils_h
|
|
@ -0,0 +1,125 @@
|
||||||
|
/*=============================================================================|
|
||||||
|
| 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_threads.h"
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void* ThreadProc(void* param)
|
||||||
|
{
|
||||||
|
PSnapThread Thread;
|
||||||
|
// Unix but not Solaris
|
||||||
|
int last_type, last_state;
|
||||||
|
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &last_type);
|
||||||
|
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &last_state);
|
||||||
|
Thread = PSnapThread(param);
|
||||||
|
|
||||||
|
if (!Thread->Terminated)
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
|
@ -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
|
|
@ -101,6 +101,11 @@ int PrivTaskDelay(int32_t ms)
|
||||||
rt_thread_mdelay(ms);
|
rt_thread_mdelay(ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t PrivGetTickTime()
|
||||||
|
{
|
||||||
|
return rt_tick_get_millisecond();
|
||||||
|
}
|
||||||
|
|
||||||
/*********************fs**************************/
|
/*********************fs**************************/
|
||||||
|
|
||||||
/************************Driver Posix Transform***********************/
|
/************************Driver Posix Transform***********************/
|
||||||
|
|
|
@ -179,6 +179,7 @@ int PrivTaskStartup(pthread_t *thread);
|
||||||
int PrivTaskDelete(pthread_t thread, int sig);
|
int PrivTaskDelete(pthread_t thread, int sig);
|
||||||
void PrivTaskQuit(void *value_ptr);
|
void PrivTaskQuit(void *value_ptr);
|
||||||
int PrivTaskDelay(int32_t ms);
|
int PrivTaskDelay(int32_t ms);
|
||||||
|
uint32_t PrivGetTickTime();
|
||||||
|
|
||||||
/*********************driver*************************/
|
/*********************driver*************************/
|
||||||
|
|
||||||
|
|
|
@ -102,6 +102,11 @@ int PrivTaskDelay(int32_t ms)
|
||||||
UserTaskDelay(ms);
|
UserTaskDelay(ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t PrivGetTickTime()
|
||||||
|
{
|
||||||
|
return CalculteTimeMsFromTick(CurrentTicksGain());
|
||||||
|
}
|
||||||
|
|
||||||
/*********************fs**************************/
|
/*********************fs**************************/
|
||||||
#ifdef FS_VFS
|
#ifdef FS_VFS
|
||||||
/************************Driver Posix Transform***********************/
|
/************************Driver Posix Transform***********************/
|
||||||
|
|
|
@ -172,6 +172,7 @@ int PrivTaskDelete(pthread_t thread, int sig);
|
||||||
void PrivTaskQuit(void *value_ptr);
|
void PrivTaskQuit(void *value_ptr);
|
||||||
int PrivTaskDelay(int32_t ms);
|
int PrivTaskDelay(int32_t ms);
|
||||||
int PrivUserTaskSearch(void);
|
int PrivUserTaskSearch(void);
|
||||||
|
uint32_t PrivGetTickTime();
|
||||||
|
|
||||||
/*********************driver*************************/
|
/*********************driver*************************/
|
||||||
|
|
||||||
|
|
|
@ -55,6 +55,8 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define SOMAXCONN 8
|
||||||
|
|
||||||
/* If your port already typedef's sa_family_t, define SA_FAMILY_T_DEFINED
|
/* If your port already typedef's sa_family_t, define SA_FAMILY_T_DEFINED
|
||||||
to prevent this code from redefining it. */
|
to prevent this code from redefining it. */
|
||||||
#if !defined(sa_family_t) && !defined(SA_FAMILY_T_DEFINED)
|
#if !defined(sa_family_t) && !defined(SA_FAMILY_T_DEFINED)
|
||||||
|
|
Loading…
Reference in New Issue