mirror of
https://github.com/thiagoralves/OpenPLC_v3.git
synced 2025-12-06 17:05:50 +08:00
Compare commits
59 Commits
6f41f757e7
...
76036ec9a7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
76036ec9a7 | ||
|
|
6ab236ee46 | ||
|
|
d4d2a2a151 | ||
|
|
ca997e5b16 | ||
|
|
f1577320e6 | ||
|
|
8d570a1e73 | ||
|
|
57d115dd3d | ||
|
|
07becdbd26 | ||
|
|
685ebf8556 | ||
|
|
f3da2df734 | ||
|
|
ddcae72b01 | ||
|
|
6eef098fcb | ||
|
|
7d93319f71 | ||
|
|
4570809599 | ||
|
|
bcfd91af33 | ||
|
|
cad11eef1b | ||
|
|
61aba319ec | ||
|
|
2ea0ebc1bd | ||
|
|
812d200200 | ||
|
|
f0465d7426 | ||
|
|
947de75ae1 | ||
|
|
b47b2ebd57 | ||
|
|
2b762ef921 | ||
|
|
792395af0f | ||
|
|
a6fbbd93d0 | ||
|
|
685cde24c6 | ||
|
|
2dbcdc9336 | ||
|
|
c18d214efd | ||
|
|
734e7393c0 | ||
|
|
a735060b1f | ||
|
|
02754b3405 | ||
|
|
b64c74be55 | ||
|
|
7cfc8f65a1 | ||
|
|
6c03b965fd | ||
|
|
71b891ac16 | ||
|
|
13a6c8ee7f | ||
|
|
c93f3cee81 | ||
|
|
a999b4749d | ||
|
|
9ebadf8ccb | ||
|
|
ac6dae30c3 | ||
|
|
4bb230a9c0 | ||
|
|
10491c693c | ||
|
|
f997d091bd | ||
|
|
d47d41e52a | ||
|
|
259e0543a5 | ||
|
|
b25902e4c8 | ||
|
|
9e3ccdfc3b | ||
|
|
35f2845e59 | ||
|
|
d83b70e60c | ||
|
|
698da2dc6c | ||
|
|
052ba55abc | ||
|
|
12399b0b2a | ||
|
|
931c1d41f7 | ||
|
|
61ed23f58a | ||
|
|
5556aeb587 | ||
|
|
dc115011c6 | ||
|
|
b46e93d063 | ||
|
|
8a9581590e | ||
|
|
4e0d67323b |
@@ -212,6 +212,14 @@ function install_libmodbus {
|
||||
fi
|
||||
}
|
||||
|
||||
function install_libsnap7 {
|
||||
echo "[LIBSNAP7]"
|
||||
cd "$OPENPLC_DIR/utils/snap7_src/build/linux"
|
||||
$1 make clean
|
||||
$1 make install || fail "Error installing Libsnap7"
|
||||
cd "$OPENPLC_DIR"
|
||||
}
|
||||
|
||||
function install_systemd_service() {
|
||||
if [ "$1" == "sudo" ]; then
|
||||
echo "[OPENPLC SERVICE]"
|
||||
@@ -245,6 +253,7 @@ function install_all_libs {
|
||||
install_opendnp3 "$1"
|
||||
disable_ethercat "$1"
|
||||
install_libmodbus "$1"
|
||||
install_libsnap7 "$1"
|
||||
}
|
||||
|
||||
function finalize_install {
|
||||
|
||||
Binary file not shown.
1
utils/snap7_src/build/bin/linux/readme.txt
Normal file
1
utils/snap7_src/build/bin/linux/readme.txt
Normal file
@@ -0,0 +1 @@
|
||||
This folder is empty, it will contain the linux library after the build
|
||||
BIN
utils/snap7_src/build/bin/win32/snap7.dll
Normal file
BIN
utils/snap7_src/build/bin/win32/snap7.dll
Normal file
Binary file not shown.
BIN
utils/snap7_src/build/bin/win32/snap7.lib
Normal file
BIN
utils/snap7_src/build/bin/win32/snap7.lib
Normal file
Binary file not shown.
BIN
utils/snap7_src/build/bin/win64/snap7.dll
Normal file
BIN
utils/snap7_src/build/bin/win64/snap7.dll
Normal file
Binary file not shown.
BIN
utils/snap7_src/build/bin/win64/snap7.lib
Normal file
BIN
utils/snap7_src/build/bin/win64/snap7.lib
Normal file
Binary file not shown.
111
utils/snap7_src/build/linux/makefile
Normal file
111
utils/snap7_src/build/linux/makefile
Normal file
@@ -0,0 +1,111 @@
|
||||
#
|
||||
# Common for every unix flavour (any changes will be reflected on all platforms)
|
||||
#
|
||||
CXXFLAGS := -O3 -fPIC -pedantic
|
||||
ConfigurationName :=Release
|
||||
IntermediateDirectory :=../temp
|
||||
OutDir := $(IntermediateDirectory)
|
||||
LinkerName :=g++
|
||||
SharedObjectLinkerName :=g++ -shared -fPIC
|
||||
DebugSwitch :=-gstab
|
||||
IncludeSwitch :=-I
|
||||
LibrarySwitch :=-l
|
||||
OutputSwitch :=-o
|
||||
LibraryPathSwitch :=-L
|
||||
PreprocessorSwitch :=-D
|
||||
SourceSwitch :=-c
|
||||
OutputFile :=../bin/linux/libsnap7.so
|
||||
PreprocessOnlySwitch :=-E
|
||||
ObjectsFileList :="filelist.txt"
|
||||
MakeDirCommand :=mkdir -p
|
||||
LinkOptions := -O3
|
||||
IncludePath := $(IncludeSwitch). $(IncludeSwitch)../../src/sys $(IncludeSwitch)../../src/core $(IncludeSwitch)../../src/lib
|
||||
Libs := $(LibrarySwitch)pthread $(LibrarySwitch)rt
|
||||
LibPath := $(LibraryPathSwitch).
|
||||
LibInstall := /usr/lib
|
||||
|
||||
##
|
||||
## Common variables (CXXFLAGS varies across platforms)
|
||||
##
|
||||
AR := ar rcus
|
||||
CXX := g++
|
||||
CC := gcc
|
||||
CFLAGS :=
|
||||
|
||||
##
|
||||
## User defined environment variables
|
||||
##
|
||||
Objects0=$(IntermediateDirectory)/sys_snap_msgsock.o $(IntermediateDirectory)/sys_snap_sysutils.o $(IntermediateDirectory)/sys_snap_tcpsrvr.o $(IntermediateDirectory)/sys_snap_threads.o $(IntermediateDirectory)/core_s7_client.o $(IntermediateDirectory)/core_s7_isotcp.o $(IntermediateDirectory)/core_s7_partner.o $(IntermediateDirectory)/core_s7_peer.o $(IntermediateDirectory)/core_s7_server.o $(IntermediateDirectory)/core_s7_text.o \
|
||||
$(IntermediateDirectory)/core_s7_micro_client.o $(IntermediateDirectory)/lib_snap7_libmain.o
|
||||
|
||||
Objects=$(Objects0)
|
||||
|
||||
##
|
||||
## Main Build Targets
|
||||
##
|
||||
.PHONY: all clean install PreBuild PostBuild
|
||||
all: $(OutputFile)
|
||||
|
||||
$(OutputFile): $(IntermediateDirectory)/.d $(Objects)
|
||||
@$(MakeDirCommand) $(@D)
|
||||
@$(MakeDirCommand) $(IntermediateDirectory)
|
||||
@echo $(Objects0) > $(ObjectsFileList)
|
||||
$(SharedObjectLinkerName) $(OutputSwitch)$(OutputFile) @$(ObjectsFileList) $(LibPath) $(Libs) $(LinkOptions)
|
||||
$(RM) $(ObjectsFileList)
|
||||
|
||||
$(IntermediateDirectory)/.d:
|
||||
@test -d ../temp || $(MakeDirCommand) ../temp
|
||||
|
||||
PreBuild:
|
||||
|
||||
PostBuild:
|
||||
|
||||
##
|
||||
## Objects
|
||||
##
|
||||
$(IntermediateDirectory)/sys_snap_msgsock.o:
|
||||
$(CXX) $(SourceSwitch) "../../src/sys/snap_msgsock.cpp" $(CXXFLAGS) -o $(IntermediateDirectory)/sys_snap_msgsock.o $(IncludePath)
|
||||
|
||||
$(IntermediateDirectory)/sys_snap_sysutils.o:
|
||||
$(CXX) $(SourceSwitch) "../../src/sys/snap_sysutils.cpp" $(CXXFLAGS) -o $(IntermediateDirectory)/sys_snap_sysutils.o $(IncludePath)
|
||||
|
||||
$(IntermediateDirectory)/sys_snap_tcpsrvr.o:
|
||||
$(CXX) $(SourceSwitch) "../../src/sys/snap_tcpsrvr.cpp" $(CXXFLAGS) -o $(IntermediateDirectory)/sys_snap_tcpsrvr.o $(IncludePath)
|
||||
|
||||
$(IntermediateDirectory)/sys_snap_threads.o:
|
||||
$(CXX) $(SourceSwitch) "../../src/sys/snap_threads.cpp" $(CXXFLAGS) -o $(IntermediateDirectory)/sys_snap_threads.o $(IncludePath)
|
||||
|
||||
$(IntermediateDirectory)/core_s7_client.o:
|
||||
$(CXX) $(SourceSwitch) "../../src/core/s7_client.cpp" $(CXXFLAGS) -o $(IntermediateDirectory)/core_s7_client.o $(IncludePath)
|
||||
|
||||
$(IntermediateDirectory)/core_s7_isotcp.o:
|
||||
$(CXX) $(SourceSwitch) "../../src/core/s7_isotcp.cpp" $(CXXFLAGS) -o $(IntermediateDirectory)/core_s7_isotcp.o $(IncludePath)
|
||||
|
||||
$(IntermediateDirectory)/core_s7_partner.o:
|
||||
$(CXX) $(SourceSwitch) "../../src/core/s7_partner.cpp" $(CXXFLAGS) -o $(IntermediateDirectory)/core_s7_partner.o $(IncludePath)
|
||||
|
||||
$(IntermediateDirectory)/core_s7_peer.o:
|
||||
$(CXX) $(SourceSwitch) "../../src/core/s7_peer.cpp" $(CXXFLAGS) -o $(IntermediateDirectory)/core_s7_peer.o $(IncludePath)
|
||||
|
||||
$(IntermediateDirectory)/core_s7_server.o:
|
||||
$(CXX) $(SourceSwitch) "../../src/core/s7_server.cpp" $(CXXFLAGS) -o $(IntermediateDirectory)/core_s7_server.o $(IncludePath)
|
||||
|
||||
$(IntermediateDirectory)/core_s7_text.o:
|
||||
$(CXX) $(SourceSwitch) "../../src/core/s7_text.cpp" $(CXXFLAGS) -o $(IntermediateDirectory)/core_s7_text.o $(IncludePath)
|
||||
|
||||
$(IntermediateDirectory)/core_s7_micro_client.o:
|
||||
$(CXX) $(SourceSwitch) "../../src/core/s7_micro_client.cpp" $(CXXFLAGS) -o $(IntermediateDirectory)/core_s7_micro_client.o $(IncludePath)
|
||||
|
||||
$(IntermediateDirectory)/lib_snap7_libmain.o:
|
||||
$(CXX) $(SourceSwitch) "../../src/lib/snap7_libmain.cpp" $(CXXFLAGS) -o $(IntermediateDirectory)/lib_snap7_libmain.o $(IncludePath)
|
||||
|
||||
##
|
||||
## Clean / Install
|
||||
##
|
||||
clean:
|
||||
$(RM) $(IntermediateDirectory)/*.o
|
||||
$(RM) $(OutputFile)
|
||||
|
||||
install: all
|
||||
cp -f $(OutputFile) $(LibInstall)
|
||||
|
||||
1
utils/snap7_src/build/temp/readme.txt
Normal file
1
utils/snap7_src/build/temp/readme.txt
Normal file
@@ -0,0 +1 @@
|
||||
This folder is empty, will contain intermediate files after the installation (you can delete the content)
|
||||
3
utils/snap7_src/build/windows/readme.txt
Normal file
3
utils/snap7_src/build/windows/readme.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
There is no Windows installation makefile.
|
||||
Instead, DLLs build witn Visual Studio 2022 are used, because they are smaller and faster.
|
||||
Anyway, if you want, the Snap7 distribution contains the makefiles to build the library using mingw(32/64).
|
||||
1
utils/snap7_src/readme.txt
Normal file
1
utils/snap7_src/readme.txt
Normal file
@@ -0,0 +1 @@
|
||||
This folder contains S7 Protocol implementation sources
|
||||
503
utils/snap7_src/src/core/s7_client.cpp
Normal file
503
utils/snap7_src/src/core/s7_client.cpp
Normal file
@@ -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();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
104
utils/snap7_src/src/core/s7_client.h
Normal file
104
utils/snap7_src/src/core/s7_client.h
Normal file
@@ -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
|
||||
1256
utils/snap7_src/src/core/s7_firmware.h
Normal file
1256
utils/snap7_src/src/core/s7_firmware.h
Normal file
File diff suppressed because it is too large
Load Diff
541
utils/snap7_src/src/core/s7_isotcp.cpp
Normal file
541
utils/snap7_src/src/core/s7_isotcp.cpp
Normal file
@@ -0,0 +1,541 @@
|
||||
/*=============================================================================|
|
||||
| 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"
|
||||
//---------------------------------------------------------------------------
|
||||
TIsoTcpSocket::TIsoTcpSocket()
|
||||
{
|
||||
RecvTimeout = 3000; // 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;
|
||||
|
||||
Result =SckConnect();
|
||||
if (Result==noError)
|
||||
{
|
||||
// Calcs the length
|
||||
Length =PDUSize(ControlPDU);
|
||||
// Send connection telegram
|
||||
SendPacket(ControlPDU, Length);
|
||||
if (LastTcpError==0)
|
||||
{
|
||||
TmpControlPDU = pbyte(ControlPDU);
|
||||
// Receives TPKT header (4 bytes)
|
||||
RecvPacket(TmpControlPDU, sizeof(TTPKT));
|
||||
if (LastTcpError==0)
|
||||
{
|
||||
// Calc the packet length
|
||||
Length =PDUSize(TmpControlPDU);
|
||||
// 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);
|
||||
if (LastTcpError==0)
|
||||
{
|
||||
// Finally checks the Connection Confirm telegram
|
||||
Result =CheckPDU(ControlPDU, pdu_type_CC);
|
||||
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;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
271
utils/snap7_src/src/core/s7_isotcp.h
Normal file
271
utils/snap7_src/src/core/s7_isotcp.h
Normal file
@@ -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
|
||||
3328
utils/snap7_src/src/core/s7_micro_client.cpp
Normal file
3328
utils/snap7_src/src/core/s7_micro_client.cpp
Normal file
File diff suppressed because it is too large
Load Diff
364
utils/snap7_src/src/core/s7_micro_client.h
Normal file
364
utils/snap7_src/src/core/s7_micro_client.h
Normal file
@@ -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);}
|
||||
};
|
||||
|
||||
typedef TSnap7MicroClient *PSnap7MicroClient;
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
#endif // s7_micro_client_h
|
||||
1178
utils/snap7_src/src/core/s7_partner.cpp
Normal file
1178
utils/snap7_src/src/core/s7_partner.cpp
Normal file
File diff suppressed because it is too large
Load Diff
284
utils/snap7_src/src/core/s7_partner.h
Normal file
284
utils/snap7_src/src/core/s7_partner.h
Normal file
@@ -0,0 +1,284 @@
|
||||
/*=============================================================================|
|
||||
| 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_partner_h
|
||||
#define s7_partner_h
|
||||
//---------------------------------------------------------------------------
|
||||
#include "snap_threads.h"
|
||||
#include "s7_peer.h"
|
||||
//---------------------------------------------------------------------------
|
||||
using namespace std;
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#define MaxPartners 256
|
||||
#define MaxAdapters 256
|
||||
#define csTimeout 1500 // Connection server destruction timeout
|
||||
|
||||
const int par_stopped = 0; // stopped
|
||||
const int par_connecting = 1; // running and active connecting
|
||||
const int par_waiting = 2; // running and waiting for a connection
|
||||
const int par_linked = 3; // running and connected
|
||||
const int par_sending = 4; // sending data
|
||||
const int par_receiving = 5; // receiving data
|
||||
const int par_binderror = 6; // error starting passive partner
|
||||
|
||||
const longword errParMask = 0xFFF00000;
|
||||
const longword errParBase = 0x000FFFFF;
|
||||
|
||||
const longword errParAddressInUse = 0x00200000;
|
||||
const longword errParNoRoom = 0x00300000;
|
||||
const longword errServerNoRoom = 0x00400000;
|
||||
const longword errParInvalidParams = 0x00500000;
|
||||
const longword errParNotLinked = 0x00600000;
|
||||
const longword errParBusy = 0x00700000;
|
||||
const longword errParFrameTimeout = 0x00800000;
|
||||
const longword errParInvalidPDU = 0x00900000;
|
||||
const longword errParSendTimeout = 0x00A00000;
|
||||
const longword errParRecvTimeout = 0x00B00000;
|
||||
const longword errParSendRefused = 0x00C00000;
|
||||
const longword errParNegotiatingPDU = 0x00D00000;
|
||||
const longword errParSendingBlock = 0x00E00000;
|
||||
const longword errParRecvingBlock = 0x00F00000;
|
||||
const longword errParBindError = 0x01000000;
|
||||
const longword errParDestroying = 0x01100000;
|
||||
const longword errParInvalidParamNumber = 0x01200000; // Invalid param (par_get/set_param)
|
||||
const longword errParCannotChangeParam = 0x01300000; // Cannot change because running
|
||||
const longword errParBufferTooSmall = 0x01400000; // Raised by LabVIEW wrapper
|
||||
|
||||
class TSnap7Partner;
|
||||
typedef TSnap7Partner *PSnap7Partner;
|
||||
|
||||
class TConnectionServer;
|
||||
typedef TConnectionServer *PConnectionServer;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// CONNECTION SERVERS MANAGER
|
||||
//------------------------------------------------------------------------------
|
||||
class TServersManager
|
||||
{
|
||||
private:
|
||||
PConnectionServer Servers[MaxAdapters];
|
||||
TSnapCriticalSection *cs;
|
||||
void Lock();
|
||||
void Unlock();
|
||||
int CreateServer(longword BindAddress, PConnectionServer &Server);
|
||||
void AddServer(PConnectionServer Server);
|
||||
public:
|
||||
int ServersCount;
|
||||
TServersManager();
|
||||
~TServersManager();
|
||||
|
||||
int GetServer(longword BindAddress, PConnectionServer &Server);
|
||||
void RemovePartner(PConnectionServer Server, PSnap7Partner Partner);
|
||||
|
||||
};
|
||||
typedef TServersManager *PServersManager;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// CONNECTION SERVER (Don't inherit from TcpSrv to avoid dependence)
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class TConnListenerThread : public TSnapThread
|
||||
{
|
||||
private:
|
||||
TMsgSocket *FListener;
|
||||
TConnectionServer *FServer;
|
||||
public:
|
||||
TConnListenerThread(TMsgSocket *Listener, TConnectionServer *Server)
|
||||
{
|
||||
FServer=Server;
|
||||
FListener=Listener;
|
||||
FreeOnTerminate=false;
|
||||
};
|
||||
void Execute();
|
||||
};
|
||||
typedef TConnListenerThread *PConnListenerThread;
|
||||
|
||||
|
||||
class TConnectionServer
|
||||
{
|
||||
private:
|
||||
TSnapCriticalSection *cs;
|
||||
bool FRunning;
|
||||
// Bind Address
|
||||
char FLocalAddress[16];
|
||||
// Server listener
|
||||
PConnListenerThread ServerThread;
|
||||
// Socket listener
|
||||
PMsgSocket SockListener;
|
||||
// Finds a partner bound to the address
|
||||
PSnap7Partner FindPartner(longword Address);
|
||||
// Locks the Partner list
|
||||
void Lock();
|
||||
// Unlocks the Partner list
|
||||
void Unlock();
|
||||
protected:
|
||||
// Workers list
|
||||
PSnap7Partner Partners[MaxPartners];
|
||||
bool Destroying;
|
||||
void Incoming(socket_t Sock);
|
||||
int Start();
|
||||
int FirstFree();
|
||||
public:
|
||||
int PartnersCount;
|
||||
longword LocalBind;
|
||||
TConnectionServer();
|
||||
~TConnectionServer();
|
||||
|
||||
int StartTo(const char *Address);
|
||||
void Stop();
|
||||
int RegisterPartner(PSnap7Partner Partner);
|
||||
void RemovePartner(PSnap7Partner Partner);
|
||||
friend class TConnListenerThread;
|
||||
};
|
||||
typedef TConnectionServer * PConnectionServer;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// PARTNER THREAD
|
||||
//------------------------------------------------------------------------------
|
||||
class TPartnerThread : public TSnapThread
|
||||
{
|
||||
private:
|
||||
TSnap7Partner *FPartner;
|
||||
longword FRecoveryTime;
|
||||
longword FKaElapsed;
|
||||
protected:
|
||||
void Execute();
|
||||
public:
|
||||
TPartnerThread(TSnap7Partner *Partner, longword RecoveryTime)
|
||||
{
|
||||
FPartner = Partner;
|
||||
FRecoveryTime =RecoveryTime;
|
||||
FreeOnTerminate =false;
|
||||
};
|
||||
~TPartnerThread(){};
|
||||
};
|
||||
typedef TPartnerThread *PPartnerThread;
|
||||
//------------------------------------------------------------------------------
|
||||
// S7 PARTNER
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
typedef struct{
|
||||
bool First;
|
||||
bool Done;
|
||||
uintptr_t Offset;
|
||||
longword TotalLength;
|
||||
longword In_R_ID;
|
||||
longword Elapsed;
|
||||
byte Seq_Out;
|
||||
}TRecvStatus;
|
||||
|
||||
typedef struct{
|
||||
bool Done;
|
||||
int Size;
|
||||
int Result;
|
||||
longword R_ID;
|
||||
longword Count;
|
||||
}TRecvLast;
|
||||
|
||||
extern "C" {
|
||||
typedef void (S7API *pfn_ParBRecvCallBack)(void * usrPtr, int opResult, longword R_ID, void *pdata, int Size);
|
||||
typedef void (S7API *pfn_ParBSendCompletion)(void * usrPtr, int opResult);
|
||||
}
|
||||
|
||||
class TSnap7Partner : public TSnap7Peer
|
||||
{
|
||||
private:
|
||||
PS7ReqHeader PDUH_in;
|
||||
void *FRecvUsrPtr;
|
||||
void *FSendUsrPtr;
|
||||
PSnapEvent SendEvt;
|
||||
PSnapEvent RecvEvt;
|
||||
PConnectionServer FServer;
|
||||
PPartnerThread FWorkerThread;
|
||||
bool FSendPending;
|
||||
bool FRecvPending;
|
||||
TRecvStatus FRecvStatus;
|
||||
TRecvLast FRecvLast;
|
||||
TPendingBuffer TxBuffer;
|
||||
TPendingBuffer RxBuffer;
|
||||
longword FSendElapsed;
|
||||
bool BindError;
|
||||
byte NextByte;
|
||||
pfn_ParBRecvCallBack OnBRecv;
|
||||
pfn_ParBSendCompletion OnBSend;
|
||||
void ClearRecv();
|
||||
byte GetNextByte();
|
||||
void CloseWorker();
|
||||
bool BlockSend();
|
||||
bool PickData();
|
||||
bool BlockRecv();
|
||||
bool ConnectionConfirm();
|
||||
protected:
|
||||
bool Stopping;
|
||||
bool Execute();
|
||||
void Disconnect();
|
||||
bool ConnectToPeer();
|
||||
bool PerformFunctionNegotiate();
|
||||
public:
|
||||
bool Active;
|
||||
bool Running;
|
||||
longword PeerAddress;
|
||||
longword SrcAddress;
|
||||
int BRecvTimeout;
|
||||
int BSendTimeout;
|
||||
longword SendTime;
|
||||
longword RecvTime;
|
||||
longword RecoveryTime;
|
||||
longword KeepAliveTime;
|
||||
longword BytesSent;
|
||||
longword BytesRecv;
|
||||
longword SendErrors;
|
||||
longword RecvErrors;
|
||||
// The partner is linked when the init sequence is terminated
|
||||
//(TCP connection + ISO connection + PDU Length negotiation)
|
||||
bool Linked;
|
||||
TSnap7Partner(bool CreateActive);
|
||||
~TSnap7Partner();
|
||||
// Control
|
||||
int Start();
|
||||
int StartTo(const char *LocAddress, const char *RemAddress, word LocTsap, word RemTsap);
|
||||
int Stop();
|
||||
int Status();
|
||||
int GetParam(int ParamNumber, void * pValue);
|
||||
int SetParam(int ParamNumber, void * pValue);
|
||||
// Block send
|
||||
int BSend(longword R_ID, void *pUsrData, int Size);
|
||||
int AsBSend(longword R_ID, void *pUsrData, int Size);
|
||||
bool CheckAsBSendCompletion(int &opResult);
|
||||
int WaitAsBSendCompletion(longword Timeout);
|
||||
int SetSendCallback(pfn_ParBSendCompletion pCompletion, void *usrPtr);
|
||||
// Block recv
|
||||
int BRecv(longword &R_ID, void *pData, int &Size, longword Timeout);
|
||||
bool CheckAsBRecvCompletion(int &opResult, longword &R_ID,
|
||||
void *pData, int &Size);
|
||||
int SetRecvCallback(pfn_ParBRecvCallBack pCompletion, void *usrPtr);
|
||||
|
||||
friend class TConnectionServer;
|
||||
friend class TPartnerThread;
|
||||
};
|
||||
|
||||
|
||||
#endif // s7_partner_h
|
||||
122
utils/snap7_src/src/core/s7_peer.cpp
Normal file
122
utils/snap7_src/src/core/s7_peer.cpp
Normal file
@@ -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;
|
||||
}
|
||||
58
utils/snap7_src/src/core/s7_peer.h
Normal file
58
utils/snap7_src/src/core/s7_peer.h
Normal file
@@ -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
|
||||
2158
utils/snap7_src/src/core/s7_server.cpp
Normal file
2158
utils/snap7_src/src/core/s7_server.cpp
Normal file
File diff suppressed because it is too large
Load Diff
261
utils/snap7_src/src/core/s7_server.h
Normal file
261
utils/snap7_src/src/core/s7_server.h
Normal file
@@ -0,0 +1,261 @@
|
||||
/*=============================================================================|
|
||||
| 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_server_h
|
||||
#define s7_server_h
|
||||
//---------------------------------------------------------------------------
|
||||
#include "snap_tcpsrvr.h"
|
||||
#include "s7_types.h"
|
||||
#include "s7_isotcp.h"
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
// Maximum number of DB, change it to increase/decrease the limit.
|
||||
// The DB table size is 12*MaxDB bytes
|
||||
|
||||
#define MaxDB 2048 // Like a S7 318
|
||||
#define MinPduSize 240
|
||||
#define CPU315PduSize 240
|
||||
//---------------------------------------------------------------------------
|
||||
// Server Interface errors
|
||||
const longword errSrvDBNullPointer = 0x00200000; // Pssed null as PData
|
||||
const longword errSrvAreaAlreadyExists = 0x00300000; // Area Re-registration
|
||||
const longword errSrvUnknownArea = 0x00400000; // Unknown area
|
||||
const longword errSrvInvalidParams = 0x00500000; // Invalid param(s) supplied
|
||||
const longword errSrvTooManyDB = 0x00600000; // Cannot register DB
|
||||
const longword errSrvInvalidParamNumber = 0x00700000; // Invalid param (srv_get/set_param)
|
||||
const longword errSrvCannotChangeParam = 0x00800000; // Cannot change because running
|
||||
|
||||
// Server Area ID (use with Register/unregister - Lock/unlock Area)
|
||||
const int srvAreaPE = 0;
|
||||
const int srvAreaPA = 1;
|
||||
const int srvAreaMK = 2;
|
||||
const int srvAreaCT = 3;
|
||||
const int srvAreaTM = 4;
|
||||
const int srvAreaDB = 5;
|
||||
|
||||
typedef struct{
|
||||
word Number; // Number (only for DB)
|
||||
word Size; // Area size (in bytes)
|
||||
pbyte PData; // Pointer to area
|
||||
PSnapCriticalSection cs;
|
||||
}TS7Area, *PS7Area;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// ISOTCP WORKER CLASS
|
||||
//------------------------------------------------------------------------------
|
||||
class TIsoTcpWorker : public TIsoTcpSocket
|
||||
{
|
||||
protected:
|
||||
virtual bool IsoPerformCommand(int &Size);
|
||||
virtual bool ExecuteSend();
|
||||
virtual bool ExecuteRecv();
|
||||
public:
|
||||
TIsoTcpWorker(){};
|
||||
~TIsoTcpWorker(){};
|
||||
// Worker execution
|
||||
bool Execute();
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
// S7 WORKER CLASS
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// SZL frame
|
||||
typedef struct{
|
||||
TS7Answer17 Answer;
|
||||
PReqFunReadSZLFirst ReqParams;
|
||||
PS7ReqSZLData ReqData;
|
||||
PS7ResParams7 ResParams;
|
||||
pbyte ResData;
|
||||
int ID;
|
||||
int Index;
|
||||
bool SZLDone;
|
||||
}TSZL;
|
||||
|
||||
// Current Event Info
|
||||
typedef struct{
|
||||
word EvRetCode;
|
||||
word EvArea;
|
||||
word EvIndex;
|
||||
word EvStart;
|
||||
word EvSize;
|
||||
}TEv;
|
||||
|
||||
// Current Block info
|
||||
typedef struct{
|
||||
PReqFunGetBlockInfo ReqParams;
|
||||
PResFunGetBlockInfo ResParams;
|
||||
TS7Answer17 Answer;
|
||||
word evError;
|
||||
word DataLength;
|
||||
}TCB;
|
||||
|
||||
class TSnap7Server; // forward declaration
|
||||
|
||||
class TS7Worker : public TIsoTcpWorker
|
||||
{
|
||||
private:
|
||||
PS7ReqHeader PDUH_in;
|
||||
int DBCnt;
|
||||
byte LastBlk;
|
||||
TSZL SZL;
|
||||
byte BCD(word Value);
|
||||
// Checks the consistence of the incoming PDU
|
||||
bool CheckPDU_in(int PayloadSize);
|
||||
void FillTime(PS7Time PTime);
|
||||
protected:
|
||||
int DataSizeByte(int WordLength);
|
||||
bool ExecuteRecv();
|
||||
void DoEvent(longword Code, word RetCode, word Param1, word Param2,
|
||||
word Param3, word Param4);
|
||||
void DoReadEvent(longword Code, word RetCode, word Param1, word Param2,
|
||||
word Param3, word Param4);
|
||||
void FragmentSkipped(int Size);
|
||||
// Entry parse
|
||||
bool IsoPerformCommand(int &Size);
|
||||
// First stage parse
|
||||
bool PerformPDUAck(int &Size);
|
||||
bool PerformPDURequest(int &Size);
|
||||
bool PerformPDUUsrData(int &Size);
|
||||
// Second stage parse : PDU Request
|
||||
PS7Area GetArea(byte S7Code, word index);
|
||||
// Group Read Area
|
||||
bool PerformFunctionRead();
|
||||
// Subfunctions Read Data
|
||||
word ReadArea(PResFunReadItem ResItemData, PReqFunReadItem ReqItemPar,
|
||||
int &PDURemainder,TEv &EV);
|
||||
word RA_NotFound(PResFunReadItem ResItem, TEv &EV);
|
||||
word RA_OutOfRange(PResFunReadItem ResItem, TEv &EV);
|
||||
word RA_SizeOverPDU(PResFunReadItem ResItem, TEv &EV);
|
||||
// Group Write Area
|
||||
bool PerformFunctionWrite();
|
||||
// Subfunctions Write Data
|
||||
byte WriteArea(PReqFunWriteDataItem ReqItemData, PReqFunWriteItem ReqItemPar,
|
||||
TEv &EV);
|
||||
byte WA_NotFound(TEv &EV);
|
||||
byte WA_InvalidTransportSize(TEv &EV);
|
||||
byte WA_OutOfRange(TEv &EV);
|
||||
byte WA_DataSizeMismatch(TEv &EV);
|
||||
// Negotiate PDU Length
|
||||
bool PerformFunctionNegotiate();
|
||||
// Control
|
||||
bool PerformFunctionControl(byte PduFun);
|
||||
// Up/Download
|
||||
bool PerformFunctionUpload();
|
||||
bool PerformFunctionDownload();
|
||||
// Second stage parse : PDU User data
|
||||
bool PerformGroupProgrammer();
|
||||
bool PerformGroupCyclicData();
|
||||
bool PerformGroupSecurity();
|
||||
// Group Block(s) Info
|
||||
bool PerformGroupBlockInfo();
|
||||
// Subfunctions Block info
|
||||
void BLK_ListAll(TCB &CB);
|
||||
void BLK_ListBoT(byte BlockType, bool Start, TCB &CB);
|
||||
void BLK_NoResource_ListBoT(PDataFunGetBot Data, TCB &CB);
|
||||
void BLK_GetBlkInfo(TCB &CB);
|
||||
void BLK_NoResource_GetBlkInfo(PResDataBlockInfo Data, TCB &CB);
|
||||
void BLK_GetBlockNum_GetBlkInfo(int &BlkNum, PReqDataBlockInfo ReqData);
|
||||
void BLK_DoBlockInfo_GetBlkInfo(PS7Area DB, PResDataBlockInfo Data, TCB &CB);
|
||||
// Clock Group
|
||||
bool PerformGetClock();
|
||||
bool PerformSetClock();
|
||||
// SZL Group
|
||||
bool PerformGroupSZL();
|
||||
// Subfunctions (called by PerformGroupSZL)
|
||||
void SZLNotAvailable();
|
||||
void SZLSystemState();
|
||||
void SZLData(void *P, int len);
|
||||
void SZL_ID424();
|
||||
void SZL_ID131_IDX003();
|
||||
public:
|
||||
TSnap7Server *FServer;
|
||||
int FPDULength;
|
||||
TS7Worker();
|
||||
~TS7Worker(){};
|
||||
};
|
||||
|
||||
typedef TS7Worker *PS7Worker;
|
||||
//------------------------------------------------------------------------------
|
||||
// S7 SERVER CLASS
|
||||
//------------------------------------------------------------------------------
|
||||
extern "C"
|
||||
{
|
||||
typedef int (S7API *pfn_RWAreaCallBack)(void *usrPtr, int Sender, int Operation, PS7Tag PTag, void *pUsrData);
|
||||
}
|
||||
const int OperationRead = 0;
|
||||
const int OperationWrite = 1;
|
||||
|
||||
class TSnap7Server : public TCustomMsgServer
|
||||
{
|
||||
private:
|
||||
// Read Callback related
|
||||
pfn_SrvCallBack OnReadEvent;
|
||||
pfn_RWAreaCallBack OnRWArea;
|
||||
// Critical section to lock Read/Write Hook Area
|
||||
PSnapCriticalSection CSRWHook;
|
||||
void *FReadUsrPtr;
|
||||
void *FRWAreaUsrPtr;
|
||||
void DisposeAll();
|
||||
int FindFirstFreeDB();
|
||||
int IndexOfDB(word DBNumber);
|
||||
protected:
|
||||
int DBCount;
|
||||
int DBLimit;
|
||||
PS7Area DB[MaxDB]; // DB
|
||||
PS7Area HA[5]; // MK,PE,PA,TM,CT
|
||||
PS7Area FindDB(word DBNumber);
|
||||
PWorkerSocket CreateWorkerSocket(socket_t Sock);
|
||||
bool ResourceLess;
|
||||
word ForcePDU;
|
||||
int RegisterDB(word Number, void *pUsrData, word Size);
|
||||
int RegisterSys(int AreaCode, void *pUsrData, word Size);
|
||||
int UnregisterDB(word DBNumber);
|
||||
int UnregisterSys(int AreaCode);
|
||||
// The Read event
|
||||
void DoReadEvent(int Sender, longword Code, word RetCode, word Param1,
|
||||
word Param2, word Param3, word Param4);
|
||||
bool DoReadArea(int Sender, int Area, int DBNumber, int Start, int Size, int WordLen, void *pUsrData);
|
||||
bool DoWriteArea(int Sender, int Area, int DBNumber, int Start, int Size, int WordLen, void *pUsrData);
|
||||
public:
|
||||
int WorkInterval;
|
||||
byte CpuStatus;
|
||||
TSnap7Server();
|
||||
~TSnap7Server();
|
||||
int StartTo(const char *Address);
|
||||
int GetParam(int ParamNumber, void *pValue);
|
||||
int SetParam(int ParamNumber, void *pValue);
|
||||
int RegisterArea(int AreaCode, word Index, void *pUsrData, word Size);
|
||||
int UnregisterArea(int AreaCode, word Index);
|
||||
int LockArea(int AreaCode, word DBNumber);
|
||||
int UnlockArea(int AreaCode, word DBNumber);
|
||||
// Sets Event callback
|
||||
int SetReadEventsCallBack(pfn_SrvCallBack PCallBack, void *UsrPtr);
|
||||
int SetRWAreaCallBack(pfn_RWAreaCallBack PCallBack, void *UsrPtr);
|
||||
friend class TS7Worker;
|
||||
};
|
||||
typedef TSnap7Server *PSnap7Server;
|
||||
|
||||
#endif // s7_server_h
|
||||
|
||||
788
utils/snap7_src/src/core/s7_text.cpp
Normal file
788
utils/snap7_src/src/core/s7_text.cpp
Normal file
@@ -0,0 +1,788 @@
|
||||
/*=============================================================================|
|
||||
| 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"
|
||||
//---------------------------------------------------------------------------
|
||||
#ifndef OS_WINDOWS
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
//---------------------------------------------------------------------------
|
||||
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;
|
||||
#ifdef OS_WINDOWS
|
||||
case WSAEPROCLIM: strcpy(Result," TCP : Too many processes\0");break;
|
||||
case WSASYSNOTREADY: strcpy(Result," TCP : Network subsystem is unusable\0");break;
|
||||
case WSAVERNOTSUPPORTED: strcpy(Result," TCP : Winsock DLL cannot support this application\0");break;
|
||||
case WSANOTINITIALISED: strcpy(Result," TCP : Winsock not initialized\0");break;
|
||||
case WSAEDISCON: strcpy(Result," TCP : Disconnect\0");break;
|
||||
case WSAHOST_NOT_FOUND: strcpy(Result," TCP : Host not found\0");break;
|
||||
case WSATRY_AGAIN: strcpy(Result," TCP : Non authoritative - host not found\0");break;
|
||||
case WSANO_RECOVERY: strcpy(Result," TCP : Non recoverable error\0");break;
|
||||
case WSANO_DATA: strcpy(Result," TCP : Valid name, no data record of requested type\0");break;
|
||||
#endif
|
||||
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* SrvTextOf(int Error, char* Result)
|
||||
{
|
||||
switch (Error)
|
||||
{
|
||||
case 0: *Result = '\0'; break;
|
||||
case errSrvCannotStart: strcpy(Result, "SRV : Server cannot start\0"); break;
|
||||
case errSrvDBNullPointer: strcpy(Result, "SRV : Null passed as area pointer\0"); break;
|
||||
case errSrvAreaAlreadyExists: strcpy(Result, "SRV : Cannot register area since already exists\0"); break;
|
||||
case errSrvUnknownArea: strcpy(Result, "SRV : Unknown Area code\0"); break;
|
||||
case errSrvInvalidParams: strcpy(Result, "SRV : Invalid param(s) supplied\0"); break;
|
||||
case errSrvTooManyDB: strcpy(Result, "SRV : DB Limit reached\0"); break;
|
||||
case errSrvInvalidParamNumber: strcpy(Result, "SRV : Invalid Param Number\0"); break;
|
||||
case errSrvCannotChangeParam: strcpy(Result, "SRV : Cannot change this param now\0");break;
|
||||
default:
|
||||
{
|
||||
char CNumber[16];
|
||||
strcpy(Result, "SRV : Unknown error (0x");
|
||||
strcat(Result, NumToString(Error, 16, 8, CNumber));
|
||||
strcat(Result, ")");
|
||||
break;
|
||||
}
|
||||
};
|
||||
return Result;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
char* ParTextOf(int Error, char* Result)
|
||||
{
|
||||
switch(Error)
|
||||
{
|
||||
case 0: *Result = '\0'; break;
|
||||
case errParAddressInUse : strcpy(Result, "PAR : Local address already in use");break;
|
||||
case errParNoRoom : strcpy(Result, "PAR : No more partners available");break;
|
||||
case errServerNoRoom : strcpy(Result, "PAR : No more servers available");break;
|
||||
case errParInvalidParams : strcpy(Result, "PAR : Invalid parameter supplied");break;
|
||||
case errParNotLinked : strcpy(Result, "PAR : Cannot perform, Partner not linked");break;
|
||||
case errParBusy : strcpy(Result, "PAR : Cannot perform, Partner Busy");break;
|
||||
case errParFrameTimeout : strcpy(Result, "PAR : Frame timeout");break;
|
||||
case errParInvalidPDU : strcpy(Result, "PAR : Invalid PDU received");break;
|
||||
case errParSendTimeout : strcpy(Result, "PAR : Send timeout");break;
|
||||
case errParRecvTimeout : strcpy(Result, "PAR : Recv timeout");break;
|
||||
case errParSendRefused : strcpy(Result, "PAR : Send refused by peer");break;
|
||||
case errParNegotiatingPDU : strcpy(Result, "PAR : Error negotiating PDU");break;
|
||||
case errParSendingBlock : strcpy(Result, "PAR : Error Sending Block");break;
|
||||
case errParRecvingBlock : strcpy(Result, "PAR : Error Receiving Block");break;
|
||||
case errParBindError : strcpy(Result, "PAR : Error Binding");break;
|
||||
case errParDestroying : strcpy(Result, "PAR : Cannot perform (destroying)");break;
|
||||
case errParInvalidParamNumber: strcpy(Result, "PAR : Invalid Param Number");break;
|
||||
case errParCannotChangeParam : strcpy(Result, "PAR : Cannot change this param now");break;
|
||||
case errParBufferTooSmall : strcpy(Result, "PAR : The buffer supplied is too small to accomplish the operation");break;
|
||||
default:
|
||||
{
|
||||
char CNumber[16];
|
||||
strcpy(Result, "PAR : 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* ErrSrvText(int Error, char* Result, int TextLen)
|
||||
{
|
||||
char TcpError[128];
|
||||
char IsoError[128];
|
||||
char SrvError[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:
|
||||
{
|
||||
SrvTextOf(Error & ErrS7Mask, SrvError);
|
||||
strcat(SrvError, IsoTextOf(Error & ErrIsoMask, IsoError));
|
||||
strcat(SrvError, TcpTextOf(Error & ErrTcpMask, TcpError));
|
||||
strncpy(Result, SrvError, TextLen);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
strncpy(Result, "OK\0", TextLen);
|
||||
return Result;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
char* ErrParText(int Error, char* Result, int TextLen)
|
||||
{
|
||||
char TcpError[128];
|
||||
char IsoError[128];
|
||||
char ParError[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:
|
||||
{
|
||||
ParTextOf(Error & ErrS7Mask, ParError);
|
||||
strcat(ParError, IsoTextOf(Error & ErrIsoMask, IsoError));
|
||||
strcat(ParError, TcpTextOf(Error & ErrTcpMask, TcpError));
|
||||
strncpy(Result, ParError, TextLen);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
strncpy(Result, "OK\0", TextLen);
|
||||
return Result;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
// SERVER EVENTS TEXT
|
||||
//---------------------------------------------------------------------------
|
||||
char* SenderText(TSrvEvent &Event, char* Result)
|
||||
{
|
||||
char Buf[64];
|
||||
char Add[16];
|
||||
TimeToString(Event.EvtTime, Buf);
|
||||
if (Event.EvtSender != 0)
|
||||
{
|
||||
strcat(Buf, " [");
|
||||
strcat(Buf, IpAddressToString(Event.EvtSender, Add));
|
||||
strcat(Buf, "] ");
|
||||
}
|
||||
else
|
||||
strcat(Buf, " Server ");
|
||||
strcpy(Result, Buf);
|
||||
return Result;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
char* TcpServerEventText(TSrvEvent &Event, char* Result)
|
||||
{
|
||||
char S[256];
|
||||
char Buf[128];
|
||||
|
||||
strcpy(S, SenderText(Event, Buf));
|
||||
|
||||
switch (Event.EvtCode)
|
||||
{
|
||||
case evcServerStarted : strcat(S,"started");break;
|
||||
case evcServerStopped : strcat(S,"stopped");break;
|
||||
case evcListenerCannotStart:
|
||||
strcat(S, "Cannot start listener - Socket Error : ");
|
||||
strcat(S, TcpTextOf(Event.EvtRetCode,Buf));
|
||||
break;
|
||||
case evcClientAdded : strcat(S,"Client added");break;
|
||||
case evcClientRejected : strcat(S,"Client refused");break;
|
||||
case evcClientNoRoom : strcat(S,"A client was refused due to maximum connections number");break;
|
||||
case evcClientException : strcat(S,"Client exception");break;
|
||||
case evcClientDisconnected : strcat(S,"Client disconnected by peer");break;
|
||||
case evcClientTerminated : strcat(S,"Client terminated");break;
|
||||
case evcClientsDropped:
|
||||
strcat(S, IntToString(Event.EvtParam1, Buf));
|
||||
strcat(S, " clients have been dropped bacause unresponsive");
|
||||
break;
|
||||
default:
|
||||
strcat(S, "Unknown event (");
|
||||
strcat(S, IntToString(Event.EvtCode, Buf));
|
||||
strcat(S,")");
|
||||
break;
|
||||
};
|
||||
strcpy(Result, S);
|
||||
return Result;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
char* PDUText(TSrvEvent &Event, char* Result)
|
||||
{
|
||||
char S[256];
|
||||
char Buf[128];
|
||||
switch (Event.EvtRetCode)
|
||||
{
|
||||
case evrFragmentRejected:
|
||||
strcpy(S, "Fragment of ");
|
||||
strcat(S, IntToString(Event.EvtParam1, Buf));
|
||||
strcat(S, " bytes rejected");
|
||||
break;
|
||||
case evrMalformedPDU:
|
||||
strcpy(S, "Malformed PDU of ");
|
||||
strcat(S, IntToString(Event.EvtParam1, Buf));
|
||||
strcat(S, " bytes rejected");
|
||||
break;
|
||||
case evrSparseBytes:
|
||||
strcpy(S, "Message of sparse ");
|
||||
strcat(S, IntToString(Event.EvtParam1, Buf));
|
||||
strcat(S, " bytes rejected");
|
||||
break;
|
||||
case evrCannotHandlePDU:
|
||||
strcpy(S, "Cannot handle this PDU");
|
||||
break;
|
||||
case evrNotImplemented:
|
||||
switch (Event.EvtParam1)
|
||||
{
|
||||
case grCyclicData:
|
||||
strcpy(S, "Function group cyclic data not yet implemented");
|
||||
break;
|
||||
case grProgrammer:
|
||||
strcpy(S, "Function group programmer not yet implemented");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
strcpy(S, "Unknown Return code (");
|
||||
strcat(S, IntToString(Event.EvtRetCode, Buf));
|
||||
strcat(S, ")");
|
||||
break;
|
||||
}
|
||||
strcpy(Result, S);
|
||||
return Result;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
char* TxtArea(TSrvEvent &Event, char* Result)
|
||||
{
|
||||
char S[64];
|
||||
char Buf[32];
|
||||
switch (Event.EvtParam1)
|
||||
{
|
||||
case S7AreaPE: strcpy(S, "Area : PE, "); break;
|
||||
case S7AreaPA: strcpy(S, "Area : PA, "); break;
|
||||
case S7AreaMK: strcpy(S, "Area : MK, "); break;
|
||||
case S7AreaCT: strcpy(S, "Area : CT, "); break;
|
||||
case S7AreaTM: strcpy(S, "Area : TM, "); break;
|
||||
case S7AreaDB:
|
||||
strcpy(S, "Area : DB");
|
||||
strcat(S, IntToString(Event.EvtParam2, Buf));
|
||||
strcat(S,", ");
|
||||
break;
|
||||
default:
|
||||
strcpy(S, "Unknown area (");
|
||||
strcat(S, IntToString(Event.EvtParam2, Buf));
|
||||
strcat(S,")");
|
||||
break;
|
||||
}
|
||||
strcpy(Result, S);
|
||||
return Result;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
char* TxtStartSize(TSrvEvent &Event, char* Result)
|
||||
{
|
||||
char N[32];
|
||||
strcpy(Result, "Start : ");
|
||||
strcat(Result, IntToString(Event.EvtParam3, N));
|
||||
strcat(Result, ", Size : ");
|
||||
strcat(Result, IntToString(Event.EvtParam4, N));
|
||||
return Result;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
char* TxtDataResult(TSrvEvent &Event, char* Result)
|
||||
{
|
||||
char N[32];
|
||||
switch (Event.EvtRetCode)
|
||||
{
|
||||
case evrNoError:
|
||||
strcpy(Result," --> OK");
|
||||
break;
|
||||
case evrErrException:
|
||||
strcpy(Result, " --> Exception error");
|
||||
break;
|
||||
case evrErrAreaNotFound:
|
||||
strcpy(Result, " --> Area not found");
|
||||
break;
|
||||
case evrErrOutOfRange:
|
||||
strcpy(Result, " --> Out of range");
|
||||
break;
|
||||
case evrErrOverPDU:
|
||||
strcpy(Result, " --> Data size exceeds PDU size");
|
||||
break;
|
||||
case evrErrTransportSize:
|
||||
strcpy(Result, " --> Invalid transport size");
|
||||
break;
|
||||
case evrDataSizeMismatch:
|
||||
strcpy(Result, " --> Data size mismatch");
|
||||
break;
|
||||
default:
|
||||
strcpy(Result, " --> Unknown error code (");
|
||||
strcat(Result, IntToString(Event.EvtRetCode, N));
|
||||
strcat(Result,")");
|
||||
break;
|
||||
};
|
||||
return Result;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
char* ControlText(word Code, char* Result)
|
||||
{
|
||||
char N[64];
|
||||
strcpy(Result, "CPU Control request : ");
|
||||
switch (Code)
|
||||
{
|
||||
case CodeControlUnknown:
|
||||
strcat(Result,"Unknown");
|
||||
break;
|
||||
case CodeControlColdStart:
|
||||
strcat(Result, "Cold START --> OK");
|
||||
break;
|
||||
case CodeControlWarmStart:
|
||||
strcat(Result, "Warm START --> OK");
|
||||
break;
|
||||
case CodeControlStop:
|
||||
strcat(Result, "STOP --> OK");
|
||||
break;
|
||||
case CodeControlCompress:
|
||||
strcat(Result, "Memory compress --> OK");
|
||||
break;
|
||||
case CodeControlCpyRamRom:
|
||||
strcat(Result, "Copy Ram to Rom --> OK");
|
||||
break;
|
||||
case CodeControlInsDel:
|
||||
strcat(Result, "Block Insert or Delete --> OK");
|
||||
break;
|
||||
default :
|
||||
strcat(Result, "Unknown control code (");
|
||||
strcat(Result, IntToString(Code, N));
|
||||
strcat(Result,")");
|
||||
}
|
||||
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;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
char* ReadSZLText(TSrvEvent &Event, char* Result)
|
||||
{
|
||||
char S[128];
|
||||
char N[64];
|
||||
strcpy(S, "Read SZL request, ID:0x");
|
||||
strcat(S, NumToString(Event.EvtParam1, 16, 4, N));
|
||||
strcat(S, " INDEX:0x");
|
||||
strcat(S, NumToString(Event.EvtParam2, 16, 4, N));
|
||||
|
||||
if (Event.EvtRetCode == evrNoError)
|
||||
strcat(S, " --> OK");
|
||||
else
|
||||
strcat(S, " --> NOT AVAILABLE");
|
||||
strcpy(Result, S);
|
||||
return Result;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
char* UploadText(TSrvEvent &Event, char* Result)
|
||||
{
|
||||
strcpy(Result,"Block upload requested --> NOT PERFORMED (due to invalid security level)");
|
||||
return Result;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
char* DownloadText(TSrvEvent &Event, char* Result)
|
||||
{
|
||||
strcpy(Result, "Block download requested --> NOT PERFORMED (due to invalid security level)");
|
||||
return Result;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
char* StrBlockType(word Code, char* Result)
|
||||
{
|
||||
char N[64];
|
||||
switch (Code)
|
||||
{
|
||||
case Block_OB:
|
||||
strcpy(Result, "OB");
|
||||
break;
|
||||
case Block_DB:
|
||||
strcpy(Result, "DB");
|
||||
break;
|
||||
case Block_SDB:
|
||||
strcpy(Result, "SDB");
|
||||
break;
|
||||
case Block_FC:
|
||||
strcpy(Result, "FC");
|
||||
break;
|
||||
case Block_SFC:
|
||||
strcpy(Result, "SFC");
|
||||
break;
|
||||
case Block_FB:
|
||||
strcpy(Result, "FB");
|
||||
break;
|
||||
case Block_SFB:
|
||||
strcpy(Result, "SFB");
|
||||
break;
|
||||
default:
|
||||
strcpy(Result, "[Unknown 0x");
|
||||
strcat(Result, NumToString(Code, 16, 4, N));
|
||||
strcat(Result,"]");
|
||||
break;
|
||||
};
|
||||
return Result;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
char* BlockInfoText(TSrvEvent &Event, char* Result)
|
||||
{
|
||||
char S[64];
|
||||
switch (Event.EvtParam1)
|
||||
{
|
||||
case evsGetBlockList:
|
||||
strcpy(Result, "Block list requested");
|
||||
break;
|
||||
case evsStartListBoT:
|
||||
strcpy(Result, "Block of type ");
|
||||
strcat(Result, StrBlockType(Event.EvtParam2,S));
|
||||
strcat(Result, " list requested (start sequence)");
|
||||
break;
|
||||
case evsListBoT:
|
||||
strcpy(Result, "Block of type ");
|
||||
strcat(Result, StrBlockType(Event.EvtParam2, S));
|
||||
strcat(Result, " list requested (next part)");
|
||||
break;
|
||||
case evsGetBlockInfo:
|
||||
strcpy(Result, "Block info requested ");
|
||||
strcat(Result, StrBlockType(Event.EvtParam2, S));
|
||||
strcat(Result, " ");
|
||||
strcat(Result, IntToString(Event.EvtParam3,S));
|
||||
break;
|
||||
};
|
||||
if (Event.EvtRetCode == evrNoError)
|
||||
strcat(Result, " --> OK");
|
||||
else
|
||||
strcat(Result, " --> NOT AVAILABLE");
|
||||
return Result;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
char* SecurityText(TSrvEvent &Event, char* Result)
|
||||
{
|
||||
switch (Event.EvtParam1)
|
||||
{
|
||||
case evsSetPassword:
|
||||
strcpy(Result,"Security request : Set session password --> OK");
|
||||
break;
|
||||
case evsClrPassword:
|
||||
strcpy(Result, "Security request : Clear session password --> OK");
|
||||
break;
|
||||
default:
|
||||
strcpy(Result, "Security request : Unknown Subfunction");
|
||||
break;
|
||||
};
|
||||
return Result;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
char* EvtSrvText(TSrvEvent &Event, char* Result, int TextLen)
|
||||
{
|
||||
char S[256];
|
||||
char C[128];
|
||||
|
||||
if (Event.EvtCode > evcSnap7Base)
|
||||
{
|
||||
strcpy(S, SenderText(Event, C));
|
||||
switch (Event.EvtCode)
|
||||
{
|
||||
case evcPDUincoming:
|
||||
strcat(S, "PDU incoming : ");
|
||||
strcat(S,PDUText(Event,C));
|
||||
break;
|
||||
case evcDataRead:
|
||||
strcat(S, "Read request, ");
|
||||
strcat(S, TxtArea(Event, C));
|
||||
strcat(S, TxtStartSize(Event, C));
|
||||
strcat(S, TxtDataResult(Event, C));
|
||||
break;
|
||||
case evcDataWrite:
|
||||
strcat(S, "Write request, ");
|
||||
strcat(S, TxtArea(Event, C));
|
||||
strcat(S, TxtStartSize(Event, C));
|
||||
strcat(S, TxtDataResult(Event, C));
|
||||
break;
|
||||
case evcNegotiatePDU:
|
||||
strcat(S, "The client requires a PDU size of ");
|
||||
strcat(S, IntToString(Event.EvtParam1, C));
|
||||
strcat(S," bytes");
|
||||
break;
|
||||
case evcControl:
|
||||
strcat(S, ControlText(Event.EvtParam1,C));
|
||||
break;
|
||||
case evcReadSZL:
|
||||
strcat(S, ReadSZLText(Event,C));
|
||||
break;
|
||||
case evcClock:
|
||||
strcat(S, ClockText(Event.EvtParam1,C));
|
||||
break;
|
||||
case evcUpload:
|
||||
strcat(S, UploadText(Event,C));
|
||||
break;
|
||||
case evcDownload:
|
||||
strcat(S, DownloadText(Event,C));
|
||||
break;
|
||||
case evcDirectory:
|
||||
strcat(S, BlockInfoText(Event,C));
|
||||
break;
|
||||
case evcSecurity:
|
||||
strcat(S, SecurityText(Event,C));
|
||||
break;
|
||||
default:
|
||||
strcat(S, "Unknown event (");
|
||||
strcat(S, IntToString(Event.EvtCode, C));
|
||||
strcat(S,")");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
strcpy(S,TcpServerEventText(Event,C));
|
||||
|
||||
strncpy(Result, S, TextLen);
|
||||
return Result;
|
||||
}
|
||||
|
||||
49
utils/snap7_src/src/core/s7_text.h
Normal file
49
utils/snap7_src/src/core/s7_text.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/*=============================================================================|
|
||||
| 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"
|
||||
#include "s7_server.h"
|
||||
#include "s7_partner.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);
|
||||
char* ErrSrvText(int Error, char* Result, int TextLen);
|
||||
char* ErrParText(int Error, char* Result, int TextLen);
|
||||
char* EvtSrvText(TSrvEvent &Event, char* Result, int TextLen);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
1066
utils/snap7_src/src/core/s7_types.h
Normal file
1066
utils/snap7_src/src/core/s7_types.h
Normal file
File diff suppressed because it is too large
Load Diff
129
utils/snap7_src/src/lib/snap7.def
Normal file
129
utils/snap7_src/src/lib/snap7.def
Normal file
@@ -0,0 +1,129 @@
|
||||
LIBRARY SNAP7.DLL
|
||||
EXPORTS
|
||||
Cli_Create
|
||||
Cli_Destroy
|
||||
Cli_ConnectTo
|
||||
Cli_SetConnectionParams
|
||||
Cli_SetConnectionType
|
||||
Cli_Connect
|
||||
Cli_Disconnect
|
||||
Cli_GetParam
|
||||
Cli_SetParam
|
||||
Cli_SetAsCallback
|
||||
Cli_ReadArea
|
||||
Cli_WriteArea
|
||||
Cli_ReadMultiVars
|
||||
Cli_WriteMultiVars
|
||||
Cli_DBRead
|
||||
Cli_DBWrite
|
||||
Cli_MBRead
|
||||
Cli_MBWrite
|
||||
Cli_EBRead
|
||||
Cli_EBWrite
|
||||
Cli_ABRead
|
||||
Cli_ABWrite
|
||||
Cli_TMRead
|
||||
Cli_TMWrite
|
||||
Cli_CTRead
|
||||
Cli_CTWrite
|
||||
Cli_ListBlocks
|
||||
Cli_GetAgBlockInfo
|
||||
Cli_GetPgBlockInfo
|
||||
Cli_ListBlocksOfType
|
||||
Cli_Upload
|
||||
Cli_FullUpload
|
||||
Cli_Download
|
||||
Cli_Delete
|
||||
Cli_DBGet
|
||||
Cli_DBFill
|
||||
Cli_GetPlcDateTime
|
||||
Cli_SetPlcDateTime
|
||||
Cli_SetPlcSystemDateTime
|
||||
Cli_GetOrderCode
|
||||
Cli_GetCpuInfo
|
||||
Cli_GetCpInfo
|
||||
Cli_ReadSZL
|
||||
Cli_ReadSZLList
|
||||
Cli_PlcHotStart
|
||||
Cli_PlcColdStart
|
||||
Cli_PlcStop
|
||||
Cli_CopyRamToRom
|
||||
Cli_Compress
|
||||
Cli_GetPlcStatus
|
||||
Cli_GetProtection
|
||||
Cli_SetSessionPassword
|
||||
Cli_ClearSessionPassword
|
||||
Cli_IsoExchangeBuffer
|
||||
Cli_GetExecTime
|
||||
Cli_GetLastError
|
||||
Cli_GetPduLength
|
||||
Cli_AsReadArea
|
||||
Cli_AsWriteArea
|
||||
Cli_AsDBRead
|
||||
Cli_AsDBWrite
|
||||
Cli_AsMBRead
|
||||
Cli_AsMBWrite
|
||||
Cli_AsEBRead
|
||||
Cli_AsEBWrite
|
||||
Cli_AsABRead
|
||||
Cli_AsABWrite
|
||||
Cli_AsTMRead
|
||||
Cli_AsTMWrite
|
||||
Cli_AsCTRead
|
||||
Cli_AsCTWrite
|
||||
Cli_AsListBlocksOfType
|
||||
Cli_AsReadSZL
|
||||
Cli_AsReadSZLList
|
||||
Cli_AsUpload
|
||||
Cli_AsFullUpload
|
||||
Cli_AsDownload
|
||||
Cli_AsCopyRamToRom
|
||||
Cli_AsCompress
|
||||
Cli_AsDBGet
|
||||
Cli_AsDBFill
|
||||
Cli_CheckAsCompletion
|
||||
Cli_WaitAsCompletion
|
||||
Cli_ErrorText
|
||||
Cli_GetConnected
|
||||
Srv_Create
|
||||
Srv_Destroy
|
||||
Srv_GetParam
|
||||
Srv_SetParam
|
||||
Srv_StartTo
|
||||
Srv_Start
|
||||
Srv_Stop
|
||||
Srv_RegisterArea
|
||||
Srv_UnregisterArea
|
||||
Srv_LockArea
|
||||
Srv_UnlockArea
|
||||
Srv_GetStatus
|
||||
Srv_SetCpuStatus
|
||||
Srv_ClearEvents
|
||||
Srv_PickEvent
|
||||
Srv_GetMask
|
||||
Srv_SetMask
|
||||
Srv_SetEventsCallback
|
||||
Srv_SetReadEventsCallback
|
||||
Srv_SetRWAreaCallback
|
||||
Srv_ErrorText
|
||||
Srv_EventText
|
||||
Par_Create
|
||||
Par_Destroy
|
||||
Par_GetParam
|
||||
Par_SetParam
|
||||
Par_StartTo
|
||||
Par_Start
|
||||
Par_Stop
|
||||
Par_BSend
|
||||
Par_AsBSend
|
||||
Par_CheckAsBSendCompletion
|
||||
Par_WaitAsBSendCompletion
|
||||
Par_SetSendCallback
|
||||
Par_BRecv
|
||||
Par_CheckAsBRecvCompletion
|
||||
Par_SetRecvCallback
|
||||
Par_GetTimes
|
||||
Par_GetStats
|
||||
Par_GetLastError
|
||||
Par_GetStatus
|
||||
Par_ErrorText
|
||||
1196
utils/snap7_src/src/lib/snap7_libmain.cpp
Normal file
1196
utils/snap7_src/src/lib/snap7_libmain.cpp
Normal file
File diff suppressed because it is too large
Load Diff
201
utils/snap7_src/src/lib/snap7_libmain.h
Normal file
201
utils/snap7_src/src/lib/snap7_libmain.h
Normal file
@@ -0,0 +1,201 @@
|
||||
/*=============================================================================|
|
||||
| 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_server.h"
|
||||
#include "s7_partner.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);
|
||||
//==============================================================================
|
||||
// SERVER EXPORT LIST
|
||||
//==============================================================================
|
||||
EXPORTSPEC S7Object S7API Srv_Create();
|
||||
EXPORTSPEC void S7API Srv_Destroy(S7Object &Server);
|
||||
EXPORTSPEC int S7API Srv_GetParam(S7Object Server, int ParamNumber, void *pValue);
|
||||
EXPORTSPEC int S7API Srv_SetParam(S7Object Server, int ParamNumber, void *pValue);
|
||||
EXPORTSPEC int S7API Srv_Start(S7Object Server);
|
||||
EXPORTSPEC int S7API Srv_StartTo(S7Object Server, const char *Address);
|
||||
EXPORTSPEC int S7API Srv_Stop(S7Object Server);
|
||||
// Data
|
||||
EXPORTSPEC int S7API Srv_RegisterArea(S7Object Server, int AreaCode, word Index, void *pUsrData, int Size);
|
||||
EXPORTSPEC int S7API Srv_UnregisterArea(S7Object Server, int AreaCode, word Index);
|
||||
EXPORTSPEC int S7API Srv_LockArea(S7Object Server, int AreaCode, word Index);
|
||||
EXPORTSPEC int S7API Srv_UnlockArea(S7Object Server, int AreaCode, word Index);
|
||||
// Events
|
||||
EXPORTSPEC int S7API Srv_ClearEvents(S7Object Server);
|
||||
EXPORTSPEC int S7API Srv_PickEvent(S7Object Server, TSrvEvent *pEvent, int &EvtReady);
|
||||
EXPORTSPEC int S7API Srv_GetMask(S7Object Server, int MaskKind, longword &Mask);
|
||||
EXPORTSPEC int S7API Srv_SetMask(S7Object Server, int MaskKind, longword Mask);
|
||||
EXPORTSPEC int S7API Srv_SetEventsCallback(S7Object Server, pfn_SrvCallBack pCallback, void *usrPtr);
|
||||
EXPORTSPEC int S7API Srv_SetReadEventsCallback(S7Object Server, pfn_SrvCallBack pCallback, void *usrPtr);
|
||||
EXPORTSPEC int S7API Srv_EventText(TSrvEvent &Event, char *Text, int TextLen);
|
||||
EXPORTSPEC int S7API Srv_SetRWAreaCallback(S7Object Server, pfn_RWAreaCallBack pCallback, void *usrPtr);
|
||||
// Misc
|
||||
EXPORTSPEC int S7API Srv_GetStatus(S7Object Server, int &ServerStatus, int &CpuStatus, int &ClientsCount);
|
||||
EXPORTSPEC int S7API Srv_SetCpuStatus(S7Object Server, int CpuStatus);
|
||||
EXPORTSPEC int S7API Srv_ErrorText(int Error, char *Text, int TextLen);
|
||||
//==============================================================================
|
||||
// PARTNER EXPORT LIST
|
||||
//==============================================================================
|
||||
EXPORTSPEC S7Object S7API Par_Create(int Active);
|
||||
EXPORTSPEC void S7API Par_Destroy(S7Object &Partner);
|
||||
EXPORTSPEC int S7API Par_GetParam(S7Object Partner, int ParamNumber, void *pValue);
|
||||
EXPORTSPEC int S7API Par_SetParam(S7Object Partner, int ParamNumber, void *pValue);
|
||||
EXPORTSPEC int S7API Par_Start(S7Object Partner);
|
||||
EXPORTSPEC int S7API Par_StartTo(S7Object Partner, const char *LocalAddress, const char *RemoteAddress,
|
||||
word LocTsap, word RemTsap);
|
||||
EXPORTSPEC int S7API Par_Stop(S7Object Partner);
|
||||
// BSend
|
||||
EXPORTSPEC int S7API Par_BSend(S7Object Partner, longword R_ID, void *pUsrData, int Size);
|
||||
EXPORTSPEC int S7API Par_AsBSend(S7Object Partner, longword R_ID, void *pUsrData, int Size);
|
||||
EXPORTSPEC int S7API Par_CheckAsBSendCompletion(S7Object Partner, int &opResult);
|
||||
EXPORTSPEC int S7API Par_WaitAsBSendCompletion(S7Object Partner, longword Timeout);
|
||||
EXPORTSPEC int S7API Par_SetSendCallback(S7Object Partner, pfn_ParBSendCompletion pCompletion, void *usrPtr);
|
||||
// BRecv
|
||||
EXPORTSPEC int S7API Par_BRecv(S7Object Partner, longword &R_ID, void *pData, int &Size, longword Timeout);
|
||||
EXPORTSPEC int S7API Par_CheckAsBRecvCompletion(S7Object Partner, int &opResult, longword &R_ID,
|
||||
void *pData, int &Size);
|
||||
EXPORTSPEC int S7API Par_SetRecvCallback(S7Object Partner, pfn_ParBRecvCallBack pCompletion, void *usrPtr);
|
||||
// Stat
|
||||
EXPORTSPEC int S7API Par_GetTimes(S7Object Partner, longword &SendTime, longword &RecvTime);
|
||||
EXPORTSPEC int S7API Par_GetStats(S7Object Partner, longword &BytesSent, longword &BytesRecv,
|
||||
longword &SendErrors, longword &RecvErrors);
|
||||
EXPORTSPEC int S7API Par_GetLastError(S7Object Partner, int &LastError);
|
||||
EXPORTSPEC int S7API Par_GetStatus(S7Object Partner, int &Status);
|
||||
EXPORTSPEC int S7API Par_ErrorText(int Error, char *Text, int TextLen);
|
||||
|
||||
|
||||
|
||||
#endif // snap7_libmain_h
|
||||
923
utils/snap7_src/src/sys/snap_msgsock.cpp
Normal file
923
utils/snap7_src/src/sys/snap_msgsock.cpp
Normal file
@@ -0,0 +1,923 @@
|
||||
/*=============================================================================|
|
||||
| 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; //INADDR_ANY;
|
||||
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);
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
#ifdef NON_BLOCKING_CONNECT
|
||||
//
|
||||
// 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;
|
||||
}
|
||||
#else
|
||||
//
|
||||
// Regular connection (Windows)
|
||||
//
|
||||
int TMsgSocket::SckConnect()
|
||||
{
|
||||
int Result;
|
||||
SetSin(RemoteSin, RemoteAddress, RemotePort);
|
||||
if (LastTcpError==0)
|
||||
{
|
||||
if (Ping(RemoteSin))
|
||||
{
|
||||
CreateSocket();
|
||||
if (LastTcpError==0)
|
||||
{
|
||||
Result=connect(FSocket, (struct sockaddr*)&RemoteSin, sizeof(RemoteSin));
|
||||
if (SockCheck(Result)==0)
|
||||
{
|
||||
GetLocal();
|
||||
// Client handle is self_address (here the connection is ACTIVE)
|
||||
ClientHandle=LocalSin.sin_addr.s_addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
LastTcpError=WSAEHOSTUNREACH;
|
||||
}
|
||||
Connected=LastTcpError==0;
|
||||
return LastTcpError;
|
||||
}
|
||||
#endif
|
||||
//---------------------------------------------------------------------------
|
||||
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;
|
||||
|
||||
#ifdef OS_WINDOWS
|
||||
// iphlpapi, is loaded dinamically because if this fails we can still try
|
||||
// to use raw sockets
|
||||
|
||||
static char const *iphlpapi = "\\iphlpapi.dll";
|
||||
#pragma pack(1)
|
||||
|
||||
//typedef byte TTxBuffer[40];
|
||||
typedef byte TTxBuffer[32];
|
||||
#pragma pack()
|
||||
|
||||
typedef HANDLE (__stdcall *pfn_IcmpCreateFile)();
|
||||
typedef bool (__stdcall *pfn_IcmpCloseHandle)(HANDLE PingHandle);
|
||||
|
||||
typedef int (__stdcall *pfn_IcmpSendEcho2)(
|
||||
HANDLE PingHandle,
|
||||
void *Event,
|
||||
void *AcpRoutine,
|
||||
void *AcpContext,
|
||||
unsigned long DestinationAddress,
|
||||
void *RequestData,
|
||||
int RequestSize,
|
||||
void *not_used, //should be *IP_OPTION_INFORMATION but we don't use it
|
||||
void *ReplyBuffer,
|
||||
int ReplySize,
|
||||
int Timeout
|
||||
);
|
||||
|
||||
static pfn_IcmpCreateFile IcmpCreateFile;
|
||||
static pfn_IcmpCloseHandle IcmpCloseHandle;
|
||||
static pfn_IcmpSendEcho2 IcmpSendEcho2;
|
||||
static HINSTANCE IcmpDllHandle = 0;
|
||||
static bool IcmpAvail = false;
|
||||
|
||||
bool IcmpInit()
|
||||
{
|
||||
char iphlppath[MAX_PATH+12];
|
||||
|
||||
int PathLen = GetSystemDirectoryA(iphlppath, MAX_PATH);
|
||||
if (PathLen != 0)
|
||||
{
|
||||
strcat(iphlppath, iphlpapi);
|
||||
IcmpDllHandle = LoadLibraryA(iphlppath);
|
||||
}
|
||||
else
|
||||
IcmpDllHandle = 0;
|
||||
|
||||
if (IcmpDllHandle != 0)
|
||||
{
|
||||
IcmpCreateFile=(pfn_IcmpCreateFile)GetProcAddress(IcmpDllHandle,"IcmpCreateFile");
|
||||
IcmpCloseHandle=(pfn_IcmpCloseHandle)GetProcAddress(IcmpDllHandle,"IcmpCloseHandle");
|
||||
IcmpSendEcho2=(pfn_IcmpSendEcho2)GetProcAddress(IcmpDllHandle,"IcmpSendEcho2");
|
||||
return (IcmpCreateFile!=NULL) && (IcmpCloseHandle!=NULL) && (IcmpSendEcho2!=NULL);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void IcmpDone()
|
||||
{
|
||||
if (IcmpDllHandle!=0)
|
||||
FreeLibrary(IcmpDllHandle);
|
||||
IcmpAvail=false;
|
||||
}
|
||||
#endif
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// 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;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
#ifdef OS_WINDOWS
|
||||
bool TPinger::WinPing(longword ip_addr, int Timeout)
|
||||
{
|
||||
HANDLE PingHandle;
|
||||
TTxBuffer TxBuffer;
|
||||
TIcmpBuffer IcmpBuffer;
|
||||
bool Result;
|
||||
|
||||
PingHandle = IcmpCreateFile();
|
||||
if (PingHandle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
memset(&TxBuffer,'\55',sizeof(TTxBuffer));
|
||||
Result=(IcmpSendEcho2(PingHandle, NULL, NULL, NULL, ip_addr,
|
||||
&TxBuffer, sizeof(TxBuffer), NULL, &IcmpBuffer, ICmpBufferSize, Timeout))>0;
|
||||
IcmpCloseHandle(PingHandle);
|
||||
return Result;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
//---------------------------------------------------------------------------
|
||||
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)
|
||||
{
|
||||
#ifdef OS_WINDOWS
|
||||
if (PingKind==pkWinHelper)
|
||||
return WinPing(ip_addr, Timeout);
|
||||
else
|
||||
#endif
|
||||
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
|
||||
// - Winsock Startup (Windows)
|
||||
// - ICMP Helper Load (Windows)
|
||||
// - Check for raw socket (Unix or Windows if ICMP load failed)
|
||||
//---------------------------------------------------------------------------
|
||||
SocketsLayer::SocketsLayer()
|
||||
{
|
||||
#ifdef OS_WINDOWS
|
||||
timeBeginPeriod(1); // it's not strictly related to socket but here is a nice place
|
||||
WSAStartup(0x202,&wsaData);
|
||||
if (IcmpInit())
|
||||
PingKind=pkWinHelper;
|
||||
else
|
||||
#endif
|
||||
if (RawSocketsCheck())
|
||||
PingKind=pkRawSocket;
|
||||
else
|
||||
PingKind=pkCannotPing;
|
||||
}
|
||||
|
||||
SocketsLayer::~SocketsLayer()
|
||||
{
|
||||
#ifdef OS_WINDOWS
|
||||
IcmpDone();
|
||||
WSACleanup();
|
||||
timeEndPeriod(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
339
utils/snap7_src/src/sys/snap_msgsock.h
Normal file
339
utils/snap7_src/src/sys/snap_msgsock.h
Normal file
@@ -0,0 +1,339 @@
|
||||
/*=============================================================================|
|
||||
| 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"
|
||||
//----------------------------------------------------------------------------
|
||||
#if defined(OS_WINDOWS) || defined (OS_SOLARIS) || defined(OS_OSX)
|
||||
# define MSG_NOSIGNAL 0
|
||||
#endif
|
||||
//----------------------------------------------------------------------------
|
||||
// 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 ;)
|
||||
//----------------------------------------------------------------------------
|
||||
#ifdef PLATFORM_UNIX
|
||||
#define NON_BLOCKING_CONNECT
|
||||
#endif
|
||||
#ifdef NON_BLOCKING_CONNECT
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
//----------------------------------------------------------------------------
|
||||
/*
|
||||
In Windows sizeof socket varies depending of the platform :
|
||||
win32 -> sizeof(SOCKET) = 4
|
||||
win64 -> sizeof(SOCKET) = 8
|
||||
|
||||
Even though sizeof(SOCKET) is 8, should be safe to cast it to int, because
|
||||
the value constitutes an index in per-process table of limited size
|
||||
and not a real pointer.
|
||||
|
||||
Other Os define the socket as int regardless of the processor.
|
||||
|
||||
We want to sleep peacefully, so it's better to define a portable socket.
|
||||
*/
|
||||
|
||||
#ifdef OS_WINDOWS
|
||||
typedef SOCKET socket_t;
|
||||
#else
|
||||
typedef int socket_t;
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
#define SD_RECEIVE 0x00
|
||||
#define SD_SEND 0x01
|
||||
#define SD_BOTH 0x02
|
||||
#define MaxPacketSize 65536
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// For other platform we need to re-define next constants
|
||||
#if defined(PLATFORM_UNIX) || defined(OS_OSX)
|
||||
|
||||
#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
|
||||
#endif
|
||||
|
||||
#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
|
||||
{
|
||||
private:
|
||||
#ifdef OS_WINDOWS
|
||||
WSADATA wsaData;
|
||||
#endif
|
||||
public:
|
||||
SocketsLayer();
|
||||
~SocketsLayer();
|
||||
};
|
||||
|
||||
#endif // snap_msgsock_h
|
||||
152
utils/snap7_src/src/sys/snap_platform.h
Normal file
152
utils/snap7_src/src/sys/snap_platform.h
Normal file
@@ -0,0 +1,152 @@
|
||||
/*=============================================================================|
|
||||
| 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
|
||||
//---------------------------------------------------------------------------
|
||||
#if defined (_WIN32)|| defined(_WIN64)|| defined(__WIN32__) || defined(__WINDOWS__)
|
||||
# define OS_WINDOWS
|
||||
#endif
|
||||
|
||||
// Visual Studio needs this to use the correct time_t size
|
||||
#if defined (_WIN32) && !defined(_WIN64) && !defined(_EMBEDDING_VS2013UP)
|
||||
# define _USE_32BIT_TIME_T
|
||||
#endif
|
||||
|
||||
// Linux, BSD and Solaris define "unix", OSX doesn't, even though it derives from BSD
|
||||
#if defined(unix) || defined(__unix__) || defined(__unix)
|
||||
# define PLATFORM_UNIX
|
||||
#endif
|
||||
|
||||
#if BSD>=0
|
||||
# define OS_BSD
|
||||
#endif
|
||||
|
||||
#if __APPLE__
|
||||
# define OS_OSX
|
||||
#endif
|
||||
|
||||
#if defined(__SVR4) || defined(__svr4__)
|
||||
# define OS_SOLARIS
|
||||
// Thanks to Rolf Stalder now it's possible to use pthreads also for Solaris
|
||||
// In any case the Solaris native threads model is still present and can be
|
||||
// used uncommenting the #define line below.
|
||||
# undef OS_SOLARIS_NATIVE_THREADS
|
||||
// # define OS_SOLARIS_NATIVE_THREADS
|
||||
#endif
|
||||
|
||||
#if defined(PLATFORM_UNIX)
|
||||
# include <unistd.h>
|
||||
# include <sys/param.h>
|
||||
# if defined(_POSIX_VERSION)
|
||||
# define POSIX
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef OS_OSX
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if (!defined (OS_WINDOWS)) && (!defined(PLATFORM_UNIX)) && (!defined(OS_BSD)) && (!defined(OS_OSX))
|
||||
# error platform still unsupported (please add it yourself and report ;-)
|
||||
#endif
|
||||
|
||||
// Visual C++ not C99 compliant (VS2008--)
|
||||
#ifdef _MSC_VER
|
||||
# if _MSC_VER >= 1600
|
||||
# include <stdint.h> // VS2010++ have it
|
||||
# else
|
||||
typedef signed __int8 int8_t;
|
||||
typedef signed __int16 int16_t;
|
||||
typedef signed __int32 int32_t;
|
||||
typedef signed __int64 int64_t;
|
||||
typedef unsigned __int8 uint8_t;
|
||||
typedef unsigned __int16 uint16_t;
|
||||
typedef unsigned __int32 uint32_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
#ifdef _WIN64
|
||||
typedef unsigned __int64 uintptr_t;
|
||||
#else
|
||||
typedef unsigned __int32 uintptr_t;
|
||||
#endif
|
||||
# endif
|
||||
#else
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include <time.h>
|
||||
#include <cstring>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef OS_WINDOWS
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <windows.h>
|
||||
# include <winsock2.h>
|
||||
# include <mmsystem.h>
|
||||
#endif
|
||||
|
||||
#ifdef OS_SOLARIS
|
||||
# include <sys/filio.h>
|
||||
# include <cstdlib>
|
||||
# include <string.h>
|
||||
#endif
|
||||
|
||||
#if defined(PLATFORM_UNIX) || defined(OS_OSX)
|
||||
# include <errno.h>
|
||||
# include <sys/time.h>
|
||||
# include <sys/socket.h>
|
||||
# include <arpa/inet.h>
|
||||
# include <netinet/tcp.h>
|
||||
# include <netinet/in.h>
|
||||
# include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#ifdef OS_WINDOWS
|
||||
# define EXPORTSPEC extern "C" __declspec ( dllexport )
|
||||
# define S7API __stdcall
|
||||
#else
|
||||
# define EXPORTSPEC extern "C"
|
||||
# define S7API
|
||||
#endif
|
||||
|
||||
// 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
|
||||
73
utils/snap7_src/src/sys/snap_sysutils.cpp
Normal file
73
utils/snap7_src/src/sys/snap_sysutils.cpp
Normal file
@@ -0,0 +1,73 @@
|
||||
/*=============================================================================|
|
||||
| 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"
|
||||
|
||||
#ifdef OS_OSX
|
||||
int clock_gettime(int clk_id, struct timespec* t)
|
||||
{
|
||||
struct timeval now;
|
||||
int rv = gettimeofday(&now, NULL);
|
||||
if (rv) return rv;
|
||||
t->tv_sec = now.tv_sec;
|
||||
t->tv_nsec = now.tv_usec * 1000;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
longword SysGetTick()
|
||||
{
|
||||
#ifdef OS_WINDOWS
|
||||
return timeGetTime();
|
||||
#else
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
return (longword) (ts.tv_sec * 1000) + (ts.tv_nsec / 1000000);
|
||||
#endif
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
void SysSleep(longword Delay_ms)
|
||||
{
|
||||
#ifdef OS_WINDOWS
|
||||
Sleep(Delay_ms);
|
||||
#else
|
||||
struct timespec ts;
|
||||
ts.tv_sec = (time_t)(Delay_ms / 1000);
|
||||
ts.tv_nsec =(long)((Delay_ms - ts.tv_sec) * 1000000);
|
||||
nanosleep(&ts, (struct timespec *)0);
|
||||
#endif
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
longword DeltaTime(longword &Elapsed)
|
||||
{
|
||||
longword TheTime;
|
||||
TheTime=SysGetTick();
|
||||
// Checks for rollover
|
||||
if (TheTime<Elapsed)
|
||||
Elapsed=0;
|
||||
return TheTime-Elapsed;
|
||||
}
|
||||
39
utils/snap7_src/src/sys/snap_sysutils.h
Normal file
39
utils/snap7_src/src/sys/snap_sysutils.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*=============================================================================|
|
||||
| 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"
|
||||
//---------------------------------------------------------------------------
|
||||
#ifdef OS_OSX
|
||||
# define CLOCK_MONOTONIC 0
|
||||
#endif
|
||||
|
||||
longword SysGetTick();
|
||||
void SysSleep(longword Delay_ms);
|
||||
longword DeltaTime(longword &Elapsed);
|
||||
|
||||
#endif // snap_sysutils_h
|
||||
487
utils/snap7_src/src/sys/snap_tcpsrvr.cpp
Normal file
487
utils/snap7_src/src/sys/snap_tcpsrvr.cpp
Normal file
@@ -0,0 +1,487 @@
|
||||
/*=============================================================================|
|
||||
| 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_tcpsrvr.h"
|
||||
//---------------------------------------------------------------------------
|
||||
// EVENTS QUEUE
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
TMsgEventQueue::TMsgEventQueue(const int Capacity, const int BlockSize)
|
||||
{
|
||||
FCapacity = Capacity;
|
||||
Max = FCapacity - 1;
|
||||
FBlockSize = BlockSize;
|
||||
Buffer = new byte[FCapacity * FBlockSize];
|
||||
Flush();
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
TMsgEventQueue::~TMsgEventQueue()
|
||||
{
|
||||
delete[] Buffer;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
void TMsgEventQueue::Flush()
|
||||
{
|
||||
IndexIn = 0;
|
||||
IndexOut = 0;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
void TMsgEventQueue::Insert(void *lpdata)
|
||||
{
|
||||
pbyte PBlock;
|
||||
if (!Full())
|
||||
{
|
||||
// Calc offset
|
||||
if (IndexIn < Max) IndexIn++;
|
||||
else IndexIn = 0;
|
||||
PBlock = Buffer + uintptr_t(IndexIn * FBlockSize);
|
||||
memcpy(PBlock, lpdata, FBlockSize);
|
||||
};
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
bool TMsgEventQueue::Extract(void *lpdata)
|
||||
{
|
||||
int IdxOut;
|
||||
pbyte PBlock;
|
||||
|
||||
if (!Empty())
|
||||
{
|
||||
// stores IndexOut
|
||||
IdxOut = IndexOut;
|
||||
if (IdxOut < Max) IdxOut++;
|
||||
else IdxOut = 0;
|
||||
PBlock = Buffer + uintptr_t(IdxOut * FBlockSize);
|
||||
// moves data
|
||||
memcpy(lpdata, PBlock, FBlockSize);
|
||||
// Updates IndexOut
|
||||
IndexOut = IdxOut;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
bool TMsgEventQueue::Empty()
|
||||
{
|
||||
return (IndexIn == IndexOut);
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
bool TMsgEventQueue::Full()
|
||||
{
|
||||
int IdxOut = IndexOut; // To avoid troubles if IndexOut changes during next line
|
||||
return ( (IdxOut == IndexIn + 1) || ((IndexIn == Max) && (IdxOut == 0)));
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
// WORKER THREAD
|
||||
//---------------------------------------------------------------------------
|
||||
TMsgWorkerThread::TMsgWorkerThread(TMsgSocket *Socket, TCustomMsgServer *Server)
|
||||
{
|
||||
FreeOnTerminate = true;
|
||||
WorkerSocket = Socket;
|
||||
FServer = Server;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
void TMsgWorkerThread::Execute()
|
||||
{
|
||||
bool Exception = false;
|
||||
bool SelfClose = false;
|
||||
// Working loop
|
||||
while (!Terminated && !SelfClose && !Exception && !FServer->Destroying)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!WorkerSocket->Execute()) // False -> End of Activities
|
||||
SelfClose = true;
|
||||
} catch (...)
|
||||
{
|
||||
Exception = true;
|
||||
}
|
||||
};
|
||||
if (!FServer->Destroying)
|
||||
{
|
||||
// Exception detected during Worker activity
|
||||
if (Exception)
|
||||
{
|
||||
WorkerSocket->ForceClose();
|
||||
FServer->DoEvent(WorkerSocket->ClientHandle, evcClientException, 0, 0, 0, 0, 0);
|
||||
}
|
||||
else
|
||||
if (SelfClose)
|
||||
{
|
||||
FServer->DoEvent(WorkerSocket->ClientHandle, evcClientDisconnected, 0, 0, 0, 0, 0);
|
||||
}
|
||||
else
|
||||
FServer->DoEvent(WorkerSocket->ClientHandle, evcClientTerminated, 0, 0, 0, 0, 0);
|
||||
}
|
||||
delete WorkerSocket;
|
||||
// Delete reference from list
|
||||
FServer->Delete(Index);
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
// LISTENER THREAD
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
TMsgListenerThread::TMsgListenerThread(TMsgSocket *Listener, TCustomMsgServer *Server)
|
||||
{
|
||||
FServer = Server;
|
||||
FListener = Listener;
|
||||
FreeOnTerminate = false;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void TMsgListenerThread::Execute()
|
||||
{
|
||||
socket_t Sock;
|
||||
bool Valid;
|
||||
|
||||
while (!Terminated)
|
||||
{
|
||||
if (FListener->CanRead(FListener->WorkInterval))
|
||||
{
|
||||
Sock = FListener->SckAccept(); // in any case we must accept
|
||||
Valid = Sock != INVALID_SOCKET;
|
||||
// check if we are not destroying
|
||||
if ((!Terminated) && (!FServer->Destroying))
|
||||
{
|
||||
if (Valid)
|
||||
FServer->Incoming(Sock);
|
||||
}
|
||||
else
|
||||
if (Valid)
|
||||
Msg_CloseSocket(Sock);
|
||||
};
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
// TCP SERVER
|
||||
//---------------------------------------------------------------------------
|
||||
TCustomMsgServer::TCustomMsgServer()
|
||||
{
|
||||
strcpy(FLocalAddress, "0.0.0.0");
|
||||
CSList = new TSnapCriticalSection();
|
||||
CSEvent = new TSnapCriticalSection();
|
||||
FEventQueue = new TMsgEventQueue(MaxEvents, sizeof (TSrvEvent));
|
||||
memset(Workers, 0, sizeof (Workers));
|
||||
for (int i = 0; i < MaxWorkers; i++)
|
||||
Workers[i] = NULL;
|
||||
Status = SrvStopped;
|
||||
EventMask = 0xFFFFFFFF;
|
||||
LogMask = 0xFFFFFFFF;
|
||||
Destroying = false;
|
||||
FLastError = 0;
|
||||
ClientsCount = 0;
|
||||
LocalBind = 0;
|
||||
MaxClients = MaxWorkers;
|
||||
OnEvent = NULL;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
TCustomMsgServer::~TCustomMsgServer()
|
||||
{
|
||||
Destroying = true;
|
||||
Stop();
|
||||
OnEvent = NULL;
|
||||
delete CSList;
|
||||
delete CSEvent;
|
||||
delete FEventQueue;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
void TCustomMsgServer::LockList()
|
||||
{
|
||||
CSList->Enter();
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
void TCustomMsgServer::UnlockList()
|
||||
{
|
||||
CSList->Leave();
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
int TCustomMsgServer::FirstFree()
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < MaxWorkers; i++)
|
||||
{
|
||||
if (Workers[i] == 0)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
int TCustomMsgServer::StartListener()
|
||||
{
|
||||
int Result;
|
||||
// Creates the listener
|
||||
SockListener = new TMsgSocket();
|
||||
strncpy(SockListener->LocalAddress, FLocalAddress, 16);
|
||||
SockListener->LocalPort = LocalPort;
|
||||
// Binds
|
||||
Result = SockListener->SckBind();
|
||||
if (Result == 0)
|
||||
{
|
||||
LocalBind = SockListener->LocalBind;
|
||||
// Listen
|
||||
Result = SockListener->SckListen();
|
||||
if (Result == 0)
|
||||
{
|
||||
// Creates the Listener thread
|
||||
ServerThread = new TMsgListenerThread(SockListener, this);
|
||||
ServerThread->Start();
|
||||
}
|
||||
else
|
||||
delete SockListener;
|
||||
}
|
||||
else
|
||||
delete SockListener;
|
||||
|
||||
return Result;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
void TCustomMsgServer::TerminateAll()
|
||||
{
|
||||
int c;
|
||||
longword Elapsed;
|
||||
bool Timeout;
|
||||
|
||||
if (ClientsCount > 0)
|
||||
{
|
||||
for (c = 0; c < MaxWorkers; c++)
|
||||
{
|
||||
if (Workers[c] != 0)
|
||||
PMsgWorkerThread(Workers[c])->Terminate();
|
||||
}
|
||||
// Wait for closing
|
||||
Elapsed = SysGetTick();
|
||||
Timeout = false;
|
||||
while (!Timeout && (ClientsCount > 0))
|
||||
{
|
||||
Timeout = DeltaTime(Elapsed) > WkTimeout;
|
||||
if (!Timeout)
|
||||
SysSleep(100);
|
||||
};
|
||||
if (ClientsCount > 0)
|
||||
KillAll(); // one o more threads are hanged
|
||||
ClientsCount = 0;
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
void TCustomMsgServer::KillAll()
|
||||
{
|
||||
int c, cnt = 0;
|
||||
LockList();
|
||||
for (c = 0; c < MaxWorkers; c++)
|
||||
{
|
||||
if (Workers[c] != 0)
|
||||
try
|
||||
{
|
||||
PMsgWorkerThread(Workers[c])->Kill();
|
||||
PMsgWorkerThread(Workers[c])->WorkerSocket->ForceClose();
|
||||
delete PMsgWorkerThread(Workers[c]);
|
||||
Workers[c] = 0;
|
||||
cnt++;
|
||||
} catch (...)
|
||||
{
|
||||
};
|
||||
}
|
||||
UnlockList();
|
||||
DoEvent(0, evcClientsDropped, 0, cnt, 0, 0, 0);
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
bool TCustomMsgServer::CanAccept(socket_t Socket)
|
||||
{
|
||||
return ((MaxClients == 0) || (ClientsCount < MaxClients));
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
PWorkerSocket TCustomMsgServer::CreateWorkerSocket(socket_t Sock)
|
||||
{
|
||||
PWorkerSocket Result;
|
||||
// Creates a funny default class : a tcp echo worker
|
||||
Result = new TEcoTcpWorker();
|
||||
Result->SetSocket(Sock);
|
||||
return Result;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
void TCustomMsgServer::DoEvent(int Sender, longword Code, word RetCode, word Param1, word Param2, word Param3, word Param4)
|
||||
{
|
||||
TSrvEvent SrvEvent;
|
||||
bool GoLog = (Code & LogMask) != 0;
|
||||
bool GoEvent = (Code & EventMask) != 0;
|
||||
|
||||
if (!Destroying && (GoLog || GoEvent))
|
||||
{
|
||||
CSEvent->Enter();
|
||||
|
||||
time(&SrvEvent.EvtTime);
|
||||
SrvEvent.EvtSender = Sender;
|
||||
SrvEvent.EvtCode = Code;
|
||||
SrvEvent.EvtRetCode = RetCode;
|
||||
SrvEvent.EvtParam1 = Param1;
|
||||
SrvEvent.EvtParam2 = Param2;
|
||||
SrvEvent.EvtParam3 = Param3;
|
||||
SrvEvent.EvtParam4 = Param4;
|
||||
|
||||
if (GoEvent && (OnEvent != NULL))
|
||||
try
|
||||
{ // callback is outside here, we have to shield it
|
||||
OnEvent(FUsrPtr, &SrvEvent, sizeof (TSrvEvent));
|
||||
} catch (...)
|
||||
{
|
||||
};
|
||||
|
||||
if (GoLog)
|
||||
FEventQueue->Insert(&SrvEvent);
|
||||
|
||||
CSEvent->Leave();
|
||||
};
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
void TCustomMsgServer::Delete(int Index)
|
||||
{
|
||||
LockList();
|
||||
Workers[Index] = 0;
|
||||
ClientsCount--;
|
||||
UnlockList();
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
void TCustomMsgServer::Incoming(socket_t Sock)
|
||||
{
|
||||
int idx;
|
||||
PWorkerSocket WorkerSocket;
|
||||
longword ClientHandle = Msg_GetSockAddr(Sock);
|
||||
|
||||
if (CanAccept(Sock))
|
||||
{
|
||||
LockList();
|
||||
// First position available in the thread buffer
|
||||
idx = FirstFree();
|
||||
if (idx >= 0)
|
||||
{
|
||||
// Creates the Worker and assigns it the connected socket
|
||||
WorkerSocket = CreateWorkerSocket(Sock);
|
||||
// Creates the Worker thread
|
||||
Workers[idx] = new TMsgWorkerThread(WorkerSocket, this);
|
||||
PMsgWorkerThread(Workers[idx])->Index = idx;
|
||||
// Update the number
|
||||
ClientsCount++;
|
||||
// And Starts the worker
|
||||
PMsgWorkerThread(Workers[idx])->Start();
|
||||
DoEvent(WorkerSocket->ClientHandle, evcClientAdded, 0, 0, 0, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
DoEvent(ClientHandle, evcClientNoRoom, 0, 0, 0, 0, 0);
|
||||
Msg_CloseSocket(Sock);
|
||||
}
|
||||
UnlockList();
|
||||
}
|
||||
else
|
||||
{
|
||||
Msg_CloseSocket(Sock);
|
||||
DoEvent(ClientHandle, evcClientRejected, 0, 0, 0, 0, 0);
|
||||
};
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
int TCustomMsgServer::Start()
|
||||
{
|
||||
int Result = 0;
|
||||
if (Status != SrvRunning)
|
||||
{
|
||||
Result = StartListener();
|
||||
if (Result != 0)
|
||||
{
|
||||
DoEvent(0, evcListenerCannotStart, Result, 0, 0, 0, 0);
|
||||
Status = SrvError;
|
||||
}
|
||||
else
|
||||
{
|
||||
DoEvent(0, evcServerStarted, SockListener->ClientHandle, LocalPort, 0, 0, 0);
|
||||
Status = SrvRunning;
|
||||
};
|
||||
};
|
||||
FLastError = Result;
|
||||
return Result;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
int TCustomMsgServer::StartTo(const char *Address, word Port)
|
||||
{
|
||||
strncpy(FLocalAddress, Address, 16);
|
||||
LocalPort = Port;
|
||||
return Start();
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
void TCustomMsgServer::Stop()
|
||||
{
|
||||
if (Status == SrvRunning)
|
||||
{
|
||||
// Kills the listener thread
|
||||
ServerThread->Terminate();
|
||||
if (ServerThread->WaitFor(ThTimeout) != WAIT_OBJECT_0)
|
||||
ServerThread->Kill();
|
||||
delete ServerThread;
|
||||
// Kills the listener
|
||||
delete SockListener;
|
||||
|
||||
// Terminate all client threads
|
||||
TerminateAll();
|
||||
|
||||
Status = SrvStopped;
|
||||
LocalBind = 0;
|
||||
DoEvent(0, evcServerStopped, 0, 0, 0, 0, 0);
|
||||
};
|
||||
FLastError = 0;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
int TCustomMsgServer::SetEventsCallBack(pfn_SrvCallBack PCallBack, void *UsrPtr)
|
||||
{
|
||||
OnEvent = PCallBack;
|
||||
FUsrPtr = UsrPtr;
|
||||
return 0;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
bool TCustomMsgServer::PickEvent(void *pEvent)
|
||||
{
|
||||
try
|
||||
{
|
||||
return FEventQueue->Extract(pEvent);
|
||||
} catch (...)
|
||||
{
|
||||
return false;
|
||||
};
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
bool TCustomMsgServer::EventEmpty()
|
||||
{
|
||||
return FEventQueue->Empty();
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
void TCustomMsgServer::EventsFlush()
|
||||
{
|
||||
CSEvent->Enter();
|
||||
FEventQueue->Flush();
|
||||
CSEvent->Leave();
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
|
||||
247
utils/snap7_src/src/sys/snap_tcpsrvr.h
Normal file
247
utils/snap7_src/src/sys/snap_tcpsrvr.h
Normal file
@@ -0,0 +1,247 @@
|
||||
/*=============================================================================|
|
||||
| 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_tcpsrvr_h
|
||||
#define snap_tcpsrvr_h
|
||||
//---------------------------------------------------------------------------
|
||||
#include "snap_msgsock.h"
|
||||
#include "snap_threads.h"
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#define MaxWorkers 1024
|
||||
#define MaxEvents 1500
|
||||
|
||||
const int SrvStopped = 0;
|
||||
const int SrvRunning = 1;
|
||||
const int SrvError = 2;
|
||||
|
||||
const longword evcServerStarted = 0x00000001;
|
||||
const longword evcServerStopped = 0x00000002;
|
||||
const longword evcListenerCannotStart = 0x00000004;
|
||||
const longword evcClientAdded = 0x00000008;
|
||||
const longword evcClientRejected = 0x00000010;
|
||||
const longword evcClientNoRoom = 0x00000020;
|
||||
const longword evcClientException = 0x00000040;
|
||||
const longword evcClientDisconnected = 0x00000080;
|
||||
const longword evcClientTerminated = 0x00000100;
|
||||
const longword evcClientsDropped = 0x00000200;
|
||||
const longword evcReserved_00000400 = 0x00000400;
|
||||
const longword evcReserved_00000800 = 0x00000800;
|
||||
const longword evcReserved_00001000 = 0x00001000;
|
||||
const longword evcReserved_00002000 = 0x00002000;
|
||||
const longword evcReserved_00004000 = 0x00004000;
|
||||
const longword evcReserved_00008000 = 0x00008000;
|
||||
|
||||
// Server Interface errors
|
||||
const longword errSrvBase = 0x0000FFFF;
|
||||
const longword errSrvMask = 0xFFFF0000;
|
||||
const longword errSrvCannotStart = 0x00100000;
|
||||
|
||||
const longword ThTimeout = 2000; // Thread timeout
|
||||
const longword WkTimeout = 3000; // Workers termination timeout
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
typedef struct{
|
||||
time_t EvtTime; // Timestamp
|
||||
int EvtSender; // Sender
|
||||
longword EvtCode; // Event code
|
||||
word EvtRetCode; // Event result
|
||||
word EvtParam1; // Param 1 (if available)
|
||||
word EvtParam2; // Param 2 (if available)
|
||||
word EvtParam3; // Param 3 (if available)
|
||||
word EvtParam4; // Param 4 (if available)
|
||||
}TSrvEvent, *PSrvEvent;
|
||||
|
||||
extern "C"
|
||||
{
|
||||
typedef void (S7API *pfn_SrvCallBack)(void * usrPtr, PSrvEvent PEvent, int Size);
|
||||
}
|
||||
#pragma pack()
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// EVENTS QUEUE
|
||||
//---------------------------------------------------------------------------
|
||||
class TMsgEventQueue
|
||||
{
|
||||
private:
|
||||
int IndexIn; // <-- insert index
|
||||
int IndexOut; // --> extract index
|
||||
int Max; // Buffer upper bound [0..Max]
|
||||
int FCapacity; // Queue capacity
|
||||
pbyte Buffer;
|
||||
int FBlockSize;
|
||||
public:
|
||||
TMsgEventQueue(const int Capacity, const int BlockSize);
|
||||
~TMsgEventQueue();
|
||||
void Flush();
|
||||
void Insert(void *lpdata);
|
||||
bool Extract(void *lpdata);
|
||||
bool Empty();
|
||||
bool Full();
|
||||
};
|
||||
typedef TMsgEventQueue *PMsgEventQueue;
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// WORKER THREAD
|
||||
//---------------------------------------------------------------------------
|
||||
class TCustomMsgServer; // forward declaration
|
||||
|
||||
// It's created when connection is accepted, it will interface with the client.
|
||||
class TMsgWorkerThread : public TSnapThread
|
||||
{
|
||||
private:
|
||||
TCustomMsgServer *FServer;
|
||||
protected:
|
||||
TMsgSocket *WorkerSocket;
|
||||
public:
|
||||
int Index;
|
||||
friend class TCustomMsgServer;
|
||||
TMsgWorkerThread(TMsgSocket *Socket, TCustomMsgServer *Server);
|
||||
void Execute();
|
||||
};
|
||||
typedef TMsgWorkerThread *PMsgWorkerThread;
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// LISTENER THREAD
|
||||
//---------------------------------------------------------------------------
|
||||
// It listens for incoming connection.
|
||||
class TMsgListenerThread : public TSnapThread
|
||||
{
|
||||
private:
|
||||
TMsgSocket *FListener;
|
||||
TCustomMsgServer *FServer;
|
||||
public:
|
||||
TMsgListenerThread(TMsgSocket *Listener, TCustomMsgServer *Server);
|
||||
void Execute();
|
||||
};
|
||||
typedef TMsgListenerThread *PMsgListenerThread;
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// TCP SERVER
|
||||
//---------------------------------------------------------------------------
|
||||
typedef TMsgSocket *PWorkerSocket;
|
||||
|
||||
class TCustomMsgServer
|
||||
{
|
||||
private:
|
||||
int FLastError;
|
||||
char FLocalAddress[16];
|
||||
// Socket listener
|
||||
PMsgSocket SockListener;
|
||||
// Server listener
|
||||
PMsgListenerThread ServerThread;
|
||||
// Critical section to lock Workers list activities
|
||||
PSnapCriticalSection CSList;
|
||||
// Event queue
|
||||
PMsgEventQueue FEventQueue;
|
||||
// Callback related
|
||||
pfn_SrvCallBack OnEvent;
|
||||
void *FUsrPtr;
|
||||
// private methods
|
||||
int StartListener();
|
||||
void LockList();
|
||||
void UnlockList();
|
||||
int FirstFree();
|
||||
protected:
|
||||
bool Destroying;
|
||||
// Critical section to lock Event activities
|
||||
PSnapCriticalSection CSEvent;
|
||||
// Workers list
|
||||
void *Workers[MaxWorkers];
|
||||
// Terminates all worker threads
|
||||
virtual void TerminateAll();
|
||||
// Kills all worker threads that are unresponsive
|
||||
void KillAll();
|
||||
// if (true the connection is accepted, otherwise the connection
|
||||
// is closed gracefully
|
||||
virtual bool CanAccept(socket_t Socket);
|
||||
// Returns the class of the worker socket, override it for real servers
|
||||
virtual PWorkerSocket CreateWorkerSocket(socket_t Sock);
|
||||
// Handles the event
|
||||
virtual void DoEvent(int Sender, longword Code, word RetCode, word Param1,
|
||||
word Param2, word Param3, word Param4);
|
||||
// Delete the worker from the list (It's invoked by Worker Thread)
|
||||
void Delete(int Index);
|
||||
// Incoming connection (It's invoked by ServerThread, the listener)
|
||||
virtual void Incoming(socket_t Sock);
|
||||
public:
|
||||
friend class TMsgWorkerThread;
|
||||
friend class TMsgListenerThread;
|
||||
word LocalPort;
|
||||
longword LocalBind;
|
||||
longword LogMask;
|
||||
longword EventMask;
|
||||
int Status;
|
||||
int ClientsCount;
|
||||
int MaxClients;
|
||||
TCustomMsgServer();
|
||||
virtual ~TCustomMsgServer();
|
||||
// Starts the server
|
||||
int Start();
|
||||
int StartTo(const char *Address, word Port);
|
||||
// Stops the server
|
||||
void Stop();
|
||||
// Sets Event callback
|
||||
int SetEventsCallBack(pfn_SrvCallBack PCallBack, void *UsrPtr);
|
||||
// Pick an event from the circular queue
|
||||
bool PickEvent(void *pEvent);
|
||||
// Returns true if (the Event queue is empty
|
||||
bool EventEmpty();
|
||||
// Flushes Event queue
|
||||
void EventsFlush();
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// TCP WORKER
|
||||
//---------------------------------------------------------------------------
|
||||
// Default worker class, a simply tcp echo to test the connection and
|
||||
// data I/O to use the server outside the project
|
||||
class TEcoTcpWorker : public TMsgSocket
|
||||
{
|
||||
public:
|
||||
bool Execute()
|
||||
{
|
||||
byte Buffer[4096];
|
||||
int Size;
|
||||
|
||||
if (CanRead(WorkInterval)) // Small time to avoid time wait during the close
|
||||
{
|
||||
Receive(&Buffer,sizeof(Buffer),Size);
|
||||
if ((LastTcpError==0) && (Size>0))
|
||||
{
|
||||
SendPacket(&Buffer,Size);
|
||||
return LastTcpError==0;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return true;
|
||||
};
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
#endif // snap_tcpsrvr_h
|
||||
162
utils/snap7_src/src/sys/snap_threads.cpp
Normal file
162
utils/snap7_src/src/sys/snap_threads.cpp
Normal file
@@ -0,0 +1,162 @@
|
||||
/*=============================================================================|
|
||||
| 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"
|
||||
//---------------------------------------------------------------------------
|
||||
#ifdef OS_WINDOWS
|
||||
DWORD WINAPI ThreadProc(LPVOID param)
|
||||
#else
|
||||
|
||||
void* ThreadProc(void* param)
|
||||
#endif
|
||||
{
|
||||
PSnapThread Thread;
|
||||
// Unix but not Solaris
|
||||
#if (defined(POSIX) || defined(OS_OSX)) && (!defined(OS_SOLARIS_NATIVE_THREADS))
|
||||
int last_type, last_state;
|
||||
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &last_type);
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &last_state);
|
||||
#endif
|
||||
Thread = PSnapThread(param);
|
||||
|
||||
if (!Thread->Terminated)
|
||||
try
|
||||
{
|
||||
Thread->Execute();
|
||||
} catch (...)
|
||||
{
|
||||
};
|
||||
Thread->Closed = true;
|
||||
if (Thread->FreeOnTerminate)
|
||||
{
|
||||
delete Thread;
|
||||
};
|
||||
#ifdef OS_WINDOWS
|
||||
ExitThread(0);
|
||||
#endif
|
||||
#if defined(POSIX) && (!defined(OS_SOLARIS_NATIVE_THREADS))
|
||||
pthread_exit((void*)0);
|
||||
#endif
|
||||
#if defined(OS_OSX)
|
||||
pthread_exit((void*)0);
|
||||
#endif
|
||||
#ifdef OS_SOLARIS_NATIVE_THREADS
|
||||
thr_exit((void*)0);
|
||||
#endif
|
||||
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();
|
||||
};
|
||||
#ifdef OS_WINDOWS
|
||||
if (Started)
|
||||
CloseHandle(th);
|
||||
#endif
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
void TSnapThread::ThreadCreate()
|
||||
{
|
||||
#ifdef OS_WINDOWS
|
||||
th = CreateThread(0, 0, ThreadProc, this, 0, 0);
|
||||
#endif
|
||||
#if defined(POSIX) && (!defined(OS_SOLARIS_NATIVE_THREADS))
|
||||
pthread_attr_t a;
|
||||
pthread_attr_init(&a);
|
||||
pthread_attr_setdetachstate(&a, PTHREAD_CREATE_DETACHED);
|
||||
pthread_create(&th, &a, &ThreadProc, this);
|
||||
#endif
|
||||
#if defined(OS_OSX)
|
||||
pthread_create(&th, 0, &ThreadProc, this);
|
||||
#endif
|
||||
#ifdef OS_SOLARIS_NATIVE_THREADS
|
||||
thr_create(0, // default stack base
|
||||
0, // default stack size
|
||||
&ThreadProc, // Thread routine
|
||||
this, // argument
|
||||
0,
|
||||
&th);
|
||||
#endif
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
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;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
45
utils/snap7_src/src/sys/snap_threads.h
Normal file
45
utils/snap7_src/src/sys/snap_threads.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/*=============================================================================|
|
||||
| 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"
|
||||
|
||||
#ifdef OS_WINDOWS
|
||||
# include "win_threads.h"
|
||||
#endif
|
||||
#if defined(POSIX) && (!defined(OS_SOLARIS_NATIVE_THREADS))
|
||||
# include "unix_threads.h"
|
||||
#endif
|
||||
#ifdef OS_SOLARIS_NATIVE_THREADS
|
||||
# include "sol_threads.h"
|
||||
#endif
|
||||
#if defined(OS_OSX)
|
||||
# include "unix_threads.h"
|
||||
#endif
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
#endif // snap_threads_h
|
||||
208
utils/snap7_src/src/sys/sol_threads.h
Normal file
208
utils/snap7_src/src/sys/sol_threads.h
Normal file
@@ -0,0 +1,208 @@
|
||||
/*=============================================================================|
|
||||
| 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/ |
|
||||
|==============================================================================|
|
||||
| |
|
||||
| Solaris 11 Threads support |
|
||||
| |
|
||||
|=============================================================================*/
|
||||
#ifndef sol_threads_h
|
||||
#define sol_threads_h
|
||||
//---------------------------------------------------------------------------
|
||||
#include "snap_platform.h"
|
||||
#include "snap_sysutils.h"
|
||||
#include <thread.h>
|
||||
#include <synch.h>
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
class TSnapCriticalSection {
|
||||
private:
|
||||
mutex_t mx;
|
||||
int result;
|
||||
public:
|
||||
|
||||
TSnapCriticalSection() {
|
||||
mutex_init(&mx, USYNC_THREAD, 0);
|
||||
};
|
||||
|
||||
~TSnapCriticalSection() {
|
||||
mutex_destroy(&mx);
|
||||
};
|
||||
|
||||
void Enter() {
|
||||
mutex_lock(&mx);
|
||||
};
|
||||
|
||||
void Leave() {
|
||||
mutex_unlock(&mx);
|
||||
};
|
||||
|
||||
bool TryEnter() {
|
||||
return 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:
|
||||
cond_t CVariable;
|
||||
mutex_t Mutex;
|
||||
bool AutoReset;
|
||||
bool State;
|
||||
public:
|
||||
|
||||
TSnapEvent(bool ManualReset)
|
||||
{
|
||||
AutoReset = !ManualReset;
|
||||
cond_init(&CVariable, USYNC_THREAD, 0) == 0;
|
||||
mutex_init(&Mutex, USYNC_THREAD, 0);
|
||||
State = false;
|
||||
}
|
||||
|
||||
~TSnapEvent()
|
||||
{
|
||||
cond_destroy(&CVariable);
|
||||
mutex_destroy(&Mutex);
|
||||
};
|
||||
|
||||
void Set()
|
||||
{
|
||||
mutex_lock(&Mutex);
|
||||
State = true;
|
||||
if (AutoReset)
|
||||
cond_signal(&CVariable);
|
||||
else
|
||||
cond_broadcast(&CVariable);
|
||||
mutex_unlock(&Mutex);
|
||||
};
|
||||
|
||||
void Reset()
|
||||
{
|
||||
mutex_lock(&Mutex);
|
||||
State = false;
|
||||
mutex_unlock(&Mutex);
|
||||
}
|
||||
|
||||
longword WaitForever()
|
||||
{
|
||||
mutex_lock(&Mutex);
|
||||
while (!State) // <-- to avoid spurious wakeups
|
||||
cond_wait(&CVariable, &Mutex);
|
||||
if (AutoReset)
|
||||
State = false;
|
||||
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) {
|
||||
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 = cond_timedwait(&CVariable, &Mutex, &ts);
|
||||
if (Result == ETIMEDOUT)
|
||||
Result = WAIT_TIMEOUT;
|
||||
}
|
||||
while (Result == 0 && !State);
|
||||
}
|
||||
else
|
||||
if (AutoReset) // take the ownership
|
||||
State = false;
|
||||
mutex_unlock(&Mutex);
|
||||
return Result;
|
||||
}
|
||||
else // Timeout<0
|
||||
return WaitForever();
|
||||
};
|
||||
};
|
||||
typedef TSnapEvent *PSnapEvent;
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
class TSnapThread {
|
||||
private:
|
||||
thread_t th;
|
||||
bool FCreateSuspended;
|
||||
void ThreadCreate();
|
||||
|
||||
void ThreadJoin()
|
||||
{
|
||||
thr_join(th, 0, 0);
|
||||
};
|
||||
|
||||
void ThreadKill()
|
||||
{
|
||||
thr_kill(th, 0);
|
||||
};
|
||||
|
||||
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 // sol_threads_h
|
||||
228
utils/snap7_src/src/sys/unix_threads.h
Normal file
228
utils/snap7_src/src/sys/unix_threads.h
Normal file
@@ -0,0 +1,228 @@
|
||||
/*=============================================================================|
|
||||
| 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/ |
|
||||
|==============================================================================|
|
||||
| |
|
||||
| Posix Threads support (Linux, FreeBSD) |
|
||||
| |
|
||||
|=============================================================================*/
|
||||
#ifndef unix_threads_h
|
||||
#define unix_threads_h
|
||||
//---------------------------------------------------------------------------
|
||||
#include "snap_platform.h"
|
||||
#include "snap_sysutils.h"
|
||||
#include <semaphore.h>
|
||||
#include <pthread.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 // unix_threads_h
|
||||
159
utils/snap7_src/src/sys/win_threads.h
Normal file
159
utils/snap7_src/src/sys/win_threads.h
Normal file
@@ -0,0 +1,159 @@
|
||||
/*=============================================================================|
|
||||
| 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/ |
|
||||
|==============================================================================|
|
||||
| |
|
||||
| Windows Threads support (Windows, ReactOS) |
|
||||
| |
|
||||
|=============================================================================*/
|
||||
#ifndef win_threads_h
|
||||
#define win_threads_h
|
||||
//---------------------------------------------------------------------------
|
||||
#include "snap_platform.h"
|
||||
#include "snap_sysutils.h"
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
class TSnapCriticalSection
|
||||
{
|
||||
private:
|
||||
CRITICAL_SECTION cs;
|
||||
public:
|
||||
|
||||
TSnapCriticalSection()
|
||||
{
|
||||
InitializeCriticalSection(&cs);
|
||||
};
|
||||
|
||||
~TSnapCriticalSection()
|
||||
{
|
||||
DeleteCriticalSection(&cs);
|
||||
};
|
||||
|
||||
void Enter()
|
||||
{
|
||||
EnterCriticalSection(&cs);
|
||||
};
|
||||
|
||||
void Leave()
|
||||
{
|
||||
LeaveCriticalSection(&cs);
|
||||
};
|
||||
|
||||
bool TryEnter()
|
||||
{
|
||||
return (TryEnterCriticalSection(&cs) != 0);
|
||||
};
|
||||
};
|
||||
typedef TSnapCriticalSection *PSnapCriticalSection;
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
class TSnapEvent
|
||||
{
|
||||
private:
|
||||
HANDLE Event;
|
||||
public:
|
||||
|
||||
TSnapEvent(bool ManualReset)
|
||||
{
|
||||
Event = CreateEvent(0, ManualReset, false, 0);
|
||||
};
|
||||
|
||||
~TSnapEvent()
|
||||
{
|
||||
if (Event != 0)
|
||||
CloseHandle(Event);
|
||||
};
|
||||
|
||||
void Set()
|
||||
{
|
||||
if (Event != 0)
|
||||
SetEvent(Event);
|
||||
};
|
||||
|
||||
void Reset()
|
||||
{
|
||||
if (Event != 0)
|
||||
ResetEvent(Event);
|
||||
};
|
||||
|
||||
longword WaitForever()
|
||||
{
|
||||
if (Event != 0)
|
||||
return WaitForSingleObject(Event, INFINITE);
|
||||
else
|
||||
return WAIT_FAILED;
|
||||
};
|
||||
|
||||
longword WaitFor(int64_t Timeout) {
|
||||
if (Event != 0)
|
||||
return WaitForSingleObject(Event, DWORD(Timeout));
|
||||
else
|
||||
return WAIT_FAILED;
|
||||
};
|
||||
};
|
||||
typedef TSnapEvent *PSnapEvent;
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
class TSnapThread {
|
||||
private:
|
||||
HANDLE th;
|
||||
bool FCreateSuspended;
|
||||
void ThreadCreate();
|
||||
|
||||
void ThreadJoin()
|
||||
{
|
||||
WaitForSingleObject(th, INFINITE);
|
||||
};
|
||||
|
||||
void ThreadKill()
|
||||
{
|
||||
TerminateThread(th, 0);
|
||||
};
|
||||
|
||||
longword ThreadWait(uint64_t Timeout)
|
||||
{
|
||||
return WaitForSingleObject(th, DWORD(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 // win_threads_h
|
||||
1281
utils/snap7_src/wrapper/oplc_snap7.cpp
Normal file
1281
utils/snap7_src/wrapper/oplc_snap7.cpp
Normal file
File diff suppressed because it is too large
Load Diff
950
utils/snap7_src/wrapper/oplc_snap7.h
Normal file
950
utils/snap7_src/wrapper/oplc_snap7.h
Normal file
@@ -0,0 +1,950 @@
|
||||
/*=============================================================================|
|
||||
| PROJECT SNAP7 1.4.3 |
|
||||
|==============================================================================|
|
||||
| Copyright (C) 2013, 2025 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/ |
|
||||
|==============================================================================|
|
||||
| |
|
||||
| This file is a modified wrapper which contains OpenPLC interface |
|
||||
| |
|
||||
|=============================================================================*/
|
||||
#ifndef snap7_h
|
||||
#define snap7_h
|
||||
//---------------------------------------------------------------------------
|
||||
// Platform detection
|
||||
//---------------------------------------------------------------------------
|
||||
#if defined (_WIN32)||defined(_WIN64)||defined(__WIN32__)||defined(__WINDOWS__)
|
||||
# define OS_WINDOWS
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(unix) || defined(__unix__) || defined(__unix)
|
||||
# define PLATFORM_UNIX
|
||||
#endif
|
||||
|
||||
#if defined(__SVR4) || defined(__svr4__)
|
||||
# define OS_SOLARIS
|
||||
#endif
|
||||
|
||||
#if BSD>=0
|
||||
# define OS_BSD
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
# define OS_OSX
|
||||
#endif
|
||||
|
||||
#if defined(PLATFORM_UNIX) || defined(OS_OSX)
|
||||
# include <unistd.h>
|
||||
# if defined(_POSIX_VERSION)
|
||||
# define POSIX
|
||||
# endif
|
||||
#endif
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// C++ Library
|
||||
//---------------------------------------------------------------------------
|
||||
#ifdef __cplusplus
|
||||
|
||||
// CANNOT INCLUDE time.h here. We will use a workaround for tm struct and time_t
|
||||
// #include <time.h>
|
||||
# include <string.h>
|
||||
|
||||
// Visual C++ not C99 compliant (VS2008--)
|
||||
#ifdef _MSC_VER
|
||||
# if _MSC_VER >= 1600
|
||||
# include <stdint.h> // VS2010++ have it
|
||||
# else
|
||||
typedef signed __int8 int8_t;
|
||||
typedef signed __int16 int16_t;
|
||||
typedef signed __int32 int32_t;
|
||||
typedef signed __int64 int64_t;
|
||||
typedef unsigned __int8 uint8_t;
|
||||
typedef unsigned __int16 uint16_t;
|
||||
typedef unsigned __int32 uint32_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
#ifdef _WIN64
|
||||
typedef unsigned __int64 uintptr_t;
|
||||
#else
|
||||
typedef unsigned __int32 uintptr_t;
|
||||
#endif
|
||||
# endif
|
||||
#else
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
#endif
|
||||
//---------------------------------------------------------------------------
|
||||
// C exact length types
|
||||
//---------------------------------------------------------------------------
|
||||
#ifndef __cplusplus
|
||||
|
||||
#ifdef OS_BSD
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
|
||||
#ifdef OS_OSX
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
|
||||
#ifdef OS_SOLARIS
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
|
||||
#if defined(_UINTPTR_T_DEFINED)
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
|
||||
#if !defined(_UINTPTR_T_DEFINED) && !defined(OS_SOLARIS) && !defined(OS_BSD) && !defined(OS_OSX)
|
||||
typedef unsigned char uint8_t; // 8 bit unsigned integer
|
||||
typedef unsigned short uint16_t; // 16 bit unsigned integer
|
||||
typedef unsigned int uint32_t; // 32 bit unsigned integer
|
||||
typedef unsigned long uintptr_t;// 64 bit unsigned integer
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef OS_WINDOWS
|
||||
# define S7API __stdcall
|
||||
#else
|
||||
# define S7API
|
||||
#endif
|
||||
|
||||
#define _s7ok 0
|
||||
#define _s7error 1
|
||||
|
||||
#pragma pack(1)
|
||||
//******************************************************************************
|
||||
// COMMON
|
||||
//******************************************************************************
|
||||
// Exact length types regardless of platform/processor
|
||||
typedef uint8_t byte;
|
||||
typedef uint16_t word;
|
||||
typedef uint32_t longword;
|
||||
typedef byte *pbyte;
|
||||
typedef word *pword;
|
||||
typedef uintptr_t S7Object; // multi platform/processor object reference
|
||||
// DON'T CONFUSE IT WITH AN OLE OBJECT, IT'S SIMPLY
|
||||
// AN INTEGER VALUE (32 OR 64 BIT) USED AS HANDLE.
|
||||
|
||||
#ifndef __cplusplus
|
||||
|
||||
typedef int bool;
|
||||
#define false 0;
|
||||
#define true 1;
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int tm_sec;
|
||||
int tm_min;
|
||||
int tm_hour;
|
||||
int tm_mday;
|
||||
int tm_mon;
|
||||
int tm_year;
|
||||
int tm_wday;
|
||||
int tm_yday;
|
||||
int tm_isdst;
|
||||
}s7tm;
|
||||
|
||||
const int errLibInvalidParam = -1;
|
||||
const int errLibInvalidObject = -2;
|
||||
|
||||
// CPU status
|
||||
#define S7CpuStatusUnknown 0x00
|
||||
#define S7CpuStatusRun 0x08
|
||||
#define S7CpuStatusStop 0x04
|
||||
|
||||
// ISO Errors
|
||||
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
|
||||
|
||||
// Tag Struct
|
||||
typedef struct{
|
||||
int Area;
|
||||
int DBNumber;
|
||||
int Start;
|
||||
int Elements;
|
||||
int WordLen;
|
||||
}TS7Tag, *PS7Tag;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// PARAMS LIST
|
||||
//------------------------------------------------------------------------------
|
||||
const int p_u16_LocalPort = 1;
|
||||
const int p_u16_RemotePort = 2;
|
||||
const int p_i32_PingTimeout = 3;
|
||||
const int p_i32_SendTimeout = 4;
|
||||
const int p_i32_RecvTimeout = 5;
|
||||
const int p_i32_WorkInterval = 6;
|
||||
const int p_u16_SrcRef = 7;
|
||||
const int p_u16_DstRef = 8;
|
||||
const int p_u16_SrcTSap = 9;
|
||||
const int p_i32_PDURequest = 10;
|
||||
const int p_i32_MaxClients = 11;
|
||||
const int p_i32_BSendTimeout = 12;
|
||||
const int p_i32_BRecvTimeout = 13;
|
||||
const int p_u32_RecoveryTime = 14;
|
||||
const int p_u32_KeepAliveTime = 15;
|
||||
|
||||
// Client/Partner Job status
|
||||
const int JobComplete = 0;
|
||||
const int JobPending = 1;
|
||||
|
||||
//******************************************************************************
|
||||
// CLIENT
|
||||
//******************************************************************************
|
||||
|
||||
// Error codes
|
||||
const longword errNegotiatingPDU = 0x00100000;
|
||||
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 int MaxVars = 20; // Max vars that can be transferred with MultiRead/MultiWrite
|
||||
|
||||
// Client Connection Type
|
||||
const word CONNTYPE_PG = 0x0001; // Connect to the PLC as a PG
|
||||
const word CONNTYPE_OP = 0x0002; // Connect to the PLC as an OP
|
||||
const word CONNTYPE_BASIC = 0x0003; // Basic connection
|
||||
|
||||
// Area ID
|
||||
const byte S7AreaPE = 0x81;
|
||||
const byte S7AreaPA = 0x82;
|
||||
const byte S7AreaMK = 0x83;
|
||||
const byte S7AreaDB = 0x84;
|
||||
const byte S7AreaCT = 0x1C;
|
||||
const byte S7AreaTM = 0x1D;
|
||||
|
||||
// Word Length
|
||||
const int S7WLBit = 0x01;
|
||||
const int S7WLByte = 0x02;
|
||||
const int S7WLChar = 0x03;
|
||||
const int S7WLWord = 0x04;
|
||||
const int S7WLInt = 0x05;
|
||||
const int S7WLDWord = 0x06;
|
||||
const int S7WLDInt = 0x07;
|
||||
const int S7WLReal = 0x08;
|
||||
const int S7WLCounter = 0x1C;
|
||||
const int S7WLTimer = 0x1D;
|
||||
|
||||
// Block type
|
||||
const byte Block_OB = 0x38;
|
||||
const byte Block_DB = 0x41;
|
||||
const byte Block_SDB = 0x42;
|
||||
const byte Block_FC = 0x43;
|
||||
const byte Block_SFC = 0x44;
|
||||
const byte Block_FB = 0x45;
|
||||
const byte Block_SFB = 0x46;
|
||||
|
||||
// Sub Block Type
|
||||
const byte SubBlk_OB = 0x08;
|
||||
const byte SubBlk_DB = 0x0A;
|
||||
const byte SubBlk_SDB = 0x0B;
|
||||
const byte SubBlk_FC = 0x0C;
|
||||
const byte SubBlk_SFC = 0x0D;
|
||||
const byte SubBlk_FB = 0x0E;
|
||||
const byte SubBlk_SFB = 0x0F;
|
||||
|
||||
// Block languages
|
||||
const byte BlockLangAWL = 0x01;
|
||||
const byte BlockLangKOP = 0x02;
|
||||
const byte BlockLangFUP = 0x03;
|
||||
const byte BlockLangSCL = 0x04;
|
||||
const byte BlockLangDB = 0x05;
|
||||
const byte BlockLangGRAPH = 0x06;
|
||||
|
||||
// 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;
|
||||
|
||||
// List Blocks
|
||||
typedef struct {
|
||||
int OBCount;
|
||||
int FBCount;
|
||||
int FCCount;
|
||||
int SFBCount;
|
||||
int SFCCount;
|
||||
int DBCount;
|
||||
int SDBCount;
|
||||
} TS7BlocksList, *PS7BlocksList;
|
||||
|
||||
// Blocks info
|
||||
typedef struct {
|
||||
int BlkType; // Block Type (OB, DB)
|
||||
int BlkNumber; // Block number
|
||||
int BlkLang; // Block Language
|
||||
int BlkFlags; // Block flags
|
||||
int MC7Size; // The real size in bytes
|
||||
int LoadSize; // Load memory size
|
||||
int LocalData; // Local data
|
||||
int SBBLength; // SBB Length
|
||||
int CheckSum; // Checksum
|
||||
int Version; // Block version
|
||||
// Chars info
|
||||
char CodeDate[11]; // Code date
|
||||
char IntfDate[11]; // Interface date
|
||||
char Author[9]; // Author
|
||||
char Family[9]; // Family
|
||||
char Header[9]; // Header
|
||||
} TS7BlockInfo, *PS7BlockInfo ;
|
||||
|
||||
typedef word TS7BlocksOfType[0x2000];
|
||||
typedef TS7BlocksOfType *PS7BlocksOfType;
|
||||
|
||||
// Order code
|
||||
typedef struct {
|
||||
char Code[21];
|
||||
byte V1;
|
||||
byte V2;
|
||||
byte V3;
|
||||
} TS7OrderCode, *PS7OrderCode;
|
||||
|
||||
// CPU Info
|
||||
typedef struct {
|
||||
char ModuleTypeName[33];
|
||||
char SerialNumber[25];
|
||||
char ASName[25];
|
||||
char Copyright[27];
|
||||
char ModuleName[25];
|
||||
} TS7CpuInfo, *PS7CpuInfo;
|
||||
|
||||
// CP Info
|
||||
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;
|
||||
|
||||
// Client completion callback
|
||||
typedef void (S7API *pfn_CliCompletion) (void *usrPtr, int opCode, int opResult);
|
||||
//------------------------------------------------------------------------------
|
||||
// Import prototypes
|
||||
//------------------------------------------------------------------------------
|
||||
S7Object S7API Cli_Create();
|
||||
void S7API Cli_Destroy(S7Object *Client);
|
||||
int S7API Cli_ConnectTo(S7Object Client, const char *Address, int Rack, int Slot);
|
||||
int S7API Cli_SetConnectionParams(S7Object Client, const char *Address, word LocalTSAP, word RemoteTSAP);
|
||||
int S7API Cli_SetConnectionType(S7Object Client, word ConnectionType);
|
||||
int S7API Cli_Connect(S7Object Client);
|
||||
int S7API Cli_Disconnect(S7Object Client);
|
||||
int S7API Cli_GetParam(S7Object Client, int ParamNumber, void *pValue);
|
||||
int S7API Cli_SetParam(S7Object Client, int ParamNumber, void *pValue);
|
||||
int S7API Cli_SetAsCallback(S7Object Client, pfn_CliCompletion pCompletion, void *usrPtr);
|
||||
// Data I/O main functions
|
||||
int S7API Cli_ReadArea(S7Object Client, int Area, int DBNumber, int Start, int Amount, int WordLen, void *pUsrData);
|
||||
int S7API Cli_WriteArea(S7Object Client, int Area, int DBNumber, int Start, int Amount, int WordLen, void *pUsrData);
|
||||
int S7API Cli_ReadMultiVars(S7Object Client, PS7DataItem Item, int ItemsCount);
|
||||
int S7API Cli_WriteMultiVars(S7Object Client, PS7DataItem Item, int ItemsCount);
|
||||
// Data I/O Lean functions
|
||||
int S7API Cli_DBRead(S7Object Client, int DBNumber, int Start, int Size, void *pUsrData);
|
||||
int S7API Cli_DBWrite(S7Object Client, int DBNumber, int Start, int Size, void *pUsrData);
|
||||
int S7API Cli_MBRead(S7Object Client, int Start, int Size, void *pUsrData);
|
||||
int S7API Cli_MBWrite(S7Object Client, int Start, int Size, void *pUsrData);
|
||||
int S7API Cli_EBRead(S7Object Client, int Start, int Size, void *pUsrData);
|
||||
int S7API Cli_EBWrite(S7Object Client, int Start, int Size, void *pUsrData);
|
||||
int S7API Cli_ABRead(S7Object Client, int Start, int Size, void *pUsrData);
|
||||
int S7API Cli_ABWrite(S7Object Client, int Start, int Size, void *pUsrData);
|
||||
int S7API Cli_TMRead(S7Object Client, int Start, int Amount, void *pUsrData);
|
||||
int S7API Cli_TMWrite(S7Object Client, int Start, int Amount, void *pUsrData);
|
||||
int S7API Cli_CTRead(S7Object Client, int Start, int Amount, void *pUsrData);
|
||||
int S7API Cli_CTWrite(S7Object Client, int Start, int Amount, void *pUsrData);
|
||||
// Directory functions
|
||||
int S7API Cli_ListBlocks(S7Object Client, TS7BlocksList *pUsrData);
|
||||
int S7API Cli_GetAgBlockInfo(S7Object Client, int BlockType, int BlockNum, TS7BlockInfo *pUsrData);
|
||||
int S7API Cli_GetPgBlockInfo(S7Object Client, void *pBlock, TS7BlockInfo *pUsrData, int Size);
|
||||
int S7API Cli_ListBlocksOfType(S7Object Client, int BlockType, TS7BlocksOfType *pUsrData, int *ItemsCount);
|
||||
// Blocks functions
|
||||
int S7API Cli_Upload(S7Object Client, int BlockType, int BlockNum, void *pUsrData, int *Size);
|
||||
int S7API Cli_FullUpload(S7Object Client, int BlockType, int BlockNum, void *pUsrData, int *Size);
|
||||
int S7API Cli_Download(S7Object Client, int BlockNum, void *pUsrData, int Size);
|
||||
int S7API Cli_Delete(S7Object Client, int BlockType, int BlockNum);
|
||||
int S7API Cli_DBGet(S7Object Client, int DBNumber, void *pUsrData, int *Size);
|
||||
int S7API Cli_DBFill(S7Object Client, int DBNumber, int FillChar);
|
||||
// Date/Time functions
|
||||
int S7API Cli_GetPlcDateTime(S7Object Client, s7tm *DateTime);
|
||||
int S7API Cli_SetPlcDateTime(S7Object Client, s7tm *DateTime);
|
||||
int S7API Cli_SetPlcSystemDateTime(S7Object Client);
|
||||
// System Info functions
|
||||
int S7API Cli_GetOrderCode(S7Object Client, TS7OrderCode *pUsrData);
|
||||
int S7API Cli_GetCpuInfo(S7Object Client, TS7CpuInfo *pUsrData);
|
||||
int S7API Cli_GetCpInfo(S7Object Client, TS7CpInfo *pUsrData);
|
||||
int S7API Cli_ReadSZL(S7Object Client, int ID, int Index, TS7SZL *pUsrData, int *Size);
|
||||
int S7API Cli_ReadSZLList(S7Object Client, TS7SZLList *pUsrData, int *ItemsCount);
|
||||
// Control functions
|
||||
int S7API Cli_PlcHotStart(S7Object Client);
|
||||
int S7API Cli_PlcColdStart(S7Object Client);
|
||||
int S7API Cli_PlcStop(S7Object Client);
|
||||
int S7API Cli_CopyRamToRom(S7Object Client, int Timeout);
|
||||
int S7API Cli_Compress(S7Object Client, int Timeout);
|
||||
int S7API Cli_GetPlcStatus(S7Object Client, int *Status);
|
||||
// Security functions
|
||||
int S7API Cli_GetProtection(S7Object Client, TS7Protection *pUsrData);
|
||||
int S7API Cli_SetSessionPassword(S7Object Client, char *Password);
|
||||
int S7API Cli_ClearSessionPassword(S7Object Client);
|
||||
// Low level
|
||||
int S7API Cli_IsoExchangeBuffer(S7Object Client, void *pUsrData, int *Size);
|
||||
// Misc
|
||||
int S7API Cli_GetExecTime(S7Object Client, int *Time);
|
||||
int S7API Cli_GetLastError(S7Object Client, int *LastError);
|
||||
int S7API Cli_GetPduLength(S7Object Client, int *Requested, int *Negotiated);
|
||||
int S7API Cli_ErrorText(int Error, char *Text, int TextLen);
|
||||
// 1.1.0
|
||||
int S7API Cli_GetConnected(S7Object Client, int *Connected);
|
||||
//------------------------------------------------------------------------------
|
||||
// Async functions
|
||||
//------------------------------------------------------------------------------
|
||||
int S7API Cli_AsReadArea(S7Object Client, int Area, int DBNumber, int Start, int Amount, int WordLen, void *pUsrData);
|
||||
int S7API Cli_AsWriteArea(S7Object Client, int Area, int DBNumber, int Start, int Amount, int WordLen, void *pUsrData);
|
||||
int S7API Cli_AsDBRead(S7Object Client, int DBNumber, int Start, int Size, void *pUsrData);
|
||||
int S7API Cli_AsDBWrite(S7Object Client, int DBNumber, int Start, int Size, void *pUsrData);
|
||||
int S7API Cli_AsMBRead(S7Object Client, int Start, int Size, void *pUsrData);
|
||||
int S7API Cli_AsMBWrite(S7Object Client, int Start, int Size, void *pUsrData);
|
||||
int S7API Cli_AsEBRead(S7Object Client, int Start, int Size, void *pUsrData);
|
||||
int S7API Cli_AsEBWrite(S7Object Client, int Start, int Size, void *pUsrData);
|
||||
int S7API Cli_AsABRead(S7Object Client, int Start, int Size, void *pUsrData);
|
||||
int S7API Cli_AsABWrite(S7Object Client, int Start, int Size, void *pUsrData);
|
||||
int S7API Cli_AsTMRead(S7Object Client, int Start, int Amount, void *pUsrData);
|
||||
int S7API Cli_AsTMWrite(S7Object Client, int Start, int Amount, void *pUsrData);
|
||||
int S7API Cli_AsCTRead(S7Object Client, int Start, int Amount, void *pUsrData);
|
||||
int S7API Cli_AsCTWrite(S7Object Client, int Start, int Amount, void *pUsrData);
|
||||
int S7API Cli_AsListBlocksOfType(S7Object Client, int BlockType, TS7BlocksOfType *pUsrData, int *ItemsCount);
|
||||
int S7API Cli_AsReadSZL(S7Object Client, int ID, int Index, TS7SZL *pUsrData, int *Size);
|
||||
int S7API Cli_AsReadSZLList(S7Object Client, TS7SZLList *pUsrData, int *ItemsCount);
|
||||
int S7API Cli_AsUpload(S7Object Client, int BlockType, int BlockNum, void *pUsrData, int *Size);
|
||||
int S7API Cli_AsFullUpload(S7Object Client, int BlockType, int BlockNum, void *pUsrData, int *Size);
|
||||
int S7API Cli_AsDownload(S7Object Client, int BlockNum, void *pUsrData, int Size);
|
||||
int S7API Cli_AsCopyRamToRom(S7Object Client, int Timeout);
|
||||
int S7API Cli_AsCompress(S7Object Client, int Timeout);
|
||||
int S7API Cli_AsDBGet(S7Object Client, int DBNumber, void *pUsrData, int *Size);
|
||||
int S7API Cli_AsDBFill(S7Object Client, int DBNumber, int FillChar);
|
||||
int S7API Cli_CheckAsCompletion(S7Object Client, int *opResult);
|
||||
int S7API Cli_WaitAsCompletion(S7Object Client, int Timeout);
|
||||
|
||||
//******************************************************************************
|
||||
// SERVER
|
||||
//******************************************************************************
|
||||
const int OperationRead = 0;
|
||||
const int OperationWrite = 1;
|
||||
|
||||
const int mkEvent = 0;
|
||||
const int mkLog = 1;
|
||||
|
||||
// Server Area ID (use with Register/unregister - Lock/unlock Area)
|
||||
const int srvAreaPE = 0;
|
||||
const int srvAreaPA = 1;
|
||||
const int srvAreaMK = 2;
|
||||
const int srvAreaCT = 3;
|
||||
const int srvAreaTM = 4;
|
||||
const int srvAreaDB = 5;
|
||||
|
||||
// Errors
|
||||
const longword errSrvCannotStart = 0x00100000; // Server cannot start
|
||||
const longword errSrvDBNullPointer = 0x00200000; // Passed null as PData
|
||||
const longword errSrvAreaAlreadyExists = 0x00300000; // Area Re-registration
|
||||
const longword errSrvUnknownArea = 0x00400000; // Unknown area
|
||||
const longword errSrvInvalidParams = 0x00500000; // Invalid param(s) supplied
|
||||
const longword errSrvTooManyDB = 0x00600000; // Cannot register DB
|
||||
const longword errSrvInvalidParamNumber = 0x00700000; // Invalid param (srv_get/set_param)
|
||||
const longword errSrvCannotChangeParam = 0x00800000; // Cannot change because running
|
||||
|
||||
// TCP Server Event codes
|
||||
const longword evcServerStarted = 0x00000001;
|
||||
const longword evcServerStopped = 0x00000002;
|
||||
const longword evcListenerCannotStart = 0x00000004;
|
||||
const longword evcClientAdded = 0x00000008;
|
||||
const longword evcClientRejected = 0x00000010;
|
||||
const longword evcClientNoRoom = 0x00000020;
|
||||
const longword evcClientException = 0x00000040;
|
||||
const longword evcClientDisconnected = 0x00000080;
|
||||
const longword evcClientTerminated = 0x00000100;
|
||||
const longword evcClientsDropped = 0x00000200;
|
||||
const longword evcReserved_00000400 = 0x00000400; // actually unused
|
||||
const longword evcReserved_00000800 = 0x00000800; // actually unused
|
||||
const longword evcReserved_00001000 = 0x00001000; // actually unused
|
||||
const longword evcReserved_00002000 = 0x00002000; // actually unused
|
||||
const longword evcReserved_00004000 = 0x00004000; // actually unused
|
||||
const longword evcReserved_00008000 = 0x00008000; // actually unused
|
||||
// S7 Server Event Code
|
||||
const longword evcPDUincoming = 0x00010000;
|
||||
const longword evcDataRead = 0x00020000;
|
||||
const longword evcDataWrite = 0x00040000;
|
||||
const longword evcNegotiatePDU = 0x00080000;
|
||||
const longword evcReadSZL = 0x00100000;
|
||||
const longword evcClock = 0x00200000;
|
||||
const longword evcUpload = 0x00400000;
|
||||
const longword evcDownload = 0x00800000;
|
||||
const longword evcDirectory = 0x01000000;
|
||||
const longword evcSecurity = 0x02000000;
|
||||
const longword evcControl = 0x04000000;
|
||||
const longword evcReserved_08000000 = 0x08000000; // actually unused
|
||||
const longword evcReserved_10000000 = 0x10000000; // actually unused
|
||||
const longword evcReserved_20000000 = 0x20000000; // actually unused
|
||||
const longword evcReserved_40000000 = 0x40000000; // actually unused
|
||||
const longword evcReserved_80000000 = 0x80000000; // actually unused
|
||||
// Masks to enable/disable all events
|
||||
const longword evcAll = 0xFFFFFFFF;
|
||||
const longword evcNone = 0x00000000;
|
||||
// Event SubCodes
|
||||
const word evsUnknown = 0x0000;
|
||||
const word evsStartUpload = 0x0001;
|
||||
const word evsStartDownload = 0x0001;
|
||||
const word evsGetBlockList = 0x0001;
|
||||
const word evsStartListBoT = 0x0002;
|
||||
const word evsListBoT = 0x0003;
|
||||
const word evsGetBlockInfo = 0x0004;
|
||||
const word evsGetClock = 0x0001;
|
||||
const word evsSetClock = 0x0002;
|
||||
const word evsSetPassword = 0x0001;
|
||||
const word evsClrPassword = 0x0002;
|
||||
// Event Params : functions group
|
||||
const word grProgrammer = 0x0041;
|
||||
const word grCyclicData = 0x0042;
|
||||
const word grBlocksInfo = 0x0043;
|
||||
const word grSZL = 0x0044;
|
||||
const word grPassword = 0x0045;
|
||||
const word grBSend = 0x0046;
|
||||
const word grClock = 0x0047;
|
||||
const word grSecurity = 0x0045;
|
||||
// Event Params : control codes
|
||||
const word CodeControlUnknown = 0x0000;
|
||||
const word CodeControlColdStart = 0x0001;
|
||||
const word CodeControlWarmStart = 0x0002;
|
||||
const word CodeControlStop = 0x0003;
|
||||
const word CodeControlCompress = 0x0004;
|
||||
const word CodeControlCpyRamRom = 0x0005;
|
||||
const word CodeControlInsDel = 0x0006;
|
||||
// Event Result
|
||||
const word evrNoError = 0x0000;
|
||||
const word evrFragmentRejected = 0x0001;
|
||||
const word evrMalformedPDU = 0x0002;
|
||||
const word evrSparseBytes = 0x0003;
|
||||
const word evrCannotHandlePDU = 0x0004;
|
||||
const word evrNotImplemented = 0x0005;
|
||||
const word evrErrException = 0x0006;
|
||||
const word evrErrAreaNotFound = 0x0007;
|
||||
const word evrErrOutOfRange = 0x0008;
|
||||
const word evrErrOverPDU = 0x0009;
|
||||
const word evrErrTransportSize = 0x000A;
|
||||
const word evrInvalidGroupUData = 0x000B;
|
||||
const word evrInvalidSZL = 0x000C;
|
||||
const word evrDataSizeMismatch = 0x000D;
|
||||
const word evrCannotUpload = 0x000E;
|
||||
const word evrCannotDownload = 0x000F;
|
||||
const word evrUploadInvalidID = 0x0010;
|
||||
const word evrResNotFound = 0x0011;
|
||||
|
||||
typedef struct{
|
||||
uint64_t EvtTime; // Timestamp, was time_t
|
||||
int EvtSender; // Sender
|
||||
longword EvtCode; // Event code
|
||||
word EvtRetCode; // Event result
|
||||
word EvtParam1; // Param 1 (if available)
|
||||
word EvtParam2; // Param 2 (if available)
|
||||
word EvtParam3; // Param 3 (if available)
|
||||
word EvtParam4; // Param 4 (if available)
|
||||
}TSrvEvent, *PSrvEvent;
|
||||
|
||||
// Server Events callback
|
||||
typedef void (S7API *pfn_SrvCallBack)(void *usrPtr, PSrvEvent PEvent, int Size);
|
||||
// Server Read/Write callback
|
||||
typedef int(S7API *pfn_RWAreaCallBack)(void *usrPtr, int Sender, int Operation, PS7Tag PTag, void *pUsrData);
|
||||
|
||||
S7Object S7API Srv_Create();
|
||||
void S7API Srv_Destroy(S7Object *Server);
|
||||
int S7API Srv_GetParam(S7Object Server, int ParamNumber, void *pValue);
|
||||
int S7API Srv_SetParam(S7Object Server, int ParamNumber, void *pValue);
|
||||
int S7API Srv_StartTo(S7Object Server, const char *Address);
|
||||
int S7API Srv_Start(S7Object Server);
|
||||
int S7API Srv_Stop(S7Object Server);
|
||||
int S7API Srv_RegisterArea(S7Object Server, int AreaCode, word Index, void *pUsrData, int Size);
|
||||
int S7API Srv_UnregisterArea(S7Object Server, int AreaCode, word Index);
|
||||
int S7API Srv_LockArea(S7Object Server, int AreaCode, word Index);
|
||||
int S7API Srv_UnlockArea(S7Object Server, int AreaCode, word Index);
|
||||
int S7API Srv_GetStatus(S7Object Server, int *ServerStatus, int *CpuStatus, int *ClientsCount);
|
||||
int S7API Srv_SetCpuStatus(S7Object Server, int CpuStatus);
|
||||
int S7API Srv_ClearEvents(S7Object Server);
|
||||
int S7API Srv_PickEvent(S7Object Server, TSrvEvent *pEvent, int *EvtReady);
|
||||
int S7API Srv_GetMask(S7Object Server, int MaskKind, longword *Mask);
|
||||
int S7API Srv_SetMask(S7Object Server, int MaskKind, longword Mask);
|
||||
int S7API Srv_SetEventsCallback(S7Object Server, pfn_SrvCallBack pCallback, void *usrPtr);
|
||||
int S7API Srv_SetReadEventsCallback(S7Object Server, pfn_SrvCallBack pCallback, void *usrPtr);
|
||||
int S7API Srv_SetRWAreaCallback(S7Object Server, pfn_RWAreaCallBack pCallback, void *usrPtr);
|
||||
int S7API Srv_EventText(TSrvEvent *Event, char *Text, int TextLen);
|
||||
int S7API Srv_ErrorText(int Error, char *Text, int TextLen);
|
||||
|
||||
//******************************************************************************
|
||||
// PARTNER
|
||||
//******************************************************************************
|
||||
|
||||
// Status
|
||||
const int par_stopped = 0; // stopped
|
||||
const int par_connecting = 1; // running and active connecting
|
||||
const int par_waiting = 2; // running and waiting for a connection
|
||||
const int par_linked = 3; // running and connected : linked
|
||||
const int par_sending = 4; // sending data
|
||||
const int par_receiving = 5; // receiving data
|
||||
const int par_binderror = 6; // error starting passive server
|
||||
|
||||
// Errors
|
||||
const longword errParAddressInUse = 0x00200000;
|
||||
const longword errParNoRoom = 0x00300000;
|
||||
const longword errServerNoRoom = 0x00400000;
|
||||
const longword errParInvalidParams = 0x00500000;
|
||||
const longword errParNotLinked = 0x00600000;
|
||||
const longword errParBusy = 0x00700000;
|
||||
const longword errParFrameTimeout = 0x00800000;
|
||||
const longword errParInvalidPDU = 0x00900000;
|
||||
const longword errParSendTimeout = 0x00A00000;
|
||||
const longword errParRecvTimeout = 0x00B00000;
|
||||
const longword errParSendRefused = 0x00C00000;
|
||||
const longword errParNegotiatingPDU = 0x00D00000;
|
||||
const longword errParSendingBlock = 0x00E00000;
|
||||
const longword errParRecvingBlock = 0x00F00000;
|
||||
const longword errParBindError = 0x01000000;
|
||||
const longword errParDestroying = 0x01100000;
|
||||
const longword errParInvalidParamNumber = 0x01200000; // Invalid param (par_get/set_param)
|
||||
const longword errParCannotChangeParam = 0x01300000; // Cannot change because running
|
||||
const longword errParBufferTooSmall = 0x01400000; // Raised by LabVIEW wrapper
|
||||
|
||||
// Brecv Data incoming Callback
|
||||
typedef void (S7API *pfn_ParRecvCallBack)(void * usrPtr, int opResult, longword R_ID, void *pData, int Size);
|
||||
// BSend Completion Callback
|
||||
typedef void (S7API *pfn_ParSendCompletion)(void * usrPtr, int opResult);
|
||||
|
||||
S7Object S7API Par_Create(int Active);
|
||||
void S7API Par_Destroy(S7Object *Partner);
|
||||
int S7API Par_GetParam(S7Object Partner, int ParamNumber, void *pValue);
|
||||
int S7API Par_SetParam(S7Object Partner, int ParamNumber, void *pValue);
|
||||
int S7API Par_StartTo(S7Object Partner, const char *LocalAddress, const char *RemoteAddress,
|
||||
word LocTsap, word RemTsap);
|
||||
int S7API Par_Start(S7Object Partner);
|
||||
int S7API Par_Stop(S7Object Partner);
|
||||
// BSend
|
||||
int S7API Par_BSend(S7Object Partner, longword R_ID, void *pUsrData, int Size);
|
||||
int S7API Par_AsBSend(S7Object Partner, longword R_ID, void *pUsrData, int Size);
|
||||
int S7API Par_CheckAsBSendCompletion(S7Object Partner, int *opResult);
|
||||
int S7API Par_WaitAsBSendCompletion(S7Object Partner, longword Timeout);
|
||||
int S7API Par_SetSendCallback(S7Object Partner, pfn_ParSendCompletion pCompletion, void *usrPtr);
|
||||
// BRecv
|
||||
int S7API Par_BRecv(S7Object Partner, longword *R_ID, void *pData, int *Size, longword Timeout);
|
||||
int S7API Par_CheckAsBRecvCompletion(S7Object Partner, int *opResult, longword *R_ID,
|
||||
void *pData, int *Size);
|
||||
int S7API Par_SetRecvCallback(S7Object Partner, pfn_ParRecvCallBack pCompletion, void *usrPtr);
|
||||
// Stat
|
||||
int S7API Par_GetTimes(S7Object Partner, longword *SendTime, longword *RecvTime);
|
||||
int S7API Par_GetStats(S7Object Partner, longword *BytesSent, longword *BytesRecv,
|
||||
longword *SendErrors, longword *RecvErrors);
|
||||
int S7API Par_GetLastError(S7Object Partner, int *LastError);
|
||||
int S7API Par_GetStatus(S7Object Partner, int *Status);
|
||||
int S7API Par_ErrorText(int Error, char *Text, int TextLen);
|
||||
|
||||
|
||||
#pragma pack()
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
//******************************************************************************
|
||||
// CLIENT CLASS DEFINITION
|
||||
//******************************************************************************
|
||||
class TS7Client
|
||||
{
|
||||
private:
|
||||
S7Object Client;
|
||||
public:
|
||||
TS7Client();
|
||||
~TS7Client();
|
||||
// Control functions
|
||||
int Connect();
|
||||
int ConnectTo(const char *RemAddress, int Rack, int Slot);
|
||||
int SetConnectionParams(const char *RemAddress, word LocalTSAP, word RemoteTSAP);
|
||||
int SetConnectionType(word ConnectionType);
|
||||
int Disconnect();
|
||||
int GetParam(int ParamNumber, void *pValue);
|
||||
int SetParam(int ParamNumber, void *pValue);
|
||||
// Data I/O Main 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 Lean 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(s7tm *DateTime);
|
||||
int SetPlcDateTime(s7tm *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);
|
||||
// Security functions
|
||||
int GetProtection(PS7Protection pUsrData);
|
||||
int SetSessionPassword(char *Password);
|
||||
int ClearSessionPassword();
|
||||
// Properties
|
||||
int ExecTime();
|
||||
int LastError();
|
||||
int PDURequested();
|
||||
int PDULength();
|
||||
int PlcStatus();
|
||||
bool Connected();
|
||||
// Async functions
|
||||
int SetAsCallback(pfn_CliCompletion pCompletion, void *usrPtr);
|
||||
bool CheckAsCompletion(int *opResult);
|
||||
int WaitAsCompletion(longword 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 TS7Client *PS7Client;
|
||||
//******************************************************************************
|
||||
// SERVER CLASS DEFINITION
|
||||
//******************************************************************************
|
||||
class TS7Server
|
||||
{
|
||||
private:
|
||||
S7Object Server;
|
||||
public:
|
||||
TS7Server();
|
||||
~TS7Server();
|
||||
// Control
|
||||
int Start();
|
||||
int StartTo(const char *Address);
|
||||
int Stop();
|
||||
int GetParam(int ParamNumber, void *pValue);
|
||||
int SetParam(int ParamNumber, void *pValue);
|
||||
// Events
|
||||
int SetEventsCallback(pfn_SrvCallBack PCallBack, void *UsrPtr);
|
||||
int SetReadEventsCallback(pfn_SrvCallBack PCallBack, void *UsrPtr);
|
||||
int SetRWAreaCallback(pfn_RWAreaCallBack PCallBack, void *UsrPtr);
|
||||
bool PickEvent(TSrvEvent *pEvent);
|
||||
void ClearEvents();
|
||||
longword GetEventsMask();
|
||||
longword GetLogMask();
|
||||
void SetEventsMask(longword Mask);
|
||||
void SetLogMask(longword Mask);
|
||||
// Resources
|
||||
int RegisterArea(int AreaCode, word Index, void *pUsrData, word Size);
|
||||
int UnregisterArea(int AreaCode, word Index);
|
||||
int LockArea(int AreaCode, word Index);
|
||||
int UnlockArea(int AreaCode, word Index);
|
||||
// Properties
|
||||
int ServerStatus();
|
||||
int GetCpuStatus();
|
||||
int SetCpuStatus(int Status);
|
||||
int ClientsCount();
|
||||
};
|
||||
typedef TS7Server *PS7Server;
|
||||
|
||||
//******************************************************************************
|
||||
// PARTNER CLASS DEFINITION
|
||||
//******************************************************************************
|
||||
class TS7Partner
|
||||
{
|
||||
private:
|
||||
S7Object Partner; // Partner Handle
|
||||
public:
|
||||
TS7Partner(bool Active);
|
||||
~TS7Partner();
|
||||
// Control
|
||||
int GetParam(int ParamNumber, void *pValue);
|
||||
int SetParam(int ParamNumber, void *pValue);
|
||||
int Start();
|
||||
int StartTo(const char *LocalAddress,
|
||||
const char *RemoteAddress,
|
||||
int LocalTSAP,
|
||||
int RemoteTSAP);
|
||||
int Stop();
|
||||
// Data I/O functions : BSend
|
||||
int BSend(longword R_ID, void *pUsrData, int Size);
|
||||
int AsBSend(longword R_ID, void *pUsrData, int Size);
|
||||
bool CheckAsBSendCompletion(int *opResult);
|
||||
int WaitAsBSendCompletion(longword Timeout);
|
||||
int SetSendCallback(pfn_ParSendCompletion pCompletion, void *usrPtr);
|
||||
// Data I/O functions : BRecv
|
||||
int BRecv(longword *R_ID, void *pUsrData, int *Size, longword Timeout);
|
||||
bool CheckAsBRecvCompletion(int *opResult, longword *R_ID, void *pUsrData, int *Size);
|
||||
int SetRecvCallback(pfn_ParRecvCallBack pCallback, void *usrPtr);
|
||||
// Properties
|
||||
int Status();
|
||||
int LastError();
|
||||
int GetTimes(longword *SendTime, longword *RecvTime);
|
||||
int GetStats(longword *BytesSent,
|
||||
longword *BytesRecv,
|
||||
longword *ErrSend,
|
||||
longword *ErrRecv);
|
||||
bool Linked();
|
||||
};
|
||||
typedef TS7Partner *PS7Partner;
|
||||
|
||||
//******************************************************************************
|
||||
// OpenPLC interface
|
||||
//******************************************************************************
|
||||
|
||||
void initializeSnap7();
|
||||
void finalizeSnap7();
|
||||
|
||||
|
||||
|
||||
#endif // __cplusplus
|
||||
#endif // snap7_h
|
||||
@@ -37,6 +37,10 @@
|
||||
#include "ethercat_src.h"
|
||||
#endif
|
||||
|
||||
#ifdef _snap7
|
||||
#include "oplc_snap7.h"
|
||||
#endif
|
||||
|
||||
#define OPLC_CYCLE 50000000
|
||||
|
||||
extern int opterr;
|
||||
@@ -103,6 +107,7 @@ int main(int argc,char **argv)
|
||||
#endif
|
||||
initializeHardware();
|
||||
initializeMB();
|
||||
|
||||
updateBuffersIn();
|
||||
updateBuffersOut();
|
||||
|
||||
@@ -114,7 +119,11 @@ int main(int argc,char **argv)
|
||||
readPersistentStorage();
|
||||
//pthread_t persistentThread;
|
||||
//pthread_create(&persistentThread, NULL, persistentStorage, NULL);
|
||||
|
||||
|
||||
#ifdef _snap7
|
||||
initializeSnap7();
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef __linux__
|
||||
@@ -243,6 +252,11 @@ int main(int argc,char **argv)
|
||||
#ifdef _ethercat_src
|
||||
ethercat_terminate_src();
|
||||
#endif
|
||||
|
||||
#ifdef _snap7
|
||||
finalizeSnap7();
|
||||
#endif
|
||||
|
||||
printf("Disabling outputs\n");
|
||||
disableOutputs();
|
||||
updateBuffersOut();
|
||||
|
||||
@@ -138,7 +138,7 @@ void mapUnusedIO()
|
||||
|
||||
for (int i = 0; i <= MAX_16B_RANGE; i++)
|
||||
{
|
||||
if (i < MIN_16B_RANGE)
|
||||
if (i < MIN_16B_RANGE)
|
||||
{
|
||||
if (int_output[i] == NULL)
|
||||
{
|
||||
@@ -339,7 +339,7 @@ void ReadHoldingRegisters(unsigned char *buffer, int bufferSize)
|
||||
for(int i = 0; i < WordDataLength; i++)
|
||||
{
|
||||
int position = Start + i;
|
||||
if (position <= MIN_16B_RANGE)
|
||||
if (position < MIN_16B_RANGE)
|
||||
{
|
||||
if (int_output[position] != NULL)
|
||||
{
|
||||
@@ -575,7 +575,7 @@ void WriteCoil(unsigned char *buffer, int bufferSize)
|
||||
int writeToRegisterWithoutLocking(int position, uint16_t value)
|
||||
{
|
||||
//analog outputs
|
||||
if (position <= MIN_16B_RANGE)
|
||||
if (position < MIN_16B_RANGE)
|
||||
{
|
||||
if (int_output[position] != NULL) *int_output[position] = value;
|
||||
}
|
||||
|
||||
@@ -134,7 +134,7 @@ login_body = """
|
||||
<button>login</button>
|
||||
</form>
|
||||
</div>
|
||||
<h3 style="font-family:'roboto', sans-serif; font-size:14px; color:#ffffff;">Release: 2025-02-06</h3>
|
||||
<h3 style="font-family:'roboto', sans-serif; font-size:14px; color:#ffffff;">Release: 2025-03-17</h3>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
@@ -10,6 +10,7 @@ cd scripts &>/dev/null
|
||||
OPENPLC_PLATFORM=$(cat openplc_platform)
|
||||
ETHERCAT_OPT=$(cat ethercat)
|
||||
OPENPLC_DRIVER=$(cat openplc_driver)
|
||||
S7_OPT=$(cat s7protocol)
|
||||
|
||||
#store the active program filename
|
||||
echo "$1" > ../active_program
|
||||
@@ -29,6 +30,27 @@ if [ "$ETHERCAT_OPT" = "ethercat" ]; then
|
||||
sed -i '7s/^/#include "ethercat_src.h" /' Res0.c
|
||||
fi
|
||||
|
||||
#check for S7 Protocol option
|
||||
if [ "$S7_OPT" = "s7protocol" ]; then
|
||||
S7_LIB="-lsnap7"
|
||||
S7_DEF="-D _snap7"
|
||||
S7_WLIB="snap7.lib"
|
||||
cp -f ../utils/snap7_src/wrapper/oplc_snap7.* ./core
|
||||
if [ "$OPENPLC_PLATFORM" = "win" ]; then
|
||||
cp -f ../utils/snap7_src/build/bin/win64/snap7.* ./core
|
||||
fi
|
||||
echo "Including Siemens S7 Protocol via snap7"
|
||||
else
|
||||
S7_LIB=""
|
||||
S7_DEF=""
|
||||
S7_WLIB=""
|
||||
# remove snap7 references (if any)
|
||||
rm -f ./core/oplc_snap7.*
|
||||
if [ "$OPENPLC_PLATFORM" = "win" ]; then
|
||||
rm -f ./core/snap7.*
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Moving Files..."
|
||||
mv -f POUS.c POUS.h LOCATED_VARIABLES.h VARIABLES.csv Config0.c Config0.h Res0.c ./core/
|
||||
if [ $? -ne 0 ]; then
|
||||
@@ -64,7 +86,7 @@ if [ "$OPENPLC_PLATFORM" = "win" ]; then
|
||||
echo "Generating glueVars..."
|
||||
./glue_generator
|
||||
echo "Compiling main program..."
|
||||
g++ *.cpp *.o -o openplc -I ./lib -pthread -fpermissive -I /usr/local/include/modbus -L /usr/local/lib -lmodbus -w
|
||||
g++ *.cpp *.o -o openplc -I ./lib -pthread -fpermissive -I /usr/local/include/modbus -L /usr/local/lib $S7_WLIB -lmodbus -w $S7_DEF
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error compiling C files"
|
||||
echo "Compilation finished with errors!"
|
||||
@@ -77,9 +99,9 @@ elif [ "$OPENPLC_PLATFORM" = "linux" ]; then
|
||||
echo "Compiling for Linux"
|
||||
echo "Generating object files..."
|
||||
if [ "$OPENPLC_DRIVER" = "sl_rp4" ]; then
|
||||
g++ -std=gnu++11 -I ./lib -c Config0.c -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w -DSL_RP4
|
||||
g++ -std=gnu++11 -I ./lib -c Config0.c $S7_LIB -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w -DSL_RP4
|
||||
else
|
||||
g++ -std=gnu++11 -I ./lib -c Config0.c -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w
|
||||
g++ -std=gnu++11 -I ./lib -c Config0.c $S7_LIB -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w
|
||||
fi
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error compiling C files"
|
||||
@@ -87,9 +109,9 @@ elif [ "$OPENPLC_PLATFORM" = "linux" ]; then
|
||||
exit 1
|
||||
fi
|
||||
if [ "$OPENPLC_DRIVER" = "sl_rp4" ]; then
|
||||
g++ -std=gnu++11 -I ./lib -c Res0.c -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w $ETHERCAT_INC -DSL_RP4
|
||||
g++ -std=gnu++11 -I ./lib -c Res0.c $S7_LIB -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w $ETHERCAT_INC $S7_DEF -DSL_RP4
|
||||
else
|
||||
g++ -std=gnu++11 -I ./lib -c Res0.c -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w $ETHERCAT_INC
|
||||
g++ -std=gnu++11 -I ./lib -c Res0.c $S7_LIB -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w $ETHERCAT_INC $S7_DEF
|
||||
fi
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error compiling C files"
|
||||
@@ -100,9 +122,9 @@ elif [ "$OPENPLC_PLATFORM" = "linux" ]; then
|
||||
./glue_generator
|
||||
echo "Compiling main program..."
|
||||
if [ "$OPENPLC_DRIVER" = "sl_rp4" ]; then
|
||||
g++ -std=gnu++11 *.cpp *.o -o openplc -I ./lib -pthread -fpermissive `pkg-config --cflags --libs libmodbus` -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w $ETHERCAT_INC -DSL_RP4
|
||||
g++ -std=gnu++11 *.cpp *.o -o openplc -I ./lib -pthread -fpermissive `pkg-config --cflags --libs libmodbus` $S7_LIB -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w $ETHERCAT_INC $S7_DEF -DSL_RP4
|
||||
else
|
||||
g++ -std=gnu++11 *.cpp *.o -o openplc -I ./lib -pthread -fpermissive `pkg-config --cflags --libs libmodbus` -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w $ETHERCAT_INC
|
||||
g++ -std=gnu++11 *.cpp *.o -o openplc -I ./lib -pthread -fpermissive `pkg-config --cflags --libs libmodbus` $S7_LIB -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w $ETHERCAT_INC $S7_DEF
|
||||
fi
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error compiling C files"
|
||||
@@ -116,9 +138,9 @@ elif [ "$OPENPLC_PLATFORM" = "rpi" ]; then
|
||||
echo "Compiling for Raspberry Pi"
|
||||
echo "Generating object files..."
|
||||
if [ "$OPENPLC_DRIVER" = "sequent" ]; then
|
||||
g++ -std=gnu++11 -I ./lib -c Config0.c -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w -DSEQUENT
|
||||
g++ -std=gnu++11 -I ./lib -c Config0.c $S7_LIB -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w -DSEQUENT
|
||||
else
|
||||
g++ -std=gnu++11 -I ./lib -c Config0.c -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w
|
||||
g++ -std=gnu++11 -I ./lib -c Config0.c $S7_LIB -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w
|
||||
fi
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error compiling C files"
|
||||
@@ -126,9 +148,9 @@ elif [ "$OPENPLC_PLATFORM" = "rpi" ]; then
|
||||
exit 1
|
||||
fi
|
||||
if [ "$OPENPLC_DRIVER" = "sequent" ]; then
|
||||
g++ -std=gnu++11 -I ./lib -c Res0.c -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w -DSEQUENT
|
||||
g++ -std=gnu++11 -I ./lib -c Res0.c $S7_LIB -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w -DSEQUENT
|
||||
else
|
||||
g++ -std=gnu++11 -I ./lib -c Res0.c -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w
|
||||
g++ -std=gnu++11 -I ./lib -c Res0.c $S7_LIB -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w
|
||||
fi
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error compiling C files"
|
||||
@@ -139,9 +161,9 @@ elif [ "$OPENPLC_PLATFORM" = "rpi" ]; then
|
||||
./glue_generator
|
||||
echo "Compiling main program..."
|
||||
if [ "$OPENPLC_DRIVER" = "sequent" ]; then
|
||||
g++ -DSEQUENT -std=gnu++11 *.cpp *.o -o openplc -I ./lib -lrt -lpigpio -lpthread -fpermissive `pkg-config --cflags --libs libmodbus` -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w
|
||||
g++ -DSEQUENT -std=gnu++11 *.cpp *.o -o openplc -I ./lib -lrt -lpigpio -lpthread -fpermissive `pkg-config --cflags --libs libmodbus` $S7_LIB -lasiodnp3 -lasiopal -lopendnp3 -lopenpal $S7_DEF -w
|
||||
else
|
||||
g++ -std=gnu++11 *.cpp *.o -o openplc -I ./lib -lrt -lpigpio -lpthread -fpermissive `pkg-config --cflags --libs libmodbus` -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w
|
||||
g++ -std=gnu++11 *.cpp *.o -o openplc -I ./lib -lrt -lpigpio -lpthread -fpermissive `pkg-config --cflags --libs libmodbus` $S7_LIB -lasiodnp3 -lasiopal -lopendnp3 -lopenpal $S7_DEF -w
|
||||
fi
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error compiling C files"
|
||||
@@ -155,13 +177,13 @@ elif [ "$OPENPLC_PLATFORM" = "opi" ]; then
|
||||
WIRINGOP_INC="-I/usr/local/include -L/usr/local/lib -lwiringPi -lwiringPiDev"
|
||||
echo "Compiling for Orange Pi"
|
||||
echo "Generating object files..."
|
||||
g++ -std=gnu++11 -I ./lib -c Config0.c -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w $WIRINGOP_INC
|
||||
g++ -std=gnu++11 -I ./lib -c Config0.c $S7_LIB -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w $WIRINGOP_INC
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error compiling C files"
|
||||
echo "Compilation finished with errors!"
|
||||
exit 1
|
||||
fi
|
||||
g++ -std=gnu++11 -I ./lib -c Res0.c -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w $WIRINGOP_INC
|
||||
g++ -std=gnu++11 -I ./lib -c Res0.c $S7_LIB -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w $WIRINGOP_INC
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error compiling C files"
|
||||
echo "Compilation finished with errors!"
|
||||
@@ -170,7 +192,7 @@ elif [ "$OPENPLC_PLATFORM" = "opi" ]; then
|
||||
echo "Generating glueVars..."
|
||||
./glue_generator
|
||||
echo "Compiling main program..."
|
||||
g++ -std=gnu++11 *.cpp *.o -o openplc -I ./lib -lrt -lpthread -fpermissive `pkg-config --cflags --libs libmodbus` -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w $WIRINGOP_INC
|
||||
g++ -std=gnu++11 *.cpp *.o -o openplc -I ./lib -lrt -lpthread -fpermissive `pkg-config --cflags --libs libmodbus` $S7_LIB -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w $S7_DEF $WIRINGOP_INC
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error compiling C files"
|
||||
echo "Compilation finished with errors!"
|
||||
|
||||
1
webserver/scripts/s7protocol
Normal file
1
webserver/scripts/s7protocol
Normal file
@@ -0,0 +1 @@
|
||||
#s7protocol
|
||||
Reference in New Issue
Block a user