Repository: mathiask88/node-snap7
Branch: master
Commit: 1b15218c7a2b
Files: 51
Total size: 913.2 KB
Directory structure:
gitextract_8115zplp/
├── .github/
│ └── workflows/
│ └── test-and-release.yml
├── .gitignore
├── .npmignore
├── LICENSE
├── README.md
├── binding.gyp
├── deps/
│ └── snap7/
│ ├── HISTORY.txt
│ ├── gpl.txt
│ ├── lgpl-3.0.txt
│ └── src/
│ ├── core/
│ │ ├── s7_client.cpp
│ │ ├── s7_client.h
│ │ ├── s7_firmware.h
│ │ ├── s7_isotcp.cpp
│ │ ├── s7_isotcp.h
│ │ ├── s7_micro_client.cpp
│ │ ├── s7_micro_client.h
│ │ ├── s7_partner.cpp
│ │ ├── s7_partner.h
│ │ ├── s7_peer.cpp
│ │ ├── s7_peer.h
│ │ ├── s7_server.cpp
│ │ ├── s7_server.h
│ │ ├── s7_text.cpp
│ │ ├── s7_text.h
│ │ └── s7_types.h
│ ├── lib/
│ │ ├── snap7.def
│ │ ├── snap7_libmain.cpp
│ │ └── snap7_libmain.h
│ └── sys/
│ ├── snap_msgsock.cpp
│ ├── snap_msgsock.h
│ ├── snap_platform.h
│ ├── snap_sysutils.cpp
│ ├── snap_sysutils.h
│ ├── snap_tcpsrvr.cpp
│ ├── snap_tcpsrvr.h
│ ├── snap_threads.cpp
│ ├── snap_threads.h
│ ├── sol_threads.h
│ ├── unix_threads.h
│ └── win_threads.h
├── doc/
│ ├── client.md
│ └── server.md
├── lib/
│ └── node-snap7.js
├── package.json
└── src/
├── node_snap7.cpp
├── node_snap7_client.cpp
├── node_snap7_client.h
├── node_snap7_server.cpp
├── node_snap7_server.h
├── snap7.cpp
└── snap7.h
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/workflows/test-and-release.yml
================================================
name: Test and Release
on: [push, pull_request, workflow_dispatch]
permissions:
contents: read
jobs:
build:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
node: [16, 18, 20, 22, 24]
arch: [x86, x64]
exclude:
- { os: ubuntu-latest, arch: x86 }
- { os: macos-latest, arch: x86 }
- { os: windows-latest, arch: x86, node: 24 }
runs-on: ${{ matrix.os }}
name: ${{ matrix.os }} / Node ${{ matrix.node }} ${{ matrix.arch }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 2
# Force Python to 3.10 until prebuild updates to node-gyp 10
- name: Use Python 3.10
if: ${{ matrix.os != 'windows-latest' }}
uses: actions/setup-python@v4
with:
python-version: '3.10'
- name: Use node ${{ matrix.node }} ${{ matrix.arch }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
architecture: ${{ matrix.arch }}
- name: Install
run: npm install
- name: Test
env:
PREBUILD_TOKEN: ${{ secrets.PREBUILD_TOKEN }}
run: npm test
================================================
FILE: .gitignore
================================================
.vscode/
build/
node_modules/
test/
================================================
FILE: .npmignore
================================================
test/
.travis.yml
appveyor.yml
.npmignore
.gitignore
================================================
FILE: LICENSE
================================================
(The MIT License)
Copyright (c) 2019 Mathias Küsel
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
================================================
FILE: README.md
================================================
# node-snap7
[](https://www.npmjs.com/package/node-snap7)
[](https://www.npmjs.com/package/node-snap7)
[](https://github.com/mathiask88/node-snap7/actions/workflows/test-and-release.yml)
[](https://www.npmjs.com/package/node-snap7)
**Current node-snap7 version:** 1.0.9\
**Current snap7 version:** 1.4.2
**In my spare time I am working on a [node-addon-api](https://github.com/nodejs/node-addon-api) rewrite and want to switch from [prebuild-install](https://github.com/prebuild/prebuild-install) to [prebuildify](https://github.com/prebuild/prebuildify).\
The current S7Server implementation has some bugs, please use with caution.**
## About
This is a node.js wrapper for snap7. Snap7 is an open source, 32/64 bit, multi-platform Ethernet communication suite for interfacing natively with Siemens S7 PLCs (See [compatibility](http://snap7.sourceforge.net/snap7_client.html#target_compatibility)).
## Installation
Install with:
npm install node-snap7
node-snap7 uses `prebuild` and `prebuild-install` for handling prebuilt binaries. See [this list](https://github.com/mathiask88/node-snap7/releases) of supported prebuilt platform binaries. When installing node-snap7 `prebuild-install` will install prebuilt binaries from GitHub if they exist and fallback to a compile step if they don't.
If you don't want to use the `prebuild` for the platform you are installing on, specify the `--build-from-source` flag when you install.
For building from source you need the following requirements:
- Windows:
- [Visual Studio 2013 Express or higher](https://www.visualstudio.com/de/vs/visual-studio-express/)
- [Python 2.7](https://www.python.org/downloads/release/python-2714/)
- Linux:
- C++11 toolchain
- [Python 2.7](https://www.python.org/downloads/release/python-2714/)
## Special thanks to
- Davide Nardella for creating snap7
## How to use
### API
- [Client](doc/client.md)
- [Server](doc/server.md)
### Client Example
```javascript
var snap7 = require('node-snap7');
var s7client = new snap7.S7Client();
s7client.ConnectTo('192.168.1.12', 0, 1, function(err) {
if(err)
return console.log(' >> Connection failed. Code #' + err + ' - ' + s7client.ErrorText(err));
// Read the first byte from PLC process outputs...
s7client.ABRead(0, 1, function(err, res) {
if(err)
return console.log(' >> ABRead failed. Code #' + err + ' - ' + s7client.ErrorText(err));
// ... and write it to stdout
console.log(res)
});
});
```
### Server Example
```javascript
var snap7 = require('node-snap7');
var s7server = new snap7.S7Server();
// Set up event listener
s7server.on("event", function(event) {
console.log(s7server.EventText(event));
});
// Create a new Buffer and register it to the server as DB1
var db1 = new Buffer(100).fill('ÿ');
s7server.RegisterArea(s7server.srvAreaDB, 1, db1);
// Start the server
s7server.StartTo('127.0.0.1');
// Close the server after 20s in this example
setTimeout(function() {
s7server.Stop();
s7server.UnregisterArea(s7server.srvAreaDB, 1);
}, 20000);
```
Have a look at the resourceless server example [here](doc/server.md#event-read-write).
## License & copyright
Copyright (c) 2019, Mathias Küsel
node-snap7 is licensed under the MIT license. All rights not explicitly granted in the MIT license are reserved. See the included LICENSE file for more details.
node-snap7 builds on the excellent work of the snap7 framework from Davide Nardella. Snap7 is issued under the GPL/LGPLv3 (see `./deps/snap7/gpl.txt ./deps/snap7/lgpl-3.0.txt`).
================================================
FILE: binding.gyp
================================================
{
"targets": [{
"target_name": "node_snap7",
"include_dirs": [
" into the make command line. If not specified
the default path is /usr/lib.
(thanks to Gijs Molenaar)
- Apple OSX, now the library suffix is .dylib instead of .so
however it's possible override the suffix using the LibExt param (see doc.)
(thanks to Gijs Molenaar)
[fixed]
- Fixed a typo error into snap7.net.cs (Cli_GetPlcStatus)
(Thanks to Dabbadoeber for reporting)
- Fixed a bug into s7_micro_client.cpp into block download function.
(Thanks to Mark Konst for reporting)
- fixed a bug into s7_partner.cpp (issues for transfers>PDU size)
(Thanks to Volker Sarnes)
- fixed a bug into s7_server.cpp (wrong bit access)
(Thanks to Thomas Costa)
- little modification to client.cs and ppartner.cs to be compiled with VS2008 which
doesn't handle the constant (default) parameter in a method declaration.
(thanks to Max Schaetzel for reporting)
======================================================================[2014-01-01]
Version 1.2.0 - New Minor platform release (fully compatible with 1.0.0)
----------------------------------------------------------------------------------
- Apple Mac OSX support (Tested under OSX 10.9.1 Mavericks)
- Some bug fixed
- Documentation improved and updated.
==================================================================================
[Added]
- Apple OSX full support :
makefiles, source examples, binary library and binary demos supplied.
new osx folders added in the entire project.
[fixed]
- S7API directive missing for two functions in snap7_libmain.h
(Thanks to Mathias Ksel for reporting)
- fixed Snap7.S7Server.Srv_RegisterArea in snap7.net.cs
(Thanks to Andr for reporting).
- Added a static var to contain the callback addresses into c# examples.
The .net garbage collector *sometime* garbages the delegates (called by unmanaged
code) if their address is not stored into a static var.
MS says that it's not a clr bug (maybe a feature ????)
However this solves the problem.
PLEASE SEE THE .NET EXAMPLES IF YOU PLAN TO USE SNAP7 (or other unmanaged)
CALLBACKS.
(Thanks to Martin Bratt for reporting).
- Srv_SetReadEventsCallback prototype missing in Snap7.pas
======================================================================[2013-11-10]
Version 1.1.0 - New Minor hardware release (fully compatible with 1.0.0)
----------------------------------------------------------------------------------
- LOGO 0BA7 Ethernet support (as client/server and Network I/O blocks)
- S7200 (via CP243) experimental support
- New Callback for S7Server that allow writing full synchronous gateways (protocol
translators)
- New rich-demos
- Some bug fixed
- Documentation improved and updated.
==================================================================================
[Added]
- Cli_GetConnected function added.
It returns the connection status of the client.
- Cli_SetConnectionType function added.
For a Client it's possible to connect to a PLC as PG/OP/S7 Basic.
- Cli_SetConnectionParams function added.
For a Client now it's possible to specifying Local and Remote TSAP before the
connection.
Needed for LOGO, S7200 and future hardware compatible with S7Protocol.
- Srv_SetReadEventsCallback function added.
It allows to trap the read event from a client *before* the data getting.
- New ClientDemo and ServerDemo for the latter functions were supplied.
- LOGO examples were supplied.
- New rich-demos for Cubieboard 2 (under Cubian OS)
- Glibc_2.11 for Linux x86_64 Release
- Full documentation updated.
[Fixed]
- Expression bug in line 491 of /examples/pascal/client.dpr
"if ParamCount=4" must be "if ParamCount=3"
(thanks to Jean-Noel Voirol)
- Bug in S7Worker (Snap7Server) that returned "Data mismatch" error in MultiWrite
function when writing ODD amount of bytes in items with index>1
- Bug in TSAP calculation in S7Client connection that sent wrong connection
telegram to S7400 when the CPU was in Rack>1
(thanks to hujingqi for the detailed analysis)
======================================================================[2013-09-03]
Version 1.0.0
==================================================================================
- First public release.
==================================================================================
================================================
FILE: deps/snap7/gpl.txt
================================================
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc.
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
Copyright (C)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
Copyright (C)
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
.
================================================
FILE: deps/snap7/lgpl-3.0.txt
================================================
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc.
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.
================================================
FILE: deps/snap7/src/core/s7_client.cpp
================================================
/*=============================================================================|
| 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();
}
};
}
================================================
FILE: deps/snap7/src/core/s7_client.h
================================================
/*=============================================================================|
| PROJECT SNAP7 1.3.0 |
|==============================================================================|
| Copyright (C) 2013, 2015 Davide Nardella |
| All rights reserved. |
|==============================================================================|
| SNAP7 is free software: you can redistribute it and/or modify |
| it under the terms of the Lesser GNU General Public License as published by |
| the Free Software Foundation, either version 3 of the License, or |
| (at your option) any later version. |
| |
| It means that you can distribute your commercial software linked with |
| SNAP7 without the requirement to distribute the source code of your |
| application and without the requirement that your application be itself |
| distributed under LGPL. |
| |
| SNAP7 is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| Lesser GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License and a |
| copy of Lesser GNU General Public License along with Snap7. |
| If not, see http://www.gnu.org/licenses/ |
|=============================================================================*/
#ifndef s7_client_h
#define s7_client_h
//---------------------------------------------------------------------------
#include "snap_threads.h"
#include "s7_micro_client.h"
//---------------------------------------------------------------------------
extern "C" {
typedef void (S7API *pfn_CliCompletion) (void * usrPtr, int opCode, int opResult);
}
class TSnap7Client;
class TClientThread: public TSnapThread
{
private:
TSnap7Client * FClient;
public:
TClientThread(TSnap7Client *Client)
{
FClient = Client;
}
void Execute();
};
//---------------------------------------------------------------------------
class TSnap7Client: public TSnap7MicroClient
{
private:
TClientThread *FThread;
bool ThreadCreated;
void CloseThread();
void OpenThread();
void StartAsyncJob();
protected:
PSnapEvent EvtJob;
PSnapEvent EvtComplete;
pfn_CliCompletion CliCompletion;
void *FUsrPtr;
void DoCompletion();
public:
friend class TClientThread;
TSnap7Client();
~TSnap7Client();
int Reset(bool DoReconnect);
int SetAsCallback(pfn_CliCompletion pCompletion, void * usrPtr);
int GetParam(int ParamNumber, void *pValue);
int SetParam(int ParamNumber, void *pValue);
// Async functions
bool CheckAsCompletion( int & opResult);
int WaitAsCompletion(unsigned long Timeout);
int AsReadArea(int Area, int DBNumber, int Start, int Amount, int WordLen, void * pUsrData);
int AsWriteArea(int Area, int DBNumber, int Start, int Amount, int WordLen, void * pUsrData);
int AsListBlocksOfType(int BlockType, PS7BlocksOfType pUsrData, int & ItemsCount);
int AsReadSZL(int ID, int Index, PS7SZL pUsrData, int & Size);
int AsReadSZLList(PS7SZLList pUsrData, int &ItemsCount);
int AsUpload(int BlockType, int BlockNum, void * pUsrData, int & Size);
int AsFullUpload(int BlockType, int BlockNum, void * pUsrData, int & Size);
int AsDownload(int BlockNum, void * pUsrData, int Size);
int AsCopyRamToRom(int Timeout);
int AsCompress(int Timeout);
int AsDBRead(int DBNumber, int Start, int Size, void * pUsrData);
int AsDBWrite(int DBNumber, int Start, int Size, void * pUsrData);
int AsMBRead(int Start, int Size, void * pUsrData);
int AsMBWrite(int Start, int Size, void * pUsrData);
int AsEBRead(int Start, int Size, void * pUsrData);
int AsEBWrite(int Start, int Size, void * pUsrData);
int AsABRead(int Start, int Size, void * pUsrData);
int AsABWrite(int Start, int Size, void * pUsrData);
int AsTMRead(int Start, int Amount, void * pUsrData);
int AsTMWrite(int Start, int Amount, void * pUsrData);
int AsCTRead(int Start, int Amount, void * pUsrData);
int AsCTWrite(int Start, int Amount, void * pUsrData);
int AsDBGet(int DBNumber, void * pUsrData, int & Size);
int AsDBFill(int DBNumber, int FillChar);
};
typedef TSnap7Client *PSnap7Client;
//---------------------------------------------------------------------------
#endif // s7_client_h
================================================
FILE: deps/snap7/src/core/s7_firmware.h
================================================
/*=============================================================================|
| PROJECT SNAP7 1.3.0 |
|==============================================================================|
| Copyright (C) 2013, 2015 Davide Nardella |
| All rights reserved. |
|==============================================================================|
| SNAP7 is free software: you can redistribute it and/or modify |
| it under the terms of the Lesser GNU General Public License as published by |
| the Free Software Foundation, either version 3 of the License, or |
| (at your option) any later version. |
| |
| It means that you can distribute your commercial software linked with |
| SNAP7 without the requirement to distribute the source code of your |
| application and without the requirement that your application be itself |
| distributed under LGPL. |
| |
| SNAP7 is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| Lesser GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License and a |
| copy of Lesser GNU General Public License along with Snap7. |
| If not, see http://www.gnu.org/licenses/ |
|=============================================================================*/
#ifndef s7_firmware_h
#define s7_firmware_h
//---------------------------------------------------------------------------
#include "snap_platform.h"
//******************************************************************************
// CPU DATABANK
//******************************************************************************
byte SZLNotAvail[4] = {
0x0A,0x00,0x00,0x00
};
byte SZLSysState[6] = {
0xFF,0x09,0x00,0x02,0x02,0x00
};
byte SZL_ID_0000_IDX_XXXX[236] = {
0xFF,0x09,0x00,0xE8,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x70,0x00,0x00,0x0F,0x00,0x00,0x02,0x00,
0x11,0x01,0x11,0x0F,0x11,0x00,0x12,0x01,0x12,0x0F,0x12,0x00,0x13,0x01,0x13,0x00,0x14,0x0F,0x14,
0x00,0x15,0x01,0x15,0x00,0x17,0x01,0x17,0x0F,0x17,0x00,0x18,0x01,0x18,0x0F,0x18,0x00,0x19,0x0F,
0x19,0x00,0x1A,0x0F,0x1A,0x00,0x1B,0x0F,0x1B,0x00,0x1C,0x01,0x1C,0x0F,0x1C,0x00,0x21,0x0A,0x21,
0x0F,0x21,0x02,0x22,0x00,0x23,0x0F,0x23,0x00,0x24,0x01,0x24,0x04,0x24,0x05,0x24,0x00,0x25,0x01,
0x25,0x02,0x25,0x0F,0x25,0x01,0x31,0x01,0x32,0x02,0x32,0x00,0x36,0x01,0x36,0x0F,0x36,0x00,0x37,
0x01,0x37,0x0F,0x37,0x00,0x38,0x01,0x38,0x02,0x38,0x0F,0x38,0x01,0x39,0x00,0x3A,0x0F,0x3A,0x00,
0x74,0x01,0x74,0x0F,0x74,0x05,0x91,0x0A,0x91,0x0C,0x91,0x0D,0x91,0x00,0x92,0x02,0x92,0x06,0x92,
0x0F,0x92,0x00,0x94,0x01,0x94,0x02,0x94,0x06,0x94,0x07,0x94,0x0F,0x94,0x00,0x95,0x01,0x95,0x0F,
0x95,0x06,0x96,0x0C,0x96,0x0C,0x97,0x0D,0x97,0x01,0x9A,0x02,0x9A,0x0F,0x9A,0x0C,0x9B,0x00,0x9C,
0x01,0x9C,0x02,0x9C,0x03,0x9C,0x0F,0x9C,0x00,0xA0,0x01,0xA0,0x0F,0xA0,0x00,0xB1,0x00,0xB2,0x00,
0xB3,0x00,0xB4,0x01,0xB5,0x02,0xB5,0x03,0xB5,0x04,0xB5,0x05,0xB5,0x06,0xB5,0x07,0xB5,0x08,0xB5,
0x01,0xB6,0x02,0xB6,0x03,0xB6,0x04,0xB6
};
byte SZL_ID_0F00_IDX_XXXX[12] = {
0xFF,0x09,0x00,0x08,0x0F,0x00,0x00,0x00,0x00,0x02,0x00,0x70
};
byte SZL_ID_0002_IDX_XXXX[458] = { // <--Wrapped to 458 bytes
0xFF,0x09,0x01,0xC6,0x00,0x02,0x00,0x00,0x00,0x08,0x00,0x71,0x01,0xAC,0x00,0x01,0x00,0x28,0x00,
0x1C,0x01,0xAC,0x24,0x00,0x00,0x24,0x00,0x00,0x01,0xAC,0x23,0x00,0x00,0x06,0x04,0xB0,0x01,0xAC,
0x22,0x00,0x00,0x08,0x00,0x01,0x01,0xAC,0x31,0x00,0x04,0x00,0x00,0x01,0x01,0xAC,0x12,0xFF,0x00,
0x08,0x00,0x01,0x01,0xAC,0x12,0x31,0x00,0x08,0x00,0x01,0x01,0xAD,0x00,0x00,0x80,0x00,0x00,0x01,
0x01,0xAD,0x01,0x00,0x80,0x00,0x00,0x01,0x01,0xAD,0x02,0x00,0x80,0x00,0x00,0x01,0x01,0xAD,0x03,
0x00,0x80,0x00,0x00,0x01,0x01,0xAD,0x04,0x00,0x80,0x00,0x00,0x01,0x01,0xAD,0x05,0x00,0x80,0x00,
0x00,0x01,0x01,0xAD,0x06,0x00,0x80,0x00,0x00,0x01,0x01,0xAD,0x07,0x00,0x80,0x00,0x00,0x01,0x01,
0xAD,0x00,0x01,0x80,0x00,0x00,0x01,0x01,0xAD,0x01,0x01,0x80,0x00,0x00,0x01,0x01,0xAD,0x02,0x01,
0x80,0x00,0x00,0x01,0x01,0xAD,0x03,0x01,0x80,0x00,0x00,0x01,0x01,0xAD,0x04,0x01,0x80,0x00,0x00,
0x01,0x01,0xAD,0x05,0x01,0x80,0x00,0x00,0x01,0x01,0xAD,0x06,0x01,0x80,0x00,0x00,0x01,0x01,0xAD,
0x07,0x01,0x80,0x00,0x00,0x01,0x01,0xAD,0x00,0x03,0x80,0x00,0x00,0x01,0x01,0xAD,0x01,0x03,0x80,
0x00,0x00,0x01,0x01,0xAD,0x02,0x03,0x80,0x00,0x00,0x01,0x01,0xAD,0x03,0x03,0x80,0x00,0x00,0x01,
0x01,0xAD,0x04,0x03,0x80,0x00,0x00,0x01,0x01,0xAD,0x05,0x03,0x80,0x00,0x00,0x01,0x01,0xAD,0x06,
0x03,0x80,0x00,0x00,0x01,0x01,0xAD,0x07,0x03,0x80,0x00,0x00,0x01,0x01,0xAD,0x00,0x04,0x80,0x00,
0x00,0x01,0x01,0xAD,0x01,0x04,0x80,0x00,0x00,0x01,0x01,0xAD,0x02,0x04,0x80,0x00,0x00,0x01,0x01,
0xAD,0x03,0x04,0x80,0x00,0x00,0x01,0x01,0xAD,0x04,0x04,0x80,0x00,0x00,0x01,0x01,0xAD,0x05,0x04,
0x80,0x00,0x00,0x01,0x01,0xAD,0x06,0x04,0x80,0x00,0x00,0x01,0x01,0xAD,0x07,0x04,0x80,0x00,0x00,
0x01,0x01,0xAD,0x00,0x05,0x80,0x00,0x00,0x01,0x01,0xAD,0x01,0x05,0x80,0x00,0x00,0x01,0x01,0xAD,
0x02,0x05,0x80,0x00,0x00,0x01,0x01,0xAD,0x03,0x05,0x80,0x00,0x00,0x01,0x01,0xAD,0x04,0x05,0x80,
0x00,0x00,0x01,0x01,0xAD,0x05,0x05,0x80,0x00,0x00,0x01,0x01,0xAD,0x06,0x05,0x80,0x00,0x00,0x01,
0x01,0xAD,0x07,0x05,0x80,0x00,0x00,0x01,0x01,0xAD,0x00,0x06,0x80,0x00,0x00,0x01,0x01,0xAD,0x01,
0x06,0x80,0x00,0x00,0x01,0x01,0xAD,0x02,0x06,0x80,0x00,0x00,0x01,0x01,0xAD,0x03,0x06,0x80,0x00,
0x00,0x01,0x01,0xAD,0x04,0x06,0x80,0x00,0x00,0x01,0x01,0xAD,0x05,0x06,0x80,0x00,0x00,0x01,0x01,
0xAD,0x06,0x06,0x80,0x00,0x00,0x01,0x01,0xAD,0x07,0x06,0x80,0x00,0x00,0x01,0x01,0xAD,0x00,0x07,
0x80,0x00
};
byte SZL_ID_0011_IDX_XXXX[124] = {
0xFF,0x09,0x00,0x78,0x00,0x11,0x00,0x00,0x00,0x1C,0x00,0x04,0x00,0x01,0x36,0x45,0x53,0x37,0x20,
0x33,0x31,0x35,0x2D,0x32,0x45,0x48,0x31,0x34,0x2D,0x30,0x41,0x42,0x30,0x20,0x00,0xC0,0x00,0x04,
0x00,0x01,0x00,0x06,0x36,0x45,0x53,0x37,0x20,0x33,0x31,0x35,0x2D,0x32,0x45,0x48,0x31,0x34,0x2D,
0x30,0x41,0x42,0x30,0x20,0x00,0xC0,0x00,0x04,0x00,0x01,0x00,0x07,0x20,0x20,0x20,0x20,0x20,0x20,
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0xC0,0x56,0x03,0x02,
0x06,0x00,0x81,0x42,0x6F,0x6F,0x74,0x20,0x4C,0x6F,0x61,0x64,0x65,0x72,0x20,0x20,0x20,0x20,0x20,
0x20,0x20,0x20,0x20,0x00,0x00,0x41,0x20,0x09,0x09
};
byte SZL_ID_0012_IDX_XXXX[58] = {
0xFF,0x09,0x00,0x36,0x00,0x12,0x00,0x00,0x00,0x02,0x00,0x17,0x00,0x01,0x01,0x01,0x01,0x04,0x03,
0x02,0x03,0x03,0x03,0x04,0x03,0x06,0x03,0x07,0x03,0x08,0x03,0x09,0x03,0x0A,0x03,0x0B,0x03,0x0C,
0x03,0x0D,0x03,0x0E,0x03,0x0F,0x03,0x10,0x03,0x11,0x03,0x12,0x03,0x13,0x03,0x14,0x03,0x15,0x03,
0x17
};
byte SZL_ID_0013_IDX_XXXX[192] = {
0xFF,0x09,0x00,0xBC,0x00,0x13,0x00,0x00,0x00,0x24,0x00,0x05,0x00,0x01,0x00,0x01,0x00,0x06,0x00,
0x00,0x00,0x11,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x26,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x01,0x00,0x00,0x00,0x00,0x00,
0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x02,0x00,0x08,0x00,0x00,0x00,0x02,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,
0x0C,0x06,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x02,0x00,0x80,0x00,0x00,0x00,0x02,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x02,0x00,0x00,0x0C,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x00,0x20,0x00,0x00,
0x00,0x00
};
byte SZL_ID_0014_IDX_XXXX[84] = {
0xFF,0x09,0x00,0x50,0x00,0x14,0x00,0x00,0x00,0x08,0x00,0x09,0x00,0x01,0x00,0x01,0x08,0x00,0x00,
0x00,0x00,0x02,0x00,0x01,0x08,0x00,0x00,0x00,0x00,0x03,0x00,0x01,0x40,0x00,0x00,0x80,0x00,0x04,
0x00,0x01,0x01,0x00,0x00,0x00,0x00,0x05,0x00,0x01,0x01,0x00,0x00,0x08,0x00,0x06,0x00,0x01,0x08,
0x00,0x00,0x00,0x00,0x07,0x00,0x01,0x80,0x00,0x00,0x00,0x00,0x08,0x00,0x01,0x08,0x00,0x00,0x10,
0x00,0x09,0x00,0x01,0x00,0x20,0x00,0x00
};
byte SZL_ID_0015_IDX_XXXX[62] = {
0xFF,0x09,0x00,0x3A,0x00,0x15,0x00,0x00,0x00,0x0A,0x00,0x05,0x08,0x00,0x00,0x16,0x03,0xD1,0x00,
0x00,0xFF,0xFE,0x0A,0x00,0x3E,0x81,0x03,0xD1,0x00,0x00,0xFF,0xFE,0x0B,0x00,0x04,0x22,0x03,0xD1,
0x00,0x00,0xFF,0xFE,0x0C,0x00,0x1F,0x40,0x03,0xD1,0x00,0x00,0xFF,0xFE,0x0E,0x00,0x1F,0x40,0x03,
0xD1,0x00,0x00,0xFF,0xFE
};
byte SZL_ID_0F14_IDX_XXXX[12] = {
0xFF,0x09,0x00,0x08,0x0F,0x14,0x00,0x00,0x00,0x08,0x00,0x09
};
byte SZL_ID_0019_IDX_XXXX[40] = {
0xFF,0x09,0x00,0x24,0x00,0x19,0x00,0x00,0x00,0x04,0x00,0x07,0x00,0x01,0x00,0x00,0x00,0x04,0x01,
0x00,0x00,0x05,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x0B,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x15,
0x00,0x00
};
byte SZL_ID_0F19_IDX_XXXX[12] = {
0xFF,0x09,0x00,0x08,0x0F,0x19,0x00,0x00,0x00,0x04,0x00,0x07
};
byte SZL_ID_001C_IDX_XXXX[352] = {
0xFF,0x09,0x01,0x5C,0x00,0x1C,0x00,0x00,0x00,0x22,0x00,0x0A,0x00,0x01,0x53,0x4E,0x41,0x50,0x37,
0x2D,0x53,0x45,0x52,0x56,0x45,0x52,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x43,0x50,0x55,0x20,0x33,0x31,0x35,0x2D,0x32,
0x20,0x50,0x4E,0x2F,0x44,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x04,0x4F,0x72,0x69,0x67,0x69,0x6E,0x61,0x6C,0x20,0x53,0x69,0x65,0x6D,0x65,0x6E,0x73,0x20,
0x45,0x71,0x75,0x69,0x70,0x6D,0x65,0x6E,0x74,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x53,0x20,
0x43,0x2D,0x43,0x32,0x55,0x52,0x32,0x38,0x39,0x32,0x32,0x30,0x31,0x32,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x43,0x50,0x55,0x20,0x33,0x31,
0x35,0x2D,0x32,0x20,0x50,0x4E,0x2F,0x44,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x4D,0x4D,0x43,0x20,0x32,0x36,0x37,0x46,0x46,0x31,
0x31,0x46,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x09,0x00,0x2A,0xF6,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x0A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
byte SZL_ID_0F1C_IDX_XXXX[12] = {
0xFF,0x09,0x00,0x08,0x0F,0x1C,0x00,0x00,0x00,0x22,0x00,0x0A
};
byte SZL_ID_0036_IDX_XXXX[12] = {
0xFF,0x09,0x00,0x08,0x00,0x36,0x00,0x00,0x00,0x00,0x00,0x00
};
byte SZL_ID_0F36_IDX_XXXX[12] = {
0xFF,0x09,0x00,0x08,0x0F,0x36,0x00,0x00,0x00,0x00,0x00,0x00
};
byte SZL_ID_0025_IDX_XXXX[16] = {
0xFF,0x09,0x00,0x0C,0x00,0x25,0x00,0x00,0x00,0x04,0x00,0x01,0x01,0x0C,0x3D,0x00
};
byte SZL_ID_0F25_IDX_XXXX[12] = {
0xFF,0x09,0x00,0x08,0x0F,0x25,0x00,0x00,0x00,0x04,0x00,0x01
};
byte SZL_ID_0037_IDX_XXXX[60] = {
0xFF,0x09,0x00,0x38,0x00,0x37,0x00,0x00,0x00,0x30,0x00,0x01,0x07,0xFE,0xC0,0xA8,0x01,0x0A,0xFF,
0xFF,0xFF,0x00,0xC0,0xA8,0x01,0x0A,0x00,0x1B,0x1B,0x1D,0x1A,0x2D,0x01,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x8F,0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00
};
byte SZL_ID_0F37_IDX_XXXX[12] = {
0xFF,0x09,0x00,0x08,0x0F,0x37,0x00,0x00,0x00,0x30,0x00,0x01
};
byte SZL_ID_0074_IDX_XXXX[40] = {
0xFF,0x09,0x00,0x24,0x00,0x74,0x00,0x00,0x00,0x04,0x00,0x07,0x00,0x01,0x00,0x00,0x00,0x04,0x01,
0x00,0x00,0x05,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x0B,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x15,
0x00,0x00
};
byte SZL_ID_0F74_IDX_XXXX[12] = {
0xFF,0x09,0x00,0x08,0x0F,0x74,0x00,0x00,0x00,0x04,0x00,0x07
};
byte SZL_ID_0591_IDX_XXXX[76] = {
0xFF,0x09,0x00,0x48,0x05,0x91,0x00,0x00,0x00,0x10,0x00,0x04,0x00,0x00,0x02,0x01,0x07,0xFF,0xC4,
0xC0,0xC4,0xC0,0x00,0x00,0xB4,0x02,0x00,0x11,0x00,0x00,0x02,0x02,0x07,0xFE,0xA7,0xC4,0xA7,0xC4,
0x00,0x00,0xB4,0x02,0x00,0x11,0x00,0x00,0x02,0x03,0x07,0xFD,0x97,0xC5,0x97,0xC5,0x00,0x00,0xB4,
0x02,0x00,0x11,0x00,0x00,0x02,0x04,0x07,0xFC,0x97,0xC5,0x97,0xC5,0x00,0x00,0xB4,0x02,0x00,0x11
};
byte SZL_ID_0A91_IDX_XXXX[44] = {
0xFF,0x09,0x00,0x28,0x0A,0x91,0x00,0x00,0x00,0x10,0x00,0x02,0x01,0x00,0x02,0x01,0x07,0xFF,0xC4,
0xC0,0xC4,0xC0,0x00,0x01,0xFE,0x02,0x00,0x11,0x80,0x00,0x00,0x00,0x07,0xFB,0xA7,0xC4,0xA7,0xC4,
0x00,0x01,0xFE,0x02,0x00,0x11
};
byte SZL_ID_0F92_IDX_XXXX[12] = {
0xFF,0x09,0x00,0x08,0x0F,0x92,0x00,0x00,0x00,0x10,0x00,0x01
};
byte SZL_ID_0294_IDX_XXXX[270] = {
0xFF,0x09,0x01,0x0A,0x02,0x94,0x00,0x00,0x01,0x02,0x00,0x01,0x00,0x00,0x03,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00
};
byte SZL_ID_0794_IDX_XXXX[270] = {
0xFF,0x09,0x01,0x0A,0x07,0x94,0x00,0x00,0x01,0x02,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00
};
byte SZL_ID_0F94_IDX_XXXX[12] = {
0xFF,0x09,0x00,0x08,0x0F,0x94,0x00,0x00,0x01,0x02,0x00,0x01
};
byte SZL_ID_0095_IDX_XXXX[52] = {
0xFF,0x09,0x00,0x30,0x00,0x95,0x00,0x00,0x00,0x28,0x00,0x01,0x64,0x00,0x02,0x02,0x07,0xFE,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
byte SZL_ID_0F95_IDX_XXXX[12] = {
0xFF,0x09,0x00,0x08,0x0F,0x95,0x00,0x00,0x00,0x28,0x00,0x01
};
byte SZL_ID_00A0_IDX_XXXX[212] = {
0xFF,0x09,0x00,0xD0,0x00,0xA0,0x00,0x00,0x00,0x14,0x00,0x0A,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,
0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x86,0x13,0x81,0xFE,0x64,0xC7,0x72,
0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x76,0x43,0x01,0xFF,0x46,0xC7,
0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x29,0x66,0x43,0x04,0xFF,0x84,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x52,0x13,0x90,0x16,0x43,0x02,0xFF,
0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x56,0x13,0x81,
0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x46,0x43,
0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x79,0x46,
0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x51,0x19,0x48,
0x26,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50,0x45,
0x09,0x96,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50,
0x45,0x09,0x86
};
byte SZL_ID_0FA0_IDX_XXXX[12] = {
0xFF,0x09,0x00,0x08,0x0F,0xA0,0x00,0x00,0x00,0x14,0x01,0xF4
};
byte SZL_ID_0017_IDX_XXXX[458] = { // <--Wrapped to 458 bytes
0xFF,0x09,0x01,0xC6,0x00,0x17,0x00,0x00,0x00,0x04,0x00,0x73,0x00,0x00,0x00,0x01,0x00,0x01,0x00,
0x03,0x00,0x02,0x00,0x02,0x00,0x03,0x00,0x01,0x00,0x04,0x00,0x01,0x00,0x07,0x00,0x01,0x00,0x16,
0x00,0x01,0x00,0x64,0x00,0x01,0x00,0x65,0x00,0x01,0x00,0x66,0x00,0x01,0x00,0x67,0x00,0x01,0x00,
0x7A,0x00,0x01,0x00,0xC8,0x00,0x01,0x00,0xD2,0x00,0x01,0x02,0xBC,0x00,0x01,0x02,0xBD,0x00,0x01,
0x02,0xBE,0x00,0x01,0x02,0xBF,0x00,0x01,0x02,0xC0,0x00,0x01,0x02,0xC1,0x00,0x01,0x02,0xC2,0x00,
0x01,0x02,0xC3,0x00,0x01,0x02,0xC4,0x00,0x01,0x02,0xC5,0x00,0x01,0x02,0xC6,0x00,0x01,0x02,0xC7,
0x00,0x01,0x02,0xC8,0x00,0x01,0x02,0xC9,0x00,0x01,0x02,0xCA,0x00,0x01,0x02,0xCB,0x00,0x01,0x02,
0xCC,0x00,0x01,0x02,0xCD,0x00,0x01,0x02,0xCE,0x00,0x01,0x02,0xCF,0x00,0x01,0x02,0xD0,0x00,0x01,
0x02,0xD1,0x00,0x01,0x02,0xD2,0x00,0x01,0x02,0xD3,0x00,0x01,0x02,0xD4,0x00,0x01,0x02,0xD5,0x00,
0x01,0x02,0xD6,0x00,0x01,0x02,0xD7,0x00,0x01,0x02,0xD8,0x00,0x01,0x02,0xD9,0x00,0x01,0x02,0xDA,
0x00,0x01,0x02,0xDB,0x00,0x01,0x02,0xDC,0x00,0x01,0x02,0xDD,0x00,0x01,0x02,0xDE,0x00,0x01,0x02,
0xDF,0x00,0x01,0x02,0xE0,0x00,0x01,0x02,0xE1,0x00,0x01,0x02,0xE2,0x00,0x01,0x02,0xE3,0x00,0x01,
0x02,0xE4,0x00,0x01,0x02,0xE5,0x00,0x01,0x02,0xE6,0x00,0x01,0x02,0xE7,0x00,0x01,0x02,0xE8,0x00,
0x01,0x02,0xE9,0x00,0x01,0x02,0xEA,0x00,0x01,0x02,0xEB,0x00,0x01,0x02,0xEC,0x00,0x01,0x02,0xED,
0x00,0x01,0x02,0xEE,0x00,0x01,0x02,0xEF,0x00,0x01,0x02,0xF0,0x00,0x01,0x02,0xF1,0x00,0x01,0x02,
0xF2,0x00,0x01,0x02,0xF3,0x00,0x01,0x02,0xF4,0x00,0x01,0x02,0xF5,0x00,0x01,0x02,0xF6,0x00,0x01,
0x02,0xF7,0x00,0x01,0x02,0xF8,0x00,0x01,0x02,0xF9,0x00,0x01,0x02,0xFA,0x00,0x01,0x02,0xFB,0x00,
0x01,0x02,0xFC,0x00,0x01,0x02,0xFD,0x00,0x01,0x02,0xFE,0x00,0x01,0x02,0xFF,0x00,0x01,0x03,0x00,
0x00,0x01,0x03,0x01,0x00,0x01,0x03,0x02,0x00,0x01,0x03,0x03,0x00,0x01,0x03,0x04,0x00,0x01,0x03,
0x05,0x00,0x01,0x03,0x06,0x00,0x01,0x03,0x07,0x00,0x01,0x03,0x08,0x00,0x01,0x03,0x09,0x00,0x01,
0x03,0x0A,0x00,0x01,0x03,0x0B,0x00,0x01,0x03,0x0C,0x00,0x01,0x03,0x0D,0x00,0x01,0x03,0x0E,0x00,
0x01,0x03,0x0F,0x00,0x01,0x03,0x10,0x00,0x01,0x03,0x11,0x00,0x01,0x03,0x12,0x00,0x01,0x03,0x13,
0x00,0x01,0x03,0x14,0x00,0x01,0x03,0x15,0x00,0x01,0x03,0x16,0x00,0x01,0x03,0x17,0x00,0x01,0x03,
0x18,0x00,0x01,0x03,0x19,0x00,0x01,0x03,0x1A,0x00,0x01,0x03,0x1B,0x00,0x01,0x03,0x1C,0x00,0x01,
0x03,0x1D
};
byte SZL_ID_0F17_IDX_XXXX[12] = {
0xFF,0x09,0x00,0x08,0x0F,0x17,0x00,0x00,0x00,0x04,0x00,0x73
};
byte SZL_ID_0018_IDX_XXXX[28] = {
0xFF,0x09,0x00,0x18,0x00,0x18,0x00,0x00,0x00,0x04,0x00,0x04,0x00,0x00,0x00,0x08,0x00,0x01,0x00,
0x08,0x00,0x02,0x00,0x08,0x00,0x03,0x00,0x08
};
byte SZL_ID_0F18_IDX_XXXX[12] = {
0xFF,0x09,0x00,0x08,0x0F,0x18,0x00,0x00,0x00,0x04,0x00,0x04
};
byte SZL_ID_001A_IDX_XXXX[48] = {
0xFF,0x09,0x00,0x2C,0x00,0x1A,0x00,0x00,0x00,0x0C,0x00,0x03,0x09,0x01,0x01,0x05,0x00,0x08,0x00,
0x00,0x00,0x80,0x00,0x00,0x12,0x01,0x00,0x02,0x00,0x06,0x00,0x00,0x00,0x06,0x00,0x00,0x18,0x01,
0x00,0x02,0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x00
};
byte SZL_ID_0F1A_IDX_XXXX[12] = {
0xFF,0x09,0x00,0x08,0x0F,0x1A,0x00,0x00,0x00,0x0C,0x00,0x03
};
byte SZL_ID_001B_IDX_XXXX[132] = {
0xFF,0x09,0x00,0x80,0x00,0x1B,0x00,0x00,0x00,0x14,0x00,0x06,0x09,0x00,0x00,0x00,0x00,0x02,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x06,0x00,0x00,0x00,0x00,0x09,0x00,0x00,0x70,0x00,0x02,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xF3,0xFA,0x00,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x26,0x00,0x00,0x00,0x00,0x12,0x00,0x00,0x70,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0xFF,0xDA,0x00,0x00,0x00,0x00,0x18,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,
0x00,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00
};
byte SZL_ID_0F1B_IDX_XXXX[12] = {
0xFF,0x09,0x00,0x08,0x0F,0x1B,0x00,0x00,0x00,0x14,0x00,0x06
};
byte SZL_ID_0021_IDX_XXXX[100] = {
0xFF,0x09,0x00,0x60,0x00,0x21,0x00,0x00,0x00,0x04,0x00,0x16,0x01,0x01,0x01,0x01,0x01,0x11,0xFE,
0x0A,0x01,0x21,0xFE,0x14,0x01,0x22,0xFE,0x15,0x01,0x33,0xFE,0x20,0x01,0x34,0xFE,0x21,0x01,0x35,
0xFE,0x22,0x01,0x36,0xFE,0x23,0x01,0x41,0xFE,0x28,0x01,0x55,0xFE,0x37,0x01,0x56,0xFE,0x38,0x01,
0x57,0xFE,0x39,0x01,0x64,0xFE,0x3D,0x00,0x01,0xFE,0x50,0x00,0x42,0xFE,0x52,0x00,0x61,0xFE,0x53,
0x00,0xA1,0xFE,0x55,0x00,0xC1,0xFE,0x56,0x00,0xD2,0xFE,0x57,0x00,0x81,0xFE,0x64,0x00,0x21,0xFE,
0x79,0x00,0x42,0xFE,0x7A
};
byte SZL_ID_0A21_IDX_XXXX[16] = {
0xFF,0x09,0x00,0x0C,0x0A,0x21,0x00,0x00,0x00,0x04,0x00,0x01,0x01,0x01,0x01,0x01
};
byte SZL_ID_0F21_IDX_XXXX[12] = {
0xFF,0x09,0x00,0x08,0x0F,0x21,0x00,0x00,0x00,0x04,0x00,0x16
};
byte SZL_ID_0023_IDX_XXXX[228] = {
0xFF,0x09,0x00,0xE0,0x00,0x23,0x00,0x00,0x00,0x12,0x00,0x0C,0x1A,0x00,0x00,0x00,0x10,0xBE,0x00,
0x00,0x08,0x00,0x0B,0xC0,0xFC,0x01,0xFF,0xFF,0xFF,0xF3,0x19,0x00,0x00,0x00,0x10,0x01,0x00,0x00,
0x08,0x00,0x0B,0xC0,0xFC,0x01,0xFF,0xFF,0xFF,0xF3,0x10,0x00,0x00,0x00,0x10,0x26,0x00,0x00,0x08,
0x00,0x0B,0xC0,0xFC,0x01,0xFF,0xFF,0xFF,0xF3,0x0C,0x00,0x00,0x00,0x10,0x01,0x00,0x00,0x08,0x00,
0x0B,0xC0,0xFC,0x01,0xFF,0xFF,0xFF,0xF3,0x0B,0x00,0x00,0x00,0x10,0x01,0x00,0x00,0x08,0x00,0x0B,
0xC0,0xFC,0x01,0xFF,0xFF,0xFF,0xF3,0x0A,0x00,0x00,0x00,0x10,0x01,0x00,0x00,0x08,0x00,0x0B,0xC0,
0xFC,0x01,0xFF,0xFF,0xFF,0xF3,0x09,0x00,0x00,0x00,0x10,0x01,0x00,0x00,0x08,0x00,0x0B,0xC0,0xFC,
0x01,0xFF,0xFF,0xFF,0xF3,0x04,0x00,0x00,0x00,0x10,0x01,0x00,0x00,0x08,0x00,0x0B,0xC0,0xFC,0x01,
0xFF,0xFF,0xFF,0xF3,0x03,0x00,0x00,0x00,0x10,0x01,0x00,0x00,0x08,0x00,0x0B,0xC0,0xFC,0x01,0xFF,
0xFF,0xFF,0xF3,0x02,0x00,0x00,0x00,0x10,0x16,0x00,0x00,0x08,0x00,0x0B,0xC0,0xFC,0x01,0xFF,0xFF,
0xFF,0xF3,0x01,0x00,0x00,0x00,0x10,0x01,0x00,0x00,0x08,0x00,0x0B,0xC0,0xFC,0x01,0xFF,0xFF,0xFF,
0xF3,0x1B,0x00,0x00,0x00,0x10,0x01,0x00,0x00,0x08,0x00,0x0B,0xC0,0xFC,0x01,0xFF,0xFF,0xFF,0xF3
};
byte SZL_ID_0F23_IDX_XXXX[12] = {
0xFF,0x09,0x00,0x08,0x0F,0x23,0x00,0x00,0x00,0x12,0x00,0x0C
};
byte SZL_ID_0024_IDX_XXXX[92] = {
0xFF,0x09,0x00,0x58,0x00,0x24,0x00,0x00,0x00,0x14,0x00,0x04,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,
0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x86,0x43,0x01,0xFF,0x46,0xC7,0x72,
0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x29,0x66,0x43,0x04,0xFF,0x84,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x52,0x13,0x90,0x16,0x43,0x02,0xFF,0x68,
0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x56
};
byte SZL_ID_0124_IDX_XXXX[32] = {
0xFF,0x09,0x00,0x1C,0x01,0x24,0x00,0x00,0x00,0x14,0x00,0x01,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,
0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x86
};
byte SZL_ID_0424_IDX_XXXX[32] = {
0xFF,0x09,0x00,0x1C,0x04,0x24,0x00,0x00,0x00,0x14,0x00,0x01,0x51,0x44,0xFF,
0x08, // <-- CPU Status
0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x05,0x02,0x01,0x55,0x90,0x67
};
byte SZL_ID_0038_IDX_XXXX[78] = {
0xFF,0x09,0x00,0x4A,0x00,0x38,0x00,0x00,0x00,0x42,0x00,0x01,0x00,0x01,0x07,0xFE,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xAB,0xE3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0xEE,0x49,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00
};
byte SZL_ID_0F38_IDX_XXXX[12] = {
0xFF,0x09,0x00,0x08,0x0F,0x38,0x00,0x00,0x00,0x42,0x00,0x01
};
byte SZL_ID_003A_IDX_XXXX[12] = {
0xFF,0x09,0x00,0x08,0x00,0x3A,0x00,0x00,0x00,0x94,0x00,0x00
};
byte SZL_ID_0F3A_IDX_XXXX[12] = {
0xFF,0x09,0x00,0x08,0x0F,0x3A,0x00,0x00,0x00,0x94,0x00,0x08
};
byte SZL_ID_0F9A_IDX_XXXX[12] = {
0xFF,0x09,0x00,0x08,0x0F,0x9A,0x00,0x00,0x01,0x1C,0x00,0x01
};
byte SZL_ID_0D91_IDX_0000[28] = {
0xFF,0x09,0x00,0x18,0x0D,0x91,0x00,0x00,0x00,0x10,0x00,0x01,0x00,0x00,0x02,0x00,0x7F,0xFF,0x00,
0xC0,0x00,0xC0,0x00,0x00,0xB4,0x02,0x00,0x11
};
byte SZL_ID_0092_IDX_0000[28] = {
0xFF,0x09,0x00,0x18,0x00,0x92,0x00,0x00,0x00,0x10,0x00,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
byte SZL_ID_0292_IDX_0000[28] = {
0xFF,0x09,0x00,0x18,0x02,0x92,0x00,0x00,0x00,0x10,0x00,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
byte SZL_ID_0692_IDX_0000[28] = {
0xFF,0x09,0x00,0x18,0x06,0x92,0x00,0x00,0x00,0x10,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
byte SZL_ID_0094_IDX_0000[270] = {
0xFF,0x09,0x01,0x0A,0x00,0x94,0x00,0x00,0x01,0x02,0x00,0x01,0x00,0x00,0x03,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00
};
byte SZL_ID_0D97_IDX_0000[60] = {
0xFF,0x09,0x00,0x38,0x0D,0x97,0x00,0x00,0x00,0x30,0x00,0x01,0x7F,0xFF,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x02,0x00,0x04,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00
};
byte SZL_ID_0111_IDX_0001[40] = {
0xFF,0x09,0x00,0x24,0x01,0x11,0x00,0x01,0x00,0x1C,0x00,0x01,0x00,0x01,0x36,0x45,0x53,0x37,0x20,
0x33,0x31,0x35,0x2D,0x32,0x45,0x48,0x31,0x34,0x2D,0x30,0x41,0x42,0x30,0x20,0x00,0xC0,0x00,0x04,
0x00,0x01
};
byte SZL_ID_0111_IDX_0006[40] = {
0xFF,0x09,0x00,0x24,0x01,0x11,0x00,0x06,0x00,0x1C,0x00,0x01,0x00,0x06,0x36,0x45,0x53,0x37,0x20,
0x33,0x31,0x35,0x2D,0x32,0x45,0x48,0x31,0x34,0x2D,0x30,0x41,0x42,0x30,0x20,0x00,0xC0,0x00,0x04,
0x00,0x01
};
byte SZL_ID_0111_IDX_0007[40] = {
0xFF,0x09,0x00,0x24,0x01,0x11,0x00,0x07,0x00,0x1C,0x00,0x01,0x00,0x07,0x20,0x20,0x20,0x20,0x20,
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0xC0,0x56,0x03,
0x02,0x06
};
byte SZL_ID_0F11_IDX_0001[12] = {
0xFF,0x09,0x00,0x08,0x0F,0x11,0x00,0x00,0x00,0x1C,0x00,0x04
};
byte SZL_ID_0F11_IDX_0006[12] = {
0xFF,0x09,0x00,0x08,0x0F,0x11,0x00,0x00,0x00,0x1C,0x00,0x04
};
byte SZL_ID_0F11_IDX_0007[12] = {
0xFF,0x09,0x00,0x08,0x0F,0x11,0x00,0x00,0x00,0x1C,0x00,0x04
};
byte SZL_ID_0112_IDX_0000[14] = {
0xFF,0x09,0x00,0x0A,0x01,0x12,0x00,0x00,0x00,0x02,0x00,0x01,0x00,0x01
};
byte SZL_ID_0112_IDX_0100[16] = {
0xFF,0x09,0x00,0x0C,0x01,0x12,0x01,0x00,0x00,0x02,0x00,0x02,0x01,0x01,0x01,0x04
};
byte SZL_ID_0112_IDX_0200[12] = {
0xFF,0x09,0x00,0x08,0x01,0x12,0x02,0x00,0x00,0x00,0x00,0x00
};
byte SZL_ID_0112_IDX_0400[12] = {
0xFF,0x09,0x00,0x08,0x01,0x12,0x04,0x00,0x00,0x00,0x00,0x00
};
byte SZL_ID_0F12_IDX_0000[12] = {
0xFF,0x09,0x00,0x08,0x0F,0x12,0x00,0x00,0x00,0x02,0x00,0x17
};
byte SZL_ID_0F12_IDX_0100[12] = {
0xFF,0x09,0x00,0x08,0x0F,0x12,0x00,0x00,0x00,0x02,0x00,0x17
};
byte SZL_ID_0F12_IDX_0200[12] = {
0xFF,0x09,0x00,0x08,0x0F,0x12,0x00,0x00,0x00,0x02,0x00,0x17
};
byte SZL_ID_0F12_IDX_0400[12] = {
0xFF,0x09,0x00,0x08,0x0F,0x12,0x00,0x00,0x00,0x02,0x00,0x17
};
byte SZL_ID_0113_IDX_0001[48] = {
0xFF,0x09,0x00,0x2C,0x01,0x13,0x00,0x01,0x00,0x24,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x06,0x00,
0x00,0x00,0x11,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x26,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
byte SZL_ID_0115_IDX_0800[22] = {
0xFF,0x09,0x00,0x12,0x01,0x15,0x08,0x00,0x00,0x0A,0x00,0x01,0x08,0x00,0x00,0x16,0x03,0xD1,0x00,
0x00,0xFF,0xFE
};
byte SZL_ID_011C_IDX_0001[46] = {
0xFF,0x09,0x00,0x2A,0x01,0x1C,0x00,0x01,0x00,0x22,0x00,0x01,0x00,0x01,0x53,0x4D,0x41,0x52,0x54,
0x37,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
byte SZL_ID_011C_IDX_0002[46] = {
0xFF,0x09,0x00,0x2A,0x01,0x1C,0x00,0x02,0x00,0x22,0x00,0x01,0x00,0x02,0x43,0x50,0x55,0x20,0x33,
0x31,0x35,0x2D,0x32,0x20,0x50,0x4E,0x2F,0x44,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
byte SZL_ID_011C_IDX_0003[46] = {
0xFF,0x09,0x00,0x2A,0x01,0x1C,0x00,0x03,0x00,0x22,0x00,0x01,0x00,0x03,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
byte SZL_ID_011C_IDX_0004[46] = {
0xFF,0x09,0x00,0x2A,0x01,0x1C,0x00,0x04,0x00,0x22,0x00,0x01,0x00,0x04,0x4F,0x72,0x69,0x67,0x69,
0x6E,0x61,0x6C,0x20,0x53,0x69,0x65,0x6D,0x65,0x6E,0x73,0x20,0x45,0x71,0x75,0x69,0x70,0x6D,0x65,
0x6E,0x74,0x00,0x00,0x00,0x00,0x00,0x00
};
byte SZL_ID_011C_IDX_0005[46] = {
0xFF,0x09,0x00,0x2A,0x01,0x1C,0x00,0x05,0x00,0x22,0x00,0x01,0x00,0x05,0x53,0x20,0x43,0x2D,0x43,
0x32,0x55,0x52,0x32,0x38,0x39,0x32,0x32,0x30,0x31,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
byte SZL_ID_011C_IDX_0007[46] = {
0xFF,0x09,0x00,0x2A,0x01,0x1C,0x00,0x07,0x00,0x22,0x00,0x01,0x00,0x07,0x43,0x50,0x55,0x20,0x33,
0x31,0x35,0x2D,0x32,0x20,0x50,0x4E,0x2F,0x44,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
byte SZL_ID_011C_IDX_0008[46] = {
0xFF,0x09,0x00,0x2A,0x01,0x1C,0x00,0x08,0x00,0x22,0x00,0x01,0x00,0x08,0x4D,0x4D,0x43,0x20,0x32,
0x36,0x37,0x46,0x46,0x31,0x31,0x46,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
byte SZL_ID_011C_IDX_0009[46] = {
0xFF,0x09,0x00,0x2A,0x01,0x1C,0x00,0x09,0x00,0x22,0x00,0x01,0x00,0x09,0x00,0x2A,0xF6,0x00,0x00,
0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
byte SZL_ID_011C_IDX_000A[46] = {
0xFF,0x09,0x00,0x2A,0x01,0x1C,0x00,0x0A,0x00,0x22,0x00,0x01,0x00,0x0A,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
byte SZL_ID_011C_IDX_000B[46] = {
0xFF,0x09,0x00,0x2A,0x01,0x1C,0x00,0x0B,0x00,0x22,0x00,0x01,0x00,0x0B,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
byte SZL_ID_0222_IDX_0001[40] = {
0xFF,0x09,0x00,0x24,0x02,0x22,0x00,0x01,0x00,0x1C,0x00,0x01,0x11,0x03,0x01,0x01,0xC8,0x58,0x00,
0x00,0x00,0x00,0x00,0x01,0x94,0x02,0x05,0x02,0x01,0x56,0x64,0x77,0x00,0x10,0x00,0x08,0x00,0x00,
0x00,0x00
};
byte SZL_ID_0222_IDX_000A[40] = {
0xFF,0x09,0x00,0x24,0x02,0x22,0x00,0x0A,0x00,0x1C,0x00,0x01,0x10,0x11,0x02,0x0A,0x00,0x50,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00
};
byte SZL_ID_0222_IDX_0014[40] = {
0xFF,0x09,0x00,0x24,0x02,0x22,0x00,0x14,0x00,0x1C,0x00,0x01,0x10,0x21,0x03,0x14,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00
};
byte SZL_ID_0222_IDX_0028[40] = {
0xFF,0x09,0x00,0x24,0x02,0x22,0x00,0x28,0x00,0x1C,0x00,0x01,0x10,0x41,0x10,0x28,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00
};
byte SZL_ID_0222_IDX_0050[40] = {
0xFF,0x09,0x00,0x24,0x02,0x22,0x00,0x50,0x00,0x1C,0x00,0x01,0x35,0x01,0xFE,0x50,0xC8,0x58,0x00,
0x00,0x00,0x00,0x00,0x96,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,
0x00,0x00
};
byte SZL_ID_0222_IDX_0064[40] = {
0xFF,0x09,0x00,0x24,0x02,0x22,0x00,0x64,0x00,0x1C,0x00,0x01,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43,
0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x76,0x00,0x00,0x00,0x08,0x00,0x00,
0x00,0x00
};
byte SZL_ID_0125_IDX_0000[16] = {
0xFF,0x09,0x00,0x0C,0x01,0x25,0x00,0x00,0x00,0x04,0x00,0x01,0x00,0x03,0x01,0x00
};
byte SZL_ID_0125_IDX_0001[16] = {
0xFF,0x09,0x00,0x0C,0x01,0x25,0x00,0x01,0x00,0x04,0x00,0x01,0x01,0x0C,0x3D,0x00
};
byte SZL_ID_0225_IDX_0001[16] = {
0xFF,0x09,0x00,0x0C,0x02,0x25,0x00,0x01,0x00,0x04,0x00,0x01,0x00,0x03,0x01,0x00
};
byte SZL_ID_0132_IDX_0001[52] = {
0xFF,0x09,0x00,0x30,0x01,0x32,0x00,0x01,0x00,0x28,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,
0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03
};
byte SZL_ID_0132_IDX_0002[52] = {
0xFF,0x09,0x00,0x30,0x01,0x32,0x00,0x02,0x00,0x28,0x00,0x01,0x00,0x02,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x0E,0x00,0x00,0x00,0x00,0x06,0x01,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
byte SZL_ID_0132_IDX_0003[52] = {
0xFF,0x09,0x00,0x30,0x01,0x32,0x00,0x03,0x00,0x28,0x00,0x01,0x00,0x03,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
byte SZL_ID_0132_IDX_0004[52] = {
0xFF,0x09,0x00,0x30,0x01,0x32,0x00,0x04,0x00,0x28,0x00,0x01,0x00,0x04,0x00,0x01,0x00,0x00,0x00,
0x01,0x00,0x02,0x00,0x00,0x00,0x00,0x56,0x56,0x10,0x01,0x33,0x7B,0x02,0x00,0x75,0xF4,0x02,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
byte SZL_ID_0132_IDX_0005[52] = {
0xFF,0x09,0x00,0x30,0x01,0x32,0x00,0x05,0x00,0x28,0x00,0x01,0x00,0x05,0x00,0x00,0x00,0x01,0x00,
0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
byte SZL_ID_0132_IDX_0006[52] = {
0xFF,0x09,0x00,0x30,0x01,0x32,0x00,0x06,0x00,0x28,0x00,0x01,0x00,0x06,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
byte SZL_ID_0132_IDX_0007[52] = {
0xFF,0x09,0x00,0x30,0x01,0x32,0x00,0x07,0x00,0x28,0x00,0x01,0x00,0x07,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
byte SZL_ID_0132_IDX_0008[52] = {
0xFF,0x09,0x00,0x30,0x01,0x32,0x00,0x08,0x00,0x28,0x00,0x01,0x00,0x08,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x05,0x02,
0x01,0x56,0x94,0x57,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
byte SZL_ID_0132_IDX_0009[52] = {
0xFF,0x09,0x00,0x30,0x01,0x32,0x00,0x09,0x00,0x28,0x00,0x01,0x00,0x09,0x00,0x02,0xDC,0x6C,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
byte SZL_ID_0132_IDX_000A[52] = {
0xFF,0x09,0x00,0x30,0x01,0x32,0x00,0x0A,0x00,0x28,0x00,0x01,0x00,0x0A,0x00,0x02,0xDC,0x6C,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
byte SZL_ID_0132_IDX_000B[52] = {
0xFF,0x09,0x00,0x30,0x01,0x32,0x00,0x0B,0x00,0x28,0x00,0x01,0x00,0x0B,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
byte SZL_ID_0132_IDX_000C[52] = {
0xFF,0x09,0x00,0x30,0x01,0x32,0x00,0x0C,0x00,0x28,0x00,0x01,0x00,0x0C,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
byte SZL_ID_0232_IDX_0001[52] = {
0xFF,0x09,0x00,0x30,0x02,0x32,0x00,0x01,0x00,0x28,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,
0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03
};
byte SZL_ID_0232_IDX_0004[52] = {
0xFF,0x09,0x00,0x30,0x02,0x32,0x00,0x04,0x00,0x28,0x00,0x01,0x00,0x04,0x00,0x01,0x00,0x00,0x00,
0x01,0x00,0x02,0x00,0x00,0x00,0x00,0x56,0x56,0x10,0x01,0x33,0x7B,0x02,0x00,0x75,0xF4,0x02,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
byte SZL_ID_0137_IDX_07FE[60] = {
0xFF,0x09,0x00,0x38,0x01,0x37,0x07,0xFE,0x00,0x30,0x00,0x01,0x07,0xFE,0xC0,0xA8,0x01,0x0A,0xFF,
0xFF,0xFF,0x00,0xC0,0xA8,0x01,0x0A,0x00,0x1B,0x1B,0x1D,0x1A,0x2D,0x01,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x8F,0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00
};
byte SZL_ID_0174_IDX_0001[16] = {
0xFF,0x09,0x00,0x0C,0x01,0x74,0x00,0x01,0x00,0x04,0x00,0x01,0x00,0x01,0x00,0x00
};
byte SZL_ID_0174_IDX_0004[16] = {
0xFF,0x09,0x00,0x0C,0x01,0x74,0x00,0x04,0x00,0x04,0x00,0x01,0x00,0x04,0x01,0x00
};
byte SZL_ID_0174_IDX_0005[16] = {
0xFF,0x09,0x00,0x0C,0x01,0x74,0x00,0x05,0x00,0x04,0x00,0x01,0x00,0x05,0x00,0x00
};
byte SZL_ID_0174_IDX_0006[16] = {
0xFF,0x09,0x00,0x0C,0x01,0x74,0x00,0x06,0x00,0x04,0x00,0x01,0x00,0x06,0x00,0x00
};
byte SZL_ID_0174_IDX_000B[16] = {
0xFF,0x09,0x00,0x0C,0x01,0x74,0x00,0x0B,0x00,0x04,0x00,0x01,0x00,0x0B,0x00,0x00
};
byte SZL_ID_0174_IDX_000C[16] = {
0xFF,0x09,0x00,0x0C,0x01,0x74,0x00,0x0C,0x00,0x04,0x00,0x01,0x00,0x0C,0x00,0x00
};
byte SZL_ID_0194_IDX_0064[270] = {
0xFF,0x09,0x01,0x0A,0x01,0x94,0x00,0x64,0x01,0x02,0x00,0x01,0x00,0x64,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00
};
byte SZL_ID_0694_IDX_0064[270] = {
0xFF,0x09,0x01,0x0A,0x06,0x94,0x00,0x64,0x01,0x02,0x00,0x01,0x00,0x64,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00
};
byte SZL_ID_01A0_IDX_0000[12] = {
0xFF,0x09,0x00,0x08,0x01,0xA0,0x00,0x00,0x00,0x14,0x00,0x00
};
byte SZL_ID_01A0_IDX_0001[32] = {
0xFF,0x09,0x00,0x1C,0x01,0xA0,0x00,0x00,0x00,0x14,0x00,0x01,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,
0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x86
};
byte SZL_ID_01A0_IDX_0002[52] = {
0xFF,0x09,0x00,0x30,0x01,0xA0,0x00,0x00,0x00,0x14,0x00,0x02,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,
0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x86,0x13,0x81,0xFE,0x64,0xC7,0x72,
0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x76
};
byte SZL_ID_01A0_IDX_0003[72] = {
0xFF,0x09,0x00,0x44,0x01,0xA0,0x00,0x00,0x00,0x14,0x00,0x03,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,
0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x86,0x13,0x81,0xFE,0x64,0xC7,0x72,
0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x76,0x43,0x01,0xFF,0x46,0xC7,
0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x29,0x66
};
byte SZL_ID_01A0_IDX_0004[92] = {
0xFF,0x09,0x00,0x58,0x01,0xA0,0x00,0x00,0x00,0x14,0x00,0x04,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,
0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x86,0x13,0x81,0xFE,0x64,0xC7,0x72,
0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x76,0x43,0x01,0xFF,0x46,0xC7,
0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x29,0x66,0x43,0x04,0xFF,0x84,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x52,0x13,0x90,0x16
};
byte SZL_ID_01A0_IDX_0005[112] = {
0xFF,0x09,0x00,0x6C,0x01,0xA0,0x00,0x00,0x00,0x14,0x00,0x05,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,
0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x86,0x13,0x81,0xFE,0x64,0xC7,0x72,
0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x76,0x43,0x01,0xFF,0x46,0xC7,
0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x29,0x66,0x43,0x04,0xFF,0x84,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x52,0x13,0x90,0x16,0x43,0x02,0xFF,
0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x56
};
byte SZL_ID_01A0_IDX_0006[132] = {
0xFF,0x09,0x00,0x80,0x01,0xA0,0x00,0x00,0x00,0x14,0x00,0x06,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,
0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x86,0x13,0x81,0xFE,0x64,0xC7,0x72,
0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x76,0x43,0x01,0xFF,0x46,0xC7,
0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x29,0x66,0x43,0x04,0xFF,0x84,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x52,0x13,0x90,0x16,0x43,0x02,0xFF,
0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x56,0x13,0x81,
0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x46
};
byte SZL_ID_01A0_IDX_0007[152] = {
0xFF,0x09,0x00,0x94,0x01,0xA0,0x00,0x00,0x00,0x14,0x00,0x07,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,
0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x86,0x13,0x81,0xFE,0x64,0xC7,0x72,
0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x76,0x43,0x01,0xFF,0x46,0xC7,
0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x29,0x66,0x43,0x04,0xFF,0x84,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x52,0x13,0x90,0x16,0x43,0x02,0xFF,
0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x56,0x13,0x81,
0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x46,0x43,
0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x79,0x46
};
byte SZL_ID_01A0_IDX_0008[172] = {
0xFF,0x09,0x00,0xA8,0x01,0xA0,0x00,0x00,0x00,0x14,0x00,0x08,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,
0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x86,0x13,0x81,0xFE,0x64,0xC7,0x72,
0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x76,0x43,0x01,0xFF,0x46,0xC7,
0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x29,0x66,0x43,0x04,0xFF,0x84,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x52,0x13,0x90,0x16,0x43,0x02,0xFF,
0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x56,0x13,0x81,
0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x46,0x43,
0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x79,0x46,
0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x51,0x19,0x48,
0x26
};
byte SZL_ID_01A0_IDX_0009[192] = {
0xFF,0x09,0x00,0xBC,0x01,0xA0,0x00,0x00,0x00,0x14,0x00,0x09,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,
0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x86,0x13,0x81,0xFE,0x64,0xC7,0x72,
0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x76,0x43,0x01,0xFF,0x46,0xC7,
0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x29,0x66,0x43,0x04,0xFF,0x84,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x52,0x13,0x90,0x16,0x43,0x02,0xFF,
0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x56,0x13,0x81,
0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x46,0x43,
0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x79,0x46,
0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x51,0x19,0x48,
0x26,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50,0x45,
0x09,0x96
};
byte SZL_ID_01A0_IDX_000A[212] = {
0xFF,0x09,0x00,0xD0,0x01,0xA0,0x00,0x00,0x00,0x14,0x00,0x0A,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,
0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x86,0x13,0x81,0xFE,0x64,0xC7,0x72,
0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x76,0x43,0x01,0xFF,0x46,0xC7,
0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x29,0x66,0x43,0x04,0xFF,0x84,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x52,0x13,0x90,0x16,0x43,0x02,0xFF,
0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x56,0x13,0x81,
0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x46,0x43,
0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x79,0x46,
0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x51,0x19,0x48,
0x26,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50,0x45,
0x09,0x96,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50,
0x45,0x09,0x86
};
byte SZL_ID_01A0_IDX_000B[232] = {
0xFF,0x09,0x00,0xE4,0x01,0xA0,0x00,0x00,0x00,0x14,0x00,0x0B,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,
0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x86,0x13,0x81,0xFE,0x64,0xC7,0x72,
0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x76,0x43,0x01,0xFF,0x46,0xC7,
0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x29,0x66,0x43,0x04,0xFF,0x84,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x52,0x13,0x90,0x16,0x43,0x02,0xFF,
0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x56,0x13,0x81,
0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x46,0x43,
0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x79,0x46,
0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x51,0x19,0x48,
0x26,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50,0x45,
0x09,0x96,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50,
0x45,0x09,0x86,0x43,0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,
0x50,0x45,0x00,0x96
};
byte SZL_ID_01A0_IDX_000C[252] = {
0xFF,0x09,0x00,0xF8,0x01,0xA0,0x00,0x00,0x00,0x14,0x00,0x0C,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,
0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x86,0x13,0x81,0xFE,0x64,0xC7,0x72,
0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x76,0x43,0x01,0xFF,0x46,0xC7,
0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x29,0x66,0x43,0x04,0xFF,0x84,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x52,0x13,0x90,0x16,0x43,0x02,0xFF,
0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x56,0x13,0x81,
0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x46,0x43,
0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x79,0x46,
0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x51,0x19,0x48,
0x26,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50,0x45,
0x09,0x96,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50,
0x45,0x09,0x86,0x43,0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,
0x50,0x45,0x00,0x96,0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,
0x23,0x50,0x42,0x54,0x66
};
byte SZL_ID_01A0_IDX_000D[272] = {
0xFF,0x09,0x01,0x0C,0x01,0xA0,0x00,0x00,0x00,0x14,0x00,0x0D,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,
0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x86,0x13,0x81,0xFE,0x64,0xC7,0x72,
0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x76,0x43,0x01,0xFF,0x46,0xC7,
0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x29,0x66,0x43,0x04,0xFF,0x84,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x52,0x13,0x90,0x16,0x43,0x02,0xFF,
0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x56,0x13,0x81,
0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x46,0x43,
0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x79,0x46,
0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x51,0x19,0x48,
0x26,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50,0x45,
0x09,0x96,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50,
0x45,0x09,0x86,0x43,0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,
0x50,0x45,0x00,0x96,0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,
0x23,0x50,0x42,0x54,0x66,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,
0x04,0x23,0x50,0x32,0x40,0x46
};
byte SZL_ID_01A0_IDX_000E[292] = {
0xFF,0x09,0x01,0x20,0x01,0xA0,0x00,0x00,0x00,0x14,0x00,0x0E,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,
0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x86,0x13,0x81,0xFE,0x64,0xC7,0x72,
0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x76,0x43,0x01,0xFF,0x46,0xC7,
0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x29,0x66,0x43,0x04,0xFF,0x84,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x52,0x13,0x90,0x16,0x43,0x02,0xFF,
0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x56,0x13,0x81,
0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x46,0x43,
0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x79,0x46,
0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x51,0x19,0x48,
0x26,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50,0x45,
0x09,0x96,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50,
0x45,0x09,0x86,0x43,0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,
0x50,0x45,0x00,0x96,0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,
0x23,0x50,0x42,0x54,0x66,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,
0x04,0x23,0x50,0x32,0x40,0x46,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,
0x02,0x04,0x23,0x50,0x32,0x40,0x36
};
byte SZL_ID_01A0_IDX_000F[312] = {
0xFF,0x09,0x01,0x34,0x01,0xA0,0x00,0x00,0x00,0x14,0x00,0x0F,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,
0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x86,0x13,0x81,0xFE,0x64,0xC7,0x72,
0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x76,0x43,0x01,0xFF,0x46,0xC7,
0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x29,0x66,0x43,0x04,0xFF,0x84,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x52,0x13,0x90,0x16,0x43,0x02,0xFF,
0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x56,0x13,0x81,
0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x46,0x43,
0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x79,0x46,
0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x51,0x19,0x48,
0x26,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50,0x45,
0x09,0x96,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50,
0x45,0x09,0x86,0x43,0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,
0x50,0x45,0x00,0x96,0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,
0x23,0x50,0x42,0x54,0x66,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,
0x04,0x23,0x50,0x32,0x40,0x46,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,
0x02,0x04,0x23,0x50,0x32,0x40,0x36,0x43,0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,
0x94,0x02,0x04,0x23,0x50,0x32,0x31,0x46
};
byte SZL_ID_01A0_IDX_0010[332] = {
0xFF,0x09,0x01,0x48,0x01,0xA0,0x00,0x00,0x00,0x14,0x00,0x10,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,
0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x86,0x13,0x81,0xFE,0x64,0xC7,0x72,
0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x76,0x43,0x01,0xFF,0x46,0xC7,
0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x29,0x66,0x43,0x04,0xFF,0x84,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x52,0x13,0x90,0x16,0x43,0x02,0xFF,
0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x56,0x13,0x81,
0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x46,0x43,
0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x79,0x46,
0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x51,0x19,0x48,
0x26,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50,0x45,
0x09,0x96,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50,
0x45,0x09,0x86,0x43,0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,
0x50,0x45,0x00,0x96,0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,
0x23,0x50,0x42,0x54,0x66,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,
0x04,0x23,0x50,0x32,0x40,0x46,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,
0x02,0x04,0x23,0x50,0x32,0x40,0x36,0x43,0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,
0x94,0x02,0x04,0x23,0x50,0x32,0x31,0x46,0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x94,0x02,0x04,0x23,0x50,0x29,0x92,0x26
};
byte SZL_ID_01A0_IDX_0011[352] = {
0xFF,0x09,0x01,0x5C,0x01,0xA0,0x00,0x00,0x00,0x14,0x00,0x11,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,
0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x86,0x13,0x81,0xFE,0x64,0xC7,0x72,
0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x76,0x43,0x01,0xFF,0x46,0xC7,
0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x29,0x66,0x43,0x04,0xFF,0x84,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x52,0x13,0x90,0x16,0x43,0x02,0xFF,
0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x56,0x13,0x81,
0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x46,0x43,
0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x79,0x46,
0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x51,0x19,0x48,
0x26,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50,0x45,
0x09,0x96,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50,
0x45,0x09,0x86,0x43,0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,
0x50,0x45,0x00,0x96,0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,
0x23,0x50,0x42,0x54,0x66,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,
0x04,0x23,0x50,0x32,0x40,0x46,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,
0x02,0x04,0x23,0x50,0x32,0x40,0x36,0x43,0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,
0x94,0x02,0x04,0x23,0x50,0x32,0x31,0x46,0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x94,0x02,0x04,0x23,0x50,0x29,0x92,0x26,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14,
0x77,0x14,0x94,0x02,0x04,0x23,0x49,0x22,0x26,0x66
};
byte SZL_ID_01A0_IDX_0012[372] = {
0xFF,0x09,0x01,0x70,0x01,0xA0,0x00,0x00,0x00,0x14,0x00,0x12,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,
0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x86,0x13,0x81,0xFE,0x64,0xC7,0x72,
0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x76,0x43,0x01,0xFF,0x46,0xC7,
0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x29,0x66,0x43,0x04,0xFF,0x84,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x52,0x13,0x90,0x16,0x43,0x02,0xFF,
0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x56,0x13,0x81,
0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x46,0x43,
0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x79,0x46,
0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x51,0x19,0x48,
0x26,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50,0x45,
0x09,0x96,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50,
0x45,0x09,0x86,0x43,0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,
0x50,0x45,0x00,0x96,0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,
0x23,0x50,0x42,0x54,0x66,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,
0x04,0x23,0x50,0x32,0x40,0x46,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,
0x02,0x04,0x23,0x50,0x32,0x40,0x36,0x43,0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,
0x94,0x02,0x04,0x23,0x50,0x32,0x31,0x46,0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x94,0x02,0x04,0x23,0x50,0x29,0x92,0x26,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14,
0x77,0x14,0x94,0x02,0x04,0x23,0x49,0x22,0x26,0x66,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,
0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x49,0x22,0x26,0x56
};
byte SZL_ID_01A0_IDX_0013[392] = {
0xFF,0x09,0x01,0x84,0x01,0xA0,0x00,0x00,0x00,0x14,0x00,0x13,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,
0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x86,0x13,0x81,0xFE,0x64,0xC7,0x72,
0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x76,0x43,0x01,0xFF,0x46,0xC7,
0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x29,0x66,0x43,0x04,0xFF,0x84,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x52,0x13,0x90,0x16,0x43,0x02,0xFF,
0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x56,0x13,0x81,
0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x46,0x43,
0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x79,0x46,
0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x51,0x19,0x48,
0x26,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50,0x45,
0x09,0x96,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50,
0x45,0x09,0x86,0x43,0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,
0x50,0x45,0x00,0x96,0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,
0x23,0x50,0x42,0x54,0x66,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,
0x04,0x23,0x50,0x32,0x40,0x46,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,
0x02,0x04,0x23,0x50,0x32,0x40,0x36,0x43,0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,
0x94,0x02,0x04,0x23,0x50,0x32,0x31,0x46,0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x94,0x02,0x04,0x23,0x50,0x29,0x92,0x26,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14,
0x77,0x14,0x94,0x02,0x04,0x23,0x49,0x22,0x26,0x66,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,
0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x49,0x22,0x26,0x56,0x43,0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,
0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x49,0x22,0x17,0x66
};
byte SZL_ID_01A0_IDX_0014[412] = {
0xFF,0x09,0x01,0x98,0x01,0xA0,0x00,0x00,0x00,0x14,0x00,0x14,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,
0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x86,0x13,0x81,0xFE,0x64,0xC7,0x72,
0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x76,0x43,0x01,0xFF,0x46,0xC7,
0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x29,0x66,0x43,0x04,0xFF,0x84,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x52,0x13,0x90,0x16,0x43,0x02,0xFF,
0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x56,0x13,0x81,
0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x46,0x43,
0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x79,0x46,
0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x51,0x19,0x48,
0x26,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50,0x45,
0x09,0x96,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50,
0x45,0x09,0x86,0x43,0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,
0x50,0x45,0x00,0x96,0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,
0x23,0x50,0x42,0x54,0x66,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,
0x04,0x23,0x50,0x32,0x40,0x46,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,
0x02,0x04,0x23,0x50,0x32,0x40,0x36,0x43,0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,
0x94,0x02,0x04,0x23,0x50,0x32,0x31,0x46,0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x94,0x02,0x04,0x23,0x50,0x29,0x92,0x26,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14,
0x77,0x14,0x94,0x02,0x04,0x23,0x49,0x22,0x26,0x66,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,
0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x49,0x22,0x26,0x56,0x43,0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,
0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x49,0x22,0x17,0x66,0x43,0x04,0xFF,0x84,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x49,0x19,0x75,0x46
};
byte SZL_ID_01A0_IDX_0015[432] = {
0xFF,0x09,0x01,0xAC,0x01,0xA0,0x00,0x00,0x00,0x14,0x00,0x15,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,
0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x86,0x13,0x81,0xFE,0x64,0xC7,0x72,
0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x38,0x76,0x43,0x01,0xFF,0x46,0xC7,
0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x52,0x16,0x29,0x66,0x43,0x04,0xFF,0x84,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x52,0x13,0x90,0x16,0x43,0x02,0xFF,
0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x56,0x13,0x81,
0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x88,0x46,0x43,
0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x51,0x21,0x79,0x46,
0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x51,0x19,0x48,
0x26,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50,0x45,
0x09,0x96,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x50,
0x45,0x09,0x86,0x43,0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,
0x50,0x45,0x00,0x96,0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,
0x23,0x50,0x42,0x54,0x66,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,
0x04,0x23,0x50,0x32,0x40,0x46,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,0x94,
0x02,0x04,0x23,0x50,0x32,0x40,0x36,0x43,0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,0x08,0x14,0x77,0x14,
0x94,0x02,0x04,0x23,0x50,0x32,0x31,0x46,0x43,0x04,0xFF,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x94,0x02,0x04,0x23,0x50,0x29,0x92,0x26,0x43,0x02,0xFF,0x68,0xC7,0x00,0x00,0x00,0x08,0x14,
0x77,0x14,0x94,0x02,0x04,0x23,0x49,0x22,0x26,0x66,0x13,0x81,0xFE,0x64,0xC7,0x72,0x43,0x04,0x08,
0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x49,0x22,0x26,0x56,0x43,0x01,0xFF,0x46,0xC7,0x72,0x43,0x04,
0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x49,0x22,0x17,0x66,0x43,0x04,0xFF,0x84,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x94,0x02,0x04,0x23,0x49,0x19,0x75,0x46,0x43,0x02,0xFF,0x68,0xC7,0x00,
0x00,0x00,0x08,0x14,0x77,0x14,0x94,0x02,0x04,0x23,0x48,0x32,0x21,0x16
};
byte SZL_ID_0117_IDX_0000[16] = {
0xFF,0x09,0x00,0x0C,0x01,0x17,0x00,0x00,0x00,0x04,0x00,0x01,0x00,0x00,0x00,0x01
};
byte SZL_ID_0117_IDX_0001[16] = {
0xFF,0x09,0x00,0x0C,0x01,0x17,0x00,0x01,0x00,0x04,0x00,0x01,0x00,0x01,0x00,0x03
};
byte SZL_ID_0117_IDX_0002[16] = {
0xFF,0x09,0x00,0x0C,0x01,0x17,0x00,0x02,0x00,0x04,0x00,0x01,0x00,0x02,0x00,0x02
};
byte SZL_ID_0117_IDX_0003[16] = {
0xFF,0x09,0x00,0x0C,0x01,0x17,0x00,0x03,0x00,0x04,0x00,0x01,0x00,0x03,0x00,0x01
};
byte SZL_ID_0117_IDX_0004[16] = {
0xFF,0x09,0x00,0x0C,0x01,0x17,0x00,0x04,0x00,0x04,0x00,0x01,0x00,0x04,0x00,0x01
};
byte SZL_ID_0118_IDX_0000[16] = {
0xFF,0x09,0x00,0x0C,0x01,0x18,0x00,0x00,0x00,0x04,0x00,0x01,0x00,0x00,0x00,0x08
};
byte SZL_ID_0118_IDX_0001[16] = {
0xFF,0x09,0x00,0x0C,0x01,0x18,0x00,0x01,0x00,0x04,0x00,0x01,0x00,0x01,0x00,0x08
};
byte SZL_ID_0118_IDX_0002[16] = {
0xFF,0x09,0x00,0x0C,0x01,0x18,0x00,0x02,0x00,0x04,0x00,0x01,0x00,0x02,0x00,0x08
};
byte SZL_ID_0118_IDX_0003[16] = {
0xFF,0x09,0x00,0x0C,0x01,0x18,0x00,0x03,0x00,0x04,0x00,0x01,0x00,0x03,0x00,0x08
};
byte SZL_ID_0131_IDX_0001[52] = {
0xFF,0x09,0x00,0x30,0x01,0x31,0x00,0x01,0x00,0x28,0x00,0x01,0x00,0x01,
0x08,0x00, // PDU SIZE : We expose 2048 00F0
0x04,0x00, // Max Commections : We expose 1024 0010
0x00,0xB7,0x1B,0x00,0x00,0x02,0xDC,0x6C,0x05,0xF5,0xE1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
byte SZL_ID_0131_IDX_0002[52] = {
0xFF,0x09,0x00,0x30,0x01,0x31,0x00,0x02,0x00,0x28,0x00,0x01,0x00,0x02,0xBE,0xFD,0x4F,0x00,0x00,
0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x3C,0x01,0x08,0x00,0x00,0x00,0x7D,0x00,0x00,0x05,0x03,0x0F,
0x00,0x00,0x08,0x00,0x00,0x0C,0x00,0x0A,0x00,0x00,0x00,0x01,0x00,0x00
};
byte SZL_ID_0131_IDX_0003[52] = {
0xFF,0x09,0x00,0x30,0x01,0x31,0x00,0x03,0x00,0x28,0x00,0x01,0x00,0x03,0x7F,0xFC,0x83,0x01,
0x00,0xF0, // Max size of consistently readable data (will be set = PDU size)
0x00,0x10,0x00,0x01,0x02,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
byte SZL_ID_0131_IDX_0004[52] = {
0xFF,0x09,0x00,0x30,0x01,0x31,0x00,0x04,0x00,0x28,0x00,0x01,0x00,0x04,0xFE,0x01,0x62,0x41,0x63,
0x00,0x1E,0x00,0x10,0x10,0x10,0x04,0x02,0x00,0x00,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
byte SZL_ID_0131_IDX_0005[52] = {
0xFF,0x09,0x00,0x30,0x01,0x31,0x00,0x05,0x00,0x28,0x00,0x01,0x00,0x05,0x3E,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x10,0x01,0xF4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
byte SZL_ID_0131_IDX_0006[52] = {
0xFF,0x09,0x00,0x30,0x01,0x31,0x00,0x06,0x00,0x28,0x00,0x01,0x00,0x06,0xF3,0x00,0x00,0xF8,0x01,
0xF0,0xFF,0x4E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x20,
0x01,0x00,0x00,0x0E,0x00,0x4C,0xFF,0xFF,0x05,0xC0,0x00,0x00,0x00,0x00
};
byte SZL_ID_0131_IDX_0007[52] = {
0xFF,0x09,0x00,0x30,0x01,0x31,0x00,0x07,0x00,0x28,0x00,0x01,0x00,0x07,0x01,0x00,0x3F,0x00,0x20,
0x01,0x01,0x00,0x00,0x00,0x01,0x08,0x01,0x08,0x01,0x08,0x20,0x08,0x02,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
byte SZL_ID_0131_IDX_0008[52] = {
0xFF,0x09,0x00,0x30,0x01,0x31,0x00,0x08,0x00,0x28,0x00,0x01,0x00,0x08,0x70,0x03,0x70,0x02,0x70,
0x02,0x40,0x32,0x40,0x32,0x40,0x32,0x40,0x64,0x40,0x32,0x40,0x32,0x40,0x64,0x40,0x64,0x40,0x64,
0x40,0x64,0x40,0x64,0x40,0x64,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
byte SZL_ID_0131_IDX_0009[52] = {
0xFF,0x09,0x00,0x30,0x01,0x31,0x00,0x09,0x00,0x28,0x00,0x01,0x00,0x09,0x04,0x06,0x01,0x00,0x01,
0xF7,0x01,0xF7,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
byte SZL_ID_0C91_IDX_07FE[28] = {
0xFF,0x09,0x00,0x18,0x0C,0x91,0x07,0xFE,0x00,0x10,0x00,0x01,0x00,0x00,0x02,0x02,0x07,0xFE,0xA7,
0xC4,0xA7,0xC4,0x00,0x00,0xB4,0x02,0x00,0x11
};
#endif
================================================
FILE: deps/snap7/src/core/s7_isotcp.cpp
================================================
/*=============================================================================|
| 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->HLengthPDUType!=PduTypeExpected)) // Checks PDU Type
return SetIsoError(errIsoInvalidPDU);
else
return noError;
}
else
return SetIsoError(errIsoNullPointer);
}
//---------------------------------------------------------------------------
int TIsoTcpSocket::SetIsoError(int Error)
{
LastIsoError = Error | LastTcpError;
return LastIsoError;
}
//---------------------------------------------------------------------------
void TIsoTcpSocket::ClrIsoError()
{
LastIsoError=0;
LastTcpError=0;
}
//---------------------------------------------------------------------------
int TIsoTcpSocket::BuildControlPDU()
{
int ParLen, IsoLen;
ClrIsoError();
FControlPDU.COTP.Params.PduSizeCode=0xC0; // code that identifies TPDU size
FControlPDU.COTP.Params.PduSizeLen =0x01; // 1 byte this field
switch(IsoPDUSize)
{
case 128:
FControlPDU.COTP.Params.PduSizeVal =0x07;
break;
case 256:
FControlPDU.COTP.Params.PduSizeVal =0x08;
break;
case 512:
FControlPDU.COTP.Params.PduSizeVal =0x09;
break;
case 1024:
FControlPDU.COTP.Params.PduSizeVal =0x0A;
break;
case 2048:
FControlPDU.COTP.Params.PduSizeVal =0x0B;
break;
case 4096:
FControlPDU.COTP.Params.PduSizeVal =0x0C;
break;
case 8192:
FControlPDU.COTP.Params.PduSizeVal =0x0D;
break;
default:
FControlPDU.COTP.Params.PduSizeVal =0x0B; // Our Default
};
// Build TSAPs
FControlPDU.COTP.Params.TSAP[0]=0xC1; // code that identifies source TSAP
FControlPDU.COTP.Params.TSAP[1]=2; // source TSAP Len
FControlPDU.COTP.Params.TSAP[2]=(SrcTSap>>8) & 0xFF; // HI part
FControlPDU.COTP.Params.TSAP[3]=SrcTSap & 0xFF; // LO part
FControlPDU.COTP.Params.TSAP[4]=0xC2; // code that identifies dest TSAP
FControlPDU.COTP.Params.TSAP[5]=2; // dest TSAP Len
FControlPDU.COTP.Params.TSAP[6]=(DstTSap>>8) & 0xFF; // HI part
FControlPDU.COTP.Params.TSAP[7]=DstTSap & 0xFF; // LO part
// Params length
ParLen=11; // 2 Src TSAP (Code+field Len) +
// 2 Src TSAP len +
// 2 Dst TSAP (Code+field Len) +
// 2 Src TSAP len +
// 3 PDU size (Code+field Len+Val) = 11
// Telegram length
IsoLen=sizeof(TTPKT)+ // TPKT Header
7 + // COTP Header Size without params
ParLen; // COTP params
FControlPDU.TPKT.Version =isoTcpVersion;
FControlPDU.TPKT.Reserved =0;
FControlPDU.TPKT.HI_Lenght=0; // Connection Telegram size cannot exced 255 bytes, so
// this field is always 0
FControlPDU.TPKT.LO_Lenght=IsoLen;
FControlPDU.COTP.HLength =ParLen + 6; // <-- 6 = 7 - 1 (COTP Header size - 1)
FControlPDU.COTP.PDUType =pdu_type_CR; // Connection Request
FControlPDU.COTP.DstRef =DstRef; // Destination reference
FControlPDU.COTP.SrcRef =SrcRef; // Source reference
FControlPDU.COTP.CO_R =0x00; // Class + Option : RFC0983 states that it must be always 0x40
// but for some equipment (S7) must be 0 in disaccord of specifications !!!
return noError;
}
//---------------------------------------------------------------------------
int TIsoTcpSocket::PDUSize(void *pPDU)
{
return PIsoHeaderInfo(pPDU)->TPKT.HI_Lenght*256+PIsoHeaderInfo( pPDU )->TPKT.LO_Lenght;
}
//---------------------------------------------------------------------------
void TIsoTcpSocket::IsoParsePDU(TIsoControlPDU pdu)
{
// Currently we accept a connection with any kind of src/dst tsap
// Override to implement special filters.
}
//---------------------------------------------------------------------------
int TIsoTcpSocket::IsoConfirmConnection(u_char PDUType)
{
PIsoControlPDU CPDU = PIsoControlPDU(&PDU);
u_short TempRef;
ClrIsoError();
PDU.COTP.PDUType=PDUType;
// Exchange SrcRef<->DstRef, not strictly needed by COTP 8073 but S7PLC as client needs it.
TempRef=CPDU->COTP.DstRef;
CPDU->COTP.DstRef=CPDU->COTP.SrcRef;
CPDU->COTP.SrcRef=0x0100;//TempRef;
return SendPacket(&PDU,PDUSize(&PDU));
}
//---------------------------------------------------------------------------
void TIsoTcpSocket::FragmentSkipped(int Size)
{
// override for log purpose
}
//---------------------------------------------------------------------------
int TIsoTcpSocket::isoConnect()
{
pbyte TmpControlPDU;
PIsoControlPDU ControlPDU;
u_int Length;
int Result;
// Build the default connection telegram
BuildControlPDU();
ControlPDU =&FControlPDU;
// Checks the format
Result =CheckPDU(ControlPDU, pdu_type_CR);
if (Result!=0)
return Result;
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 (IsoLenDataHeaderSize : check the PDUType
switch (Info->PDUType)
{
case pdu_type_CR:
PduKind=pkConnectionRequest;
break;
case pdu_type_DR:
PduKind=pkDisconnectRequest;
break;
case pdu_type_DT:
PduKind=pkValidData;
break;
default:
PduKind=pkUnrecognizedType;
};
}
================================================
FILE: deps/snap7/src/core/s7_isotcp.h
================================================
/*=============================================================================|
| PROJECT SNAP7 1.3.0 |
|==============================================================================|
| Copyright (C) 2013, 2015 Davide Nardella |
| All rights reserved. |
|==============================================================================|
| SNAP7 is free software: you can redistribute it and/or modify |
| it under the terms of the Lesser GNU General Public License as published by |
| the Free Software Foundation, either version 3 of the License, or |
| (at your option) any later version. |
| |
| It means that you can distribute your commercial software linked with |
| SNAP7 without the requirement to distribute the source code of your |
| application and without the requirement that your application be itself |
| distributed under LGPL. |
| |
| SNAP7 is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| Lesser GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License and a |
| copy of Lesser GNU General Public License along with Snap7. |
| If not, see http://www.gnu.org/licenses/ |
|=============================================================================*/
#ifndef s7_isotcp_h
#define s7_isotcp_h
//---------------------------------------------------------------------------
#include "snap_msgsock.h"
//---------------------------------------------------------------------------
#pragma pack(1)
#define isoTcpVersion 3 // RFC 1006
#define isoTcpPort 102 // RFC 1006
#define isoInvalidHandle 0
#define MaxTSAPLength 16 // Max Lenght for Src and Dst TSAP
#define MaxIsoFragments 64 // Max fragments
#define IsoPayload_Size 4096 // Iso telegram Buffer size
#define noError 0
const longword errIsoMask = 0x000F0000;
const longword errIsoBase = 0x0000FFFF;
const longword errIsoConnect = 0x00010000; // Connection error
const longword errIsoDisconnect = 0x00020000; // Disconnect error
const longword errIsoInvalidPDU = 0x00030000; // Bad format
const longword errIsoInvalidDataSize = 0x00040000; // Bad Datasize passed to send/recv : buffer is invalid
const longword errIsoNullPointer = 0x00050000; // Null passed as pointer
const longword errIsoShortPacket = 0x00060000; // A short packet received
const longword errIsoTooManyFragments = 0x00070000; // Too many packets without EoT flag
const longword errIsoPduOverflow = 0x00080000; // The sum of fragments data exceded maximum packet size
const longword errIsoSendPacket = 0x00090000; // An error occurred during send
const longword errIsoRecvPacket = 0x000A0000; // An error occurred during recv
const longword errIsoInvalidParams = 0x000B0000; // Invalid TSAP params
const longword errIsoResvd_1 = 0x000C0000; // Unassigned
const longword errIsoResvd_2 = 0x000D0000; // Unassigned
const longword errIsoResvd_3 = 0x000E0000; // Unassigned
const longword errIsoResvd_4 = 0x000F0000; // Unassigned
const longword ISO_OPT_TCP_NODELAY = 0x00000001; // Disable Nagle algorithm
const longword ISO_OPT_INSIDE_MTU = 0x00000002; // Max packet size < MTU ethernet card
// TPKT Header - ISO on TCP - RFC 1006 (4 bytes)
typedef struct{
u_char Version; // Always 3 for RFC 1006
u_char Reserved; // 0
u_char HI_Lenght; // High part of packet lenght (entire frame, payload and TPDU included)
u_char LO_Lenght; // Low part of packet lenght (entire frame, payload and TPDU included)
} TTPKT; // Packet length : min 7 max 65535
typedef struct {
u_char PduSizeCode;
u_char PduSizeLen;
u_char PduSizeVal;
u_char TSAP[245]; // We don't know in advance these fields....
} TCOPT_Params ;
// PDU Type constants - ISO 8073, not all are mentioned in RFC 1006
// For our purposes we use only those labeled with **
// These constants contains 4 low bit order 0 (credit nibble)
//
// $10 ED : Expedited Data
// $20 EA : Expedited Data Ack
// $40 UD : CLTP UD
// $50 RJ : Reject
// $70 AK : Ack data
// ** $80 DR : Disconnect request (note : S7 doesn't use it)
// ** $C0 DC : Disconnect confirm (note : S7 doesn't use it)
// ** $D0 CC : Connection confirm
// ** $E0 CR : Connection request
// ** $F0 DT : Data
//
// COTP Header for CONNECTION REQUEST/CONFIRM - DISCONNECT REQUEST/CONFIRM
typedef struct {
u_char HLength; // Header length : initialized to 6 (length without params - 1)
// descending classes that add values in params field must update it.
u_char PDUType; // 0xE0 Connection request
// 0xD0 Connection confirm
// 0x80 Disconnect request
// 0xDC Disconnect confirm
u_short DstRef; // Destination reference : Always 0x0000
u_short SrcRef; // Source reference : Always 0x0000
u_char CO_R; // If the telegram is used for Connection request/Confirm,
// the meaning of this field is CLASS+OPTION :
// Class (High 4 bits) + Option (Low 4 bits)
// Class : Always 4 (0100) but is ignored in input (RFC States this)
// Option : Always 0, also this in ignored.
// If the telegram is used for Disconnect request,
// the meaning of this field is REASON :
// 1 Congestion at TSAP
// 2 Session entity not attached to TSAP
// 3 Address unknown (at TCP connect time)
// 128+0 Normal disconnect initiated by the session
// entity.
// 128+1 Remote transport entity congestion at connect
// request time
// 128+3 Connection negotiation failed
// 128+5 Protocol Error
// 128+8 Connection request refused on this network
// connection
// Parameter data : depending on the protocol implementation.
// ISO 8073 define several type of parameters, but RFC 1006 recognizes only
// TSAP related parameters and PDU size. See RFC 0983 for more details.
TCOPT_Params Params;
/* Other params not used here, list only for completeness
ACK_TIME = 0x85, 1000 0101 Acknowledge Time
RES_ERROR = 0x86, 1000 0110 Residual Error Rate
PRIORITY = 0x87, 1000 0111 Priority
TRANSIT_DEL = 0x88, 1000 1000 Transit Delay
THROUGHPUT = 0x89, 1000 1001 Throughput
SEQ_NR = 0x8A, 1000 1010 Subsequence Number (in AK)
REASSIGNMENT = 0x8B, 1000 1011 Reassignment Time
FLOW_CNTL = 0x8C, 1000 1100 Flow Control Confirmation (in AK)
TPDU_SIZE = 0xC0, 1100 0000 TPDU Size
SRC_TSAP = 0xC1, 1100 0001 TSAP-ID / calling TSAP ( in CR/CC )
DST_TSAP = 0xC2, 1100 0010 TSAP-ID / called TSAP
CHECKSUM = 0xC3, 1100 0011 Checksum
VERSION_NR = 0xC4, 1100 0100 Version Number
PROTECTION = 0xC5, 1100 0101 Protection Parameters (user defined)
OPT_SEL = 0xC6, 1100 0110 Additional Option Selection
PROTO_CLASS = 0xC7, 1100 0111 Alternative Protocol Classes
PREF_MAX_TPDU_SIZE = 0xF0, 1111 0000
INACTIVITY_TIMER = 0xF2, 1111 0010
ADDICC = 0xe0 1110 0000 Additional Information on Connection Clearing
*/
} TCOTP_CO ;
typedef TCOTP_CO *PCOTP_CO;
// COTP Header for DATA EXCHANGE
typedef struct {
u_char HLength; // Header length : 3 for this header
u_char PDUType; // 0xF0 for this header
u_char EoT_Num; // EOT (bit 7) + PDU Number (bits 0..6)
// EOT = 1 -> End of Trasmission Packet (This packet is complete)
// PDU Number : Always 0
} TCOTP_DT;
typedef TCOTP_DT *PCOTP_DT;
// Info part of a PDU, only common parts. We use it to check the consistence
// of a telegram regardless of it's nature (control or data).
typedef struct {
TTPKT TPKT; // TPKT Header
// Common part of any COTP
u_char HLength; // Header length : 3 for this header
u_char PDUType; // Pdu type
} TIsoHeaderInfo ;
typedef TIsoHeaderInfo *PIsoHeaderInfo;
// PDU Type consts (Code + Credit)
const byte pdu_type_CR = 0xE0; // Connection request
const byte pdu_type_CC = 0xD0; // Connection confirm
const byte pdu_type_DR = 0x80; // Disconnect request
const byte pdu_type_DC = 0xC0; // Disconnect confirm
const byte pdu_type_DT = 0xF0; // Data transfer
const byte pdu_EoT = 0x80; // End of Trasmission Packet (This packet is complete)
const longword DataHeaderSize = sizeof(TTPKT)+sizeof(TCOTP_DT);
const longword IsoFrameSize = IsoPayload_Size+DataHeaderSize;
typedef struct {
TTPKT TPKT; // TPKT Header
TCOTP_CO COTP; // COPT Header for CONNECTION stuffs
} TIsoControlPDU;
typedef TIsoControlPDU *PIsoControlPDU;
typedef u_char TIsoPayload[IsoPayload_Size];
typedef struct {
TTPKT TPKT; // TPKT Header
TCOTP_DT COTP; // COPT Header for DATA EXCHANGE
TIsoPayload Payload; // Payload
} TIsoDataPDU ;
typedef TIsoDataPDU *PIsoDataPDU;
typedef TIsoPayload *PIsoPayload;
typedef enum {
pkConnectionRequest,
pkDisconnectRequest,
pkEmptyFragment,
pkInvalidPDU,
pkUnrecognizedType,
pkValidData
} TPDUKind ;
#pragma pack()
void ErrIsoText(int Error, char *Msg, int len);
class TIsoTcpSocket : public TMsgSocket
{
private:
TIsoControlPDU FControlPDU;
int IsoMaxFragments; // max fragments allowed for an ISO telegram
// Checks the PDU format
int CheckPDU(void *pPDU, u_char PduTypeExpected);
// Receives the next fragment
int isoRecvFragment(void *From, int Max, int &Size, bool &EoT);
protected:
TIsoDataPDU PDU;
int SetIsoError(int Error);
// Builds the control PDU starting from address properties
virtual int BuildControlPDU();
// Calcs the PDU size
int PDUSize(void *pPDU);
// Parses the connection request PDU to extract TSAP and PDU size info
virtual void IsoParsePDU(TIsoControlPDU PDU);
// Confirms the connection, override this method for special pourpose
// By default it checks the PDU format and resend it changing the pdu type
int IsoConfirmConnection(u_char PDUType);
void ClrIsoError();
virtual void FragmentSkipped(int Size);
public:
word SrcTSap; // Source TSAP
word DstTSap; // Destination TSAP
word SrcRef; // Source Reference
word DstRef; // Destination Reference
int IsoPDUSize;
int LastIsoError;
//--------------------------------------------------------------------------
TIsoTcpSocket();
~TIsoTcpSocket();
// HIGH Level functions (work on payload hiding the underlying protocol)
// Connects with a peer, the connection PDU is automatically built starting from address scheme (see below)
int isoConnect();
// Disconnects from a peer, if OnlyTCP = true, only a TCP disconnect is performed,
// otherwise a disconnect PDU is built and send.
int isoDisconnect(bool OnlyTCP);
// Sends a buffer, a valid header is created
int isoSendBuffer(void *Data, int Size);
// Receives a buffer
int isoRecvBuffer(void *Data, int & Size);
// Exchange cycle send->receive
int isoExchangeBuffer(void *Data, int & Size);
// A PDU is ready (at least its header) to be read
bool IsoPDUReady();
// Same as isoSendBuffer, but the entire PDU has to be provided (in any case a check is performed)
int isoSendPDU(PIsoDataPDU Data);
// Same as isoRecvBuffer, but it returns the entire PDU, automatically enques the fragments
int isoRecvPDU(PIsoDataPDU Data);
// Same as isoExchangeBuffer, but the entire PDU has to be provided (in any case a check is performed)
int isoExchangePDU(PIsoDataPDU Data);
// Peeks an header info to know which kind of telegram is incoming
void IsoPeek(void *pPDU, TPDUKind &PduKind);
};
#endif // s7_isotcp_h
================================================
FILE: deps/snap7/src/core/s7_micro_client.cpp
================================================
/*=============================================================================|
| PROJECT SNAP7 1.3.0 |
|==============================================================================|
| Copyright (C) 2013, 2015 Davide Nardella |
| All rights reserved. |
|==============================================================================|
| SNAP7 is free software: you can redistribute it and/or modify |
| it under the terms of the Lesser GNU General Public License as published by |
| the Free Software Foundation, either version 3 of the License, or |
| (at your option) any later version. |
| |
| It means that you can distribute your commercial software linked with |
| SNAP7 without the requirement to distribute the source code of your |
| application and without the requirement that your application be itself |
| distributed under LGPL. |
| |
| SNAP7 is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| Lesser GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License and a |
| copy of Lesser GNU General Public License along with Snap7. |
| If not, see http://www.gnu.org/licenses/ |
|=============================================================================*/
#include "s7_micro_client.h"
//---------------------------------------------------------------------------
TSnap7MicroClient::TSnap7MicroClient()
{
SrcRef =0x0100; // RFC0983 states that SrcRef and DetRef should be 0
// and, in any case, they are ignored.
// S7 instead requires a number != 0
// Libnodave uses 0x0100
// S7Manager uses 0x0D00
// TIA Portal V12 uses 0x1D00
// WinCC uses 0x0300
// Seems that every non zero value is good enough...
DstRef =0x0000;
SrcTSap =0x0100;
DstTSap =0x0000; // It's filled by connection functions
ConnectionType = CONNTYPE_PG; // Default connection type
memset(&Job,0,sizeof(TSnap7Job));
}
//---------------------------------------------------------------------------
TSnap7MicroClient::~TSnap7MicroClient()
{
Destroying = true;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opReadArea()
{
PReqFunReadParams ReqParams;
PResFunReadParams ResParams;
PS7ResHeader23 Answer;
PResFunReadItem ResData;
word RPSize; // ReqParams size
int WordSize;
uintptr_t Offset;
pbyte Target;
int Address;
int IsoSize;
int Start;
int MaxElements; // Max elements that we can transfer in a PDU
word NumElements; // Num of elements that we are asking for this telegram
int TotElements; // Total elements requested
int Size;
int Result;
WordSize=DataSizeByte(Job.WordLen); // The size in bytes of an element that we are asking for
if (WordSize==0)
return errCliInvalidWordLen;
// First check : params bounds
if ((Job.Number<0) || (Job.Number>65535) || (Job.Start<0) || (Job.Amount<1))
return errCliInvalidParams;
// Second check : transport size
if ((Job.WordLen==S7WLBit) && (Job.Amount>1))
return errCliInvalidTransportSize;
// Request Params size
RPSize =sizeof(TReqFunReadItem)+2; // 1 item + FunRead + ItemsCount
// Setup pointers (note : PDUH_out and PDU.Payload are the same pointer)
ReqParams =PReqFunReadParams(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
Answer =PS7ResHeader23(&PDU.Payload);
ResParams =PResFunReadParams(pbyte(Answer)+ResHeaderSize23);
ResData =PResFunReadItem(pbyte(ResParams)+sizeof(TResFunReadParams));
// Each packet cannot exceed the PDU length (in bytes) negotiated, and moreover
// we must ensure to transfer a "finite" number of item per PDU
MaxElements=(PDULength-sizeof(TS7ResHeader23)-sizeof(TResFunReadParams)-4) / WordSize;
TotElements=Job.Amount;
Start =Job.Start;
Offset =0;
Result =0;
while ((TotElements>0) && (Result==0))
{
NumElements=TotElements;
if (NumElements>MaxElements)
NumElements=MaxElements;
Target=pbyte(Job.pData)+Offset;
//----------------------------------------------- Read next slice-----
PDUH_out->P = 0x32; // Always 0x32
PDUH_out->PDUType = PduType_request; // 0x01
PDUH_out->AB_EX = 0x0000; // Always 0x0000
PDUH_out->Sequence = GetNextWord(); // AutoInc
PDUH_out->ParLen = SwapWord(RPSize); // 14 bytes params
PDUH_out->DataLen = 0x0000; // No data
ReqParams->FunRead = pduFuncRead; // 0x04
ReqParams->ItemsCount = 1;
ReqParams->Items[0].ItemHead[0] = 0x12;
ReqParams->Items[0].ItemHead[1] = 0x0A;
ReqParams->Items[0].ItemHead[2] = 0x10;
ReqParams->Items[0].TransportSize = Job.WordLen;
ReqParams->Items[0].Length = SwapWord(NumElements);
ReqParams->Items[0].Area = Job.Area;
if (Job.Area==S7AreaDB)
ReqParams->Items[0].DBNumber = SwapWord(Job.Number);
else
ReqParams->Items[0].DBNumber = 0x0000;
// Adjusts the offset
if ((Job.WordLen==S7WLBit) || (Job.WordLen==S7WLCounter) || (Job.WordLen==S7WLTimer))
Address = Start;
else
Address = Start*8;
ReqParams->Items[0].Address[2] = Address & 0x000000FF;
Address = Address >> 8;
ReqParams->Items[0].Address[1] = Address & 0x000000FF;
Address = Address >> 8;
ReqParams->Items[0].Address[0] = Address & 0x000000FF;
IsoSize = sizeof(TS7ReqHeader)+RPSize;
Result = isoExchangeBuffer(0,IsoSize);
// Get Data
if (Result==0) // 1St level Iso
{
Size = 0;
// Item level error
if (ResData->ReturnCode==0xFF) // <-- 0xFF means Result OK
{
// Calcs data size in bytes
Size = SwapWord(ResData->DataLength);
// Adjust Size in accord of TransportSize
if ((ResData->TransportSize != TS_ResOctet) && (ResData->TransportSize != TS_ResReal) && (ResData->TransportSize != TS_ResBit))
Size = Size >> 3;
memcpy(Target, &ResData->Data[0], Size);
}
else
Result = CpuError(ResData->ReturnCode);
Offset+=Size;
};
//--------------------------------------------------------------------
TotElements -= NumElements;
Start += NumElements*WordSize;
}
return Result;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opWriteArea()
{
PReqFunWriteParams ReqParams;
PReqFunWriteDataItem ReqData; // only 1 item for WriteArea Function
PResFunWrite ResParams;
PS7ResHeader23 Answer;
word RPSize; // ReqParams size
word RHSize; // Request headers size
bool First = true;
pbyte Source;
pbyte Target;
int Address;
int IsoSize;
int WordSize;
word Size;
uintptr_t Offset = 0;
int Start; // where we are starting from for this telegram
int MaxElements; // Max elements that we can transfer in a PDU
word NumElements; // Num of elements that we are asking for this telegram
int TotElements; // Total elements requested
int Result = 0;
WordSize=DataSizeByte(Job.WordLen); // The size in bytes of an element that we are pushing
if (WordSize==0)
return errCliInvalidWordLen;
// First check : params bounds
if ((Job.Number<0) || (Job.Number>65535) || (Job.Start<0) || (Job.Amount<1))
return errCliInvalidParams;
// Second check : transport size
if ((Job.WordLen==S7WLBit) && (Job.Amount>1))
return errCliInvalidTransportSize;
RHSize =sizeof(TS7ReqHeader)+ // Request header
2+ // FunWrite+ItemCount (of TReqFunWriteParams)
sizeof(TReqFunWriteItem)+// 1 item reference
4; // ReturnCode+TransportSize+DataLength
RPSize =sizeof(TReqFunWriteItem)+2;
// Setup pointers (note : PDUH_out and PDU.Payload are the same pointer)
ReqParams=PReqFunWriteParams(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
ReqData =PReqFunWriteDataItem(pbyte(ReqParams)+sizeof(TReqFunWriteItem)+2); // 2 = FunWrite+ItemsCount
Target =pbyte(ReqData)+4; // 4 = ReturnCode+TransportSize+DataLength
Answer =PS7ResHeader23(&PDU.Payload);
ResParams=PResFunWrite(pbyte(Answer)+ResHeaderSize23);
// Each packet cannot exceed the PDU length (in bytes) negotiated, and moreover
// we must ensure to transfer a "finite" number of item per PDU
MaxElements=(PDULength-RHSize) / WordSize;
TotElements=Job.Amount;
Start =Job.Start;
while ((TotElements>0) && (Result==0))
{
NumElements=TotElements;
if (NumElements>MaxElements)
NumElements=MaxElements;
Source=pbyte(Job.pData)+Offset;
Size=NumElements * WordSize;
PDUH_out->P=0x32; // Always 0x32
PDUH_out->PDUType=PduType_request; // 0x01
PDUH_out->AB_EX=0x0000; // Always 0x0000
PDUH_out->Sequence=GetNextWord(); // AutoInc
PDUH_out->ParLen =SwapWord(RPSize); // 14 bytes params
PDUH_out->DataLen =SwapWord(Size+4);
ReqParams->FunWrite=pduFuncWrite; // 0x05
ReqParams->ItemsCount=1;
ReqParams->Items[0].ItemHead[0]=0x12;
ReqParams->Items[0].ItemHead[1]=0x0A;
ReqParams->Items[0].ItemHead[2]=0x10;
ReqParams->Items[0].TransportSize=Job.WordLen;
ReqParams->Items[0].Length=SwapWord(NumElements);
ReqParams->Items[0].Area=Job.Area;
if (Job.Area==S7AreaDB)
ReqParams->Items[0].DBNumber=SwapWord(Job.Number);
else
ReqParams->Items[0].DBNumber=0x0000;
// Adjusts the offset
if ((Job.WordLen==S7WLBit) || (Job.WordLen==S7WLCounter) || (Job.WordLen==S7WLTimer))
Address=Start;
else
Address=Start*8;
ReqParams->Items[0].Address[2]=Address & 0x000000FF;
Address=Address >> 8;
ReqParams->Items[0].Address[1]=Address & 0x000000FF;
Address=Address >> 8;
ReqParams->Items[0].Address[0]=Address & 0x000000FF;
ReqData->ReturnCode=0x00;
switch(Job.WordLen)
{
case S7WLBit:
ReqData->TransportSize=TS_ResBit;
break;
case S7WLInt:
case S7WLDInt:
ReqData->TransportSize=TS_ResInt;
break;
case S7WLReal:
ReqData->TransportSize=TS_ResReal;
break;
case S7WLChar :
case S7WLCounter:
case S7WLTimer:
ReqData->TransportSize=TS_ResOctet;
break;
default:
ReqData->TransportSize=TS_ResByte;
break;
};
if ((ReqData->TransportSize!=TS_ResOctet) && (ReqData->TransportSize!=TS_ResReal) && (ReqData->TransportSize!=TS_ResBit))
ReqData->DataLength=SwapWord(Size*8);
else
ReqData->DataLength=SwapWord(Size);
memcpy(Target, Source, Size);
IsoSize=RHSize + Size;
Result=isoExchangeBuffer(0,IsoSize);
if (Result==0) // 1St check : Iso result
{
Result=CpuError(SwapWord(Answer->Error)); // 2nd level global error
if (Result==0)
{ // 2th check : item error
if (ResParams->Data[0] == 0xFF) // <-- 0xFF means Result OK
Result=0;
else
// Now we check the error : if it's the first part we report the cpu error
// otherwise we warn that the function failed but some data were written
if (First)
Result=CpuError(ResParams->Data[0]);
else
Result=errCliPartialDataWritten;
};
Offset+=Size;
};
First=false;
TotElements-=NumElements;
Start+=(NumElements*WordSize);
}
return Result;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opReadMultiVars()
{
PS7DataItem Item;
PReqFunReadParams ReqParams;
PS7ResHeader23 Answer;
PResFunReadParams ResParams;
TResFunReadData ResData;
word RPSize; // ReqParams size
uintptr_t Offset =0 ;
word Slice;
longword Address;
int IsoSize;
pbyte P;
int ItemsCount, c, Result;
Item = PS7DataItem(Job.pData);
ItemsCount = Job.Amount;
// Some useful initial check to detail the errors (Since S7 CPU always answers
// with $05 if (something is wrong in params)
if (ItemsCount>MaxVars)
return errCliTooManyItems;
// Adjusts Word Length in case of timers and counters and clears results
for (c = 0; c < ItemsCount; c++)
{
Item->Result=0;
if (Item->Area==S7AreaCT)
Item->WordLen=S7WLCounter;
if (Item->Area==S7AreaTM)
Item->WordLen=S7WLTimer;
Item++;
};
// Let's build the PDU
RPSize = word(2 + ItemsCount * sizeof(TReqFunReadItem));
ReqParams = PReqFunReadParams(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
Answer = PS7ResHeader23(&PDU.Payload);
ResParams = PResFunReadParams(pbyte(Answer)+ResHeaderSize23);
// Fill Header
PDUH_out->P=0x32; // Always 0x32
PDUH_out->PDUType=PduType_request; // 0x01
PDUH_out->AB_EX=0x0000; // Always 0x0000
PDUH_out->Sequence=GetNextWord(); // AutoInc
PDUH_out->ParLen=SwapWord(RPSize); // Request params size
PDUH_out->DataLen=0x0000; // No data in output
// Fill Params
ReqParams->FunRead=pduFuncRead; // 0x04
ReqParams->ItemsCount=ItemsCount;
Item = PS7DataItem(Job.pData);
for (c = 0; c < ItemsCount; c++)
{
ReqParams->Items[c].ItemHead[0]=0x12;
ReqParams->Items[c].ItemHead[1]=0x0A;
ReqParams->Items[c].ItemHead[2]=0x10;
ReqParams->Items[c].TransportSize=Item->WordLen;
ReqParams->Items[c].Length=SwapWord(Item->Amount);
ReqParams->Items[c].Area=Item->Area;
// Automatically drops DBNumber if (Area is not DB
if (Item->Area==S7AreaDB)
ReqParams->Items[c].DBNumber=SwapWord(Item->DBNumber);
else
ReqParams->Items[c].DBNumber=0x0000;
// Adjusts the offset
if ((Item->WordLen==S7WLBit) || (Item->WordLen==S7WLCounter) || (Item->WordLen==S7WLTimer))
Address=Item->Start;
else
Address=Item->Start*8;
// Builds the offset
ReqParams->Items[c].Address[2]=Address & 0x000000FF;
Address=Address >> 8;
ReqParams->Items[c].Address[1]=Address & 0x000000FF;
Address=Address >> 8;
ReqParams->Items[c].Address[0]=Address & 0x000000FF;
Item++;
};
IsoSize=RPSize+sizeof(TS7ReqHeader);
if (IsoSize>PDULength)
return errCliSizeOverPDU;
Result=isoExchangeBuffer(0,IsoSize);
if (Result!=0)
return Result;
// Function level error
if (Answer->Error!=0)
return CpuError(SwapWord(Answer->Error));
if (ResParams->ItemCount!=ItemsCount)
return errCliInvalidPlcAnswer;
P=pbyte(ResParams)+sizeof(TResFunReadParams);
Item = PS7DataItem(Job.pData);
for (c = 0; c < ItemsCount; c++)
{
ResData[c] =PResFunReadItem(pbyte(P)+Offset);
Slice=0;
// Item level error
if (ResData[c]->ReturnCode==0xFF) // <-- 0xFF means Result OK
{
// Calcs data size in bytes
Slice=SwapWord(ResData[c]->DataLength);
// Adjust Size in accord of TransportSize
if ((ResData[c]->TransportSize != TS_ResOctet) && (ResData[c]->TransportSize != TS_ResReal) && (ResData[c]->TransportSize != TS_ResBit))
Slice=Slice >> 3;
memcpy(Item->pdata, ResData[c]->Data, Slice);
Item->Result=0;
}
else
Item->Result=CpuError(ResData[c]->ReturnCode);
if ((Slice % 2)!=0)
Slice++; // Skip fill byte for Odd frame
Offset+=(4+Slice);
Item++;
};
return Result;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opWriteMultiVars()
{
PS7DataItem Item;
PReqFunWriteParams ReqParams;
PResFunWrite ResParams;
TReqFunWriteData ReqData;
PS7ResHeader23 Answer;
pbyte P;
uintptr_t Offset;
longword Address;
int ItemsCount, c, IsoSize;
word RPSize; // ReqParams size
word Size; // Write data size
int WordSize, Result;
Item = PS7DataItem(Job.pData);
ItemsCount = Job.Amount;
// Some useful initial check to detail the errors (Since S7 CPU always answers
// with $05 if (something is wrong in params)
if (ItemsCount>MaxVars)
return errCliTooManyItems;
// Adjusts Word Length in case of timers and counters and clears results
for (c = 0; c < ItemsCount; c++)
{
Item->Result=0;
if (Item->Area==S7AreaCT)
Item->WordLen=S7WLCounter;
if (Item->Area==S7AreaTM)
Item->WordLen=S7WLTimer;
Item++;
};
// Let's build the PDU : setup pointers
RPSize = word(2 + ItemsCount * sizeof(TReqFunWriteItem));
ReqParams = PReqFunWriteParams(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
Answer = PS7ResHeader23(&PDU.Payload);
ResParams = PResFunWrite(pbyte(Answer)+ResHeaderSize23);
P=pbyte(ReqParams)+RPSize;
// Fill Header
PDUH_out->P=0x32; // Always 0x32
PDUH_out->PDUType=PduType_request; // 0x01
PDUH_out->AB_EX=0x0000; // Always 0x0000
PDUH_out->Sequence=GetNextWord(); // AutoInc
PDUH_out->ParLen=SwapWord(RPSize); // Request params size
// Fill Params
ReqParams->FunWrite=pduFuncWrite; // 0x05
ReqParams->ItemsCount=ItemsCount;
Offset=0;
Item = PS7DataItem(Job.pData);
for (c = 0; c < ItemsCount; c++)
{
// Items Params
ReqParams->Items[c].ItemHead[0]=0x12;
ReqParams->Items[c].ItemHead[1]=0x0A;
ReqParams->Items[c].ItemHead[2]=0x10;
ReqParams->Items[c].TransportSize=Item->WordLen;
ReqParams->Items[c].Length=SwapWord(Item->Amount);
ReqParams->Items[c].Area=Item->Area;
if (Item->Area==S7AreaDB)
ReqParams->Items[c].DBNumber=SwapWord(Item->DBNumber);
else
ReqParams->Items[c].DBNumber=0x0000;
// Adjusts the offset
if ((Item->WordLen==S7WLBit) || (Item->WordLen==S7WLCounter) || (Item->WordLen==S7WLTimer))
Address=Item->Start;
else
Address=Item->Start*8;
// Builds the offset
ReqParams->Items[c].Address[2]=Address & 0x000000FF;
Address=Address >> 8;
ReqParams->Items[c].Address[1]=Address & 0x000000FF;
Address=Address >> 8;
ReqParams->Items[c].Address[0]=Address & 0x000000FF;
// Items Data
ReqData[c]=PReqFunWriteDataItem(pbyte(P)+Offset);
ReqData[c]->ReturnCode=0x00;
switch (Item->WordLen)
{
case S7WLBit :
ReqData[c]->TransportSize=TS_ResBit;
break;
case S7WLInt :
case S7WLDInt :
ReqData[c]->TransportSize=TS_ResInt;
break;
case S7WLReal :
ReqData[c]->TransportSize=TS_ResReal;
break;
case S7WLChar :
case S7WLCounter :
case S7WLTimer : ReqData[c]->TransportSize=TS_ResOctet;
break;
default :
ReqData[c]->TransportSize=TS_ResByte; // byte/word/dword etc.
break;
};
WordSize=DataSizeByte(Item->WordLen);
Size=Item->Amount * WordSize;
if ((ReqData[c]->TransportSize!=TS_ResOctet) && (ReqData[c]->TransportSize!=TS_ResReal) && (ReqData[c]->TransportSize!=TS_ResBit))
ReqData[c]->DataLength=SwapWord(Size*8);
else
ReqData[c]->DataLength=SwapWord(Size);
memcpy(ReqData[c]->Data, Item->pdata, Size);
if ((Size % 2) != 0 && (ItemsCount - c != 1))
Size++; // Skip fill byte for Odd frame (except for the last one)
Offset+=(4+Size); // next item
Item++;
};
PDUH_out->DataLen=SwapWord(word(Offset));
IsoSize=RPSize+sizeof(TS7ReqHeader)+int(Offset);
if (IsoSize>PDULength)
return errCliSizeOverPDU;
Result=isoExchangeBuffer(0,IsoSize);
if (Result!=0)
return Result;
// Function level error
if (Answer->Error!=0)
return CpuError(SwapWord(Answer->Error));
if (ResParams->ItemCount!=ItemsCount)
return errCliInvalidPlcAnswer;
Item = PS7DataItem(Job.pData);
for (c = 0; c < ItemsCount; c++)
{
// Item level error
if (ResParams->Data[c]==0xFF) // <-- 0xFF means Result OK
Item->Result=0;
else
Item->Result=CpuError(ResParams->Data[c]);
Item++;
};
return Result;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opListBlocks()
{
PReqFunGetBlockInfo ReqParams;
PReqDataFunBlocks ReqData;
PResFunGetBlockInfo ResParams;
PDataFunListAll ResData;
PS7ResHeader17 Answer;
PS7BlocksList List;
int IsoSize, Result;
// Setup pointers (note : PDUH_out and PDU.Payload are the same pointer)
ReqParams=PReqFunGetBlockInfo(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
ReqData =PReqDataFunBlocks(pbyte(ReqParams)+sizeof(TReqFunGetBlockInfo));
Answer =PS7ResHeader17(&PDU.Payload);
ResParams=PResFunGetBlockInfo(pbyte(Answer)+ResHeaderSize17);
ResData =PDataFunListAll(pbyte(ResParams)+sizeof(TResFunGetBlockInfo));
List =PS7BlocksList(Job.pData);
// Fill Header
PDUH_out->P=0x32; // Always 0x32
PDUH_out->PDUType=PduType_userdata; // 0x07
PDUH_out->AB_EX=0x0000; // Always 0x0000
PDUH_out->Sequence=GetNextWord(); // AutoInc
PDUH_out->ParLen=SwapWord(sizeof(TReqFunGetBlockInfo)); // 8 bytes params
PDUH_out->DataLen=SwapWord(sizeof(TReqDataFunBlocks)); // 4 bytes data
// Fill params (mostly constants)
ReqParams->Head[0]=0x00;
ReqParams->Head[1]=0x01;
ReqParams->Head[2]=0x12;
ReqParams->Plen =0x04;
ReqParams->Uk =0x11;
ReqParams->Tg =grBlocksInfo;
ReqParams->SubFun =SFun_ListAll;
ReqParams->Seq =0x00;
// Fill data
ReqData[0] =0x0A;
ReqData[1] =0x00;
ReqData[2] =0x00;
ReqData[3] =0x00;
IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqFunGetBlockInfo)+sizeof(TReqDataFunBlocks);
Result=isoExchangeBuffer(0,IsoSize);
// Get Data
if (Result==0)
{
if (ResParams->ErrNo==0)
{
if (SwapWord(ResData->Length)!=28)
return errCliInvalidPlcAnswer;
for (int c = 0; c < 7; c++)
{
switch (ResData->Blocks[c].BType)
{
case Block_OB:
List->OBCount=SwapWord(ResData->Blocks[c].BCount);
break;
case Block_DB:
List->DBCount=SwapWord(ResData->Blocks[c].BCount);
break;
case Block_SDB:
List->SDBCount=SwapWord(ResData->Blocks[c].BCount);
break;
case Block_FC:
List->FCCount=SwapWord(ResData->Blocks[c].BCount);
break;
case Block_SFC:
List->SFCCount=SwapWord(ResData->Blocks[c].BCount);
break;
case Block_FB:
List->FBCount=SwapWord(ResData->Blocks[c].BCount);
break;
case Block_SFB:
List->SFBCount=SwapWord(ResData->Blocks[c].BCount);
break;
}
}
}
else
Result=CpuError(SwapWord(ResParams->ErrNo));
}
return Result;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opListBlocksOfType()
{
PReqFunGetBlockInfo ReqParams;
PReqDataBlockOfType ReqData;
PS7ResHeader17 Answer;
PResFunGetBlockInfo ResParams;
PDataFunGetBot ResData;
longword *PadData;
word *List;
bool First;
bool Done = false;
byte BlockType, In_Seq;
int Count, Last, IsoSize, Result;
int c, CThis;
word DataLength;
bool RoomError = false;
BlockType=Job.Area;
List=(word*)(&opData);
// Setup pointers (note : PDUH_out and PDU.Payload are the same pointer)
ReqParams=PReqFunGetBlockInfo(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
Answer =PS7ResHeader17(&PDU.Payload);
ResParams=PResFunGetBlockInfo(pbyte(Answer)+ResHeaderSize17);
ResData =PDataFunGetBot(pbyte(ResParams)+sizeof(TResFunGetBlockInfo));
// Get Data
First =true;
In_Seq=0x00; // first group sequence, next will come from PLC
Count =0;
Last =0;
do
{
//<--------------------------------------------------------- Get next slice
// Fill Header
PDUH_out->P=0x32; // Always 0x32
PDUH_out->PDUType=PduType_userdata; // 0x07
PDUH_out->AB_EX=0x0000; // Always 0x0000
PDUH_out->Sequence=GetNextWord(); // AutoInc
if (First)
{
PDUH_out->ParLen=SwapWord(8); // 8 bytes params
PDUH_out->DataLen=SwapWord(6); // 6 bytes data
DataLength=14;
}
else
{
PDUH_out->ParLen=SwapWord(12); // 12 bytes params
PDUH_out->DataLen=SwapWord(4); // 4 bytes data
DataLength=16;
}
// Fill params (mostly constants)
ReqParams->Head[0]=0x00;
ReqParams->Head[1]=0x01;
ReqParams->Head[2]=0x12;
if (First)
ReqParams->Plen =0x04;
else
ReqParams->Plen =0x08;
if (First)
ReqParams->Uk = 0x11;
else
ReqParams->Uk = 0x12;
ReqParams->Tg =grBlocksInfo;
ReqParams->SubFun =SFun_ListBoT;
ReqParams->Seq =In_Seq;
// Fill data
if (First)
{
// overlap resvd and error to avoid another struct...
ReqData =PReqDataBlockOfType(pbyte(ReqParams)+sizeof(TReqFunGetBlockInfo));
ReqData->RetVal =0xFF;
ReqData->TSize =TS_ResOctet;
ReqData->Length =SwapWord(0x0002);
ReqData->Zero =0x30; // zero ascii '0'
ReqData->BlkType =BlockType;
}
else
{
PadData =(longword*)(pbyte(ReqParams)+sizeof(TReqFunGetBlockInfo));
ReqData =PReqDataBlockOfType(pbyte(ReqParams)+sizeof(TReqFunGetBlockInfo)+4);
*PadData =0x00000000;
ReqData->RetVal =0x0A;
ReqData->TSize =0x00;
ReqData->Length =0x0000;
ReqData->Zero =0x00;
ReqData->BlkType =0x00;
};
IsoSize=sizeof(TS7ReqHeader)+DataLength;
Result=isoExchangeBuffer(0,IsoSize);
if (Result==0)
{
if (ResParams->ErrNo==0)
{
if (ResData->RetVal==0xFF)
{
Done=((ResParams->Rsvd & 0xFF00) == 0); // Low order byte = 0x00 => the sequence is done
In_Seq=ResParams->Seq; // every next telegram must have this number
CThis=((SwapWord(ResData->DataLen) - 4 ) / 4) + 1; // Partial counter
for (c=0; c < CThis+1; c++)
{
*List=SwapWord(ResData->Items[c].BlockNum);
Last++;
List++;
if (Last==0x8000)
{
Done=true;
break;
};
};
Count+=CThis; // Total counter
List--;
}
else
Result=errCliItemNotAvailable;
}
else
Result=errCliItemNotAvailable;
};
First=false;
//---------------------------------------------------------> Get next slice
}
while ((!Done) && (Result==0));
*Job.pAmount=0;
if (Result==0)
{
if (Count>Job.Amount)
{
Count=Job.Amount;
RoomError=true;
}
memcpy(Job.pData, &opData, Count*2);
*Job.pAmount=Count;
if (RoomError) // Result==0 -> override if romerror
Result=errCliPartialDataRead;
};
return Result;
}
//---------------------------------------------------------------------------
void TSnap7MicroClient::FillTime(word SiemensTime, char *PTime)
{
// SiemensTime -> number of seconds after 1/1/1984
// This is not S7 date and time but is used only internally for block info
time_t TheDate = (SiemensTime * 86400)+ DeltaSecs;
struct tm * timeinfo = localtime (&TheDate);
if (timeinfo!=NULL) {
strftime(PTime,11,"%Y/%m/%d",timeinfo);
}
else
*PTime='\0';
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opAgBlockInfo()
{
PS7BlockInfo BlockInfo;
PReqFunGetBlockInfo ReqParams;
PReqDataBlockInfo ReqData;
PS7ResHeader17 Answer;
PResFunGetBlockInfo ResParams;
PResDataBlockInfo ResData;
byte BlockType;
int BlockNum, IsoSize, Result;
BlockType=Job.Area;
BlockNum =Job.Number;
BlockInfo=PS7BlockInfo(Job.pData);
memset(BlockInfo,0,sizeof(TS7BlockInfo));
// Setup pointers (note : PDUH_out and PDU.Payload are the same pointer)
ReqParams=PReqFunGetBlockInfo(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
ReqData =PReqDataBlockInfo(pbyte(ReqParams)+sizeof(TReqFunGetBlockInfo));
Answer =PS7ResHeader17(&PDU.Payload);
ResParams=PResFunGetBlockInfo(pbyte(Answer)+ResHeaderSize17);
ResData =PResDataBlockInfo(pbyte(ResParams)+sizeof(TResFunGetBlockInfo));
// Fill Header
PDUH_out->P=0x32; // Always 0x32
PDUH_out->PDUType=PduType_userdata; // 0x07
PDUH_out->AB_EX=0x0000; // Always 0x0000
PDUH_out->Sequence=GetNextWord(); // AutoInc
PDUH_out->ParLen=SwapWord(sizeof(TReqFunGetBlockInfo)); // 8 bytes params
PDUH_out->DataLen=SwapWord(sizeof(TReqDataBlockInfo)); // 4 bytes data
// Fill params (mostly constants)
ReqParams->Head[0]=0x00;
ReqParams->Head[1]=0x01;
ReqParams->Head[2]=0x12;
ReqParams->Plen =0x04;
ReqParams->Uk =0x11;
ReqParams->Tg =grBlocksInfo;
ReqParams->SubFun =SFun_BlkInfo;
ReqParams->Seq =0x00;
// Fill data
ReqData->RetVal =0xFF;
ReqData->TSize =TS_ResOctet;
ReqData->DataLen =SwapWord(0x0008);
ReqData->BlkPrfx =0x30;
ReqData->BlkType =BlockType;
ReqData->A =0x41;
ReqData->AsciiBlk[0]=(BlockNum / 10000)+0x30;
BlockNum=BlockNum % 10000;
ReqData->AsciiBlk[1]=(BlockNum / 1000)+0x30;
BlockNum=BlockNum % 1000;
ReqData->AsciiBlk[2]=(BlockNum / 100)+0x30;
BlockNum=BlockNum % 100;
ReqData->AsciiBlk[3]=(BlockNum / 10)+0x30;
BlockNum=BlockNum % 10;
ReqData->AsciiBlk[4]=(BlockNum / 1)+0x30;
IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqFunGetBlockInfo)+sizeof(TReqDataBlockInfo);
Result=isoExchangeBuffer(0,IsoSize);
// Get Data
if (Result==0)
{
if (ResParams->ErrNo==0)
{
if (SwapWord(ResData->Length)<40) // 78
return errCliInvalidPlcAnswer;
if (ResData->RetVal==0xFF) // <-- 0xFF means Result OK
{
//<----------------------------------------------Fill block info
BlockInfo->BlkType=ResData->SubBlkType;
BlockInfo->BlkNumber=SwapWord(ResData->BlkNumber);
BlockInfo->BlkLang=ResData->BlkLang;
BlockInfo->BlkFlags=ResData->BlkFlags;
BlockInfo->MC7Size=SwapWord(ResData->MC7Len);
BlockInfo->LoadSize=SwapDWord(ResData->LenLoadMem);
BlockInfo->LocalData=SwapWord(ResData->LocDataLen);
BlockInfo->SBBLength=SwapWord(ResData->SbbLen);
BlockInfo->CheckSum=SwapWord(ResData->BlkChksum);
BlockInfo->Version=ResData->Version;
memcpy(BlockInfo->Author, ResData->Author, 8);
memcpy(BlockInfo->Family,ResData->Family,8);
memcpy(BlockInfo->Header,ResData->Header,8);
FillTime(SwapWord(ResData->CodeTime_dy),BlockInfo->CodeDate);
FillTime(SwapWord(ResData->IntfTime_dy),BlockInfo->IntfDate);
//---------------------------------------------->Fill block info
}
else
Result=CpuError(ResData->RetVal);
}
else
Result=CpuError(SwapWord(ResParams->ErrNo));
};
return Result;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opDBGet()
{
TS7BlockInfo BI;
void * usrPData;
int * usrPSize;
int Result, Room;
bool RoomError = false;
// Stores user pointer
usrPData=Job.pData;
usrPSize=Job.pAmount;
Room =Job.Amount;
// 1 Pass : Get block info
Job.Area=Block_DB;
Job.pData=&BI;
Result=opAgBlockInfo();
// 2 Pass : Read the whole (MC7Size bytes) DB.
if (Result==0)
{
// Check user space
if (BI.MC7Size>Room)
{
Job.Amount=Room;
RoomError=true;
}
else
Job.Amount =BI.MC7Size;
// The data is read even if the buffer is small (the error is reported).
// Imagine that we want to read only a small amount of data at the
// beginning of a DB regardless it's size....
Job.Area =S7AreaDB;
Job.WordLen=S7WLByte;
Job.Start =0;
Job.pData =usrPData;
Result =opReadArea();
if (Result==0)
*usrPSize=Job.Amount;
}
if ((Result==0) && RoomError)
return errCliBufferTooSmall;
else
return Result;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opDBFill()
{
TS7BlockInfo BI;
int Result;
// new op : get block info
Job.Op =s7opAgBlockInfo;
Job.Area =Block_DB;
Job.pData=&BI;
Result =opAgBlockInfo();
// Restore original op
Job.Op =s7opDBFill;
// Fill internal buffer then write it
if (Result==0)
{
Job.Amount =BI.MC7Size;
Job.Area =S7AreaDB;
Job.WordLen=S7WLByte;
Job.Start =0;
memset(&opData, byte(Job.IParam), Job.Amount);
Job.pData =&opData;
Result =opWriteArea();
}
return Result;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opUpload()
{
PS7ResHeader23 Answer;
int IsoSize;
byte Upload_ID = 0; // not strictly needed, only to avoid warning
byte BlockType;
int BlockNum, BlockLength, Result;
bool Done, Full; // if full==true, the data will be compatible to full download function
uintptr_t Offset;
bool RoomError = false;
BlockType=Job.Area;
BlockNum =Job.Number;
Full =Job.IParam==1;
// Setup Answer (is the same for all Upload pdus)
Answer= PS7ResHeader23(&PDU.Payload);
// Init sequence
Done =false;
Offset=0;
//<-------------------------------------------------------------StartUpload
PReqFunStartUploadParams ReqParams;
PResFunStartUploadParams ResParams;
// Setup pointers (note : PDUH_out and PDU.Payload are the same pointer)
ReqParams=PReqFunStartUploadParams(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
ResParams=PResFunStartUploadParams(pbyte(Answer)+ResHeaderSize23);
// Init Header
PDUH_out->P=0x32; // Always 0x32
PDUH_out->PDUType=PduType_request; // 0x01
PDUH_out->AB_EX=0x0000; // Always 0x0000
PDUH_out->Sequence=GetNextWord(); // AutoInc
PDUH_out->ParLen=SwapWord(sizeof(TReqFunStartUploadParams));// params size
PDUH_out->DataLen=0x0000; // No data
// Init Params
ReqParams->FunSUpld=pduStartUpload;
ReqParams->Uk6[0]=0x00;
ReqParams->Uk6[1]=0x00;
ReqParams->Uk6[2]=0x00;
ReqParams->Uk6[3]=0x00;
ReqParams->Uk6[4]=0x00;
ReqParams->Uk6[5]=0x00;
ReqParams->Upload_ID=Upload_ID; // At begining is 0) we will put upload id incoming from plc
ReqParams->Len_1 =0x09; // 9 bytes from here
ReqParams->Prefix=0x5F;
ReqParams->BlkPrfx=0x30; // '0'
ReqParams->BlkType=BlockType;
// Block number
ReqParams->AsciiBlk[0]=(BlockNum / 10000)+0x30;
BlockNum=BlockNum % 10000;
ReqParams->AsciiBlk[1]=(BlockNum / 1000)+0x30;
BlockNum=BlockNum % 1000;
ReqParams->AsciiBlk[2]=(BlockNum / 100)+0x30;
BlockNum=BlockNum % 100;
ReqParams->AsciiBlk[3]=(BlockNum / 10)+0x30;
BlockNum=BlockNum % 10;
ReqParams->AsciiBlk[4]=(BlockNum / 1)+0x30;
ReqParams->A=0x41; // 'A'
IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqFunStartUploadParams);
Result=isoExchangeBuffer(0,IsoSize);
// Get Upload Infos (only ID now)
if (Result==0)
{
if (Answer->Error==0)
Upload_ID=ResParams->Upload_ID;
else
Result=CpuError(SwapWord(Answer->Error));
};
//------------------------------------------------------------->StartUpload
if (Result==0)
{
//<--------------------------------------------------------FirstUpload
PReqFunUploadParams ReqParams;
PResFunUploadParams ResParams;
PResFunUploadDataHeaderFirst ResDataHeader;
pbyte Source;
pbyte Target;
int Size;
// Setup pointers (note : PDUH_out and PDU.Payload are the same pointer)
ReqParams=PReqFunUploadParams(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
// First upload pdu consists of params, block info header, data.
ResParams=PResFunUploadParams(pbyte(Answer)+ResHeaderSize23);
ResDataHeader=PResFunUploadDataHeaderFirst(pbyte(ResParams)+sizeof(TResFunUploadParams));
if (Full)
Source=pbyte(ResDataHeader)+4; // skip only the mini header
else
Source=pbyte(ResDataHeader)+sizeof(TResFunUploadDataHeaderFirst); // not full : skip the data header
// Init Header
PDUH_out->P=0x32; // Always 0x32
PDUH_out->PDUType=PduType_request; // 0x01
PDUH_out->AB_EX=0x0000; // Always 0x0000
PDUH_out->Sequence=GetNextWord(); // AutoInc
PDUH_out->ParLen=SwapWord(sizeof(TReqFunUploadParams));// params size
PDUH_out->DataLen=0x0000; // No data
// Init Params
ReqParams->FunUpld=pduUpload;
ReqParams->Uk6[0]=0x00;
ReqParams->Uk6[1]=0x00;
ReqParams->Uk6[2]=0x00;
ReqParams->Uk6[3]=0x00;
ReqParams->Uk6[4]=0x00;
ReqParams->Uk6[5]=0x00;
ReqParams->Upload_ID=Upload_ID; // At begining is 0) we will put upload id incoming from plc
IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqFunUploadParams);
Result=isoExchangeBuffer(0,IsoSize);
// Get Upload Infos (only ID now)
if (Result==0)
{
if (Answer->Error==0)
{
Done=ResParams->EoU==0;
if (Full)
Size=SwapWord(Answer->DataLen)-4; // Full data Size
else
Size=SwapWord(Answer->DataLen)-sizeof(TResFunUploadDataHeaderFirst); // Size of this data slice
BlockLength=SwapWord(ResDataHeader->MC7Len); // Full block size in byte
Target=pbyte(&opData)+Offset;
memcpy(Target, Source, Size);
Offset+=Size;
}
else
Result=errCliUploadSequenceFailed;
};
//-------------------------------------------------------->FirstUpload
while (!Done && (Result==0))
{
//<----------------------------------------------------NextUpload
PReqFunUploadParams ReqParams;
PResFunUploadParams ResParams;
PResFunUploadDataHeaderNext ResDataHeader;
pbyte Source;
pbyte Target;
int Size;
// Setup pointers (note : PDUH_out and PDU.Payload are the same pointer)
ReqParams=PReqFunUploadParams(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
// Next upload pdu consists of params, small info header, data.
ResParams=PResFunUploadParams(pbyte(Answer)+ResHeaderSize23);
ResDataHeader=PResFunUploadDataHeaderNext(pbyte(ResParams)+sizeof(TResFunUploadParams));
Source=pbyte(ResDataHeader)+sizeof(TResFunUploadDataHeaderNext);
// Init Header
PDUH_out->P=0x32; // Always 0x32
PDUH_out->PDUType=PduType_request; // 0x01
PDUH_out->AB_EX=0x0000; // Always 0x0000
PDUH_out->Sequence=GetNextWord(); // AutoInc
PDUH_out->ParLen=SwapWord(sizeof(TReqFunUploadParams));// params size
PDUH_out->DataLen=0x0000; // No data
// Init Params
ReqParams->FunUpld=pduUpload;
ReqParams->Uk6[0]=0x00;
ReqParams->Uk6[1]=0x00;
ReqParams->Uk6[2]=0x00;
ReqParams->Uk6[3]=0x00;
ReqParams->Uk6[4]=0x00;
ReqParams->Uk6[5]=0x00;
ReqParams->Upload_ID=Upload_ID; // At begining is 0) we will put upload id incoming from plc
IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqFunUploadParams);
Result=isoExchangeBuffer(0,IsoSize);
// Get Upload Infos (only ID now)
if (Result==0)
{
if (Answer->Error==0)
{
Done=ResParams->EoU==0;
Size=SwapWord(Answer->DataLen)-sizeof(TResFunUploadDataHeaderNext); // Size of this data slice
Target=pbyte(&opData)+Offset;
memcpy(Target, Source, Size);
Offset+=Size;
}
else
Result=errCliUploadSequenceFailed;
};
//---------------------------------------------------->NextUpload
}
if (Result==0)
{
//<----------------------------------------------------EndUpload;
PReqFunEndUploadParams ReqParams;
PResFunEndUploadParams ResParams;
// Setup pointers (note : PDUH_out and PDU.Payload are the same pointer)
ReqParams=PReqFunEndUploadParams(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
ResParams=PResFunEndUploadParams(pbyte(Answer)+ResHeaderSize23);
// Init Header
PDUH_out->P=0x32; // Always 0x32
PDUH_out->PDUType=PduType_request; // 0x01
PDUH_out->AB_EX=0x0000; // Always 0x0000
PDUH_out->Sequence=GetNextWord(); // AutoInc
PDUH_out->ParLen=SwapWord(sizeof(TReqFunEndUploadParams));// params size
PDUH_out->DataLen=0x0000; // No data
// Init Params
ReqParams->FunEUpld=pduEndUpload;
ReqParams->Uk6[0]=0x00;
ReqParams->Uk6[1]=0x00;
ReqParams->Uk6[2]=0x00;
ReqParams->Uk6[3]=0x00;
ReqParams->Uk6[4]=0x00;
ReqParams->Uk6[5]=0x00;
ReqParams->Upload_ID=Upload_ID; // At begining is 0) we will put upload id incoming from plc
IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqFunEndUploadParams);
Result=isoExchangeBuffer(0,IsoSize);
// Get EndUpload Result
if (Result==0)
{
if ((Answer->Error!=0) || (ResParams->FunEUpld!=pduEndUpload))
Result=errCliUploadSequenceFailed;
};
//---------------------------------------------------->EndUpload;
}
};
*Job.pAmount=0;
if (Result==0)
{
if (Full)
{
opSize=int(Offset);
if (opSize<78)
Result=errCliInvalidDataSizeRecvd;
}
else
{
opSize=BlockLength;
if (opSize<1)
Result=errCliInvalidDataSizeRecvd;
};
if (Result==0)
{
// Checks user space
if (Job.Amount override if romerror
Result=errCliPartialDataRead;
};
};
return Result;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opDownload()
{
PS7CompactBlockInfo Info;
PS7BlockFooter Footer;
int BlockNum, StoreBlockNum, BlockAmount;
int BlockSize, BlockSizeLd;
int BlockType, Remainder;
int Result, IsoSize;
bool Done = false;
uintptr_t Offset;
BlockAmount=Job.Amount;
BlockNum =Job.Number;
Result=CheckBlock(-1,-1,&opData,BlockAmount);
if (Result==0)
{
Info=PS7CompactBlockInfo(&opData);
// Gets blocktype
BlockType=SubBlockToBlock(Info->SubBlkType);
if (BlockNum>=0)
Info->BlkNum=SwapWord(BlockNum); // change the number
else
BlockNum=SwapWord(Info->BlkNum); // use the header's number
BlockSizeLd=BlockAmount; // load mem needed for this block
BlockSize =SwapWord(Info->MC7Len); // net size
Footer=PS7BlockFooter(pbyte(&opData)+BlockSizeLd-sizeof(TS7BlockFooter));
Footer->Chksum=0x0000;
Offset=0;
Remainder=BlockAmount;
//<---------------------------------------------- Start Download request
PReqStartDownloadParams ReqParams;
PResStartDownloadParams ResParams;
PS7ResHeader23 Answer;
// Setup pointers (note : PDUH_out and PDU.Payload are the same pointer)
ReqParams=PReqStartDownloadParams(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
Answer =PS7ResHeader23(&PDU.Payload);
ResParams=PResStartDownloadParams(pbyte(Answer)+ResHeaderSize23);
// Init Header
PDUH_out->P=0x32; // Always 0x32
PDUH_out->PDUType=PduType_request; // 0x01
PDUH_out->AB_EX=0x0000; // Always 0x0000
PDUH_out->Sequence=GetNextWord(); // AutoInc
PDUH_out->ParLen=SwapWord(sizeof(TReqStartDownloadParams));
PDUH_out->DataLen=0x0000; // No data
// Init Params
ReqParams->FunSDwnld = pduReqDownload;
ReqParams->Uk6[0]=0x00;
ReqParams->Uk6[1]=0x01;
ReqParams->Uk6[2]=0x00;
ReqParams->Uk6[3]=0x00;
ReqParams->Uk6[4]=0x00;
ReqParams->Uk6[5]=0x00;
ReqParams->Dwnld_ID=0x00;
ReqParams->Len_1 =0x09;
ReqParams->Prefix=0x5F;
ReqParams->BlkPrfx=0x30;
ReqParams->BlkType=BlockType;
StoreBlockNum=BlockNum;
ReqParams->AsciiBlk[0]=(BlockNum / 10000)+0x30;
BlockNum=BlockNum % 10000;
ReqParams->AsciiBlk[1]=(BlockNum / 1000)+0x30;
BlockNum=BlockNum % 1000;
ReqParams->AsciiBlk[2]=(BlockNum / 100)+0x30;
BlockNum=BlockNum % 100;
ReqParams->AsciiBlk[3]=(BlockNum / 10)+0x30;
BlockNum=BlockNum % 10;
ReqParams->AsciiBlk[4]=(BlockNum / 1)+0x30;
ReqParams->P =0x50;
ReqParams->Len_2=0x0D;
ReqParams->Uk1 =0x31; // '1'
BlockNum=StoreBlockNum;
// Load memory
ReqParams->AsciiLoad[0]=(BlockSizeLd / 100000)+0x30;
BlockSizeLd=BlockSizeLd % 100000;
ReqParams->AsciiLoad[1]=(BlockSizeLd / 10000)+0x30;
BlockSizeLd=BlockSizeLd % 10000;
ReqParams->AsciiLoad[2]=(BlockSizeLd / 1000)+0x30;
BlockSizeLd=BlockSizeLd % 1000;
ReqParams->AsciiLoad[3]=(BlockSizeLd / 100)+0x30;
BlockSizeLd=BlockSizeLd % 100;
ReqParams->AsciiLoad[4]=(BlockSizeLd / 10)+0x30;
BlockSizeLd=BlockSizeLd % 10;
ReqParams->AsciiLoad[5]=(BlockSizeLd / 1)+0x30;
// MC7 memory
ReqParams->AsciiMC7[0]=(BlockSize / 100000)+0x30;
BlockSize=BlockSize % 100000;
ReqParams->AsciiMC7[1]=(BlockSize / 10000)+0x30;
BlockSize=BlockSize % 10000;
ReqParams->AsciiMC7[2]=(BlockSize / 1000)+0x30;
BlockSize=BlockSize % 1000;
ReqParams->AsciiMC7[3]=(BlockSize / 100)+0x30;
BlockSize=BlockSize % 100;
ReqParams->AsciiMC7[4]=(BlockSize / 10)+0x30;
BlockSize=BlockSize % 10;
ReqParams->AsciiMC7[5]=(BlockSize / 1)+0x30;
IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqStartDownloadParams);
Result=isoExchangeBuffer(0,IsoSize);
// Get Result
if (Result==0)
{
if (SwapWord(Answer->Error)!=Code7NeedPassword)
{
if ((Answer->Error!=0) || (*ResParams!=pduReqDownload))
Result=errCliDownloadSequenceFailed;
}
else
Result=errCliNeedPassword;
}
//----------------------------------------------> Start Download request
if (Result==0)
{
do
{
//<-------------------------------- Download sequence (PLC requests)
PReqDownloadParams ReqParams;
PS7ResHeader23 Answer;
PResDownloadParams ResParams;
PResDownloadDataHeader ResData;
int Slice, Size, MaxSlice;
word Sequence;
pbyte Source;
pbyte Target;
ReqParams=PReqDownloadParams(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
Answer =PS7ResHeader23(&PDU.Payload);
ResParams=PResDownloadParams(pbyte(Answer)+ResHeaderSize23);
ResData =PResDownloadDataHeader(pbyte(ResParams)+sizeof(TResDownloadParams));
Target =pbyte(ResData)+sizeof(TResDownloadDataHeader);
Source =pbyte(&opData)+Offset;
Result=isoRecvBuffer(0,Size);
if (Result==0)
{
if ((u_int(Size)>sizeof(TS7ReqHeader)) && (ReqParams->Fun==pduDownload))
{
Sequence=PDUH_out->Sequence;
// Max data slice that we can fit in this pdu
MaxSlice=PDULength-ResHeaderSize23-sizeof(TResDownloadParams)-sizeof(TResDownloadDataHeader);
Slice=Remainder;
if (Slice>MaxSlice)
Slice=MaxSlice;
Remainder-=Slice;
Offset+=Slice;
Done=Remainder<=0;
// Init Answer
Answer->P=0x32;
Answer->PDUType=PduType_response;
Answer->AB_EX=0x0000;
Answer->Sequence=Sequence;
Answer->ParLen =SwapWord(sizeof(TResDownloadParams));
Answer->DataLen=SwapWord(word(sizeof(TResDownloadDataHeader))+Slice);
Answer->Error =0x0000;
// Init Params
ResParams->FunDwnld=pduDownload;
if (Remainder>0)
ResParams->EoS=0x01;
else
ResParams->EoS=0x00;
// Init Data
ResData->DataLen=SwapWord(Slice);
ResData->FB_00=0xFB00;
memcpy(Target, Source, Slice);
// Send the slice
IsoSize=ResHeaderSize23+sizeof(TResDownloadParams)+sizeof(TResDownloadDataHeader)+Slice;
Result=isoSendBuffer(0,IsoSize);
}
else
Result=errCliDownloadSequenceFailed;
};
//--------------------------------> Download sequence (PLC requests)
}
while (!Done && (Result==0));
if (Result==0)
{
//<-------------------------------------------Perform Download Ended
PReqDownloadParams ReqParams;
PS7ResHeader23 Answer;
PResEndDownloadParams ResParams;
int Size;
word Sequence;
ReqParams=PReqDownloadParams(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
Answer =PS7ResHeader23(&PDU.Payload);
ResParams=PResEndDownloadParams(pbyte(Answer)+ResHeaderSize23);
Result=isoRecvBuffer(0,Size);
if (Result==0)
{
if ((u_int(Size)>sizeof(TS7ReqHeader)) && (ReqParams->Fun==pduDownloadEnded))
{
Sequence=PDUH_out->Sequence;
// Init Answer
Answer->P=0x32;
Answer->PDUType=PduType_response;
Answer->AB_EX=0x0000;
Answer->Sequence=Sequence;
Answer->ParLen =SwapWord(sizeof(TResEndDownloadParams));
Answer->DataLen=0x0000;
Answer->Error =0x0000;
// Init Params
*ResParams=pduDownloadEnded;
IsoSize=ResHeaderSize23+sizeof(TResEndDownloadParams);
Result=isoSendBuffer(0,IsoSize);
}
else
Result=errCliDownloadSequenceFailed;
};
//------------------------------------------->Perform Download Ended
if (Result==0)
{
//<----------------------------------- Insert block into the unit
PReqControlBlockParams ReqParams;
PS7ResHeader23 Answer;
pbyte ResParams;
// Setup pointers (note : PDUH_out and PDU.Payload are the same pointer)
ReqParams=PReqControlBlockParams(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
Answer=PS7ResHeader23(&PDU.Payload);
ResParams=pbyte(Answer)+ResHeaderSize23;
// Init Header
PDUH_out->P=0x32; // Always 0x32
PDUH_out->PDUType=PduType_request; // 0x01
PDUH_out->AB_EX=0x0000; // Always 0x0000
PDUH_out->Sequence=GetNextWord(); // AutoInc
PDUH_out->ParLen=SwapWord(sizeof(TReqControlBlockParams));
PDUH_out->DataLen=0x0000; // No data
// Init Params
ReqParams->Fun = pduControl;
ReqParams->Uk7[0]=0x00;
ReqParams->Uk7[1]=0x00;
ReqParams->Uk7[2]=0x00;
ReqParams->Uk7[3]=0x00;
ReqParams->Uk7[4]=0x00;
ReqParams->Uk7[5]=0x00;
ReqParams->Uk7[6]=0xFD;
ReqParams->Len_1 =SwapWord(0x0A);
ReqParams->NumOfBlocks=0x01;
ReqParams->ByteZero =0x00;
ReqParams->AsciiZero =0x30;
ReqParams->BlkType=BlockType;
ReqParams->AsciiBlk[0]=(BlockNum / 10000)+0x30;
BlockNum=BlockNum % 10000;
ReqParams->AsciiBlk[1]=(BlockNum / 1000)+0x30;
BlockNum=BlockNum % 1000;
ReqParams->AsciiBlk[2]=(BlockNum / 100)+0x30;
BlockNum=BlockNum % 100;
ReqParams->AsciiBlk[3]=(BlockNum / 10)+0x30;
BlockNum=BlockNum % 10;
ReqParams->AsciiBlk[4]=(BlockNum / 1)+0x30;
ReqParams->SFun =SFun_Insert;
ReqParams->Len_2=0x05;
ReqParams->Cmd[0]='_';
ReqParams->Cmd[1]='I';
ReqParams->Cmd[2]='N';
ReqParams->Cmd[3]='S';
ReqParams->Cmd[4]='E';
IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqControlBlockParams);
Result=isoExchangeBuffer(0,IsoSize);
if (Result==0)
{
if ((Answer->Error!=0) || (*ResParams!=pduControl))
Result=errCliInsertRefused;
};
//-----------------------------------> Insert block into the unit
}
};
};
};
return Result;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opDelete()
{
PReqControlBlockParams ReqParams;
PS7ResHeader23 Answer;
pbyte ResParams;
int IsoSize, BlockType, BlockNum, Result;
BlockType=Job.Area;
BlockNum =Job.Number;
// Setup pointers (note : PDUH_out and PDU.Payload are the same pointer)
ReqParams=PReqControlBlockParams(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
Answer =PS7ResHeader23(&PDU.Payload);
ResParams=pbyte(Answer)+ResHeaderSize23;
// Init Header
PDUH_out->P=0x32; // Always 0x32
PDUH_out->PDUType=PduType_request; // 0x01
PDUH_out->AB_EX=0x0000; // Always 0x0000
PDUH_out->Sequence=GetNextWord(); // AutoInc
PDUH_out->ParLen=SwapWord(sizeof(TReqControlBlockParams));
PDUH_out->DataLen=0x0000; // No data
// Init Params
ReqParams->Fun = pduControl;
ReqParams->Uk7[0]=0x00;
ReqParams->Uk7[1]=0x00;
ReqParams->Uk7[2]=0x00;
ReqParams->Uk7[3]=0x00;
ReqParams->Uk7[4]=0x00;
ReqParams->Uk7[5]=0x00;
ReqParams->Uk7[6]=0xFD;
ReqParams->Len_1 =SwapWord(0x0A);
ReqParams->NumOfBlocks=0x01;
ReqParams->ByteZero =0x00;
ReqParams->AsciiZero =0x30;
ReqParams->BlkType=BlockType;
ReqParams->AsciiBlk[0]=(BlockNum / 10000)+0x30;
BlockNum=BlockNum % 10000;
ReqParams->AsciiBlk[1]=(BlockNum / 1000)+0x30;
BlockNum=BlockNum % 1000;
ReqParams->AsciiBlk[2]=(BlockNum / 100)+0x30;
BlockNum=BlockNum % 100;
ReqParams->AsciiBlk[3]=(BlockNum / 10)+0x30;
BlockNum=BlockNum % 10;
ReqParams->AsciiBlk[4]=(BlockNum / 1)+0x30;
ReqParams->SFun =SFun_Delete;
ReqParams->Len_2=0x05;
ReqParams->Cmd[0]='_';
ReqParams->Cmd[1]='D';
ReqParams->Cmd[2]='E';
ReqParams->Cmd[3]='L';
ReqParams->Cmd[4]='E';
IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqControlBlockParams);
Result=isoExchangeBuffer(0,IsoSize);
if (Result==0)
{
if (SwapWord(Answer->Error)!=Code7NeedPassword)
{
if ((Answer->Error!=0) || (*ResParams!=pduControl))
Result=errCliDeleteRefused;
}
else
Result=errCliNeedPassword;
}
return Result;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opReadSZL()
{
PS7Answer17 Answer;
PReqFunReadSZLFirst ReqParamsFirst;
PReqFunReadSZLNext ReqParamsNext;
PS7ReqSZLData ReqDataFirst;
PS7ReqSZLData ReqDataNext;
PS7ResParams7 ResParams;
PS7ResSZLDataFirst ResDataFirst;
PS7ResSZLDataNext ResDataNext;
PSZL_HEADER Header;
PS7SZLList Target;
pbyte PDataFirst;
pbyte PDataNext;
word ID, Index;
int IsoSize, DataSize, DataSZL, Result;
bool First, Done;
bool NoRoom = false;
uintptr_t Offset =0;
byte Seq_in =0x00;
ID=Job.ID;
Index=Job.Index;
opSize=0;
// Setup pointers (note : PDUH_out and PDU.Payload are the same pointer)
ReqParamsFirst=PReqFunReadSZLFirst(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
ReqParamsNext =PReqFunReadSZLNext(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
ReqDataFirst =PS7ReqSZLData(pbyte(ReqParamsFirst)+sizeof(TReqFunReadSZLFirst));
ReqDataNext =PS7ReqSZLData(pbyte(ReqParamsNext)+sizeof(TReqFunReadSZLNext));
Answer =PS7Answer17(&PDU.Payload);
ResParams =PS7ResParams7(pbyte(Answer)+ResHeaderSize17);
ResDataFirst =PS7ResSZLDataFirst(pbyte(ResParams)+sizeof(TS7Params7));
ResDataNext =PS7ResSZLDataNext(pbyte(ResParams)+sizeof(TS7Params7));
PDataFirst =pbyte(ResDataFirst)+8; // skip header
PDataNext =pbyte(ResDataNext)+4; // skip header
Header =PSZL_HEADER(&opData);
First=true;
Done =false;
do
{
//<------------------------------------------------------- read slices
if (First)
{
//<-------------------------------------------------- prepare first
DataSize=sizeof(TS7ReqSZLData);
// Fill Header
PDUH_out->P=0x32; // Always 0x32
PDUH_out->PDUType=PduType_userdata; // 0x07
PDUH_out->AB_EX=0x0000; // Always 0x0000
PDUH_out->Sequence=GetNextWord(); // AutoInc
PDUH_out->ParLen=SwapWord(sizeof(TReqFunReadSZLFirst)); // 8 bytes params
PDUH_out->DataLen=SwapWord(DataSize); // 8/4 bytes data
// Fill Params
ReqParamsFirst->Head[0]=0x00;
ReqParamsFirst->Head[1]=0x01;
ReqParamsFirst->Head[2]=0x12;
ReqParamsFirst->Plen =0x04;
ReqParamsFirst->Uk =0x11;
ReqParamsFirst->Tg =grSZL;
ReqParamsFirst->SubFun =SFun_ReadSZL; //0x03
ReqParamsFirst->Seq =Seq_in;
// Fill Data
ReqDataFirst->Ret =0xFF;
ReqDataFirst->TS =TS_ResOctet;
ReqDataFirst->DLen =SwapWord(0x0004);
ReqDataFirst->ID =SwapWord(ID);
ReqDataFirst->Index =SwapWord(Index);
IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqFunReadSZLFirst)+DataSize;
//--------------------------------------------------> prepare first
}
else
{
//<-------------------------------------------------- prepare next
DataSize=sizeof(TS7ReqSZLData)-4;
// Fill Header
PDUH_out->P=0x32; // Always 0x32
PDUH_out->PDUType=PduType_userdata; // 0x07
PDUH_out->AB_EX=0x0000; // Always 0x0000
PDUH_out->Sequence=GetNextWord(); // AutoInc
PDUH_out->ParLen=SwapWord(sizeof(TReqFunReadSZLNext)); // 8 bytes params
PDUH_out->DataLen=SwapWord(DataSize);// 8/4 bytes data
// Fill Params
ReqParamsNext->Head[0]=0x00;
ReqParamsNext->Head[1]=0x01;
ReqParamsNext->Head[2]=0x12;
ReqParamsNext->Plen =0x08;
ReqParamsNext->Uk =0x12;
ReqParamsNext->Tg =grSZL;
ReqParamsNext->SubFun =SFun_ReadSZL;
ReqParamsNext->Seq =Seq_in;
ReqParamsNext->Rsvd =0x0000;
ReqParamsNext->ErrNo =0x0000;
// Fill Data
ReqDataNext->Ret =0x0A;
ReqDataNext->TS =0x00;
ReqDataNext->DLen =0x0000;
ReqDataNext->ID =0x0000;
ReqDataNext->Index =0x0000;
IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqFunReadSZLNext)+DataSize;
//--------------------------------------------------> prepare next
}
Result=isoExchangeBuffer(0,IsoSize);
// Get Data
if (Result==0)
{
if (First)
{
//<------------------------------------------ get data first
if (ResParams->Err==0)
{
if (ResDataFirst->Ret==0xFF) // <-- 0xFF means Result OK
{
// Gets Amount of this slice
DataSZL=SwapWord(ResDataFirst->DLen)-4;// Skips extra params (ID, Index ...)
// Gets end of Sequence Flag
Done=(ResParams->resvd & 0xFF00) == 0; // Low order byte = 0x00 => the sequence is done
// Gets Unit's function sequence
Seq_in=ResParams->Seq;
Target=PS7SZLList(pbyte(&opData)+Offset);
memcpy(Target, PDataFirst, DataSZL);
Offset+=DataSZL;
}
else
Result=CpuError(ResDataFirst->Ret);
}
else
Result=CpuError(ResDataFirst->Ret);
//------------------------------------------> get data first
}
else
{
//<------------------------------------------ get data next
if (ResParams->Err==0)
{
if (ResDataNext->Ret==0xFF) // <-- 0xFF means Result OK
{
// Gets Amount of this slice
DataSZL=SwapWord(ResDataNext->DLen);
// Gets end of Sequence Flag
Done=(ResParams->resvd & 0xFF00) == 0; // Low order byte = 0x00 => the sequence is done
// Gets Unit's function sequence
Seq_in=ResParams->Seq;
Target=PS7SZLList(pbyte(&opData)+Offset);
memcpy(Target, PDataNext, DataSZL);
Offset+=DataSZL;
}
else
Result=CpuError(ResDataNext->Ret);
}
else
Result=CpuError(ResDataNext->Ret);
//------------------------------------------> get data next
}
First=false;
}
//-------------------------------------------------------> read slices
}
while ((!Done) && (Result==0));
// Check errors and adjust header
if (Result==0)
{
// Adjust big endian header
Header->LENTHDR=SwapWord(Header->LENTHDR);
Header->N_DR =SwapWord(Header->N_DR);
opSize=int(Offset);
if (Job.IParam==1) // if 1 data has to be copied into user buffer
{
// Check buffer size
if (opSize>Job.Amount)
{
opSize=Job.Amount;
NoRoom=true;
}
memcpy(Job.pData, &opData, opSize);
*Job.pAmount=opSize;
};
};
if ((Result==0)&& NoRoom)
Result=errCliBufferTooSmall;
return Result;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opReadSZLList()
{
PS7SZLList usrSZLList, opDataList;
int ItemsCount, ItemsCount_in, c, Result;
bool NoRoom = false;
Job.ID =0x0000;
Job.Index =0x0000;
Job.IParam =0;
ItemsCount_in=Job.Amount; // stores the room
Job.Amount =sizeof(opData); // read into the internal buffer
Result =opReadSZL();
if (Result==0)
{
opDataList=PS7SZLList(&opData); // Source
usrSZLList=PS7SZLList(Job.pData); // Target
ItemsCount=(opSize-sizeof(SZL_HEADER)) / 2;
// Check input size
if (ItemsCount>ItemsCount_in)
{
ItemsCount=ItemsCount_in; // Trim itemscount
NoRoom=true;
}
for (c = 0; c < ItemsCount; c++)
usrSZLList->List[c]=SwapWord(opDataList->List[c]);
*Job.pAmount=ItemsCount;
}
else
*Job.pAmount=0;
if ((Result==0) && NoRoom)
Result=errCliBufferTooSmall;
return Result;
}
//---------------------------------------------------------------------------
byte TSnap7MicroClient::BCDtoByte(byte B)
{
return ((B >> 4) * 10) + (B & 0x0F);
}
//---------------------------------------------------------------------------
byte TSnap7MicroClient::WordToBCD(word Value)
{
return ((Value / 10) << 4) | (Value % 10);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opGetDateTime()
{
PTimeStruct DateTime;
PReqFunDateTime ReqParams;
PReqDataGetDateTime ReqData;
PS7ResParams7 ResParams;
PResDataGetTime ResData;
PS7ResHeader17 Answer;
int IsoSize, Result;
word AYear;
// Setup pointers (note : PDUH_out and PDU.Payload are the same pointer)
ReqParams=PReqFunDateTime(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
ReqData =PReqDataGetDateTime(pbyte(ReqParams)+sizeof(TReqFunDateTime));
Answer =PS7ResHeader17(&PDU.Payload);
ResParams=PS7ResParams7(pbyte(Answer)+ResHeaderSize17);
ResData =PResDataGetTime(pbyte(ResParams)+sizeof(TS7Params7));
DateTime =PTimeStruct(Job.pData);
// Fill Header
PDUH_out->P=0x32; // Always 0x32
PDUH_out->PDUType=PduType_userdata; // 0x07
PDUH_out->AB_EX=0x0000; // Always 0x0000
PDUH_out->Sequence=GetNextWord(); // AutoInc
PDUH_out->ParLen=SwapWord(sizeof(TReqFunDateTime)); // 8 bytes params
PDUH_out->DataLen=SwapWord(sizeof(TReqDataGetDateTime)); // 4 bytes data
// Fill params (mostly constants)
ReqParams->Head[0]=0x00;
ReqParams->Head[1]=0x01;
ReqParams->Head[2]=0x12;
ReqParams->Plen =0x04;
ReqParams->Uk =0x11;
ReqParams->Tg =grClock;
ReqParams->SubFun =SFun_ReadClock;
ReqParams->Seq =0x00;
// Fill Data
*ReqData =0x0000000A;
IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqFunDateTime)+sizeof(TReqDataGetDateTime);
Result=isoExchangeBuffer(0,IsoSize);
// Get Data
if (Result==0)
{
if (ResParams->Err==0)
{
if (ResData->RetVal==0xFF) // <-- 0xFF means Result OK
{
// Decode Plc Date and Time
AYear=BCDtoByte(ResData->Time[0]);
if (AYear<90)
AYear=AYear+100;
DateTime->tm_year=AYear;
DateTime->tm_mon =BCDtoByte(ResData->Time[1])-1;
DateTime->tm_mday=BCDtoByte(ResData->Time[2]);
DateTime->tm_hour=BCDtoByte(ResData->Time[3]);
DateTime->tm_min =BCDtoByte(ResData->Time[4]);
DateTime->tm_sec =BCDtoByte(ResData->Time[5]);
DateTime->tm_wday=(ResData->Time[7] & 0x0F)-1;
}
else
Result=CpuError(ResData->RetVal);
}
else
Result=CpuError(ResData->RetVal);
}
return Result;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opSetDateTime()
{
PTimeStruct DateTime;
PReqFunDateTime ReqParams;
PReqDataSetTime ReqData;
PS7ResParams7 ResParams;
PS7ResHeader17 Answer;
word AYear;
int IsoSize, Result;
// Setup pointers (note : PDUH_out and PDU.Payload are the same pointer)
ReqParams=PReqFunDateTime(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
ReqData =PReqDataSetTime(pbyte(ReqParams)+sizeof(TReqFunDateTime));
Answer =PS7ResHeader17(&PDU.Payload);
ResParams=PS7ResParams7(pbyte(Answer)+ResHeaderSize17);
DateTime =PTimeStruct(Job.pData);
// Fill Header
PDUH_out->P=0x32; // Always 0x32
PDUH_out->PDUType=PduType_userdata; // 0x07
PDUH_out->AB_EX=0x0000; // Always 0x0000
PDUH_out->Sequence=GetNextWord(); // AutoInc
PDUH_out->ParLen=SwapWord(sizeof(TReqFunDateTime)); // 8 bytes params
PDUH_out->DataLen=SwapWord(sizeof(TReqDataSetTime)); // 4 bytes data
// Fill params (mostly constants)
ReqParams->Head[0]=0x00;
ReqParams->Head[1]=0x01;
ReqParams->Head[2]=0x12;
ReqParams->Plen =0x04;
ReqParams->Uk =0x11;
ReqParams->Tg =grClock;
ReqParams->SubFun =SFun_SetClock;
ReqParams->Seq =0x00;
// EncodeSiemensDateTime;
if (DateTime->tm_year<100)
AYear=DateTime->tm_year;
else
AYear=DateTime->tm_year-100;
ReqData->RetVal=0xFF;
ReqData->TSize =TS_ResOctet;
ReqData->Length=SwapWord(0x000A);
ReqData->Rsvd =0x00;
ReqData->HiYear=0x19; // *must* be 19 tough it's not the Hi part of the year...
ReqData->Time[0]=WordToBCD(AYear);
ReqData->Time[1]=WordToBCD(DateTime->tm_mon+1);
ReqData->Time[2]=WordToBCD(DateTime->tm_mday);
ReqData->Time[3]=WordToBCD(DateTime->tm_hour);
ReqData->Time[4]=WordToBCD(DateTime->tm_min);
ReqData->Time[5]=WordToBCD(DateTime->tm_sec);
ReqData->Time[6]=0;
ReqData->Time[7]=DateTime->tm_wday+1;
IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqFunDateTime)+sizeof(TReqDataSetTime);
Result=isoExchangeBuffer(0,IsoSize);
// Get Result
if (Result==0)
{
if (ResParams->Err!=0)
Result=CpuError(SwapWord(ResParams->Err));
};
return Result;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opGetOrderCode()
{
PS7OrderCode OC;
int Result;
Job.ID =0x0011;
Job.Index =0x0000;
Job.IParam =0;
Result =opReadSZL();
if (Result==0)
{
OC=PS7OrderCode(Job.pData);
memset(OC,0,sizeof(TS7OrderCode));
memcpy(OC->Code,&opData[6],20);
OC->V1=opData[opSize-3];
OC->V2=opData[opSize-2];
OC->V3=opData[opSize-1];
};
return Result;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opGetCpuInfo()
{
PS7CpuInfo Info;
int Result;
// Store Pointer
Info=PS7CpuInfo(Job.pData);
// Clear data in order to have the end of strings (\0) correctly setted
memset(Info, 0, sizeof(TS7CpuInfo));
Job.ID =0x001C;
Job.Index =0x0000;
Job.IParam=0;
Result =opReadSZL();
if (Result==0)
{
memcpy(Info->ModuleTypeName,&opData[176],32);
memcpy(Info->SerialNumber,&opData[142],24);
memcpy(Info->ASName,&opData[6],24);
memcpy(Info->Copyright,&opData[108],26);
memcpy(Info->ModuleName,&opData[40],24);
}
return Result;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opGetCpInfo()
{
PS7CpInfo Info;
int Result;
// Store Pointer
Info=PS7CpInfo(Job.pData);
memset(Info,0,sizeof(TS7CpInfo));
Job.ID =0x0131;
Job.Index =0x0001;
Job.IParam=0;
Result =opReadSZL();
if (Result==0)
{
Info->MaxPduLengt=opData[6]*256+opData[7];
Info->MaxConnections=opData[8]*256+opData[9];
Info->MaxMpiRate=DWordAt(&opData[10]);
Info->MaxBusRate=DWordAt(&opData[14]);
};
return Result;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opGetPlcStatus()
{
int *Status;
int Result;
Status =(int*)Job.pData;
Job.ID =0x0424;
Job.Index =0x0000;
Job.IParam =0;
Result =opReadSZL();
if (Result==0)
{
switch (opData[7])
{
case S7CpuStatusUnknown :
case S7CpuStatusRun :
case S7CpuStatusStop : *Status=opData[7];
break;
default :
// Since RUN status is always $08 for all CPUs and CPs, STOP status
// sometime can be coded as $03 (especially for old cpu...)
*Status=S7CpuStatusStop;
}
}
else
*Status=0;
return Result;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opPlcStop()
{
PReqFunPlcStop ReqParams;
PResFunCtrl ResParams;
PS7ResHeader23 Answer;
int IsoSize, Result;
char p_program[] = {'P','_','P','R','O','G','R','A','M'};
// Setup pointers (note : PDUH_out and PDU.Payload are the same pointer)
ReqParams=PReqFunPlcStop(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
Answer =PS7ResHeader23(&PDU.Payload);
ResParams=PResFunCtrl(pbyte(Answer)+ResHeaderSize23);
// Fill Header
PDUH_out->P=0x32; // Always 0x32
PDUH_out->PDUType=PduType_request; // 0x01
PDUH_out->AB_EX=0x0000; // Always 0x0000
PDUH_out->Sequence=GetNextWord(); // AutoInc
PDUH_out->ParLen=SwapWord(sizeof(TReqFunPlcStop));
PDUH_out->DataLen=0x0000; // No Data
// Fill Params
ReqParams->Fun=pduStop;
memset(ReqParams->Uk_5,0,5);
ReqParams->Len_2=0x09;
memcpy(ReqParams->Cmd,&p_program,9);
IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqFunPlcStop);
Result=isoExchangeBuffer(0,IsoSize);
if (Result==0)
{
if (Answer->Error!=0)
{
if (ResParams->ResFun!=pduStop)
Result=errCliCannotStopPLC;
else
if (ResParams->para ==0x07)
Result=errCliAlreadyStop;
else
Result=errCliCannotStopPLC;
};
};
return Result;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opPlcHotStart()
{
PReqFunPlcHotStart ReqParams;
PResFunCtrl ResParams;
PS7ResHeader23 Answer;
int IsoSize, Result;
char p_program[] = {'P','_','P','R','O','G','R','A','M'};
// Setup pointers (note : PDUH_out and PDU.Payload are the same pointer)
ReqParams=PReqFunPlcHotStart(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
Answer =PS7ResHeader23(&PDU.Payload);
ResParams=PResFunCtrl(pbyte(Answer)+ResHeaderSize23);
// Fill Header
PDUH_out->P=0x32; // Always 0x32
PDUH_out->PDUType=PduType_request; // 0x01
PDUH_out->AB_EX=0x0000; // Always 0x0000
PDUH_out->Sequence=GetNextWord(); // AutoInc
PDUH_out->ParLen=SwapWord(sizeof(TReqFunPlcHotStart)); // 16 bytes params
PDUH_out->DataLen=0x0000; // No Data
// Fill Params
ReqParams->Fun=pduStart;
ReqParams->Uk_7[0]=0x00;
ReqParams->Uk_7[1]=0x00;
ReqParams->Uk_7[2]=0x00;
ReqParams->Uk_7[3]=0x00;
ReqParams->Uk_7[4]=0x00;
ReqParams->Uk_7[5]=0x00;
ReqParams->Uk_7[6]=0xFD;
ReqParams->Len_1=0x0000;
ReqParams->Len_2=0x09;
memcpy(ReqParams->Cmd,&p_program,9);
IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqFunPlcHotStart);
Result=isoExchangeBuffer(0,IsoSize);
if (Result==0)
{
if ((Answer->Error!=0))
{
if ((ResParams->ResFun!=pduStart))
Result=errCliCannotStartPLC;
else
{
if (ResParams->para==0x03)
Result=errCliAlreadyRun;
else
if (ResParams->para==0x02)
Result=errCliCannotStartPLC;
else
Result=errCliCannotStartPLC;
}
}
};
return Result;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opPlcColdStart()
{
PReqFunPlcColdStart ReqParams;
PResFunCtrl ResParams;
PS7ResHeader23 Answer;
int IsoSize, Result;
char p_program[] = {'P','_','P','R','O','G','R','A','M'};
// Setup pointers (note : PDUH_out and PDU.Payload are the same pointer)
ReqParams=PReqFunPlcColdStart(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
Answer =PS7ResHeader23(&PDU.Payload);
ResParams=PResFunCtrl(pbyte(Answer)+ResHeaderSize23);
// Fill Header
PDUH_out->P=0x32; // Always 0x32
PDUH_out->PDUType=PduType_request; // 0x01
PDUH_out->AB_EX=0x0000; // Always 0x0000
PDUH_out->Sequence=GetNextWord(); // AutoInc
PDUH_out->ParLen=SwapWord(sizeof(TReqFunPlcColdStart)); // 22 bytes params
PDUH_out->DataLen=0x0000; // No Data
// Fill Params
ReqParams->Fun=pduStart;
ReqParams->Uk_7[0]=0x00;
ReqParams->Uk_7[1]=0x00;
ReqParams->Uk_7[2]=0x00;
ReqParams->Uk_7[3]=0x00;
ReqParams->Uk_7[4]=0x00;
ReqParams->Uk_7[5]=0x00;
ReqParams->Uk_7[6]=0xFD;
ReqParams->Len_1=SwapWord(0x0002);
ReqParams->SFun =SwapWord(0x4320); // Cold start
ReqParams->Len_2=0x09;
memcpy(ReqParams->Cmd,&p_program,9);
IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqFunPlcColdStart);
Result=isoExchangeBuffer(0,IsoSize);
if (Result==0)
{
if ((Answer->Error!=0))
{
if ((ResParams->ResFun!=pduStart))
Result=errCliCannotStartPLC;
else
{
if (ResParams->para==0x03)
Result=errCliAlreadyRun;
else
if (ResParams->para==0x02)
Result=errCliCannotStartPLC;
else
Result=errCliCannotStartPLC;
}
}
};
return Result;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opCopyRamToRom()
{
PReqFunCopyRamToRom ReqParams;
PResFunCtrl ResParams;
PS7ResHeader23 Answer;
int IsoSize, CurTimeout, Result;
char _modu[] = {'_','M','O','D','U'};
// Setup pointers (note : PDUH_out and PDU.Payload are the same pointer)
ReqParams=PReqFunCopyRamToRom(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
Answer =PS7ResHeader23(&PDU.Payload);
ResParams=PResFunCtrl(pbyte(Answer)+ResHeaderSize23);
// Fill Header
PDUH_out->P=0x32; // Always 0x32
PDUH_out->PDUType=PduType_request; // 0x01
PDUH_out->AB_EX=0x0000; // Always 0x0000
PDUH_out->Sequence=GetNextWord(); // AutoInc
PDUH_out->ParLen=SwapWord(sizeof(TReqFunCopyRamToRom));
PDUH_out->DataLen=0x0000; // No Data
// Fill Params
ReqParams->Fun=pduControl;
ReqParams->Uk_7[0]=0x00;
ReqParams->Uk_7[1]=0x00;
ReqParams->Uk_7[2]=0x00;
ReqParams->Uk_7[3]=0x00;
ReqParams->Uk_7[4]=0x00;
ReqParams->Uk_7[5]=0x00;
ReqParams->Uk_7[6]=0xFD;
ReqParams->Len_1=SwapWord(0x0002);
ReqParams->SFun =SwapWord(0x4550);
ReqParams->Len_2=0x05;
memcpy(ReqParams->Cmd,&_modu,5);
IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqFunCopyRamToRom);
// Changes the timeout
CurTimeout=RecvTimeout;
RecvTimeout=Job.IParam;
Result=isoExchangeBuffer(0,IsoSize);
// Restores the timeout
RecvTimeout=CurTimeout;
if (Result==0)
{
if ((Answer->Error!=0) || (ResParams->ResFun!=pduControl))
Result=errCliCannotCopyRamToRom;
}
return Result;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opCompress()
{
PReqFunCompress ReqParams;
PResFunCtrl ResParams;
PS7ResHeader23 Answer;
int IsoSize, CurTimeout, Result;
char _garb[] = {'_','G','A','R','B'};
// Setup pointers (note : PDUH_out and PDU.Payload are the same pointer)
ReqParams=PReqFunCompress(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
Answer =PS7ResHeader23(&PDU.Payload);
ResParams=PResFunCtrl(pbyte(Answer)+ResHeaderSize23);
// Fill Header
PDUH_out->P=0x32; // Always 0x32
PDUH_out->PDUType=PduType_request; // 0x01
PDUH_out->AB_EX=0x0000; // Always 0x0000
PDUH_out->Sequence=GetNextWord(); // AutoInc
PDUH_out->ParLen=SwapWord(sizeof(TReqFunCompress));
PDUH_out->DataLen=0x0000; // No Data
// Fill Params
ReqParams->Fun=pduControl;
ReqParams->Uk_7[0]=0x00;
ReqParams->Uk_7[1]=0x00;
ReqParams->Uk_7[2]=0x00;
ReqParams->Uk_7[3]=0x00;
ReqParams->Uk_7[4]=0x00;
ReqParams->Uk_7[5]=0x00;
ReqParams->Uk_7[6]=0xFD;
ReqParams->Len_1=0x0000;
ReqParams->Len_2=0x05;
memcpy(ReqParams->Cmd,&_garb,5);
IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqFunCompress);
// Changes the timeout
CurTimeout=RecvTimeout;
RecvTimeout=Job.IParam;
Result=isoExchangeBuffer(0,IsoSize);
// Restores the timeout
RecvTimeout=CurTimeout;
if (Result==0)
{
if (((Answer->Error!=0) || (ResParams->ResFun!=pduControl)))
Result=errCliCannotCompress;
}
return Result;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opGetProtection()
{
PS7Protection Info, usrInfo;
int Result;
// Store Pointer
usrInfo=PS7Protection(Job.pData);
memset(usrInfo, 0, sizeof(TS7Protection));
Job.ID =0x0232;
Job.Index =0x0004;
Job.IParam=0; // No copy in Usr Data pointed by Job.pData
Result =opReadSZL();
if (Result==0)
{
Info=PS7Protection(pbyte(&opData)+6);
usrInfo->sch_schal=SwapWord(Info->sch_schal);
usrInfo->sch_par =SwapWord(Info->sch_par);
usrInfo->sch_rel =SwapWord(Info->sch_rel);
usrInfo->bart_sch =SwapWord(Info->bart_sch);
usrInfo->anl_sch =SwapWord(Info->anl_sch);
}
return Result;
}
//******************************************************************************
// NOTE
// PASSWORD HACKING IS VERY FAR FROM THE AIM OF THIS PROJECT
// NEXT FUNCTION ONLY ENCODES THE ASCII PASSWORD TO BE DOWNLOADED IN THE PLC.
//
// MOREOVER **YOU NEED TO KNOW** THE CORRECT PASSWORD TO MEET THE CPU
// SECURITY LEVEL
//******************************************************************************
int TSnap7MicroClient::opSetPassword()
{
PReqFunSecurity ReqParams;
PReqDataSecurity ReqData;
PResParamsSecurity ResParams;
PS7ResHeader23 Answer;
int c, IsoSize, Result;
// Setup pointers (note : PDUH_out and PDU.Payload are the same pointer)
ReqParams=PReqFunSecurity(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
ReqData =PReqDataSecurity(pbyte(ReqParams)+sizeof(TReqFunSecurity));
Answer =PS7ResHeader23(&PDU.Payload);
ResParams=PResParamsSecurity(pbyte(Answer)+ResHeaderSize17);
// Fill Header
PDUH_out->P=0x32; // Always 0x32
PDUH_out->PDUType=PduType_userdata; // 0x07
PDUH_out->AB_EX=0x0000; // Always 0x0000
PDUH_out->Sequence=GetNextWord(); // AutoInc
PDUH_out->ParLen =SwapWord(sizeof(TReqFunSecurity));
PDUH_out->DataLen=SwapWord(sizeof(TReqDataSecurity));
// Fill params (mostly constants)
ReqParams->Head[0]=0x00;
ReqParams->Head[1]=0x01;
ReqParams->Head[2]=0x12;
ReqParams->Plen =0x04;
ReqParams->Uk =0x11;
ReqParams->Tg =grSecurity;
ReqParams->SubFun =SFun_EnterPwd;
ReqParams->Seq =0x00;
// Fill Data
ReqData->Ret =0xFF;
ReqData->TS =TS_ResOctet;
ReqData->DLen =SwapWord(0x0008); // 8 bytes data : password
// Encode the password
ReqData->Pwd[0]=opData[0] ^ 0x55;
ReqData->Pwd[1]=opData[1] ^ 0x55;
for (c = 2; c < 8; c++){
ReqData->Pwd[c]=opData[c] ^ 0x55 ^ ReqData->Pwd[c-2];
};
IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqFunSecurity)+sizeof(TReqDataSecurity);
Result=isoExchangeBuffer(0,IsoSize);
// Get Return
if (Result==0)
{
if (ResParams->Err!=0)
Result=CpuError(SwapWord(ResParams->Err));
};
return Result;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opClearPassword()
{
PReqFunSecurity ReqParams;
PReqDataSecurity ReqData;
PResParamsSecurity ResParams;
PS7ResHeader23 Answer;
int IsoSize, Result;
// Setup pointers (note : PDUH_out and PDU.Payload are the same pointer)
ReqParams=PReqFunSecurity(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
ReqData =PReqDataSecurity(pbyte(ReqParams)+sizeof(TReqFunSecurity));
Answer =PS7ResHeader23(&PDU.Payload);
ResParams=PResParamsSecurity(pbyte(Answer)+ResHeaderSize17);
// Fill Header
PDUH_out->P=0x32; // Always 0x32
PDUH_out->PDUType=PduType_userdata; // 0x07
PDUH_out->AB_EX=0x0000; // Always 0x0000
PDUH_out->Sequence=GetNextWord(); // AutoInc
PDUH_out->ParLen =SwapWord(sizeof(TReqFunSecurity));
PDUH_out->DataLen=SwapWord(0x0004); // We need only 4 bytes
// Fill params (mostly constants)
ReqParams->Head[0]=0x00;
ReqParams->Head[1]=0x01;
ReqParams->Head[2]=0x12;
ReqParams->Plen =0x04;
ReqParams->Uk =0x11;
ReqParams->Tg =grSecurity;
ReqParams->SubFun =SFun_CancelPwd;
ReqParams->Seq =0x00;
// Fill Data
ReqData->Ret =0x0A;
ReqData->TS =0x00;
ReqData->DLen =0x0000;
IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqFunSecurity)+4;
Result=isoExchangeBuffer(0,IsoSize);
// Get Return
if (Result==0)
{
if (ResParams->Err!=0)
Result=CpuError(SwapWord(ResParams->Err));
};
return Result;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::CpuError(int Error)
{
switch(Error)
{
case 0 : return 0;
case Code7AddressOutOfRange : return errCliAddressOutOfRange;
case Code7InvalidTransportSize : return errCliInvalidTransportSize;
case Code7WriteDataSizeMismatch : return errCliWriteDataSizeMismatch;
case Code7ResItemNotAvailable :
case Code7ResItemNotAvailable1 : return errCliItemNotAvailable;
case Code7DataOverPDU : return errCliSizeOverPDU;
case Code7InvalidValue : return errCliInvalidValue;
case Code7FunNotAvailable : return errCliFunNotAvailable;
case Code7NeedPassword : return errCliNeedPassword;
case Code7InvalidPassword : return errCliInvalidPassword;
case Code7NoPasswordToSet :
case Code7NoPasswordToClear : return errCliNoPasswordToSetOrClear;
default:
return errCliFunctionRefused;
};
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::DataSizeByte(int WordLength)
{
switch (WordLength){
case S7WLBit : return 1; // S7 sends 1 byte per bit
case S7WLByte : return 1;
case S7WLChar : return 1;
case S7WLWord : return 2;
case S7WLDWord : return 4;
case S7WLInt : return 2;
case S7WLDInt : return 4;
case S7WLReal : return 4;
case S7WLCounter : return 2;
case S7WLTimer : return 2;
default : return 0;
}
}
//---------------------------------------------------------------------------
longword TSnap7MicroClient::DWordAt(void * P)
{
longword DW;
DW=*(longword*)P;
return SwapDWord(DW);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::CheckBlock(int BlockType, int BlockNum, void * pBlock, int Size)
{
PS7CompactBlockInfo Info = PS7CompactBlockInfo(pBlock);
if (BlockType>=0) // if (BlockType<0 the test is skipped
{
if ((BlockType!=Block_OB)&&(BlockType!=Block_DB)&&(BlockType!=Block_FB)&&
(BlockType!=Block_FC)&&(BlockType!=Block_SDB)&&(BlockType!=Block_SFC)&&
(BlockType!=Block_SFB))
return errCliInvalidBlockType;
}
if (BlockNum>=0) // if (BlockNum<0 the test is skipped
{
if (BlockNum>0xFFFF)
return errCliInvalidBlockNumber;
};
if (SwapDWord(Info->LenLoadMem)!=longword(Size))
return errCliInvalidBlockSize;
// Check the presence of the footer
if (SwapWord(Info->MC7Len)+sizeof(TS7CompactBlockInfo)>=u_int(Size))
return errCliInvalidBlockSize;
return 0;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::SubBlockToBlock(int SBB)
{
switch (SBB)
{
case SubBlk_OB : return Block_OB;
case SubBlk_DB : return Block_DB;
case SubBlk_SDB : return Block_SDB;
case SubBlk_FC : return Block_FC;
case SubBlk_SFC : return Block_SFC;
case SubBlk_FB : return Block_FB;
case SubBlk_SFB : return Block_SFB;
default : return 0;
};
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::PerformOperation()
{
ClrError();
int Operation=Job.Op;
switch(Operation)
{
case s7opNone:
Job.Result=errCliInvalidParams;
break;
case s7opReadArea:
Job.Result=opReadArea();
break;
case s7opWriteArea:
Job.Result=opWriteArea();
break;
case s7opReadMultiVars:
Job.Result=opReadMultiVars();
break;
case s7opWriteMultiVars:
Job.Result=opWriteMultiVars();
break;
case s7opDBGet:
Job.Result=opDBGet();
break;
case s7opDBFill:
Job.Result=opDBFill();
break;
case s7opUpload:
Job.Result=opUpload();
break;
case s7opDownload:
Job.Result=opDownload();
break;
case s7opDelete:
Job.Result=opDelete();
break;
case s7opListBlocks:
Job.Result=opListBlocks();
break;
case s7opAgBlockInfo:
Job.Result=opAgBlockInfo();
break;
case s7opListBlocksOfType:
Job.Result=opListBlocksOfType();
break;
case s7opReadSzlList:
Job.Result=opReadSZLList();
break;
case s7opReadSZL:
Job.Result=opReadSZL();
break;
case s7opGetDateTime:
Job.Result=opGetDateTime();
break;
case s7opSetDateTime:
Job.Result=opSetDateTime();
break;
case s7opGetOrderCode:
Job.Result=opGetOrderCode();
break;
case s7opGetCpuInfo:
Job.Result=opGetCpuInfo();
break;
case s7opGetCpInfo:
Job.Result=opGetCpInfo();
break;
case s7opGetPlcStatus:
Job.Result=opGetPlcStatus();
break;
case s7opPlcHotStart:
Job.Result=opPlcHotStart();
break;
case s7opPlcColdStart:
Job.Result=opPlcColdStart();
break;
case s7opCopyRamToRom:
Job.Result=opCopyRamToRom();
break;
case s7opCompress:
Job.Result=opCompress();
break;
case s7opPlcStop:
Job.Result=opPlcStop();
break;
case s7opGetProtection:
Job.Result=opGetProtection();
break;
case s7opSetPassword:
Job.Result=opSetPassword();
break;
case s7opClearPassword:
Job.Result=opClearPassword();
break;
}
Job.Time =SysGetTick()-JobStart;
Job.Pending=false;
return SetError(Job.Result);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::Disconnect()
{
JobStart=SysGetTick();
PeerDisconnect();
Job.Time=SysGetTick()-JobStart;
Job.Pending=false;
return 0;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::Reset(bool DoReconnect)
{
Job.Pending=false;
if (DoReconnect) {
Disconnect();
return Connect();
}
else
return 0;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::Connect()
{
int Result;
JobStart=SysGetTick();
Result =PeerConnect();
Job.Time=SysGetTick()-JobStart;
return Result;
}
//---------------------------------------------------------------------------
void TSnap7MicroClient::SetConnectionType(word ConnType)
{
ConnectionType=ConnType;
}
//---------------------------------------------------------------------------
void TSnap7MicroClient::SetConnectionParams(const char *RemAddress, word LocalTSAP, word RemoteTSAP)
{
SrcTSap = LocalTSAP;
DstTSap = RemoteTSAP;
strncpy(RemoteAddress, RemAddress, 16);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::ConnectTo(const char *RemAddress, int Rack, int Slot)
{
word RemoteTSAP = (ConnectionType<<8)+(Rack*0x20)+Slot;
SetConnectionParams(RemAddress, SrcTSap, RemoteTSAP);
return Connect();
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::GetParam(int ParamNumber, void *pValue)
{
switch (ParamNumber)
{
case p_u16_RemotePort:
*Puint16_t(pValue)=RemotePort;
break;
case p_i32_PingTimeout:
*Pint32_t(pValue)=PingTimeout;
break;
case p_i32_SendTimeout:
*Pint32_t(pValue)=SendTimeout;
break;
case p_i32_RecvTimeout:
*Pint32_t(pValue)=RecvTimeout;
break;
case p_i32_WorkInterval:
*Pint32_t(pValue)=WorkInterval;
break;
case p_u16_SrcRef:
*Puint16_t(pValue)=SrcRef;
break;
case p_u16_DstRef:
*Puint16_t(pValue)=DstRef;
break;
case p_u16_SrcTSap:
*Puint16_t(pValue)=SrcTSap;
break;
case p_i32_PDURequest:
*Pint32_t(pValue)=PDURequest;
break;
default: return errCliInvalidParamNumber;
}
return 0;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::SetParam(int ParamNumber, void *pValue)
{
switch (ParamNumber)
{
case p_u16_RemotePort:
if (!Connected)
RemotePort=*Puint16_t(pValue);
else
return errCliCannotChangeParam;
break;
case p_i32_PingTimeout:
PingTimeout=*Pint32_t(pValue);
break;
case p_i32_SendTimeout:
SendTimeout=*Pint32_t(pValue);
break;
case p_i32_RecvTimeout:
RecvTimeout=*Pint32_t(pValue);
break;
case p_i32_WorkInterval:
WorkInterval=*Pint32_t(pValue);
break;
case p_u16_SrcRef:
SrcRef=*Puint16_t(pValue);
break;
case p_u16_DstRef:
DstRef=*Puint16_t(pValue);
break;
case p_u16_SrcTSap:
SrcTSap=*Puint16_t(pValue);
break;
case p_i32_PDURequest:
PDURequest=*Pint32_t(pValue);
break;
default: return errCliInvalidParamNumber;
}
return 0;
}
//---------------------------------------------------------------------------
// Data I/O functions
int TSnap7MicroClient::ReadArea(int Area, int DBNumber, int Start, int Amount, int WordLen, void * pUsrData)
{
if (!Job.Pending)
{
Job.Pending = true;
Job.Op = s7opReadArea;
Job.Area = Area;
Job.Number = DBNumber;
Job.Start = Start;
Job.Amount = Amount;
Job.WordLen = WordLen;
Job.pData = pUsrData;
JobStart = SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::WriteArea(int Area, int DBNumber, int Start, int Amount, int WordLen, void * pUsrData)
{
if (!Job.Pending)
{
Job.Pending = true;
Job.Op = s7opWriteArea;
Job.Area = Area;
Job.Number = DBNumber;
Job.Start = Start;
Job.Amount = Amount;
Job.WordLen = WordLen;
Job.pData = pUsrData;
JobStart = SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::ReadMultiVars(PS7DataItem Item, int ItemsCount)
{
if (!Job.Pending)
{
Job.Pending =true;
Job.Op =s7opReadMultiVars;
Job.Amount =ItemsCount;
Job.pData =Item;
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::WriteMultiVars(PS7DataItem Item, int ItemsCount)
{
if (!Job.Pending)
{
Job.Pending =true;
Job.Op =s7opWriteMultiVars;
Job.Amount =ItemsCount;
Job.pData =Item;
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::DBRead(int DBNumber, int Start, int Size, void * pUsrData)
{
return ReadArea(S7AreaDB, DBNumber, Start, Size, S7WLByte, pUsrData);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::DBWrite(int DBNumber, int Start, int Size, void * pUsrData)
{
return WriteArea(S7AreaDB, DBNumber, Start, Size, S7WLByte, pUsrData);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::MBRead(int Start, int Size, void * pUsrData)
{
return ReadArea(S7AreaMK, 0, Start, Size, S7WLByte, pUsrData);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::MBWrite(int Start, int Size, void * pUsrData)
{
return WriteArea(S7AreaMK, 0, Start, Size, S7WLByte, pUsrData);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::EBRead(int Start, int Size, void * pUsrData)
{
return ReadArea(S7AreaPE, 0, Start, Size, S7WLByte, pUsrData);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::EBWrite(int Start, int Size, void * pUsrData)
{
return WriteArea(S7AreaPE, 0, Start, Size, S7WLByte, pUsrData);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::ABRead(int Start, int Size, void * pUsrData)
{
return ReadArea(S7AreaPA, 0, Start, Size, S7WLByte, pUsrData);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::ABWrite(int Start, int Size, void * pUsrData)
{
return WriteArea(S7AreaPA, 0, Start, Size, S7WLByte, pUsrData);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::TMRead(int Start, int Amount, void * pUsrData)
{
return ReadArea(S7AreaTM, 0, Start, Amount, S7WLTimer, pUsrData);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::TMWrite(int Start, int Amount, void * pUsrData)
{
return WriteArea(S7AreaTM, 0, Start, Amount, S7WLTimer, pUsrData);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::CTRead(int Start, int Amount, void * pUsrData)
{
return ReadArea(S7AreaCT, 0, Start, Amount, S7WLCounter, pUsrData);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::CTWrite(int Start, int Amount, void * pUsrData)
{
return WriteArea(S7AreaCT, 0, Start, Amount, S7WLCounter, pUsrData);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::ListBlocks(PS7BlocksList pUsrData)
{
if (!Job.Pending)
{
Job.Pending =true;
Job.Op =s7opListBlocks;
Job.pData =pUsrData;
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::GetAgBlockInfo(int BlockType, int BlockNum, PS7BlockInfo pUsrData)
{
if (!Job.Pending)
{
Job.Pending =true;
Job.Op =s7opAgBlockInfo;
Job.Area =BlockType;
Job.Number =BlockNum;
Job.pData =pUsrData;
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::GetPgBlockInfo(void * pBlock, PS7BlockInfo pUsrData, int Size)
{
PS7CompactBlockInfo Info;
PS7BlockFooter Footer;
int Result=CheckBlock(-1,-1,pBlock,Size);
if (Result==0)
{
Info=PS7CompactBlockInfo(pBlock);
pUsrData->BlkType =Info->SubBlkType;
pUsrData->BlkNumber=SwapWord(Info->BlkNum);
pUsrData->BlkLang =Info->BlkLang;
pUsrData->BlkFlags =Info->BlkFlags;
pUsrData->MC7Size =SwapWord(Info->MC7Len);
pUsrData->LoadSize =SwapDWord(Info->LenLoadMem);
pUsrData->LocalData=SwapDWord(Info->LocDataLen);
pUsrData->SBBLength=SwapDWord(Info->SbbLen);
pUsrData->CheckSum =0; // this info is not available
pUsrData->Version =0; // this info is not available
FillTime(SwapWord(Info->CodeTime_dy),pUsrData->CodeDate);
FillTime(SwapWord(Info->IntfTime_dy),pUsrData->IntfDate);
Footer=PS7BlockFooter(pbyte(Info)+pUsrData->LoadSize-sizeof(TS7BlockFooter));
memcpy(pUsrData->Author,Footer->Author,8);
memcpy(pUsrData->Family,Footer->Family,8);
memcpy(pUsrData->Header,Footer->Header,8);
};
return SetError(Result);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::ListBlocksOfType(int BlockType, TS7BlocksOfType *pUsrData, int &ItemsCount)
{
if (!Job.Pending)
{
if (ItemsCount<1)
return SetError(errCliInvalidBlockSize);
Job.Pending =true;
Job.Op =s7opListBlocksOfType;
Job.Area =BlockType;
Job.pData =pUsrData;
Job.pAmount =&ItemsCount;
Job.Amount =ItemsCount;
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::Upload(int BlockType, int BlockNum, void * pUsrData, int & Size)
{
if (!Job.Pending)
{
if (Size<=0)
return SetError(errCliInvalidBlockSize);
Job.Pending =true;
Job.Op =s7opUpload;
Job.Area =BlockType;
Job.pData =pUsrData;
Job.pAmount =&Size;
Job.Amount =Size;
Job.Number =BlockNum;
Job.IParam =0; // not full upload, only data
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::FullUpload(int BlockType, int BlockNum, void * pUsrData, int & Size)
{
if (!Job.Pending)
{
if (Size<=0)
return SetError(errCliInvalidBlockSize);
Job.Pending =true;
Job.Op =s7opUpload;
Job.Area =BlockType;
Job.pData =pUsrData;
Job.pAmount =&Size;
Job.Amount =Size;
Job.Number =BlockNum;
Job.IParam =1; // header + data + footer
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::Download(int BlockNum, void * pUsrData, int Size)
{
if (!Job.Pending)
{
Job.Pending =true;
Job.Op =s7opDownload;
memcpy(&opData, pUsrData, Size);
Job.Number =BlockNum;
Job.Amount =Size;
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::Delete(int BlockType, int BlockNum)
{
if (!Job.Pending)
{
Job.Pending =true;
Job.Op =s7opDelete;
Job.Area =BlockType;
Job.Number =BlockNum;
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::DBGet(int DBNumber, void * pUsrData, int & Size)
{
if (!Job.Pending)
{
if (Size<=0)
return SetError(errCliInvalidBlockSize);
Job.Pending =true;
Job.Op =s7opDBGet;
Job.Number =DBNumber;
Job.pData =pUsrData;
Job.pAmount =&Size;
Job.Amount =Size;
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::DBFill(int DBNumber, int FillChar)
{
if (!Job.Pending)
{
Job.Pending =true;
Job.Op =s7opDBFill;
Job.Number =DBNumber;
Job.IParam =FillChar;
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::GetPlcDateTime(tm &DateTime)
{
if (!Job.Pending)
{
Job.Pending =true;
Job.Op =s7opGetDateTime;
Job.pData =&DateTime;
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::SetPlcDateTime(tm * DateTime)
{
if (!Job.Pending)
{
Job.Pending =true;
Job.Op =s7opSetDateTime;
Job.pData =DateTime;
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::SetPlcSystemDateTime()
{
time_t Now;
time(&Now);
struct tm * DateTime = localtime (&Now);
return SetPlcDateTime(DateTime);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::GetOrderCode(PS7OrderCode pUsrData)
{
if (!Job.Pending)
{
Job.Pending =true;
Job.Op =s7opGetOrderCode;
Job.pData =pUsrData;
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::GetCpuInfo(PS7CpuInfo pUsrData)
{
if (!Job.Pending)
{
Job.Pending =true;
Job.Op =s7opGetCpuInfo;
Job.pData =pUsrData;
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::GetCpInfo(PS7CpInfo pUsrData)
{
if (!Job.Pending)
{
Job.Pending =true;
Job.Op =s7opGetCpInfo;
Job.pData =pUsrData;
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::ReadSZL(int ID, int Index, PS7SZL pUsrData, int &Size)
{
if (!Job.Pending)
{
Job.Pending =true;
Job.Op =s7opReadSZL;
Job.ID =ID;
Job.Index =Index;
Job.pData =pUsrData;
Job.pAmount =&Size;
Job.Amount =Size;
Job.IParam =1; // Data has to be copied into user buffer
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::ReadSZLList(PS7SZLList pUsrData, int &ItemsCount)
{
if (!Job.Pending)
{
Job.Pending =true;
Job.Op =s7opReadSzlList;
Job.pData =pUsrData;
Job.pAmount =&ItemsCount;
Job.Amount =ItemsCount;
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::PlcHotStart()
{
if (!Job.Pending)
{
Job.Pending =true;
Job.Op =s7opPlcHotStart;
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::PlcColdStart()
{
if (!Job.Pending)
{
Job.Pending =true;
Job.Op =s7opPlcColdStart;
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::PlcStop()
{
if (!Job.Pending)
{
Job.Pending =true;
Job.Op =s7opPlcStop;
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::CopyRamToRom(int Timeout)
{
if (!Job.Pending)
{
if (Timeout>0)
{
Job.Pending =true;
Job.Op =s7opCopyRamToRom;
Job.IParam =Timeout;
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliInvalidParams);
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::Compress(int Timeout)
{
if (!Job.Pending)
{
if (Timeout>0)
{
Job.Pending =true;
Job.Op =s7opCompress;
Job.IParam =Timeout;
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliInvalidParams);
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::GetPlcStatus(int & Status)
{
if (!Job.Pending)
{
Job.Pending =true;
Job.Op =s7opGetPlcStatus;
Job.pData =&Status;
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::GetProtection(PS7Protection pUsrData)
{
if (!Job.Pending)
{
Job.Pending =true;
Job.Op =s7opGetProtection;
Job.pData =pUsrData;
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::SetSessionPassword(char *Password)
{
if (!Job.Pending)
{
size_t L = strlen(Password);
// checks the len
if ((L<1) || (L>8))
return SetError(errCliInvalidParams);
Job.Pending =true;
// prepares an 8 char string filled with spaces
memset(&opData,0x20,8);
// copies
strncpy((char*)&opData,Password,L);
Job.Op =s7opSetPassword;
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::ClearSessionPassword()
{
if (!Job.Pending)
{
Job.Pending =true;
Job.Op =s7opClearPassword;
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
================================================
FILE: deps/snap7/src/core/s7_micro_client.h
================================================
/*=============================================================================|
| 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
================================================
FILE: deps/snap7/src/core/s7_partner.cpp
================================================
/*=============================================================================|
| 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_partner.h"
//------------------------------------------------------------------------------
static PServersManager ServersManager = NULL;
//------------------------------------------------------------------------------
int ServersManager_GetServer(longword BindAddress, PConnectionServer &Server)
{
if (ServersManager == NULL)
{
ServersManager = new TServersManager();
}
return ServersManager->GetServer(BindAddress, Server);
}
//------------------------------------------------------------------------------
void ServersManager_RemovePartner(PConnectionServer Server, PSnap7Partner Partner)
{
if (ServersManager != NULL)
{
ServersManager->RemovePartner(Server, Partner);
if (ServersManager->ServersCount==0)
{
delete ServersManager;
ServersManager = NULL;
}
}
}
//------------------------------------------------------------------------------
// CONNECTION SERVERS MANAGER
//------------------------------------------------------------------------------
TServersManager::TServersManager()
{
cs = new TSnapCriticalSection;
memset(Servers,0,sizeof(Servers));
ServersCount=0;
}
//---------------------------------------------------------------------------
TServersManager::~TServersManager()
{
int c;
Lock();
if (ServersCount>0)
{
for (c = 0; c < MaxAdapters; c++)
{
if (Servers[c]!=0)
{
delete Servers[c];
Servers[c]=0;
ServersCount--;
}
}
}
Unlock();
delete cs;
}
//---------------------------------------------------------------------------
void TServersManager::Lock()
{
cs->Enter();
}
//---------------------------------------------------------------------------
void TServersManager::Unlock()
{
cs->Leave();
}
//---------------------------------------------------------------------------
void TServersManager::AddServer(PConnectionServer Server)
{
int c;
Lock();
for (c = 0; c < MaxAdapters; c++)
{
if (Servers[c]==0)
{
Servers[c]=Server;
ServersCount++;
break;
}
}
Unlock();
}
//---------------------------------------------------------------------------
int TServersManager::CreateServer(longword BindAddress, PConnectionServer &Server)
{
in_addr sin;
sin.s_addr=BindAddress;
int Result;
if (ServersCountStartTo(inet_ntoa(sin));
if (Result!=0)
{
delete Server;
Server=0;
return Result;
}
AddServer(Server);
return 0;
}
else
return errServerNoRoom;
}
//---------------------------------------------------------------------------
int TServersManager::GetServer(longword BindAddress, PConnectionServer &Server)
{
int c;
Server=0;
for (c = 0; c < ServersCount; c++)
{
if (Servers[c]->LocalBind==BindAddress)
{
Server=Servers[c];
break;
}
}
if (Server==0)
return CreateServer(BindAddress, Server);
else
return 0;
}
//---------------------------------------------------------------------------
void TServersManager::RemovePartner(PConnectionServer Server, PSnap7Partner Partner)
{
int c;
Server->RemovePartner(Partner);
if (Server->PartnersCount==0)
{
Lock();
for (c = 0; c < MaxAdapters; c++)
{
if (Servers[c]==Server)
{
Servers[c]=0;
ServersCount--;
break;
}
}
Unlock();
delete Server;
}
}
//---------------------------------------------------------------------------
// CONNECTION SERVER
//------------------------------------------------------------------------------
void TConnListenerThread::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);
};
}
}
//------------------------------------------------------------------------------
TConnectionServer::TConnectionServer()
{
cs = new TSnapCriticalSection;
memset(Partners,0,sizeof(Partners));
FRunning = false;
PartnersCount = 0;
}
//------------------------------------------------------------------------------
TConnectionServer::~TConnectionServer()
{
Stop();
delete cs;
}
//---------------------------------------------------------------------------
void TConnectionServer::Lock()
{
cs->Enter();
}
void TConnectionServer::Unlock()
{
cs->Leave();
}
//---------------------------------------------------------------------------
int TConnectionServer::Start()
{
int Result;
// Creates the listener
SockListener = new TMsgSocket();
strncpy(SockListener->LocalAddress,FLocalAddress,16);
SockListener->LocalPort=isoTcpPort;
// Binds
Result=SockListener->SckBind();
if (Result==0)
{
LocalBind=SockListener->LocalBind;
// Listen
Result=SockListener->SckListen();
if (Result==0)
{
// Creates the Listener thread
ServerThread = new TConnListenerThread(SockListener, this);
ServerThread->Start();
}
else
delete SockListener;
}
else
delete SockListener;
FRunning=Result==0;
return Result;
}
//---------------------------------------------------------------------------
int TConnectionServer::StartTo(const char *Address)
{
strncpy(FLocalAddress,Address,16);
return Start();
}
//---------------------------------------------------------------------------
void TConnectionServer::Stop()
{
if (FRunning)
{
// Kills the listener thread
ServerThread->Terminate();
if (ServerThread->WaitFor(csTimeout)!=WAIT_OBJECT_0)
ServerThread->Kill();
delete ServerThread;
// Kills the listener
delete SockListener;
FRunning = false;
}
}
//---------------------------------------------------------------------------
PSnap7Partner TConnectionServer::FindPartner(longword Address)
{
int c;
PSnap7Partner Result;
for (c = 0; c < MaxPartners; c++)
{
Result=Partners[c];
if (Result!=NULL)
{
if (Result->PeerAddress==Address)
return Result;
}
}
return NULL;
}
//------------------------------------------------------------------------------
int TConnectionServer::FirstFree()
{
int i;
for (i = 0; i < MaxPartners; i++)
{
if (Partners[i]==0)
return i;
}
return -1;
}
//------------------------------------------------------------------------------
int TConnectionServer::RegisterPartner(PSnap7Partner Partner)
{
PSnap7Partner aPartner;
int idx;
// check if already exists a passive partner linked to the same peer address
aPartner=FindPartner(Partner->PeerAddress);
if (aPartner==NULL)
{
Lock();
idx=FirstFree();
if (idx>=0)
{
Partners[idx]=Partner;
PartnersCount++;
}
Unlock();
if (idx>=0)
return 0;
else
return errParNoRoom;
}
else
return errParAddressInUse;
}
//------------------------------------------------------------------------------
void TConnectionServer::RemovePartner(PSnap7Partner Partner)
{
int c;
Lock();
for (c = 0; c < MaxPartners; c++)
{
if (Partners[c]==Partner)
{
Partners[c]=0;
PartnersCount--;
break;
}
}
Unlock();
}
//------------------------------------------------------------------------------
void TConnectionServer::Incoming(socket_t Sock)
{
longword Address;
PSnap7Partner Partner;
Address=Msg_GetSockAddr(Sock);
// Looks for a partner that is waiting for a connection from this address
Lock();
Partner=FindPartner(Address);
Unlock();
// if partner exists must not be already connected : a partner can be connected
// with only one peer at time
if ((Partner!=NULL) && (!Partner->Stopping) && (!Partner->Connected))
Partner->SetSocket(Sock);
else
Msg_CloseSocket(Sock); // we are not interested
}
//------------------------------------------------------------------------------
// PARTHER THREAD
//------------------------------------------------------------------------------
void TPartnerThread::Execute()
{
longword TheTime;
FKaElapsed=SysGetTick();
while ((!Terminated) && (!FPartner->Destroying))
{
// Check connection
while (!Terminated && !FPartner->Connected && !FPartner->Destroying)
{
if (!FPartner->ConnectToPeer())
SysSleep(FRecoveryTime);
}
// Execution
if ((!Terminated) && (!FPartner->Destroying) && (!FPartner->Execute()))
SysSleep(FRecoveryTime);
// Keep Alive
if (!Terminated && (!FPartner->Destroying) && FPartner->Active && FPartner->Connected)
{
TheTime=SysGetTick();
if (TheTime-FKaElapsed>FPartner->KeepAliveTime)
{
FKaElapsed=TheTime;
if (!FPartner->Ping(FPartner->RemoteAddress))
FPartner->Disconnect();
};
};
};
}
//------------------------------------------------------------------------------
// S7 PARTNER
//------------------------------------------------------------------------------
TSnap7Partner::TSnap7Partner(bool CreateActive)
{
// We skip RFC/ISO header, our PDU is the ISO payload
PDUH_in=PS7ReqHeader(&PDU.Payload);
FWorkerThread=0;
OnBRecv = 0;
OnBSend = 0;
Active=CreateActive;
SendEvt = new TSnapEvent(true);
RecvEvt = new TSnapEvent(true);
FSendPending = false;
FRecvPending = false;
memset(&FRecvStatus,0,sizeof(TRecvStatus));
memset(&FRecvLast,0,sizeof(TRecvLast));
FSendElapsed = 0;
Destroying = false;
// public
Linked =false;
Running =false;
BindError =false;
BRecvTimeout =3000;
BSendTimeout =3000;
RecoveryTime =500;
KeepAliveTime =5000;
NextByte =0;
PeerAddress =0;
SendTime =0;
RecvTime =0;
BytesSent =0;
BytesRecv =0;
SendErrors =0;
RecvErrors =0;
}
//------------------------------------------------------------------------------
TSnap7Partner::~TSnap7Partner()
{
Stop();
OnBRecv = 0;
OnBSend = 0;
delete SendEvt;
delete RecvEvt;
}
//------------------------------------------------------------------------------
byte TSnap7Partner::GetNextByte()
{
NextByte++;
if (NextByte==0xFF)
NextByte=1;
return NextByte;
}
//------------------------------------------------------------------------------
int TSnap7Partner::Start()
{
int Result;
PeerAddress=inet_addr(RemoteAddress);
SrcAddress =inet_addr(LocalAddress);
if (!Running)
{
if (!Active)
{
Result=ServersManager_GetServer(SrcAddress,FServer);
if (Result==0)
FServer->RegisterPartner(this);
BindError=Result!=0;
}
else
{
Linked=PeerConnect()==0;
Result=0; // we need to create the worker thread even tough it's not linked
};
// if ok create the worker thread
if (Result==0)
{
FWorkerThread = new TPartnerThread(this, RecoveryTime);
FWorkerThread->Start();
}
}
else
Result=0;
Running=Result==0;
return Result;
}
//------------------------------------------------------------------------------
int TSnap7Partner::StartTo(const char *LocAddress, const char *RemAddress, word LocTsap, word RemTsap)
{
SrcTSap=LocTsap;
DstTSap=RemTsap;
strcpy(LocalAddress,LocAddress);
strcpy(RemoteAddress,RemAddress);
return Start();
}
//------------------------------------------------------------------------------
int TSnap7Partner::Stop()
{
if (Running)
{
Stopping=true; // to prevent incoming connections
CloseWorker();
if (!Active && (FServer!=0))
ServersManager_RemovePartner(FServer, this);
if (Connected)
Disconnect();
Running =false;
Stopping=false;
};
BindError=false;
return 0;
}
//------------------------------------------------------------------------------
void TSnap7Partner::Disconnect()
{
PeerDisconnect();
Linked=false;
}
//------------------------------------------------------------------------------
int TSnap7Partner::GetParam(int ParamNumber, void * pValue)
{
switch (ParamNumber)
{
case p_u16_LocalPort:
*Puint16_t(pValue)=LocalPort;
break;
case p_u16_RemotePort:
*Puint16_t(pValue)=RemotePort;
break;
case p_i32_PingTimeout:
*Pint32_t(pValue)=PingTimeout;
break;
case p_i32_SendTimeout:
*Pint32_t(pValue)=SendTimeout;
break;
case p_i32_RecvTimeout:
*Pint32_t(pValue)=RecvTimeout;
break;
case p_i32_WorkInterval:
*Pint32_t(pValue)=WorkInterval;
break;
case p_u16_SrcRef:
*Puint16_t(pValue)=SrcRef;
break;
case p_u16_DstRef:
*Puint16_t(pValue)=DstRef;
break;
case p_u16_SrcTSap:
*Puint16_t(pValue)=SrcTSap;
break;
case p_i32_PDURequest:
*Pint32_t(pValue)=PDURequest;
break;
case p_i32_BSendTimeout:
*Pint32_t(pValue)=BSendTimeout;
break;
case p_i32_BRecvTimeout:
*Pint32_t(pValue)=BRecvTimeout;
break;
case p_u32_RecoveryTime:
*Puint32_t(pValue)=RecoveryTime;
break;
case p_u32_KeepAliveTime:
*Puint32_t(pValue)=KeepAliveTime;
break;
default: return errParInvalidParamNumber;
}
return 0;
}
//------------------------------------------------------------------------------
int TSnap7Partner::SetParam(int ParamNumber, void * pValue)
{
switch (ParamNumber)
{
case p_u16_RemotePort:
if (!Connected && Active)
RemotePort=*Puint16_t(pValue);
else
return errParCannotChangeParam;
break;
case p_i32_PingTimeout:
PingTimeout=*Pint32_t(pValue);
break;
case p_i32_SendTimeout:
SendTimeout=*Pint32_t(pValue);
break;
case p_i32_RecvTimeout:
RecvTimeout=*Pint32_t(pValue);
break;
case p_i32_WorkInterval:
WorkInterval=*Pint32_t(pValue);
break;
case p_u16_SrcRef:
SrcRef=*Puint16_t(pValue);
break;
case p_u16_DstRef:
DstRef=*Puint16_t(pValue);
break;
case p_u16_SrcTSap:
SrcTSap=*Puint16_t(pValue);
break;
case p_i32_PDURequest:
PDURequest=*Pint32_t(pValue);
break;
case p_i32_BSendTimeout:
BSendTimeout=*Pint32_t(pValue);
break;
case p_i32_BRecvTimeout:
BRecvTimeout=*Pint32_t(pValue);
break;
case p_u32_RecoveryTime:
RecoveryTime=*Puint32_t(pValue);
break;
case p_u32_KeepAliveTime:
KeepAliveTime=*Puint32_t(pValue);
break;
default: return errParInvalidParamNumber;
}
return 0;
}
//------------------------------------------------------------------------------
void TSnap7Partner::ClearRecv()
{
memset(&FRecvStatus,0,sizeof(TRecvStatus));
FRecvPending=false;
}
//------------------------------------------------------------------------------
bool TSnap7Partner::ConnectToPeer()
{
bool Result;
if (Active)
{
Result=PeerConnect()==0; // try to Connect
Linked=Result;
}
else
Result =false; // nothing : we are waiting for a connection
return Result;
}
//------------------------------------------------------------------------------
bool TSnap7Partner::PerformFunctionNegotiate()
{
PReqFunNegotiateParams ReqParams;
PResFunNegotiateParams ResParams;
TS7Answer23 Answer;
int Size;
// Setup pointers
ReqParams=PReqFunNegotiateParams(pbyte(PDUH_in)+sizeof(TS7ReqHeader));
ResParams=PResFunNegotiateParams(pbyte(&Answer)+sizeof(TS7ResHeader23));
// We are here only because we found a PduType_request, the partner can only
// handle Bs} requests and pdu negotiation requests.
// So, now we must check the incoming function
if (ReqParams->FunNegotiate!=pduNegotiate)
{
LastError=errParInvalidPDU;
return false;
};
// Prepares the answer
Answer.Header.P=0x32;
Answer.Header.PDUType =0x03;
Answer.Header.AB_EX =0x0000;
Answer.Header.Sequence=PDUH_in->Sequence;
Answer.Header.ParLen =SwapWord(sizeof(TResFunNegotiateParams));
Answer.Header.DataLen =0x0000;
Answer.Header.Error =0x0000;
// Params point at the } of the header
ResParams->FunNegotiate=pduNegotiate;
ResParams->Unknown=0x0;
// Checks PDU request length
if (SwapWord(ResParams->PDULength)>IsoPayload_Size)
ResParams->PDULength=SwapWord(IsoPayload_Size);
else
ResParams->PDULength=ReqParams->PDULength;
// We offer the same
ResParams->ParallelJobs_1=ReqParams->ParallelJobs_1;
ResParams->ParallelJobs_2=ReqParams->ParallelJobs_2;
// And store the value
PDULength=SwapWord(ResParams->PDULength);
// Sends the answer
Size=sizeof(TS7ResHeader23) + sizeof(TResFunNegotiateParams);
if (isoSendBuffer(&Answer, Size)!=0)
SetError(errParNegotiatingPDU);
Linked=LastError==0;
return Linked;
}
//------------------------------------------------------------------------------
void TSnap7Partner::CloseWorker()
{
int Timeout;
if (FWorkerThread)
{
FWorkerThread->Terminate();
if (FRecvPending || FSendPending)
Timeout=3000;
else
Timeout=1000;
if (FWorkerThread->WaitFor(Timeout)!=WAIT_OBJECT_0)
FWorkerThread->Kill();
try {
delete FWorkerThread;
}
catch (...){
}
FWorkerThread=0;
}
}
//------------------------------------------------------------------------------
bool TSnap7Partner::BlockSend()
{
PBSendReqParams ReqParams;
PBSendReqParams ResParams;
PBsendRequestData DataSendReq;
int TotalSize;
int SentSize;
int Slice;
int MaxSlice;
uintptr_t Offset;
pbyte Source;
bool First, Last;
byte Seq_IN;
int TxIsoSize;
pbyte Data;
pword TotalPackSize;
int DataPtrOffset;
word Extra;
ClrError();
TotalSize=TxBuffer.Size;
SentSize =TotalSize;
Offset=0;
First =true;
Seq_IN=0x00;
// With BSend we can transfer up to 32k (S7300) or 64k (S7400), but splitted
// into slice that cannot exced the PDU size negotiated (including various headers).
MaxSlice=PDULength-sizeof(TS7ReqHeader)-sizeof(TBSendParams)-sizeof(TBsendRequestData)-2;
ReqParams=PBSendReqParams(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
ResParams=ReqParams; // pdu 7 is symmetrical
while ((TotalSize>0) && (LastError==0))
{
Source=pbyte(&TxBuffer.Data)+Offset;
Slice=TotalSize;
if (Slice>MaxSlice)
Slice=MaxSlice;
TotalSize-=Slice;
Offset+=Slice;
Last=TotalSize==0;
// Prepare send
DataPtrOffset=sizeof(TS7ReqHeader)+sizeof(TBSendParams);
// Header
PDUH_out->P=0x32; // Always 0x32
PDUH_out->PDUType=PduType_userdata; // 7
PDUH_out->AB_EX=0x0000; // Always 0x0000
PDUH_out->Sequence=GetNextWord(); // Autoinc
PDUH_out->ParLen=SwapWord(sizeof(TBSendParams)); // 16 bytes
ReqParams->Head[0]=0x00;
ReqParams->Head[1]=0x01;
ReqParams->Head[2]=0x12;
ReqParams->Plen =0x08; // length from here up the end of the record
ReqParams->Uk =0x12;
ReqParams->Tg =grBSend; // 0x46
ReqParams->SubFun =0x01;
ReqParams->Seq =Seq_IN;
ReqParams->Err =0x0000;
if (Last)
ReqParams->EoS =0x00;
else
ReqParams->EoS =0x01;
// Next byte is auto inc and not zero for partial sequences
// Is zero for lonely sequences.
if (First && Last)
ReqParams->IDSeq=0x00;
else
ReqParams->IDSeq=GetNextByte();
DataSendReq=PBsendRequestData(pbyte(PDUH_out)+DataPtrOffset);
if (First)
{
// in the first pdu, after data header there is the whole packet length
TotalPackSize=pword(pbyte(DataSendReq)+sizeof(TBsendRequestData));
Data=pbyte(TotalPackSize)+sizeof(word);
*TotalPackSize=SwapWord(word(TxBuffer.Size));
Extra=2; // extra bytes (total pack size indicator)
}
else
{
Data=pbyte(DataSendReq)+sizeof(TBsendRequestData);
Extra=0;
};
PDUH_out->DataLen=SwapWord(word(sizeof(TBsendRequestData))+Slice+Extra);
DataSendReq->Len =SwapWord(Slice+8+Extra);
TxIsoSize=Slice+sizeof(TS7ReqHeader)+sizeof(TBSendParams)+sizeof(TBsendRequestData)+Extra;
DataSendReq->FF =0xFF;
DataSendReq->TRSize =TS_ResOctet;
DataSendReq->DHead[0]=0x12;
DataSendReq->DHead[1]=0x06;
DataSendReq->DHead[2]=0x13;
DataSendReq->DHead[3]=0x00;
DataSendReq->R_ID =SwapDWord(TxBuffer.R_ID);
memcpy(Data, Source ,Slice);
if (isoExchangeBuffer(NULL, TxIsoSize)!=0)
SetError(errParSendingBlock);
if (LastError==0)
{
Seq_IN=ResParams->Seq;
if (SwapWord(ResParams->Err)!=0)
LastError=errParSendRefused;
}
if (First)
{
First =false;
MaxSlice+=2; // only in the first frame we have the extra info
};
};
SendTime=SysGetTick()-FSendElapsed;
if (LastError==0)
BytesSent+=SentSize;
return LastError==0;
}
//------------------------------------------------------------------------------
bool TSnap7Partner::PickData()
{
PBSendReqParams ReqParams;
PBSendReqParams ResParams;
PBSendResData ResData;
PBsendRequestData DataSendReq;
pbyte Source, Target;
pword TotalPackSize;
word Slice;
int AnswerLen;
ClrError();
// Setup pointers
ReqParams =PBSendReqParams(pbyte(PDUH_in)+sizeof(TS7ReqHeader));
ResParams =ReqParams; // pdu 7 is symmetrical
DataSendReq=PBsendRequestData(pbyte(ReqParams)+sizeof(TBSendParams));
// Checks if PDU is a BSend request
if ((PDUH_in->PDUType!=PduType_userdata) || (ReqParams->Tg!=grBSend))
{
LastError=errParInvalidPDU;
return false;
}
if (FRecvStatus.First)
{
TotalPackSize=(word*)(pbyte(DataSendReq)+sizeof(TBsendRequestData));
FRecvStatus.TotalLength=SwapWord(*TotalPackSize);
Source=pbyte(DataSendReq)+sizeof(TBsendRequestData)+2;
FRecvStatus.In_R_ID=SwapDWord(DataSendReq->R_ID);
FRecvStatus.Offset=0;
Slice=SwapWord(DataSendReq->Len)-10;
}
else {
Slice=SwapWord(DataSendReq->Len)-8;
Source=pbyte(DataSendReq)+sizeof(TBsendRequestData);
}
FRecvStatus.Done=ReqParams->EoS==0x00;
Target=pbyte(&RxBuffer)+FRecvStatus.Offset;
memcpy(Target, Source, Slice);
FRecvStatus.Offset+=Slice;
ResData =PBSendResData(pbyte(ResParams)+sizeof(TBSendParams));
// Send Answer
PDUH_out->ParLen =SwapWord(sizeof(TBSendParams));
PDUH_out->DataLen =SwapWord(sizeof(TBSendResData));
ResParams->Head[0]=0x00;
ResParams->Head[1]=0x01;
ResParams->Head[2]=0x12;
ResParams->Plen =0x08; // length from here up the end of the record
ResParams->Uk =0x12;
ResParams->Tg =0x86;
ResParams->SubFun =0x01;
ResParams->Seq =FRecvStatus.Seq_Out;
ResParams->Err =0x0000;
ResParams->EoS =0x00;
ResParams->IDSeq =0x00;
ResData->DHead[0] =0x0A;
ResData->DHead[1] =0x00;
ResData->DHead[2] =0x00;
ResData->DHead[3] =0x00;
AnswerLen=sizeof(TS7ReqHeader)+sizeof(TBSendParams)+sizeof(TBSendResData);
if (isoSendBuffer(NULL,AnswerLen)!=0)
SetError(errParRecvingBlock);
return LastError==0;
}
//------------------------------------------------------------------------------
bool TSnap7Partner::BlockRecv()
{
bool Result;
if (!FRecvPending) // Start sequence
{
FRecvPending=true;
FRecvStatus.First=true;
FRecvStatus.Done =false;
FRecvStatus.Seq_Out =GetNextByte();
FRecvStatus.Elapsed =SysGetTick();
FRecvLast.Done=false;
FRecvLast.Result=0;
FRecvLast.R_ID=0;
FRecvLast.Size=0;
RecvTime =0;
FRecvLast.Count++;
if (FRecvLast.Count==0xFFFFFFFF)
FRecvLast.Count=0;
};
Result=PickData();
FRecvStatus.First=false;
if (!Result || FRecvStatus.Done)
{
FRecvLast.Result=LastError;
if (Result)
{
BytesRecv+=FRecvStatus.TotalLength;
RecvTime=SysGetTick()-FRecvStatus.Elapsed;
FRecvLast.R_ID=FRecvStatus.In_R_ID;
FRecvLast.Size=FRecvStatus.TotalLength;
};
RecvEvt->Set();
if ((OnBRecv!=NULL) && !Destroying)
OnBRecv(FRecvUsrPtr, FRecvLast.Result, FRecvLast.R_ID, &RxBuffer, FRecvLast.Size);
FRecvLast.Done=true;
ClearRecv();
};
return Result;
}
//------------------------------------------------------------------------------
bool TSnap7Partner::ConnectionConfirm()
{
if (FRecvPending)
ClearRecv();
IsoConfirmConnection(pdu_type_CC); // <- Connection confirm
return LastTcpError!=WSAECONNRESET;
}
//------------------------------------------------------------------------------
int TSnap7Partner::Status()
{
if (Running)
{
if (Linked)
{
if (FRecvPending)
return par_receiving;
else
if (FSendPending)
return par_sending;
else
return par_linked;
}
else
if (Active)
return par_connecting;
else
return par_waiting;
}
else{
if ((!Active) && BindError)
return par_binderror;
else
return par_stopped;
}
}
//------------------------------------------------------------------------------
bool TSnap7Partner::Execute()
{
TPDUKind PduKind;
bool RTimeout;
bool Result =true;
// Checks if there is something to send (and we are not receiving...)
if (FSendPending && !FRecvPending)
{
Result=BlockSend();
SendEvt->Set();
if ((OnBSend!=NULL) && (!Destroying))
OnBSend(FSendUsrPtr, LastError);
FSendPending=false;
}
if (Destroying)
return false;
// Checks if there is something to recv
if (Result && CanRead(WorkInterval))
{
// Peeks info and returns PDU Kind
isoRecvPDU(&PDU);
if (LastTcpError==0)
{
// First check valid data incoming (most likely situation)
IsoPeek(&PDU,PduKind);
if (PduKind==pkValidData)
{
if (PDUH_in->PDUType==PduType_request)
{
if (FRecvPending)
ClearRecv();
Result=PerformFunctionNegotiate();
}
else // Pdu type userdata
Result=BlockRecv();
}
else
if (PduKind==pkConnectionRequest)
Result=ConnectionConfirm();
else // nothing else
Purge();
}
else
Result=false;
};
if (LastTcpError==WSAECONNRESET)
{
Result=false;
Linked=false;
}
else
if (!Result)
Disconnect();
// Check BRecv sequence timeout
RTimeout= FRecvPending && (SysGetTick()-FRecvStatus.Elapsed>longword(BRecvTimeout));
if (RTimeout)
{
LastError=errParFrameTimeout;
RecvEvt->Set();
if ((OnBRecv!=NULL) && !Destroying)
OnBRecv(FRecvUsrPtr, LastError, 0, &RxBuffer,0);
};
if (!Result || RTimeout)
ClearRecv(); // parframetimeout
return Result;
}
//------------------------------------------------------------------------------
int TSnap7Partner::BSend(longword R_ID, void *pUsrData, int Size)
{
// The block send is managed into the worker thread.
// Sync Bsend consists of AsBSend+WaitAsCompletion
int Result=AsBSend(R_ID, pUsrData, Size);
if (Result==0)
Result=WaitAsBSendCompletion(BSendTimeout);
return Result;
}
//------------------------------------------------------------------------------
int TSnap7Partner::AsBSend(longword R_ID, void *pUsrData, int Size)
{
SendTime=0;
if (Linked)
{
if (!FSendPending)
{
memcpy(&TxBuffer.Data, pUsrData, Size);
TxBuffer.R_ID=R_ID;
TxBuffer.Size=Size;
SendEvt->Reset();
FSendPending=true;
FSendElapsed=SysGetTick();
return 0;
}
else
return errParBusy;
}
else
return SetError(errParNotLinked);
}
//------------------------------------------------------------------------------
bool TSnap7Partner::CheckAsBSendCompletion(int &opResult)
{
if (!Destroying)
{
if (!FSendPending)
opResult=LastError;
else
opResult=errParBusy;
return !FSendPending;
}
else
{
opResult=errParDestroying;
return true;
}
}
//------------------------------------------------------------------------------
int TSnap7Partner::WaitAsBSendCompletion(longword Timeout)
{
if (SendEvt->WaitFor(BSendTimeout)==WAIT_OBJECT_0)
{
if (!Destroying)
return LastError;
else
return SetError(errParDestroying);
}
else
return SetError(errParSendTimeout);
}
//------------------------------------------------------------------------------
int TSnap7Partner::SetSendCallback(pfn_ParBSendCompletion pCompletion, void *usrPtr)
{
OnBSend=pCompletion;
FSendUsrPtr=usrPtr;
return 0;
}
//------------------------------------------------------------------------------
int TSnap7Partner::BRecv(longword &R_ID, void *pData, int &Size, longword Timeout)
{
int Result=0;
if (RecvEvt->WaitFor(Timeout)==WAIT_OBJECT_0)
{
R_ID =FRecvLast.R_ID;
Size =FRecvLast.Size;
if (FRecvLast.Result==0)
{
if (pData!=NULL)
memcpy(pData, &RxBuffer, Size);
else
Result=errParInvalidParams;
}
else
Result=FRecvLast.Result;
RecvEvt->Reset();
}
else
Result=errParRecvTimeout;
return SetError(Result);
}
//------------------------------------------------------------------------------
bool TSnap7Partner::CheckAsBRecvCompletion(int &opResult, longword &R_ID,
void *pData, int &Size)
{
if (Destroying)
{
Size=0;
opResult=errParDestroying;
return true;
}
bool Result=FRecvLast.Done;
if (Result)
{
Size=FRecvLast.Size;
R_ID=FRecvLast.R_ID;
opResult=FRecvLast.Result;
if ((pData!=NULL) && (Size>0) && (opResult==0))
memcpy(pData, &RxBuffer, Size);
FRecvLast.Done=false;
}
return Result;
}
//------------------------------------------------------------------------------
int TSnap7Partner::SetRecvCallback(pfn_ParBRecvCallBack pCompletion, void *usrPtr)
{
OnBRecv=pCompletion;
FRecvUsrPtr=usrPtr;
return 0;
}
//------------------------------------------------------------------------------
================================================
FILE: deps/snap7/src/core/s7_partner.h
================================================
/*=============================================================================|
| 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
================================================
FILE: deps/snap7/src/core/s7_peer.cpp
================================================
/*=============================================================================|
| 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;
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;
}
================================================
FILE: deps/snap7/src/core/s7_peer.h
================================================
/*=============================================================================|
| 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
================================================
FILE: deps/snap7/src/core/s7_server.cpp
================================================
/*=============================================================================|
| 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_server.h"
#include "s7_firmware.h"
const byte BitMask[8] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
//------------------------------------------------------------------------------
// ISO/TCP WORKER CLASS
//------------------------------------------------------------------------------
bool TIsoTcpWorker::IsoPerformCommand(int &Size)
{
return true;
}
//---------------------------------------------------------------------------
bool TIsoTcpWorker::ExecuteSend()
{
return true;
}
//---------------------------------------------------------------------------
bool TIsoTcpWorker::ExecuteRecv()
{
TPDUKind PduKind;
int PayloadSize;
if (CanRead(WorkInterval)) // should be Small to avoid time wait during the close
{
isoRecvPDU(&PDU);
if (LastTcpError==0)
{
IsoPeek(&PDU,PduKind);
// First check valid data incoming (most likely situation)
if (PduKind==pkValidData)
{
PayloadSize=PDUSize(&PDU)-DataHeaderSize;
return IsoPerformCommand(PayloadSize);
};
// Connection request incoming
if (PduKind==pkConnectionRequest)
{
IsoConfirmConnection(pdu_type_CC); // <- Connection confirm
return LastTcpError!=WSAECONNRESET;
};
// Disconnect request incoming (only for isotcp full complient equipment, not S7)
if (PduKind==pkDisconnectRequest)
{
IsoConfirmConnection(pdu_type_DC); // <- Disconnect confirm
return false;
};
// Empty fragment, maybe an ACK
if (PduKind==pkEmptyFragment)
{
PayloadSize=0;
return IsoPerformCommand(PayloadSize);
};
// Valid PDU format but we have to discard it
if (PduKind==pkUnrecognizedType)
{
return LastTcpError!=WSAECONNRESET;
};
// Here we have an Invalid PDU
Purge();
return true;
}
else
return LastTcpError!=WSAECONNRESET;
}
else
return true;
}
//---------------------------------------------------------------------------
bool TIsoTcpWorker::Execute()
{
return ExecuteSend() && ExecuteRecv();
}
//------------------------------------------------------------------------------
// S7 WORKER CLASS
//------------------------------------------------------------------------------
TS7Worker::TS7Worker()
{
// We skip RFC/ISO header, our PDU is the payload
PDUH_in =PS7ReqHeader(&PDU.Payload);
FPDULength=2048;
DBCnt =0;
LastBlk =Block_DB;
}
bool TS7Worker::ExecuteRecv()
{
WorkInterval=FServer->WorkInterval;
return TIsoTcpWorker::ExecuteRecv();
}
//------------------------------------------------------------------------------
bool TS7Worker::CheckPDU_in(int PayloadSize)
{
// Checks the size : packet size must match with header infos
int Size=SwapWord(PDUH_in->ParLen)+SwapWord(PDUH_in->DataLen)+ReqHeaderSize;
if (Size!=PayloadSize)
return false;
// Checks PDUType : must be 1 or 7
if ((PDUH_in->PDUType!=PduType_request) &&
(PDUH_in->PDUType!=PduType_userdata))
return false;
else
return true;
}
//------------------------------------------------------------------------------
byte TS7Worker::BCD(word Value)
{
return ((Value / 10) << 4) + (Value % 10);
}
//------------------------------------------------------------------------------
void TS7Worker::FillTime(PS7Time PTime)
{
time_t Now;
time(&Now);
struct tm *DT = localtime (&Now);
PTime->bcd_year=BCD(DT->tm_year-100);
PTime->bcd_mon =BCD(DT->tm_mon+1);
PTime->bcd_day =BCD(DT->tm_mday);
PTime->bcd_hour=BCD(DT->tm_hour);
PTime->bcd_min =BCD(DT->tm_min);
PTime->bcd_sec =BCD(DT->tm_sec);
PTime->bcd_himsec=0;
PTime->bcd_dow =BCD(DT->tm_wday);
}
//------------------------------------------------------------------------------
void TS7Worker::DoEvent(longword Code, word RetCode, word Param1, word Param2,
word Param3, word Param4)
{
FServer->DoEvent(ClientHandle,Code,RetCode,Param1,Param2,Param3,Param4);
}
//------------------------------------------------------------------------------
void TS7Worker::DoReadEvent(longword Code, word RetCode, word Param1, word Param2,
word Param3, word Param4)
{
FServer->DoReadEvent(ClientHandle,Code,RetCode,Param1,Param2,Param3,Param4);
}
//------------------------------------------------------------------------------
void TS7Worker::FragmentSkipped(int Size)
{
// do nothing could be used for debug purpose
}
//------------------------------------------------------------------------------
bool TS7Worker::IsoPerformCommand(int &Size)
{
// Checks for Ack fragment
if (Size==0)
return PerformPDUAck(Size);
// First checks PDU consistence
if (CheckPDU_in(Size))
{
switch (PDUH_in->PDUType)
{
case PduType_request : return PerformPDURequest(Size);
case PduType_userdata : return PerformPDUUsrData(Size);
}
}
else
DoEvent(evcPDUincoming, evrMalformedPDU, Size, 0, 0, 0);
return false;
}
//------------------------------------------------------------------------------
bool TS7Worker::PerformPDUAck(int &Size)
{
// here we could keep track of ack empty fragment for debug purpose
return true;
}
//------------------------------------------------------------------------------
bool TS7Worker::PerformPDURequest(int &Size)
{
pbyte P;
byte PDUFun;
bool Result = true;
// We have to store PDUfun since it will be overwritten
P = pbyte(PDUH_in)+ReqHeaderSize;
PDUFun=*P;
// Watches the function
switch (PDUFun)
{
case pduFuncRead : Result=PerformFunctionRead();
break;
case pduFuncWrite : Result=PerformFunctionWrite();
break;
case pduNegotiate : Result=PerformFunctionNegotiate();
break;
case pduStart :
case pduStop : Result=PerformFunctionControl(PDUFun);
break;
case pduStartUpload :
case pduUpload :
case pduEndUpload : Result=PerformFunctionUpload();
break;
case pduReqDownload : Result=PerformFunctionDownload();
break;
// <-- Further (custom) functions can be added here
default:
DoEvent(evcPDUincoming, evrCannotHandlePDU, Size, 0, 0, 0);
};
return Result;
}
//------------------------------------------------------------------------------
bool TS7Worker::PerformPDUUsrData(int &Size)
{
PS7ReqParams7 ReqParams;
byte Tg, SubFun;
bool Result = true;
// Set Pointer to request params
ReqParams=PS7ReqParams7(pbyte(PDUH_in)+ReqHeaderSize);
Tg=ReqParams->Tg;
SubFun=ReqParams->SubFun;
// Switch type_group
switch (Tg)
{
case grProgrammer : Result=PerformGroupProgrammer();
break;
case grCyclicData : Result=PerformGroupCyclicData();
break;
case grBlocksInfo : Result=PerformGroupBlockInfo();
break;
case grSZL : Result=PerformGroupSZL();
break;
case grPassword : Result=PerformGroupSecurity();
break;
case grClock : switch (SubFun)
{
case 0x01 : Result=PerformGetClock();
break;
case 0x02 : Result=PerformSetClock();
break;
};
break;
default:
DoEvent(evcPDUincoming, evrInvalidGroupUData, Tg, 0, 0, 0);
};
return Result;
}
//------------------------------------------------------------------------------
int TS7Worker::DataSizeByte(int WordLength)
{
switch (WordLength){
case S7WLBit : return 1; // S7 sends 1 byte per bit
case S7WLByte : return 1;
case S7WLChar : return 1;
case S7WLWord : return 2;
case S7WLDWord : return 4;
case S7WLInt : return 2;
case S7WLDInt : return 4;
case S7WLReal : return 4;
case S7WLCounter : return 2;
case S7WLTimer : return 2;
default : return 0;
}
}
//==============================================================================
// FUNCTION READ
//==============================================================================
word TS7Worker::RA_NotFound(PResFunReadItem ResItem, TEv &EV)
{
ResItem->DataLength=SwapWord(0x0004);
ResItem->ReturnCode=Code7ResItemNotAvailable;
ResItem->TransportSize=0x00;
EV.EvRetCode=evrErrAreaNotFound;
return 0;
}
//------------------------------------------------------------------------------
word TS7Worker::RA_OutOfRange(PResFunReadItem ResItem, TEv &EV)
{
ResItem->DataLength=SwapWord(0x0004);
ResItem->ReturnCode=Code7AddressOutOfRange;
ResItem->TransportSize=0x00;
EV.EvRetCode=evrErrOutOfRange;
return 0;
}
//------------------------------------------------------------------------------
word TS7Worker::RA_SizeOverPDU(PResFunReadItem ResItem, TEv &EV)
{
ResItem->DataLength=SwapWord(0x0004);
ResItem->ReturnCode=byte(SwapWord(Code7DataOverPDU));
ResItem->TransportSize=0x00;
EV.EvRetCode=evrErrOverPDU;
return 0;
}
//------------------------------------------------------------------------------
PS7Area TS7Worker::GetArea(byte S7Code, word index)
{
switch(S7Code)
{
case S7AreaPE : return FServer->HA[srvAreaPE];
case S7AreaPA : return FServer->HA[srvAreaPA];
case S7AreaMK : return FServer->HA[srvAreaMK];
case S7AreaCT : return FServer->HA[srvAreaCT];
case S7AreaTM : return FServer->HA[srvAreaTM];
case S7AreaDB : return FServer->FindDB(index);
default : return NULL;
};
}
//------------------------------------------------------------------------------
word TS7Worker::ReadArea(PResFunReadItem ResItemData, PReqFunReadItem ReqItemPar,
int &PDURemainder, TEv &EV)
{
PS7Area P;
word DBNum = 0;
word Elements;
longword Start, Size, ASize, AStart;
longword *PAdd;
byte BitIndex, ByteVal;
int Multiplier;
void *Source = NULL;
PSnapCriticalSection pcs;
P=NULL;
EV.EvStart =0;
EV.EvSize =0;
EV.EvRetCode =0;
EV.EvIndex =0;
EV.EvArea=ReqItemPar->Area;
// Get Pointer to selected Area
if (ReqItemPar->Area==S7AreaDB)
{
DBNum=SwapWord(ReqItemPar->DBNumber);
EV.EvIndex=DBNum;
};
if (!FServer->ResourceLess)
{
P = GetArea(ReqItemPar->Area, DBNum);
if (P == NULL)
return RA_NotFound(ResItemData, EV);
}
// Calcs the amount
Multiplier = DataSizeByte(ReqItemPar->TransportSize);
if (Multiplier==0)
return RA_OutOfRange(ResItemData, EV);
// Checks timers/counters coherence
if ((ReqItemPar->Area==S7AreaTM) ^ (ReqItemPar->TransportSize==S7WLTimer))
return RA_OutOfRange(ResItemData, EV);
if ((ReqItemPar->Area==S7AreaCT) ^ (ReqItemPar->TransportSize==S7WLCounter))
return RA_OutOfRange(ResItemData, EV);
// Calcs size
Elements = SwapWord(ReqItemPar->Length);
Size=Multiplier*Elements;
EV.EvSize=Size;
// The sum of the items must not exceed the PDU size negotiated
if (PDURemainder-Size<=0)
return RA_SizeOverPDU(ResItemData, EV);
else
PDURemainder-=Size;
// More then 1 bit is not supported by S7 CPU
if ((ReqItemPar->TransportSize==S7WLBit) && (Size>1))
return RA_OutOfRange(ResItemData, EV);
// Calcs the start point
PAdd=(longword*)(&ReqItemPar->Area); // points to area since we need 4 bytes for a pointer
Start=SwapDWord(*PAdd & 0xFFFFFF00);
// Checks if the address is not multiple of 8 when transport size is neither bit nor timer nor counter
if (
(ReqItemPar->TransportSize!=S7WLBit) &&
(ReqItemPar->TransportSize!=S7WLTimer) &&
(ReqItemPar->TransportSize!=S7WLCounter) &&
((Start % 8) !=0)
)
return RA_OutOfRange(ResItemData, EV);
// AStart is only for callback
if ((ReqItemPar->TransportSize != S7WLBit) && (ReqItemPar->TransportSize != S7WLCounter) && (ReqItemPar->TransportSize != S7WLTimer))
AStart = Start >> 3;
else
AStart = Start;
if ((ReqItemPar->TransportSize == S7WLCounter) || (ReqItemPar->TransportSize == S7WLTimer))
{
Start = Start >> 1; // 1 Timer or Counter = 2 bytes
}
else
{
BitIndex =Start & 0x07; // start bit
Start =Start >> 3; // start byte
}
EV.EvStart=Start;
// Checks bounds
if (!FServer->ResourceLess)
{
ASize = P->Size; // Area size
if (Start + Size > ASize)
return RA_OutOfRange(ResItemData, EV);
Source = P->PData + Start;
}
// Read Event (before copy data)
DoReadEvent(evcDataRead,0,EV.EvArea,EV.EvIndex,EV.EvStart,EV.EvSize);
if (FServer->ResourceLess)
{
memset(&ResItemData->Data, 0, Size);
if (!FServer->DoReadArea(ClientHandle, EV.EvArea, EV.EvIndex, AStart, Elements, ReqItemPar->TransportSize, &ResItemData->Data))
return RA_NotFound(ResItemData, EV);
}
else
{
// Lock the area
pcs = P->cs;
pcs->Enter();
// Get Data
memcpy(&ResItemData->Data, Source, Size);
// Unlock the area
pcs->Leave();
}
ResItemData->ReturnCode=0xFF;
// Set Result transport size and, for bit, performs the mask
switch (ReqItemPar->TransportSize)
{
case S7WLBit:
{
ByteVal=ResItemData->Data[0];
if ((ByteVal & BitMask[BitIndex])!=0)
ResItemData->Data[0]=0x01;
else
ResItemData->Data[0]=0x00;
ResItemData->TransportSize=TS_ResBit;
ResItemData->DataLength=SwapWord(Size);
};break;
case S7WLByte:
case S7WLWord:
case S7WLDWord:
{
ResItemData->TransportSize=TS_ResByte;
ResItemData->DataLength=SwapWord(Size*8);
};break;
case S7WLInt:
case S7WLDInt:
{
ResItemData->TransportSize=TS_ResInt;
ResItemData->DataLength=SwapWord(Size*8);
};break;
case S7WLReal:
{
ResItemData->TransportSize=TS_ResReal;
ResItemData->DataLength=SwapWord(Size);
};break;
case S7WLChar:
case S7WLTimer:
case S7WLCounter:
{
ResItemData->TransportSize=TS_ResOctet;
ResItemData->DataLength=SwapWord(Size);
};break;
default :
{
ResItemData->TransportSize=TS_ResByte;
ResItemData->DataLength=SwapWord(Size*8);
};break;
}
EV.EvRetCode=evrNoError;
return Size;
}
//------------------------------------------------------------------------------
bool TS7Worker::PerformFunctionRead()
{
PReqFunReadParams ReqParams;
PResFunReadParams ResParams;
TResFunReadData ResData;
TS7Answer23 Answer;
uintptr_t Offset;
word ItemSize;
int ItemsCount, c,
TotalSize,
PDURemainder;
TEv EV;
PDURemainder=FPDULength;
// Stage 1 : Setup pointers and initial check
ReqParams=PReqFunReadParams(pbyte(PDUH_in)+sizeof(TS7ReqHeader));
ResParams=PResFunReadParams(pbyte(&Answer)+ResHeaderSize23); // Params after the header
// trunk to 20 max items.
if (ReqParams->ItemsCount>MaxVars)
ReqParams->ItemsCount=MaxVars;
ItemsCount=ReqParams->ItemsCount;
// Stage 2 : gather data
Offset=sizeof(TResFunReadParams); // = 2
for (c = 0; c < ItemsCount; c++)
{
ResData[c]=PResFunReadItem(pbyte(ResParams)+Offset);
ItemSize=ReadArea(ResData[c],&ReqParams->Items[c],PDURemainder, EV);
// S7 doesn't xfer odd byte amount
if ((c1)
DoEvent(evcDataRead,EV.EvRetCode,EV.EvArea,EV.EvIndex,EV.EvStart,EV.EvSize);
}
// Stage 3 : finalize the answer and send the packet
Answer.Header.P=0x32;
Answer.Header.PDUType=0x03;
Answer.Header.AB_EX=0x0000;
Answer.Header.Sequence=PDUH_in->Sequence;
Answer.Header.ParLen=SwapWord(sizeof(TResFunReadParams));
Answer.Header.Error=0x0000; // this is zero, we will find the error in ResData.ReturnCode
Answer.Header.DataLen=SwapWord(word(Offset)-2);
ResParams->FunRead =ReqParams->FunRead;
ResParams->ItemCount=ReqParams->ItemsCount;
TotalSize=ResHeaderSize23+int(Offset);
isoSendBuffer(&Answer, TotalSize);
// For single item (most likely case) it's better to work with the event after
// we sent the answer
if (ItemsCount==1)
DoEvent(evcDataRead,EV.EvRetCode,EV.EvArea,EV.EvIndex,EV.EvStart,EV.EvSize);
return true;
}
//==============================================================================
// FUNCTION WRITE
//==============================================================================
byte TS7Worker::WA_NotFound(TEv &EV)
{
EV.EvRetCode=evrErrAreaNotFound;
return Code7ResItemNotAvailable;
}
//------------------------------------------------------------------------------
byte TS7Worker::WA_InvalidTransportSize(TEv &EV)
{
EV.EvRetCode=evrErrTransportSize;
return Code7InvalidTransportSize;
}
//------------------------------------------------------------------------------
byte TS7Worker::WA_OutOfRange(TEv &EV)
{
EV.EvRetCode=evrErrOutOfRange;
return Code7AddressOutOfRange;
}
//------------------------------------------------------------------------------
byte TS7Worker::WA_DataSizeMismatch(TEv &EV)
{
EV.EvRetCode=evrDataSizeMismatch;
return Code7WriteDataSizeMismatch;
}
//------------------------------------------------------------------------------
byte TS7Worker::WriteArea(PReqFunWriteDataItem ReqItemData, PReqFunWriteItem ReqItemPar,
TEv &EV)
{
int Multiplier;
PS7Area P = NULL;
word DBNum = 0;
word Elements;
longword *PAdd;
PSnapCriticalSection pcs;
longword Start, Size, ASize, DataLen, AStart;
pbyte Target = NULL;
byte BitIndex;
EV.EvStart =0;
EV.EvSize =0;
EV.EvRetCode =evrNoError;
EV.EvIndex =0;
EV.EvArea=ReqItemPar->Area;
// Get Pointer to selected Area
if (ReqItemPar->Area==S7AreaDB)
{
DBNum=SwapWord(ReqItemPar->DBNumber);
EV.EvIndex=DBNum;
};
if (!FServer->ResourceLess)
{
P=GetArea(ReqItemPar->Area, DBNum);
if (P==NULL)
return WA_NotFound(EV);
}
// Calcs the amount
Multiplier = DataSizeByte(ReqItemPar->TransportSize);
if (Multiplier==0)
return WA_InvalidTransportSize(EV);
// Checks timers/counters coherence
if ((ReqItemPar->Area==S7AreaTM) ^ (ReqItemPar->TransportSize==S7WLTimer))
return WA_OutOfRange(EV);
if ((ReqItemPar->Area==S7AreaCT) ^ (ReqItemPar->TransportSize==S7WLCounter))
return WA_OutOfRange(EV);
// Calcs size
Elements = SwapWord(ReqItemPar->Length);
Size = Multiplier*Elements;
EV.EvSize=Size;
// More) 1 bit is not supported by S7 CPU
if ((ReqItemPar->TransportSize==S7WLBit) && (Size>1))
return WA_OutOfRange(EV);
// Calcs the start point ??
PAdd=(longword*)&ReqItemPar->Area; // points to area since we need 4 bytes for a pointer
Start=SwapDWord(*PAdd & 0xFFFFFF00);
// Checks if the address is not multiple of 8 when transport size is neither bit nor timer nor counter
if (
(ReqItemPar->TransportSize!=S7WLBit) &&
(ReqItemPar->TransportSize!=S7WLTimer) &&
(ReqItemPar->TransportSize!=S7WLCounter) &&
((Start % 8) !=0)
)
return WA_OutOfRange(EV);
// AStart is only for callback
if ((ReqItemPar->TransportSize != S7WLBit) && (ReqItemPar->TransportSize != S7WLCounter) && (ReqItemPar->TransportSize != S7WLTimer))
AStart = Start >> 3;
else
AStart = Start;
if ((ReqItemPar->TransportSize == S7WLCounter) || (ReqItemPar->TransportSize == S7WLTimer))
{
Start = Start >> 1; // 1 Timer or Counter = 2 bytes
}
else
{
BitIndex = Start & 0x07; // start bit
Start = Start >> 3; // start byte
}
EV.EvStart =Start;
if (!FServer->ResourceLess)
{
// Checks bounds
ASize = P->Size; // Area size
if (Start + Size > ASize)
return WA_OutOfRange(EV);
Target = pbyte(P->PData + Start);
}
// Checks data size coherence
DataLen=SwapWord(ReqItemData->DataLength);
if ((ReqItemData->TransportSize!=TS_ResOctet) && (ReqItemData->TransportSize!=TS_ResReal) && (ReqItemData->TransportSize!=TS_ResBit))
DataLen=DataLen / 8;
if (DataLen!=Size)
return WA_DataSizeMismatch(EV);
if (FServer->ResourceLess)
{
if (!FServer->DoWriteArea(ClientHandle, EV.EvArea, EV.EvIndex, AStart, Elements, ReqItemPar->TransportSize, &ReqItemData->Data[0]))
return WA_NotFound(EV);
}
else
{
if (ReqItemPar->TransportSize==S7WLBit)
{
if ((ReqItemData->Data[0] & 0x01) != 0) // bit set
*Target=*Target | BitMask[BitIndex];
else // bit reset
*Target=*Target & (~BitMask[BitIndex]);
}
else {
// Lock the area
pcs = P->cs;
pcs->Enter();
// Write Data
memcpy(Target, &ReqItemData->Data[0], Size);
pcs->Leave();
};
}
return 0xFF;
}
//------------------------------------------------------------------------------
bool TS7Worker::PerformFunctionWrite()
{
PReqFunWriteParams ReqParams;
TReqFunWriteData ReqData;
PResFunWrite ResData;
TS7Answer23 Answer;
int L;
uintptr_t StartData;
int c, ItemsCount;
int ResDSize;
TEv EV;
// Stage 1 : Setup pointers and initial check
ReqParams=PReqFunWriteParams(pbyte(PDUH_in)+sizeof(TS7ReqHeader));
ResData =PResFunWrite(pbyte(&Answer)+ResHeaderSize23);
StartData=sizeof(TS7ReqHeader)+SwapWord(PDUH_in->ParLen);
ItemsCount=ReqParams->ItemsCount;
ResDSize =ResHeaderSize23+2+ItemsCount;
for (c = 0; c < ItemsCount; c++)
{
ReqData[c]=PReqFunWriteDataItem(pbyte(PDUH_in)+StartData);
if ((ReqParams->Items[c].TransportSize == S7WLTimer) || (ReqParams->Items[c].TransportSize == S7WLCounter) || (ReqParams->Items[c].TransportSize == S7WLBit))
L = SwapWord(ReqData[c]->DataLength);
else
L = (SwapWord(ReqData[c]->DataLength) / 8);
StartData+=L+4;
// the datalength is always even
if ( L % 2 != 0) StartData++;
}
ResData->FunWrite =pduFuncWrite;
ResData->ItemCount=ReqParams->ItemsCount;
// Stage 2 : Write data
for (c = 0; c < ItemsCount; c++)
{
ResData->Data[c]=WriteArea(ReqData[c],&ReqParams->Items[c], EV);
// For multiple items we have to create multiple events
if (ItemsCount>1)
DoEvent(evcDataWrite,EV.EvRetCode,EV.EvArea,EV.EvIndex,EV.EvStart,EV.EvSize);
}
// Stage 3 : finalize the answer
Answer.Header.P=0x32;
Answer.Header.PDUType=0x03;
Answer.Header.AB_EX=0x0000;
Answer.Header.Sequence=PDUH_in->Sequence;
Answer.Header.ParLen=SwapWord(0x02);
Answer.Header.Error=0x0000; // this is zero, we will find the error in ResData.ReturnCode if any
Answer.Header.DataLen=SwapWord(ItemsCount);
isoSendBuffer(&Answer,ResDSize);
// For single item (most likely case) it's better to fire the event after
// we sent the answer
if (ItemsCount==1)
DoEvent(evcDataWrite,EV.EvRetCode,EV.EvArea,EV.EvIndex,EV.EvStart,EV.EvSize);
return true;
}
//==============================================================================
// FUNCTION NEGOTIATE
//==============================================================================
bool TS7Worker::PerformFunctionNegotiate()
{
PReqFunNegotiateParams ReqParams;
PResFunNegotiateParams ResParams;
word ReqLen;
TS7Answer23 Answer;
int Size;
// Setup pointers
ReqParams=PReqFunNegotiateParams(pbyte(PDUH_in)+sizeof(TS7ReqHeader));
ResParams=PResFunNegotiateParams(pbyte(&Answer)+sizeof(TS7ResHeader23));
// Prepares the answer
Answer.Header.P=0x32;
Answer.Header.PDUType=0x03;
Answer.Header.AB_EX=0x0000;
Answer.Header.Sequence=PDUH_in->Sequence;
Answer.Header.ParLen=SwapWord(sizeof(TResFunNegotiateParams));
Answer.Header.DataLen=0x0000;
Answer.Header.Error=0x0000;
// Params point at the end of the header
ResParams->FunNegotiate=pduNegotiate;
ResParams->Unknown=0x0;
// We offer the same
ResParams->ParallelJobs_1=ReqParams->ParallelJobs_1;
ResParams->ParallelJobs_2=ReqParams->ParallelJobs_2;
if (FServer->ForcePDU == 0)
{
ReqLen = SwapWord(ReqParams->PDULength);
if (ReqLenPDULength = SwapWord(MinPduSize);
else
if (ReqLen>IsoPayload_Size)
ResParams->PDULength = SwapWord(IsoPayload_Size);
else
ResParams->PDULength = ReqParams->PDULength;
}
else
ResParams->PDULength = SwapWord(FServer->ForcePDU);
FPDULength=SwapWord(ResParams->PDULength); // Stores the value
// Sends the answer
Size=sizeof(TS7ResHeader23) + sizeof(TResFunNegotiateParams);
isoSendBuffer(&Answer, Size);
// Store the event
DoEvent(evcNegotiatePDU, evrNoError, FPDULength, 0, 0, 0);
return true;
}
//==============================================================================
// FUNCTION CONTROL
//==============================================================================
bool TS7Worker::PerformFunctionControl(byte PduFun)
{
TS7Answer23 Answer;
PResFunCtrl ResParams;
word ParLen;
word CtrlCode;
// Setup pointer
ResParams=PResFunCtrl(pbyte(&Answer)+sizeof(TS7ResHeader23));
// Prepares the answer
Answer.Header.P=0x32;
Answer.Header.PDUType=0x03;
Answer.Header.AB_EX=0x0000;
Answer.Header.Sequence=PDUH_in->Sequence;
Answer.Header.ParLen=SwapWord(0x0001); // We send only Res fun without para
Answer.Header.DataLen=0x0000;
Answer.Header.Error=0x0000;
ResParams->ResFun=PduFun;
ResParams->para =0x00;
ParLen=SwapWord(PDUH_in->ParLen);
if (PduFun==pduStop)
CtrlCode=CodeControlStop;
else
{
switch (ParLen)
{
case 16 : CtrlCode=CodeControlCompress; break;
case 18 : CtrlCode=CodeControlCpyRamRom; break;
case 20 : CtrlCode=CodeControlWarmStart; break;
case 22 : CtrlCode=CodeControlColdStart; break;
case 26 : CtrlCode=CodeControlInsDel; break;
default : CtrlCode=CodeControlUnknown;
}
}
// Sends the answer
isoSendBuffer(&Answer,sizeof(TS7ResHeader23)+1);
// Stores the event
DoEvent(evcControl,0,CtrlCode,0,0,0);
if ((CtrlCode==CodeControlWarmStart) || (CtrlCode==CodeControlColdStart))
FServer->CpuStatus=S7CpuStatusRun;
if (CtrlCode==CodeControlStop)
FServer->CpuStatus=S7CpuStatusStop;
return true;
}
//==============================================================================
// FUNCTION UPLOAD
//==============================================================================
bool TS7Worker::PerformFunctionUpload()
{
TS7Answer23 Answer;
// Upload is not implemented, however to avoid that S7 manager hangs
// we simulate a cpu read/write protected.
// We can see the directory but can't upload/download anything
// Prepares the answer
Answer.Header.P=0x32;
Answer.Header.PDUType =pduResponse;
Answer.Header.AB_EX=0x0000;
Answer.Header.Sequence=PDUH_in->Sequence;
Answer.Header.ParLen=0;
Answer.Header.DataLen=0;
Answer.Header.Error=SwapWord(Code7NeedPassword);
// Sends the answer
isoSendBuffer(&Answer,sizeof(TS7ResHeader23));
DoEvent(evcUpload,evrCannotUpload,evsStartUpload,0,0,0);
return true;
}
//==============================================================================
// FUNCTION DOWNLOAD
//==============================================================================
bool TS7Worker::PerformFunctionDownload()
{
TS7Answer23 Answer;
// Download is not implemented, however to avoid that S7 manager hangs
// we simulate a cpu read/write protected.
// We can see the directory but can't upload/download anything
// Prepares the answer
Answer.Header.P=0x32;
Answer.Header.PDUType =pduResponse;
Answer.Header.AB_EX=0x0000;
Answer.Header.Sequence=PDUH_in->Sequence;
Answer.Header.ParLen=0;
Answer.Header.DataLen=0;
Answer.Header.Error=SwapWord(Code7NeedPassword);
// Sends the answer
isoSendBuffer(&Answer,sizeof(TS7ResHeader23));
DoEvent(evcUpload,evrCannotDownload, evsStartDownload,0,0,0);
return true;
}
//==============================================================================
// FUNCTIONS PROGRAMMER AND CYCLIC DATA (NOT IMPLEMENTED...yet)
//==============================================================================
bool TS7Worker::PerformGroupProgrammer()
{
DoEvent(evcPDUincoming,evrNotImplemented,grProgrammer,0,0,0);
return true;
}
//------------------------------------------------------------------------------
bool TS7Worker::PerformGroupCyclicData()
{
DoEvent(evcPDUincoming,evrNotImplemented,grCyclicData,0,0,0);
return true;
}
//==============================================================================
// BLOCK(S) INFO FUNCTIONS
//==============================================================================
void TS7Worker::BLK_ListAll(TCB &CB)
{
PDataFunListAll Data;
int TotalSize;
TotalSize = ResHeaderSize17+sizeof(TResFunGetBlockInfo)+sizeof(TDataFunListAll);
// Prepares the answer
CB.Answer.Header.P=0x32;
CB.Answer.Header.PDUType=PduType_userdata;
CB.Answer.Header.AB_EX=0x0000;
CB.Answer.Header.Sequence=PDUH_in->Sequence;
CB.Answer.Header.ParLen =SwapWord(sizeof(TResFunGetBlockInfo));
CB.Answer.Header.DataLen=SwapWord(sizeof(TDataFunListAll));
CB.ResParams->Head[0]=CB.ReqParams->Head[0];
CB.ResParams->Head[1]=CB.ReqParams->Head[1];
CB.ResParams->Head[2]=CB.ReqParams->Head[2];
CB.ResParams->Plen =0x08;
CB.ResParams->Uk =0x12;
CB.ResParams->Tg =0x83; // Type response, group functions info
CB.ResParams->SubFun=SFun_ListAll;
CB.ResParams->Seq =CB.ReqParams->Seq;
CB.ResParams->Rsvd =0x0000;
CB.ResParams->ErrNo =0x0000;
Data=PDataFunListAll(pbyte(&CB.Answer)+ResHeaderSize17+sizeof(TResFunGetBlockInfo));
Data->RetVal=0xFF;
Data->TRSize=TS_ResOctet;
Data->Length=SwapWord(28); // 28 = Size of TDataFunListAll.Blocks
// Fill elements, only DB will have a valid number
Data->Blocks[0].Zero=0x30;
Data->Blocks[0].BType=Block_OB;
Data->Blocks[0].BCount=0x0000; // We don't have OBs
Data->Blocks[1].Zero=0x30;
Data->Blocks[1].BType=Block_FB;
Data->Blocks[1].BCount=0x0000; // We don't have FBs
Data->Blocks[2].Zero=0x30;
Data->Blocks[2].BType=Block_FC;
Data->Blocks[2].BCount=0x0000; // We don't have FCs
Data->Blocks[3].Zero=0x30;
Data->Blocks[3].BType=Block_DB;
Data->Blocks[3].BCount=SwapWord(FServer->DBCount); // Most likely we HAVE DBs
Data->Blocks[4].Zero=0x30;
Data->Blocks[4].BType=Block_SDB;
Data->Blocks[4].BCount=0x0000; // We don't have SDBs
Data->Blocks[5].Zero=0x30;
Data->Blocks[5].BType=Block_SFC;
Data->Blocks[5].BCount=0x0000; // We don't have SFCs
Data->Blocks[6].Zero=0x30;
Data->Blocks[6].BType=Block_SFB;
Data->Blocks[6].BCount=0x0000; // We don't have SFBs
// Sends
isoSendBuffer(&CB.Answer,TotalSize);
DoEvent(evcDirectory, 0, evsGetBlockList, 0, 0, 0);
}
//------------------------------------------------------------------------------
void TS7Worker::BLK_NoResource_ListBoT(PDataFunGetBot Data, TCB &CB)
{
CB.DataLength =4;
DBCnt =0; // Reset counter
CB.Answer.Header.DataLen=SwapWord(CB.DataLength);
CB.ResParams->ErrNo =0x0ED2; // function in error
Data->RetVal =0x0A; // No resource available
Data->TSize =0x00; // No transport size;
Data->DataLen =0x0000; // No data;
CB.evError =evrResNotFound;
}
//------------------------------------------------------------------------------
void TS7Worker::BLK_ListBoT(byte BlockType, bool Start, TCB &CB)
{
PDataFunGetBot Data;
int MaxItems, TotalSize, cnt;
int HiBound = FServer->DBLimit+1;
CB.evError=0;
MaxItems=(FPDULength - 32) / 4;
// Prepares the answer
CB.Answer.Header.P=0x32;
CB.Answer.Header.PDUType=PduType_userdata;
CB.Answer.Header.AB_EX=0x0000;
CB.Answer.Header.Sequence=PDUH_in->Sequence;
CB.Answer.Header.ParLen =SwapWord(sizeof(TResFunGetBlockInfo));
CB.ResParams->Head[0]=CB.ReqParams->Head[0];
CB.ResParams->Head[1]=CB.ReqParams->Head[1];
CB.ResParams->Head[2]=CB.ReqParams->Head[2];
CB.ResParams->Plen =0x08;
CB.ResParams->Uk =0x12;
CB.ResParams->Tg =0x83; // Type response, group functions info
CB.ResParams->SubFun=SFun_ListBoT;
CB.ResParams->Seq =CB.ReqParams->Seq;
CB.ResParams->Rsvd =0x0000;
Data=PDataFunGetBot(pbyte(&CB.Answer)+ResHeaderSize17+sizeof(TResFunGetBlockInfo));
if (BlockType==Block_DB)
{
cnt =0; // Local couter
if (Start)
DBCnt=-1; // Global counter
if (FServer->DBCount>0)
{
while ((cntDB[DBCnt]!=NULL)
{
Data->Items[cnt].BlockNum=SwapWord(FServer->DB[DBCnt]->Number);
Data->Items[cnt].Unknown =0x22;
Data->Items[cnt].BlockLang=0x05;
cnt++;
};
};
if ((cntRsvd=0x0023;
}
else
CB.ResParams->Rsvd=0x0123;
if (cnt>0)
{
CB.ResParams->ErrNo =0x0000;
Data->TSize =TS_ResOctet;
Data->RetVal=0xFF;
CB.DataLength=4+(cnt*word(sizeof(TDataFunGetBotItem)));
CB.Answer.Header.DataLen=SwapWord(CB.DataLength);
Data->DataLen=SwapWord(CB.DataLength-4);
}
else
BLK_NoResource_ListBoT(Data, CB);
}
else
BLK_NoResource_ListBoT(Data, CB);
}
else // we store only DBs
BLK_NoResource_ListBoT(Data, CB);
TotalSize = ResHeaderSize17+sizeof(TResFunGetBlockInfo)+CB.DataLength;
isoSendBuffer(&CB.Answer,TotalSize);
if (Start)
DoEvent(evcDirectory, CB.evError, evsStartListBoT, BlockType, 0, 0);
else
DoEvent(evcDirectory, CB.evError, evsListBoT, BlockType, 0, 0);
}
//------------------------------------------------------------------------------
void TS7Worker::BLK_NoResource_GetBlkInfo(PResDataBlockInfo Data, TCB &CB)
{
CB.DataLength =4;
CB.Answer.Header.DataLen=SwapWord(CB.DataLength);
CB.ResParams->ErrNo =0x09D2; // function in error
Data->RetVal =0x0A; // No resource available
Data->TSize =0x00; // No transport size;
Data->Length =0x0000; // No data;
CB.evError =evrResNotFound;
}
//------------------------------------------------------------------------------
void TS7Worker::BLK_GetBlockNum_GetBlkInfo(int &BlkNum, PReqDataBlockInfo ReqData)
{
BlkNum = (ReqData->AsciiBlk[4] - 0x30) +
(ReqData->AsciiBlk[3] - 0x30) * 10 +
(ReqData->AsciiBlk[2] - 0x30) * 100 +
(ReqData->AsciiBlk[1] - 0x30) * 1000 +
(ReqData->AsciiBlk[0] - 0x30) * 10000;
if (BlkNum>65535)
BlkNum=-1;
}
//------------------------------------------------------------------------------
void TS7Worker::BLK_DoBlockInfo_GetBlkInfo(PS7Area DB, PResDataBlockInfo Data, TCB &CB)
{
// Prepares the answer
CB.Answer.Header.P=0x32;
CB.Answer.Header.PDUType=PduType_userdata;
CB.Answer.Header.AB_EX=0x0000;
CB.Answer.Header.Sequence=PDUH_in->Sequence;
CB.Answer.Header.ParLen =SwapWord(sizeof(TResFunGetBlockInfo));
CB.ResParams->Head[0]=CB.ReqParams->Head[0];
CB.ResParams->Head[1]=CB.ReqParams->Head[1];
CB.ResParams->Head[2]=CB.ReqParams->Head[2];
CB.ResParams->Plen =0x08;
CB.ResParams->Uk =0x12;
CB.ResParams->Tg =0x83; // Type response, group functions info
CB.ResParams->SubFun=SFun_BlkInfo;
CB.ResParams->Seq =CB.ReqParams->Seq;
CB.ResParams->Rsvd =0x0000;
CB.ResParams->ErrNo =0x0000;
CB.DataLength =sizeof(TResDataBlockInfo);
CB.Answer.Header.DataLen=SwapWord(CB.DataLength);
CB.ResParams->ErrNo =0x0000;
Data->RetVal =0xFF;
Data->TSize =TS_ResOctet;
Data->Length =SwapWord(78); // this struct - RetValData->Tsize and length
Data->Cst_b =0x01;
Data->BlkType =0x00;
Data->Cst_w1 =0x4A00;
Data->Cst_w2 =0x0022;
Data->Cst_pp =0x7070;
Data->Unknown_1 =0x01;
Data->BlkFlags =0x01;
Data->BlkLang =BlockLangDB;
Data->SubBlkType =0x0A;
Data->CodeTime_dy =SwapWord(5800);// Nov/18/1999 my princess's birthdate
Data->IntfTime_dy =Data->CodeTime_dy;
Data->LocDataLen =0x0000;
Data->BlkNumber =SwapWord(DB->Number);
Data->SbbLen =0x1400;
Data->AddLen =0x0000;
Data->MC7Len =SwapWord(DB->Size);
Data->LenLoadMem =SwapDWord(DB->Size+92);
Data->Version =0x01;
Data->Unknown_2 =0x00;
Data->BlkChksum =0x0000;
}
//------------------------------------------------------------------------------
void TS7Worker::BLK_GetBlkInfo(TCB &CB)
{
PReqDataBlockInfo ReqData;
PResDataBlockInfo Data;
int BlkNum;
PS7Area BlkDB;
byte BlkTypeInfo;
int TotalSize;
CB.evError=0;
Data =PResDataBlockInfo(pbyte(&CB.Answer)+ResHeaderSize17+sizeof(TResFunGetBlockInfo));
ReqData=PReqDataBlockInfo(pbyte(PDUH_in)+ReqHeaderSize+sizeof(TReqFunGetBlockInfo));
memset(Data,0,sizeof(TResDataBlockInfo)); // many fields are 0
BLK_GetBlockNum_GetBlkInfo(BlkNum, ReqData);
BlkTypeInfo=ReqData->BlkType;
if (BlkTypeInfo==Block_DB)
{
if (BlkNum>=0)
{
BlkDB=FServer->FindDB(BlkNum);
if (BlkDB!=NULL)
BLK_DoBlockInfo_GetBlkInfo(BlkDB, Data, CB);
else
BLK_NoResource_GetBlkInfo(Data, CB);
}
else
BLK_NoResource_GetBlkInfo(Data, CB);
}
else
BLK_NoResource_GetBlkInfo(Data, CB);
TotalSize = ResHeaderSize17+sizeof(TResFunGetBlockInfo)+sizeof(TResDataBlockInfo);
isoSendBuffer(&CB.Answer, TotalSize);
DoEvent(evcDirectory,CB.evError,evsGetBlockInfo,BlkTypeInfo,BlkNum,0);
}
//------------------------------------------------------------------------------
bool TS7Worker::PerformGroupBlockInfo()
{
TCB CB;
pbyte BlockType;
// Setup pointers
CB.ReqParams=PReqFunGetBlockInfo(pbyte(PDUH_in)+ReqHeaderSize);
CB.ResParams=PResFunGetBlockInfo(pbyte(&CB.Answer)+ResHeaderSize17);
BlockType =pbyte(PDUH_in)+23;
switch (CB.ReqParams->SubFun)
{
case SFun_ListAll : BLK_ListAll(CB); break; // List all blocks
case SFun_ListBoT :
{
if (CB.ReqParams->Plen==4)
{
LastBlk=*BlockType;
BLK_ListBoT(*BlockType, true, CB); // start sequence from beginning
}
else
BLK_ListBoT(LastBlk, false, CB); // Continue sequence
}; break;
case SFun_BlkInfo : BLK_GetBlkInfo(CB); // Get Block info
}
return true;
}
//==============================================================================
// FUNCTION SZL
//==============================================================================
void TS7Worker::SZLNotAvailable()
{
SZL.Answer.Header.DataLen=SwapWord(sizeof(SZLNotAvail));
SZL.ResParams->Err = 0x02D4;
memcpy(SZL.ResData, &SZLNotAvail, sizeof(SZLNotAvail));
isoSendBuffer(&SZL.Answer,26);
SZL.SZLDone=false;
}
void TS7Worker::SZLSystemState()
{
SZL.Answer.Header.DataLen=SwapWord(sizeof(SZLSysState));
SZL.ResParams->Err =0x0000;
memcpy(SZL.ResData,&SZLNotAvail,sizeof(SZLSysState));
isoSendBuffer(&SZL.Answer,28);
SZL.SZLDone=true;
}
void TS7Worker::SZLData(void *P, int len)
{
int MaxSzl=FPDULength-22;
if (len>MaxSzl) {
len=MaxSzl;
}
SZL.Answer.Header.DataLen=SwapWord(word(len));
SZL.ResParams->Err =0x0000;
SZL.ResParams->resvd=0x0000; // this is the end, no more packets
memcpy(SZL.ResData, P, len);
SZL.ResData[2]=((len-4)>>8) & 0xFF;
SZL.ResData[3]=(len-4) & 0xFF;
isoSendBuffer(&SZL.Answer,22+len);
SZL.SZLDone=true;
}
// this block is dynamic (contains date/time and cpu status)
void TS7Worker::SZL_ID424()
{
PS7Time PTime;
pbyte PStatus;
SZL.Answer.Header.DataLen=SwapWord(sizeof(SZL_ID_0424_IDX_XXXX));
SZL.ResParams->Err =0x0000;
PTime=PS7Time(pbyte(SZL.ResData)+24);
PStatus =pbyte(SZL.ResData)+15;
memcpy(SZL.ResData,&SZL_ID_0424_IDX_XXXX,sizeof(SZL_ID_0424_IDX_XXXX));
FillTime(PTime);
*PStatus=FServer->CpuStatus;
SZL.SZLDone=true;
isoSendBuffer(&SZL.Answer,22+sizeof(SZL_ID_0424_IDX_XXXX));
}
void TS7Worker::SZL_ID131_IDX003()
{
word len = sizeof(SZL_ID_0131_IDX_0003);
SZL.Answer.Header.DataLen=SwapWord(len);
SZL.ResParams->Err =0x0000;
SZL.ResParams->resvd=0x0000; // this is the end, no more packets
memcpy(SZL.ResData, &SZL_ID_0131_IDX_0003, len);
// Set the max consistent data window to PDU size
SZL.ResData[18]=((FPDULength)>>8) & 0xFF;
SZL.ResData[19]=(FPDULength) & 0xFF;
isoSendBuffer(&SZL.Answer,22+len);
SZL.SZLDone=true;
}
bool TS7Worker::PerformGroupSZL()
{
SZL.SZLDone=false;
// Setup pointers
SZL.ReqParams=PReqFunReadSZLFirst(pbyte(PDUH_in)+ReqHeaderSize);
SZL.ResParams=PS7ResParams7(pbyte(&SZL.Answer)+ResHeaderSize17);
SZL.ResData =pbyte(&SZL.Answer)+ResHeaderSize17+sizeof(TS7Params7);
// Prepare Answer header
SZL.Answer.Header.P=0x32;
SZL.Answer.Header.PDUType=PduType_userdata;
SZL.Answer.Header.AB_EX=0x0000;
SZL.Answer.Header.Sequence=PDUH_in->Sequence;
SZL.Answer.Header.ParLen =SwapWord(sizeof(TS7Params7));
SZL.ResParams->Head[0]=SZL.ReqParams->Head[0];
SZL.ResParams->Head[1]=SZL.ReqParams->Head[1];
SZL.ResParams->Head[2]=SZL.ReqParams->Head[2];
SZL.ResParams->Plen =0x08;
SZL.ResParams->Uk =0x12;
SZL.ResParams->Tg =0x84; // Type response + group szl
SZL.ResParams->SubFun=SZL.ReqParams->SubFun;
SZL.ResParams->Seq =SZL.ReqParams->Seq;
SZL.ResParams->resvd=0x0000; // this is the end, no more packets
// only two subfunction are defined : 0x01 read, 0x02 system state
if (SZL.ResParams->SubFun==0x02) // 0x02 = subfunction system state
{
SZLSystemState();
return true;
};
if (SZL.ResParams->SubFun!=0x01)
{
SZLNotAvailable();
return true;
};
// From here we assume subfunction = 0x01
SZL.ReqData=PS7ReqSZLData(pbyte(PDUH_in)+ReqHeaderSize+sizeof(TReqFunReadSZLFirst));// Data after params
SZL.ID=SwapWord(SZL.ReqData->ID);
SZL.Index=SwapWord(SZL.ReqData->Index);
// Switch prebuilt Data Bank (they come from a physical CPU)
switch (SZL.ID)
{
case 0x0000 : SZLData(&SZL_ID_0000_IDX_XXXX,sizeof(SZL_ID_0000_IDX_XXXX));break;
case 0x0F00 : SZLData(&SZL_ID_0F00_IDX_XXXX,sizeof(SZL_ID_0F00_IDX_XXXX));break;
case 0x0002 : SZLData(&SZL_ID_0002_IDX_XXXX,sizeof(SZL_ID_0002_IDX_XXXX));break;
case 0x0011 : SZLData(&SZL_ID_0011_IDX_XXXX,sizeof(SZL_ID_0011_IDX_XXXX));break;
case 0x0012 : SZLData(&SZL_ID_0012_IDX_XXXX,sizeof(SZL_ID_0012_IDX_XXXX));break;
case 0x0013 : SZLData(&SZL_ID_0013_IDX_XXXX,sizeof(SZL_ID_0013_IDX_XXXX));break;
case 0x0014 : SZLData(&SZL_ID_0014_IDX_XXXX,sizeof(SZL_ID_0014_IDX_XXXX));break;
case 0x0015 : SZLData(&SZL_ID_0015_IDX_XXXX,sizeof(SZL_ID_0015_IDX_XXXX));break;
case 0x0F14 : SZLData(&SZL_ID_0F14_IDX_XXXX,sizeof(SZL_ID_0F14_IDX_XXXX));break;
case 0x0019 : SZLData(&SZL_ID_0019_IDX_XXXX,sizeof(SZL_ID_0019_IDX_XXXX));break;
case 0x0F19 : SZLData(&SZL_ID_0F19_IDX_XXXX,sizeof(SZL_ID_0F19_IDX_XXXX));break;
case 0x001C : SZLData(&SZL_ID_001C_IDX_XXXX,sizeof(SZL_ID_001C_IDX_XXXX));break;
case 0x0F1C : SZLData(&SZL_ID_0F1C_IDX_XXXX,sizeof(SZL_ID_0F1C_IDX_XXXX));break;
case 0x0036 : SZLData(&SZL_ID_0036_IDX_XXXX,sizeof(SZL_ID_0036_IDX_XXXX));break;
case 0x0F36 : SZLData(&SZL_ID_0F36_IDX_XXXX,sizeof(SZL_ID_0F36_IDX_XXXX));break;
case 0x0025 : SZLData(&SZL_ID_0025_IDX_XXXX,sizeof(SZL_ID_0025_IDX_XXXX));break;
case 0x0F25 : SZLData(&SZL_ID_0F25_IDX_XXXX,sizeof(SZL_ID_0F25_IDX_XXXX));break;
case 0x0037 : SZLData(&SZL_ID_0037_IDX_XXXX,sizeof(SZL_ID_0037_IDX_XXXX));break;
case 0x0F37 : SZLData(&SZL_ID_0F37_IDX_XXXX,sizeof(SZL_ID_0F37_IDX_XXXX));break;
case 0x0074 : SZLData(&SZL_ID_0074_IDX_XXXX,sizeof(SZL_ID_0074_IDX_XXXX));break;
case 0x0F74 : SZLData(&SZL_ID_0F74_IDX_XXXX,sizeof(SZL_ID_0F74_IDX_XXXX));break;
case 0x0591 : SZLData(&SZL_ID_0591_IDX_XXXX,sizeof(SZL_ID_0591_IDX_XXXX));break;
case 0x0A91 : SZLData(&SZL_ID_0A91_IDX_XXXX,sizeof(SZL_ID_0A91_IDX_XXXX));break;
case 0x0F92 : SZLData(&SZL_ID_0F92_IDX_XXXX,sizeof(SZL_ID_0F92_IDX_XXXX));break;
case 0x0294 : SZLData(&SZL_ID_0294_IDX_XXXX,sizeof(SZL_ID_0294_IDX_XXXX));break;
case 0x0794 : SZLData(&SZL_ID_0794_IDX_XXXX,sizeof(SZL_ID_0794_IDX_XXXX));break;
case 0x0F94 : SZLData(&SZL_ID_0F94_IDX_XXXX,sizeof(SZL_ID_0F94_IDX_XXXX));break;
case 0x0095 : SZLData(&SZL_ID_0095_IDX_XXXX,sizeof(SZL_ID_0095_IDX_XXXX));break;
case 0x0F95 : SZLData(&SZL_ID_0F95_IDX_XXXX,sizeof(SZL_ID_0F95_IDX_XXXX));break;
case 0x00A0 : SZLData(&SZL_ID_00A0_IDX_XXXX,sizeof(SZL_ID_00A0_IDX_XXXX));break;
case 0x0FA0 : SZLData(&SZL_ID_0FA0_IDX_XXXX,sizeof(SZL_ID_0FA0_IDX_XXXX));break;
case 0x0017 : SZLData(&SZL_ID_0017_IDX_XXXX,sizeof(SZL_ID_0017_IDX_XXXX));break;
case 0x0F17 : SZLData(&SZL_ID_0F17_IDX_XXXX,sizeof(SZL_ID_0F17_IDX_XXXX));break;
case 0x0018 : SZLData(&SZL_ID_0018_IDX_XXXX,sizeof(SZL_ID_0018_IDX_XXXX));break;
case 0x0F18 : SZLData(&SZL_ID_0F18_IDX_XXXX,sizeof(SZL_ID_0F18_IDX_XXXX));break;
case 0x001A : SZLData(&SZL_ID_001A_IDX_XXXX,sizeof(SZL_ID_001A_IDX_XXXX));break;
case 0x0F1A : SZLData(&SZL_ID_0F1A_IDX_XXXX,sizeof(SZL_ID_0F1A_IDX_XXXX));break;
case 0x001B : SZLData(&SZL_ID_001B_IDX_XXXX,sizeof(SZL_ID_001B_IDX_XXXX));break;
case 0x0F1B : SZLData(&SZL_ID_0F1B_IDX_XXXX,sizeof(SZL_ID_0F1B_IDX_XXXX));break;
case 0x0021 : SZLData(&SZL_ID_0021_IDX_XXXX,sizeof(SZL_ID_0021_IDX_XXXX));break;
case 0x0A21 : SZLData(&SZL_ID_0A21_IDX_XXXX,sizeof(SZL_ID_0A21_IDX_XXXX));break;
case 0x0F21 : SZLData(&SZL_ID_0F21_IDX_XXXX,sizeof(SZL_ID_0F21_IDX_XXXX));break;
case 0x0023 : SZLData(&SZL_ID_0023_IDX_XXXX,sizeof(SZL_ID_0023_IDX_XXXX));break;
case 0x0F23 : SZLData(&SZL_ID_0F23_IDX_XXXX,sizeof(SZL_ID_0F23_IDX_XXXX));break;
case 0x0024 : SZLData(&SZL_ID_0024_IDX_XXXX,sizeof(SZL_ID_0024_IDX_XXXX));break;
case 0x0124 : SZLData(&SZL_ID_0124_IDX_XXXX,sizeof(SZL_ID_0124_IDX_XXXX));break;
case 0x0424 : SZL_ID424();break;
case 0x0038 : SZLData(&SZL_ID_0038_IDX_XXXX,sizeof(SZL_ID_0038_IDX_XXXX));break;
case 0x0F38 : SZLData(&SZL_ID_0F38_IDX_XXXX,sizeof(SZL_ID_0F38_IDX_XXXX));break;
case 0x003A : SZLData(&SZL_ID_003A_IDX_XXXX,sizeof(SZL_ID_003A_IDX_XXXX));break;
case 0x0F3A : SZLData(&SZL_ID_0F3A_IDX_XXXX,sizeof(SZL_ID_0F3A_IDX_XXXX));break;
case 0x0F9A : SZLData(&SZL_ID_0F9A_IDX_XXXX,sizeof(SZL_ID_0F9A_IDX_XXXX));break;
case 0x0D91 : switch(SZL.Index){
case 0x0000 : SZLData(&SZL_ID_0D91_IDX_0000,sizeof(SZL_ID_0D91_IDX_0000));break;
default: SZLNotAvailable();break;
};
break;
case 0x0092 : switch(SZL.Index){
case 0x0000 : SZLData(&SZL_ID_0092_IDX_0000,sizeof(SZL_ID_0092_IDX_0000));break;
default : SZLNotAvailable();break;
};break;
case 0x0292 : switch(SZL.Index){
case 0x0000 : SZLData(&SZL_ID_0292_IDX_0000,sizeof(SZL_ID_0292_IDX_0000));break;
default : SZLNotAvailable();break;
};break;
case 0x0692 : switch(SZL.Index){
case 0x0000 : SZLData(&SZL_ID_0692_IDX_0000,sizeof(SZL_ID_0692_IDX_0000));break;
default : SZLNotAvailable();break;
};break;
case 0x0094 : switch(SZL.Index){
case 0x0000 : SZLData(&SZL_ID_0094_IDX_0000,sizeof(SZL_ID_0094_IDX_0000));break;
default : SZLNotAvailable();break;
};break;
case 0x0D97 : switch(SZL.Index){
case 0x0000 : SZLData(&SZL_ID_0D97_IDX_0000,sizeof(SZL_ID_0D97_IDX_0000));break;
default : SZLNotAvailable();break;
};break;
case 0x0111 : switch(SZL.Index){
case 0x0001 : SZLData(&SZL_ID_0111_IDX_0001,sizeof(SZL_ID_0111_IDX_0001));break;
case 0x0006 : SZLData(&SZL_ID_0111_IDX_0006,sizeof(SZL_ID_0111_IDX_0006));break;
case 0x0007 : SZLData(&SZL_ID_0111_IDX_0007,sizeof(SZL_ID_0111_IDX_0007));break;
default : SZLNotAvailable();break;
};break;
case 0x0F11 : switch(SZL.Index){
case 0x0001 : SZLData(&SZL_ID_0F11_IDX_0001,sizeof(SZL_ID_0F11_IDX_0001));break;
case 0x0006 : SZLData(&SZL_ID_0F11_IDX_0006,sizeof(SZL_ID_0F11_IDX_0006));break;
case 0x0007 : SZLData(&SZL_ID_0F11_IDX_0007,sizeof(SZL_ID_0F11_IDX_0007));break;
default : SZLNotAvailable();break;
};break;
case 0x0112 : switch(SZL.Index){
case 0x0000 : SZLData(&SZL_ID_0112_IDX_0000,sizeof(SZL_ID_0112_IDX_0000));break;
case 0x0100 : SZLData(&SZL_ID_0112_IDX_0100,sizeof(SZL_ID_0112_IDX_0100));break;
case 0x0200 : SZLData(&SZL_ID_0112_IDX_0200,sizeof(SZL_ID_0112_IDX_0200));break;
case 0x0400 : SZLData(&SZL_ID_0112_IDX_0400,sizeof(SZL_ID_0112_IDX_0400));break;
default : SZLNotAvailable();break;
};break;
case 0x0F12 : switch(SZL.Index){
case 0x0000 : SZLData(&SZL_ID_0F12_IDX_0000,sizeof(SZL_ID_0F12_IDX_0000));break;
case 0x0100 : SZLData(&SZL_ID_0F12_IDX_0100,sizeof(SZL_ID_0F12_IDX_0100));break;
case 0x0200 : SZLData(&SZL_ID_0F12_IDX_0200,sizeof(SZL_ID_0F12_IDX_0200));break;
case 0x0400 : SZLData(&SZL_ID_0F12_IDX_0400,sizeof(SZL_ID_0F12_IDX_0400));break;
default : SZLNotAvailable();break;
};break;
case 0x0113 : switch(SZL.Index){
case 0x0001 : SZLData(&SZL_ID_0113_IDX_0001,sizeof(SZL_ID_0113_IDX_0001));break;
default : SZLNotAvailable();break;
};break;
case 0x0115 : switch(SZL.Index){
case 0x0800 : SZLData(&SZL_ID_0115_IDX_0800,sizeof(SZL_ID_0115_IDX_0800));break;
default : SZLNotAvailable();break;
};break;
case 0x011C : switch(SZL.Index){
case 0x0001 : SZLData(&SZL_ID_011C_IDX_0001,sizeof(SZL_ID_011C_IDX_0001));break;
case 0x0002 : SZLData(&SZL_ID_011C_IDX_0002,sizeof(SZL_ID_011C_IDX_0002));break;
case 0x0003 : SZLData(&SZL_ID_011C_IDX_0003,sizeof(SZL_ID_011C_IDX_0003));break;
case 0x0004 : SZLData(&SZL_ID_011C_IDX_0004,sizeof(SZL_ID_011C_IDX_0004));break;
case 0x0005 : SZLData(&SZL_ID_011C_IDX_0005,sizeof(SZL_ID_011C_IDX_0005));break;
case 0x0007 : SZLData(&SZL_ID_011C_IDX_0007,sizeof(SZL_ID_011C_IDX_0007));break;
case 0x0008 : SZLData(&SZL_ID_011C_IDX_0008,sizeof(SZL_ID_011C_IDX_0008));break;
case 0x0009 : SZLData(&SZL_ID_011C_IDX_0009,sizeof(SZL_ID_011C_IDX_0009));break;
case 0x000A : SZLData(&SZL_ID_011C_IDX_000A,sizeof(SZL_ID_011C_IDX_000A));break;
case 0x000B : SZLData(&SZL_ID_011C_IDX_000B,sizeof(SZL_ID_011C_IDX_000B));break;
default : SZLNotAvailable();break;
};break;
case 0x0222 : switch(SZL.Index){
case 0x0001 : SZLData(&SZL_ID_0222_IDX_0001,sizeof(SZL_ID_0222_IDX_0001));break;
case 0x000A : SZLData(&SZL_ID_0222_IDX_000A,sizeof(SZL_ID_0222_IDX_000A));break;
case 0x0014 : SZLData(&SZL_ID_0222_IDX_0014,sizeof(SZL_ID_0222_IDX_0014));break;
case 0x0028 : SZLData(&SZL_ID_0222_IDX_0028,sizeof(SZL_ID_0222_IDX_0028));break;
case 0x0050 : SZLData(&SZL_ID_0222_IDX_0050,sizeof(SZL_ID_0222_IDX_0050));break;
case 0x0064 : SZLData(&SZL_ID_0222_IDX_0064,sizeof(SZL_ID_0222_IDX_0064));break;
default : SZLNotAvailable();break;
};break;
case 0x0125 : switch(SZL.Index){
case 0x0000 : SZLData(&SZL_ID_0125_IDX_0000,sizeof(SZL_ID_0125_IDX_0000));break;
case 0x0001 : SZLData(&SZL_ID_0125_IDX_0001,sizeof(SZL_ID_0125_IDX_0001));break;
default : SZLNotAvailable();break;
};break;
case 0x0225 : switch(SZL.Index){
case 0x0001 : SZLData(&SZL_ID_0225_IDX_0001,sizeof(SZL_ID_0225_IDX_0001));break;
default : SZLNotAvailable();break;
};break;
case 0x0131 : switch(SZL.Index){
case 0x0001 : SZLData(&SZL_ID_0131_IDX_0001,sizeof(SZL_ID_0131_IDX_0001));break;
case 0x0002 : SZLData(&SZL_ID_0131_IDX_0002,sizeof(SZL_ID_0131_IDX_0002));break;
case 0x0003 : SZL_ID131_IDX003();break;
case 0x0004 : SZLData(&SZL_ID_0131_IDX_0004,sizeof(SZL_ID_0131_IDX_0004));break;
case 0x0005 : SZLData(&SZL_ID_0131_IDX_0005,sizeof(SZL_ID_0131_IDX_0005));break;
case 0x0006 : SZLData(&SZL_ID_0131_IDX_0006,sizeof(SZL_ID_0131_IDX_0006));break;
case 0x0007 : SZLData(&SZL_ID_0131_IDX_0007,sizeof(SZL_ID_0131_IDX_0007));break;
case 0x0008 : SZLData(&SZL_ID_0131_IDX_0008,sizeof(SZL_ID_0131_IDX_0008));break;
case 0x0009 : SZLData(&SZL_ID_0131_IDX_0009,sizeof(SZL_ID_0131_IDX_0009));break;
default : SZLNotAvailable();break;
};break;
case 0x0117 : switch(SZL.Index){
case 0x0000 : SZLData(&SZL_ID_0117_IDX_0000,sizeof(SZL_ID_0117_IDX_0000));break;
case 0x0001 : SZLData(&SZL_ID_0117_IDX_0001,sizeof(SZL_ID_0117_IDX_0001));break;
case 0x0002 : SZLData(&SZL_ID_0117_IDX_0002,sizeof(SZL_ID_0117_IDX_0002));break;
case 0x0003 : SZLData(&SZL_ID_0117_IDX_0003,sizeof(SZL_ID_0117_IDX_0003));break;
case 0x0004 : SZLData(&SZL_ID_0117_IDX_0004,sizeof(SZL_ID_0117_IDX_0004));break;
default : SZLNotAvailable();break;
};break;
case 0x0118 : switch(SZL.Index){
case 0x0000 : SZLData(&SZL_ID_0118_IDX_0000,sizeof(SZL_ID_0118_IDX_0000));break;
case 0x0001 : SZLData(&SZL_ID_0118_IDX_0001,sizeof(SZL_ID_0118_IDX_0001));break;
case 0x0002 : SZLData(&SZL_ID_0118_IDX_0002,sizeof(SZL_ID_0118_IDX_0002));break;
case 0x0003 : SZLData(&SZL_ID_0118_IDX_0003,sizeof(SZL_ID_0118_IDX_0003));break;
default : SZLNotAvailable();break;
};break;
case 0x0132 : switch(SZL.Index){
case 0x0001 : SZLData(&SZL_ID_0132_IDX_0001,sizeof(SZL_ID_0132_IDX_0001));break;
case 0x0002 : SZLData(&SZL_ID_0132_IDX_0002,sizeof(SZL_ID_0132_IDX_0002));break;
case 0x0003 : SZLData(&SZL_ID_0132_IDX_0003,sizeof(SZL_ID_0132_IDX_0003));break;
case 0x0004 : SZLData(&SZL_ID_0132_IDX_0004,sizeof(SZL_ID_0132_IDX_0004));break;
case 0x0005 : SZLData(&SZL_ID_0132_IDX_0005,sizeof(SZL_ID_0132_IDX_0005));break;
case 0x0006 : SZLData(&SZL_ID_0132_IDX_0006,sizeof(SZL_ID_0132_IDX_0006));break;
case 0x0007 : SZLData(&SZL_ID_0132_IDX_0007,sizeof(SZL_ID_0132_IDX_0007));break;
case 0x0008 : SZLData(&SZL_ID_0132_IDX_0008,sizeof(SZL_ID_0132_IDX_0008));break;
case 0x0009 : SZLData(&SZL_ID_0132_IDX_0009,sizeof(SZL_ID_0132_IDX_0009));break;
case 0x000A : SZLData(&SZL_ID_0132_IDX_000A,sizeof(SZL_ID_0132_IDX_000A));break;
case 0x000B : SZLData(&SZL_ID_0132_IDX_000B,sizeof(SZL_ID_0132_IDX_000B));break;
case 0x000C : SZLData(&SZL_ID_0132_IDX_000C,sizeof(SZL_ID_0132_IDX_000C));break;
default : SZLNotAvailable();break;
};break;
case 0x0137 : switch(SZL.Index){
case 0x07FE : SZLData(&SZL_ID_0137_IDX_07FE,sizeof(SZL_ID_0137_IDX_07FE));break;
default : SZLNotAvailable();break;
};break;
case 0x01A0 : switch(SZL.Index){
case 0x0000 : SZLData(&SZL_ID_01A0_IDX_0000,sizeof(SZL_ID_01A0_IDX_0000));break;
case 0x0001 : SZLData(&SZL_ID_01A0_IDX_0001,sizeof(SZL_ID_01A0_IDX_0001));break;
case 0x0002 : SZLData(&SZL_ID_01A0_IDX_0002,sizeof(SZL_ID_01A0_IDX_0002));break;
case 0x0003 : SZLData(&SZL_ID_01A0_IDX_0003,sizeof(SZL_ID_01A0_IDX_0003));break;
case 0x0004 : SZLData(&SZL_ID_01A0_IDX_0004,sizeof(SZL_ID_01A0_IDX_0004));break;
case 0x0005 : SZLData(&SZL_ID_01A0_IDX_0005,sizeof(SZL_ID_01A0_IDX_0005));break;
case 0x0006 : SZLData(&SZL_ID_01A0_IDX_0006,sizeof(SZL_ID_01A0_IDX_0006));break;
case 0x0007 : SZLData(&SZL_ID_01A0_IDX_0007,sizeof(SZL_ID_01A0_IDX_0007));break;
case 0x0008 : SZLData(&SZL_ID_01A0_IDX_0008,sizeof(SZL_ID_01A0_IDX_0008));break;
case 0x0009 : SZLData(&SZL_ID_01A0_IDX_0009,sizeof(SZL_ID_01A0_IDX_0009));break;
case 0x000A : SZLData(&SZL_ID_01A0_IDX_000A,sizeof(SZL_ID_01A0_IDX_000A));break;
case 0x000B : SZLData(&SZL_ID_01A0_IDX_000B,sizeof(SZL_ID_01A0_IDX_000B));break;
case 0x000C : SZLData(&SZL_ID_01A0_IDX_000C,sizeof(SZL_ID_01A0_IDX_000C));break;
case 0x000D : SZLData(&SZL_ID_01A0_IDX_000D,sizeof(SZL_ID_01A0_IDX_000D));break;
case 0x000E : SZLData(&SZL_ID_01A0_IDX_000E,sizeof(SZL_ID_01A0_IDX_000E));break;
case 0x000F : SZLData(&SZL_ID_01A0_IDX_000F,sizeof(SZL_ID_01A0_IDX_000F));break;
case 0x0010 : SZLData(&SZL_ID_01A0_IDX_0010,sizeof(SZL_ID_01A0_IDX_0010));break;
case 0x0011 : SZLData(&SZL_ID_01A0_IDX_0011,sizeof(SZL_ID_01A0_IDX_0011));break;
case 0x0012 : SZLData(&SZL_ID_01A0_IDX_0012,sizeof(SZL_ID_01A0_IDX_0012));break;
case 0x0013 : SZLData(&SZL_ID_01A0_IDX_0013,sizeof(SZL_ID_01A0_IDX_0013));break;
case 0x0014 : SZLData(&SZL_ID_01A0_IDX_0014,sizeof(SZL_ID_01A0_IDX_0014));break;
case 0x0015 : SZLData(&SZL_ID_01A0_IDX_0015,sizeof(SZL_ID_01A0_IDX_0015));break;
default : SZLNotAvailable();break;
};break;
case 0x0174 : switch(SZL.Index){
case 0x0001 : SZLData(&SZL_ID_0174_IDX_0001,sizeof(SZL_ID_0174_IDX_0001));break;
case 0x0004 : SZLData(&SZL_ID_0174_IDX_0004,sizeof(SZL_ID_0174_IDX_0004));break;
case 0x0005 : SZLData(&SZL_ID_0174_IDX_0005,sizeof(SZL_ID_0174_IDX_0005));break;
case 0x0006 : SZLData(&SZL_ID_0174_IDX_0006,sizeof(SZL_ID_0174_IDX_0006));break;
case 0x000B : SZLData(&SZL_ID_0174_IDX_000B,sizeof(SZL_ID_0174_IDX_000B));break;
case 0x000C : SZLData(&SZL_ID_0174_IDX_000C,sizeof(SZL_ID_0174_IDX_000C));break;
default : SZLNotAvailable();break;
};break;
case 0x0194 : switch(SZL.Index){
case 0x0064 : SZLData(&SZL_ID_0194_IDX_0064,sizeof(SZL_ID_0194_IDX_0064));break;
default : SZLNotAvailable();break;
};break;
case 0x0694 : switch(SZL.Index){
case 0x0064 : SZLData(&SZL_ID_0694_IDX_0064,sizeof(SZL_ID_0694_IDX_0064));break;
default : SZLNotAvailable();break;
};break;
case 0x0232 : switch(SZL.Index){
case 0x0001 : SZLData(&SZL_ID_0232_IDX_0001,sizeof(SZL_ID_0232_IDX_0001));break;
case 0x0004 : SZLData(&SZL_ID_0232_IDX_0004,sizeof(SZL_ID_0232_IDX_0004));break;
default : SZLNotAvailable();break;
};break;
case 0x0C91 : switch(SZL.Index){
case 0x07FE : SZLData(&SZL_ID_0C91_IDX_07FE,sizeof(SZL_ID_0C91_IDX_07FE));break;
default : SZLNotAvailable();break;
};break;
default : SZLNotAvailable();break;
}
// Event
if (SZL.SZLDone)
DoEvent(evcReadSZL,evrNoError,SZL.ID,SZL.Index,0,0);
else
DoEvent(evcReadSZL,evrInvalidSZL,SZL.ID,SZL.Index,0,0);
return true;
}
//------------------------------------------------------------------------------
bool TS7Worker::PerformGroupSecurity()
{
PReqFunSecurity ReqParams;
PResParamsSecurity ResParams;
PResDataSecurity ResData;
TS7Answer17 Answer;
int TotalSize;
ReqParams=PReqFunSecurity(pbyte(PDUH_in)+ReqHeaderSize);
ResParams=PResParamsSecurity(pbyte(&Answer)+ResHeaderSize17);
ResData =PResDataSecurity(pbyte(ResParams)+sizeof(TResParamsSecurity));
// Prepares the answer
Answer.Header.P=0x32;
Answer.Header.PDUType=PduType_userdata;
Answer.Header.AB_EX=0x0000;
Answer.Header.Sequence=PDUH_in->Sequence;
Answer.Header.ParLen =SwapWord(sizeof(TResParamsSecurity));
Answer.Header.DataLen=SwapWord(0x0004);
// Params
ResParams->Head[0]=ReqParams->Head[0];
ResParams->Head[1]=ReqParams->Head[1];
ResParams->Head[2]=ReqParams->Head[2];
ResParams->Plen =0x08;
ResParams->Uk =0x12;
ResParams->Tg =0x85; // Type response, group functions info
ResParams->SubFun=ReqParams->SubFun;
ResParams->Seq =ReqParams->Seq;
ResParams->resvd =0x0000;
ResParams->Err =0x0000;
// Data
ResData->Ret =0x0A;
ResData->TS =0x00;
ResData->DLen=0x0000;
TotalSize=26;
isoSendBuffer(&Answer,TotalSize);
switch (ReqParams->SubFun)
{
case SFun_EnterPwd : DoEvent(evcSecurity,evrNoError,evsSetPassword,0,0,0); break;
case SFun_CancelPwd : DoEvent(evcSecurity,evrNoError,evsClrPassword,0,0,0); break;
default : DoEvent(evcSecurity,evrNoError,evsUnknown,0,0,0);
};
return true;
}
//------------------------------------------------------------------------------
bool TS7Worker::PerformGetClock()
{
PS7ReqParams7 ReqParams;
PS7ResParams7 ResParams;
TS7Answer17 Answer;
PResDataGetTime Data;
PS7Time PTime;
int TotalSize;
ReqParams=PS7ReqParams7(pbyte(PDUH_in)+ReqHeaderSize);
ResParams=PS7ResParams7(pbyte(&Answer)+ResHeaderSize17);
Data =PResDataGetTime(pbyte(&Answer)+ResHeaderSize17+sizeof(TS7Params7));
PTime =PS7Time(pbyte(Data)+6);
// Prepares the answer
Answer.Header.P=0x32;
Answer.Header.PDUType=PduType_userdata;
Answer.Header.AB_EX=0x0000;
Answer.Header.Sequence=PDUH_in->Sequence;
Answer.Header.ParLen =SwapWord(sizeof(TS7Params7));
Answer.Header.DataLen=SwapWord(sizeof(TResDataGetTime));
ResParams->Head[0]=ReqParams->Head[0];
ResParams->Head[1]=ReqParams->Head[1];
ResParams->Head[2]=ReqParams->Head[2];
ResParams->Plen =0x08;
ResParams->Uk =0x12;
ResParams->Tg =0x87; // Type response, group functions info
ResParams->SubFun=ReqParams->SubFun;
ResParams->Seq =ReqParams->Seq;
ResParams->resvd =0x0000;
ResParams->Err =0x0000;
Data->RetVal =0xFF;
Data->TSize =TS_ResOctet;
Data->Length =SwapWord(10);
Data->Rsvd =0x00;
Data->HiYear =0x20; // Year 2000 +
FillTime(PTime);
TotalSize=36;
isoSendBuffer(&Answer,TotalSize);
DoEvent(evcClock,evrNoError,evsGetClock,0,0,0);
return true;
}
//------------------------------------------------------------------------------
bool TS7Worker::PerformSetClock()
{
PS7ReqParams7 ReqParams;
PS7ResParams7 ResParams;
PResDataSetTime Data;
TS7Answer17 Answer;
int TotalSize;
ReqParams=PS7ReqParams7(pbyte(PDUH_in)+ReqHeaderSize);
ResParams=PS7ResParams7(pbyte(&Answer)+ResHeaderSize17);
Data =PResDataSetTime(pbyte(&Answer)+ResHeaderSize17+sizeof(TS7Params7));
// Prepares the answer
Answer.Header.P=0x32;
Answer.Header.PDUType=PduType_userdata;
Answer.Header.AB_EX=0x0000;
Answer.Header.Sequence=PDUH_in->Sequence;
Answer.Header.ParLen =SwapWord(sizeof(TS7Params7));
Answer.Header.DataLen=SwapWord(sizeof(TResDataSetTime));
ResParams->Head[0]=ReqParams->Head[0];
ResParams->Head[1]=ReqParams->Head[1];
ResParams->Head[2]=ReqParams->Head[2];
ResParams->Plen =0x08;
ResParams->Uk =0x12;
ResParams->Tg =0x87; // Type response, group functions info
ResParams->SubFun=ReqParams->SubFun;
ResParams->Seq =ReqParams->Seq;
ResParams->resvd =0x0000;
ResParams->Err =0x0000;
Data->RetVal =0x0A;
Data->TSize =0x00;
Data->Length =0x0000;
TotalSize=26;
isoSendBuffer(&Answer,TotalSize);
DoEvent(evcClock,evrNoError,evsSetClock,0,0,0);
return true;
}
//------------------------------------------------------------------------------
// S7 SERVER CLASS
//------------------------------------------------------------------------------
TSnap7Server::TSnap7Server()
{
CSRWHook = new TSnapCriticalSection();
OnReadEvent=NULL;
memset(&DB,0,sizeof(DB));
memset(&HA,0,sizeof(HA));
DBCount=0;
DBLimit=0;
ForcePDU = 0;
ResourceLess = false;
LocalPort=isoTcpPort;
CpuStatus=S7CpuStatusRun;
WorkInterval=100;
}
//------------------------------------------------------------------------------
TSnap7Server::~TSnap7Server()
{
DisposeAll();
delete CSRWHook;
}
//------------------------------------------------------------------------------
PWorkerSocket TSnap7Server::CreateWorkerSocket(socket_t Sock)
{
PWorkerSocket Result;
Result = new TS7Worker();
Result->SetSocket(Sock);
PS7Worker(Result)->FServer=this;
return Result;
}
//------------------------------------------------------------------------------
PS7Area TSnap7Server::FindDB(word DBNumber)
{
int c;
int max=DBLimit+1;
for (c=0; cNumber==DBNumber)
{
return DB[c];
}
}
}
return NULL;
}
//------------------------------------------------------------------------------
int TSnap7Server::IndexOfDB(word DBNumber)
{
int c;
int max=DBLimit+1;
for (c=0; cNumber==DBNumber)
{
return c;
}
}
}
return -1;
}
//------------------------------------------------------------------------------
int TSnap7Server::FindFirstFreeDB()
{
int c;
for (c=0; c < MaxDB; c++)
{
if (DB[c]==NULL)
return c;
}
return -1;
}
//------------------------------------------------------------------------------
int TSnap7Server::RegisterDB(word Number, void *pUsrData, word Size)
{
PS7Area TheArea;
int index;
if (pUsrData==0)
return errSrvDBNullPointer;
if (FindDB(Number)!=NULL)
return errSrvAreaAlreadyExists;
index=FindFirstFreeDB();
if (index==-1)
return errSrvTooManyDB;
TheArea =new TS7Area;
TheArea->Number=Number;
TheArea->cs=new TSnapCriticalSection();
TheArea->PData=pbyte(pUsrData);
TheArea->Size=Size;
DB[index]=TheArea;
DBCount++;
if (DBLimitcs!=0)
delete TheDB->cs;
delete TheDB;
}
}
DBCount=0;
// Unregister other
for (c = srvAreaPE; c < srvAreaDB; c++)
UnregisterSys(c);
}
//------------------------------------------------------------------------------
int TSnap7Server::RegisterSys(int AreaCode, void *pUsrData, word Size)
{
PS7Area TheArea;
if (pUsrData==0)
return errSrvDBNullPointer;
if ((AreaCodesrvAreaTM))
return errSrvUnknownArea;
if (HA[AreaCode]==0)
{
TheArea=new TS7Area;
TheArea->cs=new TSnapCriticalSection();
TheArea->PData=pbyte(pUsrData);
TheArea->Size=Size;
HA[AreaCode]=TheArea;
return 0;
}
else
return errSrvAreaAlreadyExists;
}
//------------------------------------------------------------------------------
int TSnap7Server::UnregisterDB(word DBNumber)
{
PS7Area TheDB;
int index = IndexOfDB(DBNumber);
if (index==-1)
return errSrvInvalidParams;
// Unregister should be done with the server in stop mode
// however we can minimize the risk...
TheDB=DB[index];
DB[index]=NULL;
if (TheDB->cs!=NULL)
delete TheDB->cs;
delete TheDB;
DBCount--;
return 0;
}
//------------------------------------------------------------------------------
int TSnap7Server::UnregisterSys(int AreaCode)
{
PS7Area TheArea;
if (HA[AreaCode]!=NULL)
{
// Unregister should be done with the server in stop mode
// however we can minimize the risk...
TheArea=HA[AreaCode];
HA[AreaCode]=NULL;
if (TheArea->cs!=NULL)
delete TheArea->cs;
delete TheArea;
}
return 0;
}
//------------------------------------------------------------------------------
int TSnap7Server::StartTo(const char *Address)
{
return TCustomMsgServer::StartTo(Address, LocalPort);
}
//------------------------------------------------------------------------------
int TSnap7Server::GetParam(int ParamNumber, void *pValue)
{
switch (ParamNumber)
{
case p_u16_LocalPort:
*Puint16_t(pValue)=LocalPort;
break;
case p_i32_WorkInterval:
*Pint32_t(pValue)=WorkInterval;
break;
case p_i32_MaxClients:
*Pint32_t(pValue)=MaxClients;
break;
case p_i32_PDURequest:
*Pint32_t(pValue) = ForcePDU;
break;
default: return errSrvInvalidParamNumber;
}
return 0;
}
//------------------------------------------------------------------------------
int TSnap7Server::SetParam(int ParamNumber, void *pValue)
{
switch (ParamNumber)
{
case p_u16_LocalPort:
if (Status == SrvStopped)
LocalPort = *Puint16_t(pValue);
else
return errSrvCannotChangeParam;
break;
case p_i32_PDURequest:
if (Status == SrvStopped)
{
int PDU = *Pint32_t(pValue);
if (PDU == 0)
ForcePDU = 0; // ForcePDU=0 --> The server accepts the client's proposal
else
{
if ((PDU < MinPduSize) || (PDU>IsoPayload_Size))
return errSrvInvalidParams; // Wrong value
else
ForcePDU = PDU; // The server imposes ForcePDU as PDU size
}
}
else
return errSrvCannotChangeParam;
break;
case p_i32_WorkInterval:
WorkInterval=*Pint32_t(pValue);
break;
case p_i32_MaxClients:
if (ClientsCount==0 && Status==SrvStopped)
MaxClients=*Pint32_t(pValue);
else
return errSrvCannotChangeParam;
break;
default: return errSrvInvalidParamNumber;
}
return 0;
}
//------------------------------------------------------------------------------
int TSnap7Server::RegisterArea(int AreaCode, word Index, void *pUsrData, word Size)
{
if (AreaCode==srvAreaDB)
return RegisterDB(Index, pUsrData, Size);
else
return RegisterSys(AreaCode,pUsrData, Size);
}
//------------------------------------------------------------------------------
int TSnap7Server::UnregisterArea(int AreaCode, word Index)
{
if (AreaCode==srvAreaDB)
return UnregisterDB(Index);
else
if ((AreaCode>=srvAreaPE) && (AreaCode<=srvAreaTM))
return UnregisterSys(AreaCode);
else
return errSrvInvalidParams;
}
//------------------------------------------------------------------------------
int TSnap7Server::LockArea(int AreaCode, word DBNumber)
{
int index;
if ((AreaCode>=srvAreaPE) && (AreaCode<=srvAreaTM))
{
if (HA[AreaCode]!=0)
{
HA[AreaCode]->cs->Enter();
return 0;
}
else
return errSrvInvalidParams;
}
else
if (AreaCode==srvAreaDB)
{
index=IndexOfDB(DBNumber);
if (index!=-1)
{
DB[index]->cs->Enter();
return 0;
}
else
return errSrvInvalidParams;
}
else
return errSrvInvalidParams;
}
//------------------------------------------------------------------------------
int TSnap7Server::UnlockArea(int AreaCode, word DBNumber)
{
int index;
if ((AreaCode>=srvAreaPE) && (AreaCode<=srvAreaTM))
{
if (HA[AreaCode]!=0)
{
HA[AreaCode]->cs->Leave();
return 0;
}
else
return errSrvInvalidParams;
}
else
if (AreaCode==srvAreaDB)
{
index=IndexOfDB(DBNumber);
if (index!=-1)
{
DB[index]->cs->Leave();
return 0;
}
else
return errSrvInvalidParams;
}
else
return errSrvInvalidParams;
}
//------------------------------------------------------------------------------
int TSnap7Server::SetReadEventsCallBack(pfn_SrvCallBack PCallBack, void *UsrPtr)
{
OnReadEvent = PCallBack;
FReadUsrPtr = UsrPtr;
return 0;
}
//---------------------------------------------------------------------------
int TSnap7Server::SetRWAreaCallBack(pfn_RWAreaCallBack PCallBack, void *UsrPtr)
{
OnRWArea = PCallBack;
FRWAreaUsrPtr = UsrPtr;
ResourceLess = OnRWArea != NULL;
return 0;
}
//---------------------------------------------------------------------------
void TSnap7Server::DoReadEvent(int Sender, longword Code, word RetCode, word Param1,
word Param2, word Param3, word Param4)
{
TSrvEvent SrvReadEvent;
if (!Destroying && (OnReadEvent != NULL))
{
CSEvent->Enter();
time(&SrvReadEvent.EvtTime);
SrvReadEvent.EvtSender = Sender;
SrvReadEvent.EvtCode = Code;
SrvReadEvent.EvtRetCode = RetCode;
SrvReadEvent.EvtParam1 = Param1;
SrvReadEvent.EvtParam2 = Param2;
SrvReadEvent.EvtParam3 = Param3;
SrvReadEvent.EvtParam4 = Param4;
try
{ // callback is outside here, we have to shield it
OnReadEvent(FReadUsrPtr, &SrvReadEvent, sizeof (TSrvEvent));
} catch (...)
{
};
CSEvent->Leave();
};
}
//---------------------------------------------------------------------------
bool TSnap7Server::DoReadArea(int Sender, int Area, int DBNumber, int Start, int Size, int WordLen, void *pUsrData)
{
TS7Tag Tag;
bool Result = false;
if (!Destroying && (OnRWArea != NULL))
{
CSRWHook->Enter();
try
{
Tag.Area = Area;
Tag.DBNumber = DBNumber;
Tag.Start = Start;
Tag.Size = Size;
Tag.WordLen = WordLen;
// callback is outside here, we have to shield it
Result = OnRWArea(FRWAreaUsrPtr, Sender, OperationRead, &Tag, pUsrData) == 0;
}
catch (...)
{
Result = false;
};
CSRWHook->Leave();
}
return Result;
}
//---------------------------------------------------------------------------
bool TSnap7Server::DoWriteArea(int Sender, int Area, int DBNumber, int Start, int Size, int WordLen, void *pUsrData)
{
TS7Tag Tag;
bool Result = false;
if (!Destroying && (OnRWArea != NULL))
{
CSRWHook->Enter();
try
{
Tag.Area = Area;
Tag.DBNumber = DBNumber;
Tag.Start = Start;
Tag.Size = Size;
Tag.WordLen = WordLen;
// callback is outside here, we have to shield it
Result = OnRWArea(FRWAreaUsrPtr, Sender, OperationWrite, &Tag, pUsrData) == 0;
}
catch (...)
{
Result = false;
};
CSRWHook->Leave();
}
return Result;
}
================================================
FILE: deps/snap7/src/core/s7_server.h
================================================
/*=============================================================================|
| 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
================================================
FILE: deps/snap7/src/core/s7_text.cpp
================================================
/*=============================================================================|
| 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;
}
================================================
FILE: deps/snap7/src/core/s7_text.h
================================================
/*=============================================================================|
| 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
================================================
FILE: deps/snap7/src/core/s7_types.h
================================================
/*=============================================================================|
| PROJECT SNAP7 1.3.0 |
|==============================================================================|
| Copyright (C) 2013, 2015 Davide Nardella |
| All rights reserved. |
|==============================================================================|
| SNAP7 is free software: you can redistribute it and/or modify |
| it under the terms of the Lesser GNU General Public License as published by |
| the Free Software Foundation, either version 3 of the License, or |
| (at your option) any later version. |
| |
| It means that you can distribute your commercial software linked with |
| SNAP7 without the requirement to distribute the source code of your |
| application and without the requirement that your application be itself |
| distributed under LGPL. |
| |
| SNAP7 is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| Lesser GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License and a |
| copy of Lesser GNU General Public License along with Snap7. |
| If not, see http://www.gnu.org/licenses/ |
|=============================================================================*/
#ifndef s7_types_h
#define s7_types_h
//------------------------------------------------------------------------------
#include "s7_isotcp.h"
//------------------------------------------------------------------------------
// EXPORT CONSTANTS
// Everything added in this section has to be copied into wrappers interface
//------------------------------------------------------------------------------
#ifdef OS_WINDOWS
#define SM7API __stdcall
#else
#define SM7API
#endif
// Area ID
const byte S7AreaPE = 0x81;
const byte S7AreaPA = 0x82;
const byte S7AreaMK = 0x83;
const byte S7AreaDB = 0x84;
const byte S7AreaCT = 0x1C;
const byte S7AreaTM = 0x1D;
const int MaxVars = 20;
const int S7WLBit = 0x01;
const int S7WLByte = 0x02;
const int S7WLChar = 0x03;
const int S7WLWord = 0x04;
const int S7WLInt = 0x05;
const int S7WLDWord = 0x06;
const int S7WLDInt = 0x07;
const int S7WLReal = 0x08;
const int S7WLCounter = 0x1C;
const int S7WLTimer = 0x1D;
// Block type
const byte Block_OB = 0x38;
const byte Block_DB = 0x41;
const byte Block_SDB = 0x42;
const byte Block_FC = 0x43;
const byte Block_SFC = 0x44;
const byte Block_FB = 0x45;
const byte Block_SFB = 0x46;
// Sub Block Type
const byte SubBlk_OB = 0x08;
const byte SubBlk_DB = 0x0A;
const byte SubBlk_SDB = 0x0B;
const byte SubBlk_FC = 0x0C;
const byte SubBlk_SFC = 0x0D;
const byte SubBlk_FB = 0x0E;
const byte SubBlk_SFB = 0x0F;
// Block languages
const byte BlockLangAWL = 0x01;
const byte BlockLangKOP = 0x02;
const byte BlockLangFUP = 0x03;
const byte BlockLangSCL = 0x04;
const byte BlockLangDB = 0x05;
const byte BlockLangGRAPH = 0x06;
// CPU status
const byte S7CpuStatusUnknown = 0x00;
const byte S7CpuStatusRun = 0x08;
const byte S7CpuStatusStop = 0x04;
const longword evcSnap7Base = 0x00008000;
// S7 Server Event Code
const longword evcPDUincoming = 0x00010000;
const longword evcDataRead = 0x00020000;
const longword evcDataWrite = 0x00040000;
const longword evcNegotiatePDU = 0x00080000;
const longword evcReadSZL = 0x00100000;
const longword evcClock = 0x00200000;
const longword evcUpload = 0x00400000;
const longword evcDownload = 0x00800000;
const longword evcDirectory = 0x01000000;
const longword evcSecurity = 0x02000000;
const longword evcControl = 0x04000000;
const longword evcReserved_08000000 = 0x08000000;
const longword evcReserved_10000000 = 0x10000000;
const longword evcReserved_20000000 = 0x20000000;
const longword evcReserved_40000000 = 0x40000000;
const longword evcReserved_80000000 = 0x80000000;
// Event SubCodes
const word evsUnknown = 0x0000;
const word evsStartUpload = 0x0001;
const word evsStartDownload = 0x0001;
const word evsGetBlockList = 0x0001;
const word evsStartListBoT = 0x0002;
const word evsListBoT = 0x0003;
const word evsGetBlockInfo = 0x0004;
const word evsGetClock = 0x0001;
const word evsSetClock = 0x0002;
const word evsSetPassword = 0x0001;
const word evsClrPassword = 0x0002;
// Event Result
const word evrNoError = 0;
const word evrFragmentRejected = 0x0001;
const word evrMalformedPDU = 0x0002;
const word evrSparseBytes = 0x0003;
const word evrCannotHandlePDU = 0x0004;
const word evrNotImplemented = 0x0005;
const word evrErrException = 0x0006;
const word evrErrAreaNotFound = 0x0007;
const word evrErrOutOfRange = 0x0008;
const word evrErrOverPDU = 0x0009;
const word evrErrTransportSize = 0x000A;
const word evrInvalidGroupUData = 0x000B;
const word evrInvalidSZL = 0x000C;
const word evrDataSizeMismatch = 0x000D;
const word evrCannotUpload = 0x000E;
const word evrCannotDownload = 0x000F;
const word evrUploadInvalidID = 0x0010;
const word evrResNotFound = 0x0011;
// Async mode
const int amPolling = 0;
const int amEvent = 1;
const int amCallBack = 2;
//------------------------------------------------------------------------------
// PARAMS LIST
// Notes for Local/Remote Port
// If the local port for a server and remote port for a client is != 102 they
// will be *no more compatible with S7 IsoTCP*
// A good reason to change them could be inside a debug session under Unix.
// Increasing the port over 1024 avoids the need of be root.
// Obviously you need to work with the couple Snap7Client/Snap7Server and change
// both, or, use iptable and nat the port.
//------------------------------------------------------------------------------
const int p_u16_LocalPort = 1;
const int p_u16_RemotePort = 2;
const int p_i32_PingTimeout = 3;
const int p_i32_SendTimeout = 4;
const int p_i32_RecvTimeout = 5;
const int p_i32_WorkInterval = 6;
const int p_u16_SrcRef = 7;
const int p_u16_DstRef = 8;
const int p_u16_SrcTSap = 9;
const int p_i32_PDURequest = 10;
const int p_i32_MaxClients = 11;
const int p_i32_BSendTimeout = 12;
const int p_i32_BRecvTimeout = 13;
const int p_u32_RecoveryTime = 14;
const int p_u32_KeepAliveTime = 15;
// Bool param is passed as int32_t : 0->false, 1->true
// String param (only set) is passed as pointer
typedef int16_t *Pint16_t;
typedef uint16_t *Puint16_t;
typedef int32_t *Pint32_t;
typedef uint32_t *Puint32_t;
typedef int64_t *Pint64_t;
typedef uint64_t *Puint64_t;
typedef uintptr_t *Puintptr_t;
//-----------------------------------------------------------------------------
// INTERNALS CONSTANTS
//------------------------------------------------------------------------------
const word DBMaxName = 0xFFFF; // max number (name) of DB
const longword errS7Mask = 0xFFF00000;
const longword errS7Base = 0x000FFFFF;
const longword errS7notConnected = errS7Base+0x0001; // Client not connected
const longword errS7InvalidMode = errS7Base+0x0002; // Requested a connection to...
const longword errS7InvalidPDUin = errS7Base+0x0003; // Malformed input PDU
// S7 outcoming Error code
const word Code7Ok = 0x0000;
const word Code7AddressOutOfRange = 0x0005;
const word Code7InvalidTransportSize = 0x0006;
const word Code7WriteDataSizeMismatch = 0x0007;
const word Code7ResItemNotAvailable = 0x000A;
const word Code7ResItemNotAvailable1 = 0xD209;
const word Code7InvalidValue = 0xDC01;
const word Code7NeedPassword = 0xD241;
const word Code7InvalidPassword = 0xD602;
const word Code7NoPasswordToClear = 0xD604;
const word Code7NoPasswordToSet = 0xD605;
const word Code7FunNotAvailable = 0x8104;
const word Code7DataOverPDU = 0x8500;
// Result transport size
const byte TS_ResBit = 0x03;
const byte TS_ResByte = 0x04;
const byte TS_ResInt = 0x05;
const byte TS_ResReal = 0x07;
const byte TS_ResOctet = 0x09;
// Client Job status (lib internals, not S7)
const int JobComplete = 0;
const int JobPending = 1;
// Control codes
const word CodeControlUnknown = 0;
const word CodeControlColdStart = 1; // Cold start
const word CodeControlWarmStart = 2; // Warm start
const word CodeControlStop = 3; // Stop
const word CodeControlCompress = 4; // Compress
const word CodeControlCpyRamRom = 5; // Copy Ram to Rom
const word CodeControlInsDel = 6; // Insert in working ram the block downloaded
// Delete from working ram the block selected
// PDU Type
const byte PduType_request = 1; // family request
const byte PduType_response = 3; // family response
const byte PduType_userdata = 7; // family user data
// PDU Functions
const byte pduResponse = 0x02; // Response (when error)
const byte pduFuncRead = 0x04; // Read area
const byte pduFuncWrite = 0x05; // Write area
const byte pduNegotiate = 0xF0; // Negotiate PDU length
const byte pduStart = 0x28; // CPU start
const byte pduStop = 0x29; // CPU stop
const byte pduStartUpload = 0x1D; // Start Upload
const byte pduUpload = 0x1E; // Upload
const byte pduEndUpload = 0x1F; // EndUpload
const byte pduReqDownload = 0x1A; // Start Download request
const byte pduDownload = 0x1B; // Download request
const byte pduDownloadEnded = 0x1C; // Download end request
const byte pduControl = 0x28; // Control (insert/delete..)
// PDU SubFunctions
const byte SFun_ListAll = 0x01; // List all blocks
const byte SFun_ListBoT = 0x02; // List Blocks of type
const byte SFun_BlkInfo = 0x03; // Get Block info
const byte SFun_ReadSZL = 0x01; // Read SZL
const byte SFun_ReadClock = 0x01; // Read Clock (Date and Time)
const byte SFun_SetClock = 0x02; // Set Clock (Date and Time)
const byte SFun_EnterPwd = 0x01; // Enter password for this session
const byte SFun_CancelPwd = 0x02; // Cancel password for this session
const byte SFun_Insert = 0x50; // Insert block
const byte SFun_Delete = 0x42; // Delete block
typedef tm *PTimeStruct;
//==============================================================================
// HEADERS
//==============================================================================
#pragma pack(1)
// Tag Struct
typedef struct{
int Area;
int DBNumber;
int Start;
int Size;
int WordLen;
}TS7Tag, *PS7Tag;
// Incoming header, it will be mapped onto IsoPDU payload
typedef struct {
byte P; // Telegram ID, always 32
byte PDUType; // Header type 1 or 7
word AB_EX; // AB currently unknown, maybe it can be used for long numbers.
word Sequence; // Message ID. This can be used to make sure a received answer
word ParLen; // Length of parameters which follow this header
word DataLen; // Length of data which follow the parameters
}TS7ReqHeader;
typedef TS7ReqHeader* PS7ReqHeader;
// Outcoming 12 bytes header , response for Request type 1
typedef struct{
byte P; // Telegram ID, always 32
byte PDUType; // Header type 2 or 3
word AB_EX; // AB currently unknown, maybe it can be used for long numbers.
word Sequence; // Message ID. This can be used to make sure a received answer
word ParLen; // Length of parameters which follow this header
word DataLen; // Length of data which follow the parameters
word Error; // Error code
} TS7ResHeader23;
typedef TS7ResHeader23* PS7ResHeader23;
// Outcoming 10 bytes header , response for Request type 7
typedef struct{
byte P; // Telegram ID, always 32
byte PDUType; // Header type 1 or 7
word AB_EX; // AB currently unknown, maybe it can be used for long numbers.
word Sequence; // Message ID. This can be used to make sure a received answer
word ParLen; // Length of parameters which follow this header
word DataLen; // Length of data which follow the parameters
}TS7ResHeader17;
typedef TS7ResHeader17* PS7ResHeader17;
// Outcoming 10 bytes header , response for Request type 8 (server control)
typedef struct {
byte P; // Telegram ID, always 32
byte PDUType; // Header type 8
word AB_EX; // Zero
word Sequence; // Message ID. This can be used to make sure a received answer
word DataLen; // Length of data which follow this header
word Error; // Error code
} TS7ResHeader8;
typedef TS7ResHeader8* PS7ResHeader8;
// Outcoming answer buffer header type 2 or header type 3
typedef struct{
TS7ResHeader23 Header;
byte ResData [IsoPayload_Size - sizeof(TS7ResHeader23)];
} TS7Answer23;
typedef TS7Answer23* PS7Answer23;
// Outcoming buffer header type 1 or header type 7
typedef struct {
TS7ResHeader17 Header;
byte ResData [IsoPayload_Size - sizeof(TS7ResHeader17)];
} TS7Answer17;
typedef TS7Answer17* PS7Answer17;
typedef byte TTimeBuffer[8];
typedef byte *PTimeBuffer[8];
typedef struct{
byte bcd_year;
byte bcd_mon;
byte bcd_day;
byte bcd_hour;
byte bcd_min;
byte bcd_sec;
byte bcd_himsec;
byte bcd_dow;
}TS7Time, *PS7Time;
typedef byte TS7Buffer[65536];
typedef byte *PS7Buffer;
const int ReqHeaderSize = sizeof(TS7ReqHeader);
const int ResHeaderSize23 = sizeof(TS7ResHeader23);
const int ResHeaderSize17 = sizeof(TS7ResHeader17);
// Most used request type parameters record
typedef struct {
byte Head[3];// 0x00 0x01 0x12
byte Plen; // par len 0x04
byte Uk; // unknown
byte Tg; // type and group (4 bits type and 4 bits group)
byte SubFun; // subfunction
byte Seq; // sequence
}TReqFunTypedParams;
//==============================================================================
// FUNCTION NEGOTIATE
//==============================================================================
typedef struct {
byte FunNegotiate;
byte Unknown;
word ParallelJobs_1;
word ParallelJobs_2;
word PDULength;
}TReqFunNegotiateParams;
typedef TReqFunNegotiateParams* PReqFunNegotiateParams;
typedef struct {
byte FunNegotiate;
byte Unknown;
word ParallelJobs_1;
word ParallelJobs_2;
word PDULength;
}TResFunNegotiateParams;
typedef TResFunNegotiateParams* PResFunNegotiateParams;
//==============================================================================
// FUNCTION READ
//==============================================================================
typedef struct {
byte ItemHead[3];
byte TransportSize;
word Length;
word DBNumber;
byte Area;
byte Address[3];
}TReqFunReadItem, * PReqFunReadItem;
//typedef TReqFunReadItem;
typedef struct {
byte FunRead;
byte ItemsCount;
TReqFunReadItem Items[MaxVars];
}TReqFunReadParams;
typedef TReqFunReadParams* PReqFunReadParams;
typedef struct {
byte FunRead;
byte ItemCount;
}TResFunReadParams;
typedef TResFunReadParams* PResFunReadParams;
typedef struct {
byte ReturnCode;
byte TransportSize;
word DataLength;
byte Data[IsoPayload_Size - 17]; // 17 = header + params + data header - 1
}TResFunReadItem, *PResFunReadItem;
typedef PResFunReadItem TResFunReadData[MaxVars];
//==============================================================================
// FUNCTION WRITE
//==============================================================================
typedef struct {
byte ItemHead[3];
byte TransportSize;
word Length;
word DBNumber;
byte Area;
byte Address[3];
}TReqFunWriteItem, * PReqFunWriteItem;
typedef struct {
byte FunWrite;
byte ItemsCount;
TReqFunWriteItem Items[MaxVars];
}TReqFunWriteParams;
typedef TReqFunWriteParams* PReqFunWriteParams;
typedef struct {
byte ReturnCode;
byte TransportSize;
word DataLength;
byte Data [IsoPayload_Size - 17]; // 17 = header + params + data header -1
}TReqFunWriteDataItem, *PReqFunWriteDataItem;
typedef PReqFunWriteDataItem TReqFunWriteData[MaxVars];
typedef struct {
byte FunWrite;
byte ItemCount;
byte Data[MaxVars];
}TResFunWrite;
typedef TResFunWrite* PResFunWrite;
//==============================================================================
// GROUP UPLOAD
//==============================================================================
typedef struct {
byte FunSUpld; // function start upload 0x1D
byte Uk6 [6]; // Unknown 6 bytes
byte Upload_ID;
byte Len_1;
byte Prefix;
byte BlkPrfx; // always 0x30
byte BlkType;
byte AsciiBlk[5]; // BlockNum in ascii
byte A; // always 0x41 ('A')
}TReqFunStartUploadParams;
typedef TReqFunStartUploadParams* PReqFunStartUploadParams;
typedef struct {
byte FunSUpld; // function start upload 0x1D
byte Data_1[6];
byte Upload_ID;
byte Uk[3];
byte LenLoad[5];
}TResFunStartUploadParams;
typedef TResFunStartUploadParams* PResFunStartUploadParams;
typedef struct {
byte FunUpld; // function upload 0x1E
byte Uk6[6]; // Unknown 6 bytes
byte Upload_ID;
}TReqFunUploadParams;
typedef TReqFunUploadParams* PReqFunUploadParams;
typedef struct {
byte FunUpld; // function upload 0x1E
byte EoU; // 0 = End Of Upload, 1 = Upload in progress
}TResFunUploadParams;
typedef TResFunUploadParams* PResFunUploadParams;
typedef struct {
word Length; // Payload length - 4
byte Uk_00; // Unknown 0x00
byte Uk_FB; // Unknown 0xFB
// from here is the same of TS7CompactBlockInfo
word Cst_pp;
byte Uk_01; // Unknown 0x01
byte BlkFlags;
byte BlkLang;
byte SubBlkType;
word BlkNum;
u_int LenLoadMem;
u_int BlkSec;
u_int CodeTime_ms;
word CodeTime_dy;
u_int IntfTime_ms;
word IntfTime_dy;
word SbbLen;
word AddLen;
word LocDataLen;
word MC7Len;
}TResFunUploadDataHeaderFirst;
typedef TResFunUploadDataHeaderFirst* PResFunUploadDataHeaderFirst;
typedef struct {
word Length;// Payload length - 4
byte Uk_00; // Unknown 0x00
byte Uk_FB; // Unknown 0xFB
}TResFunUploadDataHeaderNext;
typedef TResFunUploadDataHeaderNext* PResFunUploadDataHeaderNext;
typedef struct {
word Length;// Payload length - 4
byte Uk_00; // Unknown 0x00
byte Uk_FB; // Unknown 0xFB
}TResFunUploadDataHeader;
typedef TResFunUploadDataHeader* PResFunUploadDataHeader;
typedef struct {
byte ID; // 0x65
word Seq; // Sequence
byte Const_1[10];
word Lo_bound;
word Hi_Bound;
byte u_shortLen;// 0x02 byte
// 0x04 word
// 0x05 int
// 0x06 dword
// 0x07 dint
// 0x08 real
byte c1, c2;
char Author[8];
char Family[8];
char Header[8];
byte B1; // 0x11
byte B2; // 0x00
word Chksum;
byte Uk_8[8];
}TArrayUpldFooter;
typedef TArrayUpldFooter* PArrayUpldFooter;
typedef struct {
byte FunEUpld; // function end upload 0x1F
byte Uk6[6]; // Unknown 6 bytes
byte Upload_ID;
}TReqFunEndUploadParams;
typedef TReqFunEndUploadParams* PReqFunEndUploadParams;
typedef struct {
byte FunEUpld; // function end upload 0x1F
}TResFunEndUploadParams;
typedef TResFunEndUploadParams* PResFunEndUploadParams;
//==============================================================================
// GROUP DOWNLOAD
//==============================================================================
typedef struct {
byte FunSDwnld; // function start Download 0x1A
byte Uk6[6]; // Unknown 6 bytes
byte Dwnld_ID;
byte Len_1; // 0x09
byte Prefix; // 0x5F
byte BlkPrfx; // always 0x30
byte BlkType;
byte AsciiBlk[5]; // BlockNum in ascii
byte P; // 0x50 ('P')
byte Len_2; // 0x0D
byte Uk1; // 0x01
byte AsciiLoad[6];// load memory size (MC7 size + 92)
byte AsciiMC7[6]; // Block size in bytes
}TReqStartDownloadParams;
typedef TReqStartDownloadParams* PReqStartDownloadParams;
typedef byte TResStartDownloadParams;
typedef TResStartDownloadParams* PResStartDownloadParams;
typedef struct {
byte Fun; // pduDownload or pduDownloadEnded
byte Uk7[7];
byte Len_1; // 0x09
byte Prefix; // 0x5F
byte BlkPrfx; // always 0x30
byte BlkType;
byte AsciiBlk[5]; // BlockNum in ascii
byte P; // 0x50 ('P')
}TReqDownloadParams;
typedef TReqDownloadParams* PReqDownloadParams;
typedef struct {
byte FunDwnld; // 0x1B
byte EoS; // End of sequence : 0x00 - Sequence in progress : 0x01
}TResDownloadParams;
typedef TResDownloadParams* PResDownloadParams;
typedef struct {
word DataLen;
word FB_00; // 0x00 0xFB
}TResDownloadDataHeader;
typedef TResDownloadDataHeader* PResDownloadDataHeader;
typedef byte TResEndDownloadParams;
typedef TResEndDownloadParams* PResEndDownloadParams;
typedef struct {
word Cst_pp;
byte Uk_01; // Unknown 0x01
byte BlkFlags;
byte BlkLang;
byte SubBlkType;
word BlkNum;
u_int LenLoadMem;
u_int BlkSec;
u_int CodeTime_ms;
word CodeTime_dy;
u_int IntfTime_ms;
word IntfTime_dy;
word SbbLen;
word AddLen;
word LocDataLen;
word MC7Len;
}TS7CompactBlockInfo;
typedef TS7CompactBlockInfo* PS7CompactBlockInfo;
typedef struct {
byte Uk_20[20];
byte Author[8];
byte Family[8];
byte Header[8];
byte B1; // 0x11
byte B2; // 0x00
word Chksum;
byte Uk_12[8];
}TS7BlockFooter;
typedef TS7BlockFooter* PS7BlockFooter;
//==============================================================================
// FUNCTION INSERT/DELETE
//==============================================================================
typedef struct {
byte Fun; // plc control 0x28
byte Uk7[7]; // unknown 7
word Len_1; // Length part 1 : 10
byte NumOfBlocks; // number of blocks to insert
byte ByteZero; // 0x00
byte AsciiZero; // 0x30 '0'
byte BlkType;
byte AsciiBlk[5]; // BlockNum in ascii
byte SFun; // 0x50 or 0x42
byte Len_2; // Length part 2 : 0x05 bytes
char Cmd[5]; // ascii '_INSE' or '_DELE'
}TReqControlBlockParams;
typedef TReqControlBlockParams* PReqControlBlockParams;
//==============================================================================
// FUNCTIONS START/STOP/COPY RAM TO ROM/COMPRESS
//==============================================================================
typedef struct {
byte Fun; // stop 0x29
byte Uk_5[5]; // unknown 5 bytes 0x00
byte Len_2; // Length part 2 : 0x09
char Cmd[9]; // ascii 'P_PROGRAM'
}TReqFunPlcStop;
typedef TReqFunPlcStop* PReqFunPlcStop;
typedef struct {
byte Fun; // start 0x28
byte Uk_7[7]; // unknown 7
word Len_1; // Length part 1 : 0x0000
byte Len_2; // Length part 2 : 0x09
char Cmd [9]; // ascii 'P_PROGRAM'
}TReqFunPlcHotStart;
typedef TReqFunPlcHotStart* PReqFunPlcHotStart;
typedef struct {
byte Fun; // start 0x28
byte Uk_7[7]; // unknown 7
word Len_1; // Length part 1 : 0x0002
word SFun; // 'C ' 0x4320
byte Len_2; // Length part 2 : 0x09
char Cmd[9]; // ascii 'P_PROGRAM'
}TReqFunPlcColdStart;
typedef TReqFunPlcColdStart* PReqFunPlcColdStart;
typedef struct {
byte Fun; // pduControl 0x28
byte Uk_7[7]; // unknown 7
word Len_1; // Length part 1 : 0x0002
word SFun; // 'EP' 0x4550
byte Len_2; // Length part 2 : 0x05
char Cmd[5]; // ascii '_MODU'
}TReqFunCopyRamToRom;
typedef TReqFunCopyRamToRom* PReqFunCopyRamToRom;
typedef struct {
byte Fun; // pduControl 0x28
byte Uk_7[7]; // unknown 7
word Len_1; // Length part 1 : 0x00
byte Len_2; // Length part 2 : 0x05
char Cmd[5]; // ascii '_GARB'
}TReqFunCompress;
typedef TReqFunCompress* PReqFunCompress;
typedef struct {
byte ResFun;
byte para;
}TResFunCtrl;
typedef TResFunCtrl* PResFunCtrl;
//==============================================================================
// FUNCTIONS USERDATA
//==============================================================================
typedef struct {
byte Head[3]; // Always 0x00 0x01 0x12
byte Plen; // par len 0x04 or 0x08
byte Uk; // unknown
byte Tg; // type and group (4 bits type and 4 bits group)
byte SubFun; // subfunction
byte Seq; // sequence
word resvd; // present if plen=0x08 (S7 manager online functions)
word Err; // present if plen=0x08 (S7 manager online functions)
}TS7Params7;
typedef TS7Params7* PS7ReqParams7;
typedef TS7Params7* PS7ResParams7;
// for convenience Hi order bit of type are included (0x4X)
const byte grProgrammer = 0x41;
const byte grCyclicData = 0x42;
const byte grBlocksInfo = 0x43;
const byte grSZL = 0x44;
const byte grPassword = 0x45;
const byte grBSend = 0x46;
const byte grClock = 0x47;
const byte grSecurity = 0x45;
//==============================================================================
// GROUP SECURITY
//==============================================================================
typedef TReqFunTypedParams TReqFunSecurity;
typedef TReqFunSecurity* PReqFunSecurity;
typedef char TS7Password[8];
typedef struct {
byte Ret; // 0xFF for request
byte TS; // 0x09 Transport size
word DLen; // Data len : 8 bytes
byte Pwd[8]; // Password encoded into "AG" format
}TReqDataSecurity;
typedef TReqDataSecurity* PReqDataSecurity;
typedef TS7Params7 TResParamsSecurity;
typedef TResParamsSecurity* PResParamsSecurity;
typedef struct {
byte Ret;
byte TS;
word DLen;
}TResDataSecurity;
typedef TResDataSecurity* PResDataSecurity;
//==============================================================================
// GROUP BLOCKS SZL
//==============================================================================
typedef TReqFunTypedParams TReqFunReadSZLFirst;
typedef TReqFunReadSZLFirst* PReqFunReadSZLFirst;
typedef struct {
byte Head[3]; // 0x00 0x01 0x12
byte Plen; // par len 0x04
byte Uk; // unknown
byte Tg; // type and group (4 bits type and 4 bits group)
byte SubFun; // subfunction
byte Seq; // sequence
word Rsvd; // Reserved 0x0000
word ErrNo; // Error Code
}TReqFunReadSZLNext;
typedef TReqFunReadSZLNext* PReqFunReadSZLNext;
typedef struct {
byte Ret; // 0xFF for request
byte TS; // 0x09 Transport size
word DLen; // Data len
word ID; // SZL-ID
word Index;// SZL-Index
}TS7ReqSZLData;
typedef TS7ReqSZLData* PS7ReqSZLData;
typedef struct {
byte Ret;
byte TS;
word DLen;
word ID;
word Index;
word ListLen;
word ListCount;
word Data[32747];
}TS7ResSZLDataFirst;
typedef TS7ResSZLDataFirst* PS7ResSZLDataFirst;
typedef struct {
byte Ret;
byte TS;
word DLen;
word Data[32751];
}TS7ResSZLDataNext;
typedef TS7ResSZLDataNext* PS7ResSZLDataNext;
typedef struct {
byte Ret;
byte OtherInfo[9];
word Count;
word Items[32747];
}TS7ResSZLData_0;
typedef TS7ResSZLData_0* PS7ResSZLData_0;
//==============================================================================
// GROUP CLOCK
//==============================================================================
typedef TReqFunTypedParams TReqFunDateTime;
typedef TReqFunDateTime* PReqFunDateTime;
typedef byte TReqDataGetDateTime[4];
typedef longword *PReqDataGetDateTime;
typedef struct {
byte RetVal;
byte TSize;
word Length;
byte Rsvd;
byte HiYear;
TTimeBuffer Time;
}TResDataGetTime;
typedef TResDataGetTime* PResDataGetTime;
typedef TResDataGetTime TReqDataSetTime;
typedef TReqDataSetTime* PReqDataSetTime;
typedef struct {
byte RetVal;
byte TSize;
word Length;
}TResDataSetTime;
typedef TResDataSetTime* PResDataSetTime;
//==============================================================================
// GROUP BLOCKS INFO
//==============================================================================
typedef TReqFunTypedParams TReqFunGetBlockInfo;
typedef TReqFunGetBlockInfo* PReqFunGetBlockInfo;
typedef byte TReqDataFunBlocks[4];
typedef u_char* PReqDataFunBlocks;
typedef struct {
byte Head[3]; // 0x00 0x01 0x12
byte Plen; // par len 0x04
byte Uk; // unknown
byte Tg; // type and group (4 bits type and 4 bits group)
byte SubFun; // subfunction
byte Seq; // sequence
word Rsvd; // Reserved 0x0000
word ErrNo; // Error Code
}TResFunGetBlockInfo;
typedef TResFunGetBlockInfo* PResFunGetBlockInfo;
typedef struct {
byte Zero; // always 0x30 -> Ascii 0
byte BType; // Block Type
word BCount; // Block count
}TResFunGetBlockItem;
typedef struct {
byte RetVal;
byte TRSize;
word Length;
TResFunGetBlockItem Blocks[7];
}TDataFunListAll;
typedef TDataFunListAll* PDataFunListAll;
typedef struct {
word BlockNum;
byte Unknown;
byte BlockLang;
}TDataFunGetBotItem;
typedef struct {
byte RetVal;
byte TSize;
word DataLen;
TDataFunGetBotItem Items[(IsoPayload_Size - 29 ) / 4];
}TDataFunGetBot;
// Note : 29 is the size of headers iso, COPT, S7 header, params, data
typedef TDataFunGetBot* PDataFunGetBot;
typedef struct {
byte RetVal; // 0xFF
byte TSize; // Octet (0x09)
word Length; // 0x0002
byte Zero; // Ascii '0' (0x30)
byte BlkType;
}TReqDataBlockOfType;
typedef TReqDataBlockOfType* PReqDataBlockOfType;
typedef struct {
byte RetVal;
byte TSize;
word DataLen;
byte BlkPrfx; // always 0x30
byte BlkType;
byte AsciiBlk[5]; // BlockNum in ascii
byte A; // always 0x41 ('A')
}TReqDataBlockInfo;
typedef TReqDataBlockInfo* PReqDataBlockInfo;
typedef struct {
byte RetVal;
byte TSize;
word Length;
byte Cst_b;
byte BlkType;
word Cst_w1;
word Cst_w2;
word Cst_pp;
byte Unknown_1;
byte BlkFlags;
byte BlkLang;
byte SubBlkType;
word BlkNumber;
u_int LenLoadMem;
byte BlkSec[4];
u_int CodeTime_ms;
word CodeTime_dy;
u_int IntfTime_ms;
word IntfTime_dy;
word SbbLen;
word AddLen;
word LocDataLen;
word MC7Len;
byte Author[8];
byte Family[8];
byte Header[8];
byte Version;
byte Unknown_2;
word BlkChksum;
byte Resvd1[4];
byte Resvd2[4];
}TResDataBlockInfo;
typedef TResDataBlockInfo* PResDataBlockInfo;
//==============================================================================
// BSEND / BRECV
//==============================================================================
typedef struct {
int Size;
longword R_ID;
byte Data[65536];
}TPendingBuffer;
typedef struct {
TTPKT TPKT;
TCOTP_DT COTP;
byte P;
byte PDUType;
}TPacketInfo;
typedef struct {
byte Head[3];// Always 0x00 0x01 0x12
byte Plen; // par len 0x04 or 0x08
byte Uk; // unknown (0x12)
byte Tg; // type and group, 4 bits type and 4 bits group (0x46)
byte SubFun; // subfunction (0x01)
byte Seq; // sequence
byte IDSeq; // ID Sequence (come from partner)
byte EoS; // End of Sequence = 0x00 Sequence in progress = 0x01;
word Err; //
}TBSendParams;
typedef TBSendParams* PBSendReqParams;
typedef TBSendParams* PBSendResParams;
// Data frame
typedef struct {
byte FF; // 0xFF
byte TRSize; // Transport Size 0x09 (octet)
word Len; // This Telegram Length
byte DHead[4];// sequence 0x12 0x06 0x13 0x00
u_int R_ID; // R_ID
}TBsendRequestData;
typedef TBsendRequestData* PBsendRequestData;
typedef struct {
byte DHead[4]; // sequence 0x0A 0x00 0x00 0x00
}TBSendResData;
typedef TBSendResData* PBSendResData;
#pragma pack()
#endif // s7_types_h
================================================
FILE: deps/snap7/src/lib/snap7.def
================================================
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
================================================
FILE: deps/snap7/src/lib/snap7_libmain.cpp
================================================
/*=============================================================================|
| PROJECT SNAP7 1.4.1 |
|==============================================================================|
| Copyright (C) 2013, 2015 Davide Nardella |
| All rights reserved. |
|==============================================================================|
| SNAP7 is free software: you can redistribute it and/or modify |
| it under the terms of the Lesser GNU General Public License as published by |
| the Free Software Foundation, either version 3 of the License, or |
| (at your option) any later version. |
| |
| It means that you can distribute your commercial software linked with |
| SNAP7 without the requirement to distribute the source code of your |
| application and without the requirement that your application be itself |
| distributed under LGPL. |
| |
| SNAP7 is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| Lesser GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License and a |
| copy of Lesser GNU General Public License along with Snap7. |
| If not, see http://www.gnu.org/licenses/ |
|=============================================================================*/
#include "snap7_libmain.h"
#ifndef OS_WINDOWS
void libinit(void) __attribute__((constructor));
void libdone(void) __attribute__((destructor));
#endif
static bool libresult = true;
void libinit(void)
{
// in future expansions here can be inserted some initialization code
libresult=true;
}
void libdone(void)
{
// in future expansions here can be inserted some destruction code
}
#ifdef OS_WINDOWS
BOOL APIENTRY DllMain (HINSTANCE hInst,
DWORD reason,
LPVOID reserved)
{
switch (reason)
{
case DLL_PROCESS_ATTACH:
libinit();
break;
case DLL_PROCESS_DETACH:
libdone();
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
}
return libresult;
}
#endif
//***************************************************************************
// CLIENT
//***************************************************************************
S7Object S7API Cli_Create()
{
return S7Object(new TSnap7Client());
}
//---------------------------------------------------------------------------
void S7API Cli_Destroy(S7Object &Client)
{
if (Client)
{
delete PSnap7Client(Client);
Client=0;
}
}
//---------------------------------------------------------------------------
int S7API Cli_SetConnectionParams(S7Object Client, const char *Address, word LocalTSAP, word RemoteTSAP)
{
if (Client)
{
PSnap7Client(Client)->SetConnectionParams(Address, LocalTSAP, RemoteTSAP);
return 0;
}
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_SetConnectionType(S7Object Client, word ConnectionType)
{
if (Client)
{
PSnap7Client(Client)->SetConnectionType(ConnectionType);
return 0;
}
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_ConnectTo(S7Object Client, const char *Address, int Rack, int Slot)
{
if (Client)
return PSnap7Client(Client)->ConnectTo(Address, Rack, Slot);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_Connect(S7Object Client)
{
if (Client)
return PSnap7Client(Client)->Connect();
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_Disconnect(S7Object Client)
{
if (Client)
return PSnap7Client(Client)->Disconnect();
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_GetParam(S7Object Client, int ParamNumber, void *pValue)
{
if (Client)
return PSnap7Client(Client)->GetParam(ParamNumber, pValue);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_SetParam(S7Object Client, int ParamNumber, void *pValue)
{
if (Client)
return PSnap7Client(Client)->SetParam(ParamNumber, pValue);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_SetAsCallback(S7Object Client, pfn_CliCompletion pCompletion, void *usrPtr)
{
if (Client)
return PSnap7Client(Client)->SetAsCallback(pCompletion, usrPtr);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_ReadArea(S7Object Client, int Area, int DBNumber, int Start, int Amount, int WordLen, void *pUsrData)
{
if (Client)
return PSnap7Client(Client)->ReadArea(Area, DBNumber, Start, Amount, WordLen, pUsrData);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_WriteArea(S7Object Client, int Area, int DBNumber, int Start, int Amount, int WordLen, void *pUsrData)
{
if (Client)
return PSnap7Client(Client)->WriteArea(Area, DBNumber, Start, Amount, WordLen, pUsrData);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_ReadMultiVars(S7Object Client, PS7DataItem Item, int ItemsCount)
{
if (Client)
return PSnap7Client(Client)->ReadMultiVars(Item, ItemsCount);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_WriteMultiVars(S7Object Client, PS7DataItem Item, int ItemsCount)
{
if (Client)
return PSnap7Client(Client)->WriteMultiVars(Item, ItemsCount);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_DBRead(S7Object Client, int DBNumber, int Start, int Size, void *pUsrData)
{
if (Client)
return PSnap7Client(Client)->DBRead(DBNumber, Start, Size, pUsrData);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_DBWrite(S7Object Client, int DBNumber, int Start, int Size, void *pUsrData)
{
if (Client)
return PSnap7Client(Client)->DBWrite(DBNumber, Start, Size, pUsrData);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_MBRead(S7Object Client, int Start, int Size, void *pUsrData)
{
if (Client)
return PSnap7Client(Client)->MBRead(Start, Size, pUsrData);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_MBWrite(S7Object Client, int Start, int Size, void *pUsrData)
{
if (Client)
return PSnap7Client(Client)->MBWrite(Start, Size, pUsrData);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_EBRead(S7Object Client, int Start, int Size, void *pUsrData)
{
if (Client)
return PSnap7Client(Client)->EBRead(Start, Size, pUsrData);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_EBWrite(S7Object Client, int Start, int Size, void *pUsrData)
{
if (Client)
return PSnap7Client(Client)->EBWrite(Start, Size, pUsrData);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_ABRead(S7Object Client, int Start, int Size, void *pUsrData)
{
if (Client)
return PSnap7Client(Client)->ABRead(Start, Size, pUsrData);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_ABWrite(S7Object Client, int Start, int Size, void *pUsrData)
{
if (Client)
return PSnap7Client(Client)->ABWrite(Start, Size, pUsrData);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_TMRead(S7Object Client, int Start, int Amount, void *pUsrData)
{
if (Client)
return PSnap7Client(Client)->TMRead(Start, Amount, pUsrData);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_TMWrite(S7Object Client, int Start, int Amount, void *pUsrData)
{
if (Client)
return PSnap7Client(Client)->TMWrite(Start, Amount, pUsrData);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_CTRead(S7Object Client, int Start, int Amount, void *pUsrData)
{
if (Client)
return PSnap7Client(Client)->CTRead(Start, Amount, pUsrData);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_CTWrite(S7Object Client, int Start, int Amount, void *pUsrData)
{
if (Client)
return PSnap7Client(Client)->CTWrite(Start, Amount, pUsrData);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_ListBlocks(S7Object Client, TS7BlocksList *pUsrData)
{
if (Client)
return PSnap7Client(Client)->ListBlocks(pUsrData);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_GetAgBlockInfo(S7Object Client, int BlockType, int BlockNum, TS7BlockInfo *pUsrData)
{
if (Client)
return PSnap7Client(Client)->GetAgBlockInfo(BlockType, BlockNum, pUsrData);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_GetPgBlockInfo(S7Object Client, void *pBlock, TS7BlockInfo *pUsrData, int Size)
{
if (Client)
return PSnap7Client(Client)->GetPgBlockInfo(pBlock, pUsrData, Size);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_ListBlocksOfType(S7Object Client, int BlockType, TS7BlocksOfType *pUsrData, int &ItemsCount)
{
if (Client)
return PSnap7Client(Client)->ListBlocksOfType(BlockType, pUsrData, ItemsCount);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_Upload(S7Object Client, int BlockType, int BlockNum, void *pUsrData, int &Size)
{
if (Client)
return PSnap7Client(Client)->Upload(BlockType, BlockNum, pUsrData, Size);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_FullUpload(S7Object Client, int BlockType, int BlockNum, void *pUsrData, int &Size)
{
if (Client)
return PSnap7Client(Client)->FullUpload(BlockType, BlockNum, pUsrData, Size);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_Download(S7Object Client, int BlockNum, void *pUsrData, int Size)
{
if (Client)
return PSnap7Client(Client)->Download(BlockNum, pUsrData, Size);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_Delete(S7Object Client, int BlockType, int BlockNum)
{
if (Client)
return PSnap7Client(Client)->Delete(BlockType, BlockNum);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_DBGet(S7Object Client, int DBNumber, void *pUsrData, int &Size)
{
if (Client)
return PSnap7Client(Client)->DBGet(DBNumber, pUsrData, Size);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_DBFill(S7Object Client, int DBNumber, int FillChar)
{
if (Client)
return PSnap7Client(Client)->DBFill(DBNumber, FillChar);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_GetPlcDateTime(S7Object Client, tm &DateTime)
{
if (Client)
return PSnap7Client(Client)->GetPlcDateTime(DateTime);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_SetPlcDateTime(S7Object Client, tm *DateTime)
{
if (Client)
return PSnap7Client(Client)->SetPlcDateTime(DateTime);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_SetPlcSystemDateTime(S7Object Client)
{
if (Client)
return PSnap7Client(Client)->SetPlcSystemDateTime();
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_GetOrderCode(S7Object Client, TS7OrderCode *pUsrData)
{
if (Client)
return PSnap7Client(Client)->GetOrderCode(pUsrData);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_GetCpuInfo(S7Object Client, TS7CpuInfo *pUsrData)
{
if (Client)
return PSnap7Client(Client)->GetCpuInfo(pUsrData);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_GetCpInfo(S7Object Client, TS7CpInfo *pUsrData)
{
if (Client)
return PSnap7Client(Client)->GetCpInfo(pUsrData);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_ReadSZL(S7Object Client, int ID, int Index, TS7SZL *pUsrData, int &Size)
{
if (Client)
return PSnap7Client(Client)->ReadSZL(ID, Index, pUsrData, Size);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_ReadSZLList(S7Object Client, TS7SZLList *pUsrData, int &ItemsCount)
{
if (Client)
return PSnap7Client(Client)->ReadSZLList(pUsrData, ItemsCount);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_PlcHotStart(S7Object Client)
{
if (Client)
return PSnap7Client(Client)->PlcHotStart();
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_PlcColdStart(S7Object Client)
{
if (Client)
return PSnap7Client(Client)->PlcColdStart();
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_PlcStop(S7Object Client)
{
if (Client)
return PSnap7Client(Client)->PlcStop();
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_CopyRamToRom(S7Object Client, int Timeout)
{
if (Client)
return PSnap7Client(Client)->CopyRamToRom(Timeout);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_Compress(S7Object Client, int Timeout)
{
if (Client)
return PSnap7Client(Client)->Compress(Timeout);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_GetPlcStatus(S7Object Client, int &Status)
{
if (Client)
return PSnap7Client(Client)->GetPlcStatus(Status);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_GetProtection(S7Object Client, TS7Protection *pUsrData)
{
if (Client)
return PSnap7Client(Client)->GetProtection(pUsrData);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_SetSessionPassword(S7Object Client, char *Password)
{
if (Client)
return PSnap7Client(Client)->SetSessionPassword(Password);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_ClearSessionPassword(S7Object Client)
{
if (Client)
return PSnap7Client(Client)->ClearSessionPassword();
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_IsoExchangeBuffer(S7Object Client, void *pUsrData, int &Size)
{
if (Client)
return PSnap7Client(Client)->isoExchangeBuffer(pUsrData, Size);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_GetExecTime(S7Object Client, int &Time)
{
if (Client)
{
Time=PSnap7Client(Client)->Time();
return 0;
}
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_GetLastError(S7Object Client, int &LastError)
{
if (Client)
{
LastError=PSnap7Client(Client)->LastError;
return 0;
}
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_GetPduLength(S7Object Client, int &Requested, int &Negotiated)
{
if (Client)
{
Negotiated=PSnap7Client(Client)->PDULength;
Requested =PSnap7Client(Client)->PDURequest;
return 0;
}
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_ErrorText(int Error, char *Text, int TextLen)
{
try{
ErrCliText(Error, Text, TextLen);
Text[TextLen - 1] = '\0';
}
catch (...){
return errLibInvalidParam;
}
return 0;
}
//---------------------------------------------------------------------------
int S7API Cli_GetConnected(S7Object Client, int &Connected)
{
Connected=0;
if (Client)
{
Connected=PSnap7Client(Client)->Connected;
return 0;
}
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_AsReadArea(S7Object Client, int Area, int DBNumber, int Start, int Amount, int WordLen, void *pUsrData)
{
if (Client)
return PSnap7Client(Client)->AsReadArea(Area, DBNumber, Start, Amount, WordLen, pUsrData);
else
return errLibInvalidParam;
}
//---------------------------------------------------------------------------
int S7API Cli_AsWriteArea(S7Object Client, int Area, int DBNumber, int Start, int Amount, int WordLen, void *pUsrData)
{
if (Client)
return PSnap7Client(Client)->AsWriteArea(Area, DBNumber, Start, Amount, WordLen, pUsrData);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_AsDBRead(S7Object Client, int DBNumber, int Start, int Size, void *pUsrData)
{
if (Client)
return PSnap7Client(Client)->AsDBRead(DBNumber, Start, Size, pUsrData);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_AsDBWrite(S7Object Client, int DBNumber, int Start, int Size, void *pUsrData)
{
if (Client)
return PSnap7Client(Client)->AsDBWrite(DBNumber, Start, Size, pUsrData);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_AsMBRead(S7Object Client, int Start, int Size, void *pUsrData)
{
if (Client)
return PSnap7Client(Client)->AsMBRead(Start, Size, pUsrData);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_AsMBWrite(S7Object Client, int Start, int Size, void *pUsrData)
{
if (Client)
return PSnap7Client(Client)->AsMBWrite(Start, Size, pUsrData);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_AsEBRead(S7Object Client, int Start, int Size, void *pUsrData)
{
if (Client)
return PSnap7Client(Client)->AsEBRead(Start, Size, pUsrData);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_AsEBWrite(S7Object Client, int Start, int Size, void *pUsrData)
{
if (Client)
return PSnap7Client(Client)->AsEBWrite(Start, Size, pUsrData);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_AsABRead(S7Object Client, int Start, int Size, void *pUsrData)
{
if (Client)
return PSnap7Client(Client)->AsABRead(Start, Size, pUsrData);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_AsABWrite(S7Object Client, int Start, int Size, void *pUsrData)
{
if (Client)
return PSnap7Client(Client)->AsABWrite(Start, Size, pUsrData);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_AsTMRead(S7Object Client, int Start, int Amount, void *pUsrData)
{
if (Client)
return PSnap7Client(Client)->AsTMRead(Start, Amount, pUsrData);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_AsTMWrite(S7Object Client, int Start, int Amount, void *pUsrData)
{
if (Client)
return PSnap7Client(Client)->AsTMWrite(Start, Amount, pUsrData);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_AsCTRead(S7Object Client, int Start, int Amount, void *pUsrData)
{
if (Client)
return PSnap7Client(Client)->AsCTRead(Start, Amount, pUsrData);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_AsCTWrite(S7Object Client, int Start, int Amount, void *pUsrData)
{
if (Client)
return PSnap7Client(Client)->AsCTWrite(Start, Amount, pUsrData);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_AsListBlocksOfType(S7Object Client, int BlockType, TS7BlocksOfType *pUsrData, int &ItemsCount)
{
if (Client)
return PSnap7Client(Client)->AsListBlocksOfType(BlockType, pUsrData, ItemsCount);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_AsReadSZL(S7Object Client, int ID, int Index, TS7SZL *pUsrData, int &Size)
{
if (Client)
return PSnap7Client(Client)->AsReadSZL(ID, Index, pUsrData, Size);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_AsReadSZLList(S7Object Client, TS7SZLList *pUsrData, int &ItemsCount)
{
if (Client)
return PSnap7Client(Client)->AsReadSZLList(pUsrData, ItemsCount);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_AsUpload(S7Object Client, int BlockType, int BlockNum, void *pUsrData, int &Size)
{
if (Client)
return PSnap7Client(Client)->AsUpload(BlockType, BlockNum, pUsrData, Size);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_AsFullUpload(S7Object Client, int BlockType, int BlockNum, void *pUsrData, int &Size)
{
if (Client)
return PSnap7Client(Client)->AsFullUpload(BlockType, BlockNum, pUsrData, Size);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_AsDownload(S7Object Client, int BlockNum, void *pUsrData, int Size)
{
if (Client)
return PSnap7Client(Client)->AsDownload(BlockNum, pUsrData, Size);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_AsCopyRamToRom(S7Object Client, int Timeout)
{
if (Client)
return PSnap7Client(Client)->AsCopyRamToRom(Timeout);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_AsCompress(S7Object Client, int Timeout)
{
if (Client)
return PSnap7Client(Client)->Compress(Timeout);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_AsDBGet(S7Object Client, int DBNumber, void *pUsrData, int &Size)
{
if (Client)
return PSnap7Client(Client)->AsDBGet(DBNumber, pUsrData, Size);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_AsDBFill(S7Object Client, int DBNumber, int FillChar)
{
if (Client)
return PSnap7Client(Client)->AsDBFill(DBNumber, FillChar);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_CheckAsCompletion(S7Object Client, int &opResult)
{
if (Client)
{
if (PSnap7Client(Client)->CheckAsCompletion(opResult))
return JobComplete;
else
return JobPending;
}
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Cli_WaitAsCompletion(S7Object Client, int Timeout)
{
if (Client)
return PSnap7Client(Client)->WaitAsCompletion(Timeout);
else
return errLibInvalidObject;
}
//***************************************************************************
// SERVER
//***************************************************************************
S7Object S7API Srv_Create()
{
return S7Object(new TSnap7Server());
}
//---------------------------------------------------------------------------
void S7API Srv_Destroy(S7Object &Server)
{
if (Server)
{
delete PSnap7Server(Server);
Server=0;
}
}
//---------------------------------------------------------------------------
int S7API Srv_GetParam(S7Object Server, int ParamNumber, void *pValue)
{
if (Server)
return PSnap7Server(Server)->GetParam(ParamNumber, pValue);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Srv_SetParam(S7Object Server, int ParamNumber, void *pValue)
{
if (Server)
return PSnap7Server(Server)->SetParam(ParamNumber, pValue);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Srv_StartTo(S7Object Server, const char *Address)
{
if (Server)
return PSnap7Server(Server)->StartTo(Address);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Srv_Start(S7Object Server)
{
if (Server)
return PSnap7Server(Server)->Start();
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Srv_Stop(S7Object Server)
{
if (Server)
{
PSnap7Server(Server)->Stop();
return 0;
}
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Srv_RegisterArea(S7Object Server, int AreaCode, word Index, void *pUsrData, int Size)
{
if (Server)
return PSnap7Server(Server)->RegisterArea(AreaCode, Index, pUsrData, Size);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Srv_UnregisterArea(S7Object Server, int AreaCode, word Index)
{
if (Server)
return PSnap7Server(Server)->UnregisterArea(AreaCode, Index);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Srv_LockArea(S7Object Server, int AreaCode, word Index)
{
if (Server)
return PSnap7Server(Server)->LockArea(AreaCode, Index);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Srv_UnlockArea(S7Object Server, int AreaCode, word Index)
{
if (Server)
return PSnap7Server(Server)->UnlockArea(AreaCode, Index);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Srv_GetStatus(S7Object Server, int &ServerStatus, int &CpuStatus, int &ClientsCount)
{
if (Server)
{
ServerStatus=PSnap7Server(Server)->Status;
CpuStatus=PSnap7Server(Server)->CpuStatus;
ClientsCount=PSnap7Server(Server)->ClientsCount;
return 0;
}
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Srv_SetCpuStatus(S7Object Server, int CpuStatus)
{
if (Server)
{
PSnap7Server(Server)->CpuStatus=CpuStatus;
return 0;
}
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Srv_ErrorText(int Error, char *Text, int TextLen)
{
try{
ErrSrvText(Error, Text, TextLen);
Text[TextLen - 1] = '\0';
}
catch (...){
return errLibInvalidParam;
}
return 0;
}
//---------------------------------------------------------------------------
int S7API Srv_EventText(TSrvEvent &Event, char *Text, int TextLen)
{
try{
EvtSrvText(Event, Text, TextLen);
Text[TextLen - 1] = '\0';
}
catch (...){
return errLibInvalidParam;
}
return 0;
}
//---------------------------------------------------------------------------
int S7API Srv_PickEvent(S7Object Server, TSrvEvent *pEvent, int &EvtReady)
{
EvtReady=0;
if (Server)
{
EvtReady=int(PSnap7Server(Server)->PickEvent(pEvent));
return 0;
}
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Srv_ClearEvents(S7Object Server)
{
if (Server)
{
PSnap7Server(Server)->EventsFlush();
return 0;
}
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Srv_GetMask(S7Object Server, int MaskKind, longword &Mask)
{
if (Server)
{
Mask=0;
if ((MaskKind==mkEvent) || (MaskKind==mkLog))
{
if (MaskKind==mkEvent)
Mask=PSnap7Server(Server)->EventMask;
else
Mask=PSnap7Server(Server)->LogMask;
return 0;
}
else
return errLibInvalidParam;
}
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Srv_SetMask(S7Object Server, int MaskKind, longword Mask)
{
if (Server)
{
if ((MaskKind==mkEvent) || (MaskKind==mkLog))
{
if (MaskKind==mkEvent)
PSnap7Server(Server)->EventMask=Mask;
else
PSnap7Server(Server)->LogMask=Mask;
return 0;
}
else
return errLibInvalidParam;
}
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Srv_SetEventsCallback(S7Object Server, pfn_SrvCallBack pCallback, void *usrPtr)
{
if (Server)
return PSnap7Server(Server)->SetEventsCallBack(pCallback, usrPtr);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Srv_SetReadEventsCallback(S7Object Server, pfn_SrvCallBack pCallback, void *usrPtr)
{
if (Server)
return PSnap7Server(Server)->SetReadEventsCallBack(pCallback, usrPtr);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Srv_SetRWAreaCallback(S7Object Server, pfn_RWAreaCallBack pCallback, void *usrPtr)
{
if (Server)
return PSnap7Server(Server)->SetRWAreaCallBack(pCallback, usrPtr);
else
return errLibInvalidObject;
}
//***************************************************************************
// PARTNER
//***************************************************************************
S7Object S7API Par_Create(int Active)
{
return S7Object(new TSnap7Partner(Active!=0));
}
//---------------------------------------------------------------------------
void S7API Par_Destroy(S7Object &Partner)
{
if (Partner)
{
delete PSnap7Partner(Partner);
Partner=0;
}
}
//---------------------------------------------------------------------------
int S7API Par_GetParam(S7Object Partner, int ParamNumber, void *pValue)
{
if (Partner)
return PSnap7Partner(Partner)->GetParam(ParamNumber, pValue);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Par_SetParam(S7Object Partner, int ParamNumber, void *pValue)
{
if (Partner)
return PSnap7Partner(Partner)->SetParam(ParamNumber, pValue);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Par_StartTo(S7Object Partner, const char *LocalAddress, const char *RemoteAddress,
word LocTsap, word RemTsap)
{
if (Partner)
return PSnap7Partner(Partner)->StartTo(LocalAddress, RemoteAddress, LocTsap, RemTsap);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Par_Start(S7Object Partner)
{
if (Partner)
return PSnap7Partner(Partner)->Start();
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Par_Stop(S7Object Partner)
{
if (Partner)
return PSnap7Partner(Partner)->Stop();
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Par_BSend(S7Object Partner, longword R_ID, void *pUsrData, int Size)
{
if (Partner)
return PSnap7Partner(Partner)->BSend(R_ID, pUsrData, Size);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Par_AsBSend(S7Object Partner, longword R_ID, void *pUsrData, int Size)
{
if (Partner)
return PSnap7Partner(Partner)->AsBSend(R_ID, pUsrData, Size);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Par_CheckAsBSendCompletion(S7Object Partner, int &opResult)
{
if (Partner)
{
if (PSnap7Partner(Partner)->CheckAsBSendCompletion(opResult))
return JobComplete;
else
return JobPending;
}
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Par_WaitAsBSendCompletion(S7Object Partner, longword Timeout)
{
if (Partner)
return PSnap7Partner(Partner)->WaitAsBSendCompletion(Timeout);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Par_SetSendCallback(S7Object Partner, pfn_ParBSendCompletion pCompletion, void *usrPtr)
{
if (Partner)
return PSnap7Partner(Partner)->SetSendCallback(pCompletion, usrPtr);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Par_BRecv(S7Object Partner, longword &R_ID, void *pData, int &Size, longword Timeout)
{
if (Partner)
return PSnap7Partner(Partner)->BRecv(R_ID, pData, Size, Timeout);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Par_CheckAsBRecvCompletion(S7Object Partner, int &opResult, longword &R_ID,
void *pData, int &Size)
{
if (Partner)
{
if (PSnap7Partner(Partner)->CheckAsBRecvCompletion(opResult, R_ID, pData, Size))
return JobComplete;
else
return JobPending;
}
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Par_SetRecvCallback(S7Object Partner, pfn_ParBRecvCallBack pCompletion, void *usrPtr)
{
if (Partner)
return PSnap7Partner(Partner)->SetRecvCallback(pCompletion, usrPtr);
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Par_GetTimes(S7Object Partner, longword &SendTime, longword &RecvTime)
{
if (Partner)
{
SendTime=PSnap7Partner(Partner)->SendTime;
RecvTime=PSnap7Partner(Partner)->RecvTime;
return 0;
}
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Par_GetStats(S7Object Partner, longword &BytesSent, longword &BytesRecv,
longword &SendErrors, longword &RecvErrors)
{
if (Partner)
{
BytesSent=PSnap7Partner(Partner)->BytesSent;
BytesRecv=PSnap7Partner(Partner)->BytesRecv;
SendErrors=PSnap7Partner(Partner)->SendErrors;
RecvErrors=PSnap7Partner(Partner)->RecvErrors;
return 0;
}
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Par_GetLastError(S7Object Partner, int &LastError)
{
if (Partner)
{
LastError=PSnap7Partner(Partner)->LastError;
return 0;
}
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Par_GetStatus(S7Object Partner, int &Status)
{
if (Partner)
{
Status=PSnap7Partner(Partner)->Status();
return 0;
}
else
return errLibInvalidObject;
}
//---------------------------------------------------------------------------
int S7API Par_ErrorText(int Error, char *Text, int TextLen)
{
try{
ErrParText(Error, Text, TextLen);
Text[TextLen - 1] = '\0';
}
catch (...){
return errLibInvalidParam;
}
return 0;
}
================================================
FILE: deps/snap7/src/lib/snap7_libmain.h
================================================
/*=============================================================================|
| 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
================================================
FILE: deps/snap7/src/sys/snap_msgsock.cpp
================================================
/*=============================================================================|
| PROJECT SNAP7 1.3.0 |
|==============================================================================|
| Copyright (C) 2013, 2015 Davide Nardella |
| All rights reserved. |
|==============================================================================|
| SNAP7 is free software: you can redistribute it and/or modify |
| it under the terms of the Lesser GNU General Public License as published by |
| the Free Software Foundation, either version 3 of the License, or |
| (at your option) any later version. |
| |
| It means that you can distribute your commercial software linked with |
| SNAP7 without the requirement to distribute the source code of your |
| application and without the requirement that your application be itself |
| distributed under LGPL. |
| |
| SNAP7 is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| Lesser GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License and a |
| copy of Lesser GNU General Public License along with Snap7. |
| If not, see http://www.gnu.org/licenses/ |
|=============================================================================*/
#include "snap_msgsock.h"
//---------------------------------------------------------------------------
static SocketsLayer SocketsLayerInitializer;
//---------------------------------------------------------------------------
// Base class endian aware
//---------------------------------------------------------------------------
TSnapBase::TSnapBase()
{
int x = 1;
LittleEndian=*(char *)&x == 1;
}
//---------------------------------------------------------------------------
word TSnapBase::SwapWord(word Value)
{
if (LittleEndian)
return ((Value >> 8) & 0xFF) | ((Value << 8) & 0xFF00);
else
return Value;
}
//---------------------------------------------------------------------------
longword TSnapBase::SwapDWord(longword Value)
{
if (LittleEndian)
return (Value >> 24) | ((Value << 8) & 0x00FF0000) | ((Value >> 8) & 0x0000FF00) | (Value << 24);
else
return Value;
}
//---------------------------------------------------------------------------
void Msg_CloseSocket(socket_t FSocket)
{
#ifdef OS_WINDOWS
closesocket(FSocket);
#else
close(FSocket);
#endif
}
//---------------------------------------------------------------------------
longword Msg_GetSockAddr(socket_t FSocket)
{
sockaddr_in RemoteSin;
#ifdef OS_WINDOWS
int namelen = sizeof(RemoteSin);
#else
uint32_t namelen = sizeof(RemoteSin);
#endif
namelen=sizeof(sockaddr_in);
if (getpeername(FSocket,(struct sockaddr*)&RemoteSin, &namelen)==0)
return RemoteSin.sin_addr.s_addr;
else
return 0;
}
//---------------------------------------------------------------------------
TMsgSocket::TMsgSocket()
{
Pinger = new TPinger();
// Set Defaults
strcpy(LocalAddress,"0.0.0.0");
LocalPort=0;
strcpy(RemoteAddress,"127.0.0.1");
RemotePort=0;
WorkInterval=100;
RecvTimeout=500;
SendTimeout=10;
PingTimeout=750;
Connected=false;
FSocket=INVALID_SOCKET;
LastTcpError=0;
LocalBind=0;
}
//---------------------------------------------------------------------------
TMsgSocket::~TMsgSocket()
{
DestroySocket();
delete Pinger;
}
//---------------------------------------------------------------------------
void TMsgSocket::SetSin(sockaddr_in &sin, char *Address, u_short Port)
{
uint32_t in_addr;
in_addr=inet_addr(Address);
memset(&sin, 0, sizeof(sin));
LastTcpError=0;
if (in_addr!=INADDR_NONE)
{
sin.sin_addr.s_addr = in_addr;
sin.sin_family = AF_INET;
sin.sin_port = htons(Port);
}
else
LastTcpError=WSAEINVALIDADDRESS;
}
//---------------------------------------------------------------------------
void TMsgSocket::GetSin(sockaddr_in sin, char *Address, u_short &Port)
{
strcpy(Address,inet_ntoa(sin.sin_addr));
Port=htons(sin.sin_port);
}
//---------------------------------------------------------------------------
void TMsgSocket::GetLocal()
{
#ifdef OS_WINDOWS
int namelen = sizeof(LocalSin);
#else
uint32_t namelen = sizeof(LocalSin);
#endif
if (getsockname(FSocket, (struct sockaddr*)&LocalSin, &namelen)==0)
GetSin(LocalSin, LocalAddress, LocalPort);
}
//---------------------------------------------------------------------------
void TMsgSocket::GetRemote()
{
#ifdef OS_WINDOWS
int namelen = sizeof(RemoteSin);
#else
uint32_t namelen = sizeof(RemoteSin);
#endif
if (getpeername(FSocket,(struct sockaddr*)&RemoteSin, &namelen)==0)
GetSin(RemoteSin, RemoteAddress, RemotePort);
}
//---------------------------------------------------------------------------
int TMsgSocket::GetLastSocketError()
{
#ifdef OS_WINDOWS
return WSAGetLastError();
#else
return errno;
#endif
}
//---------------------------------------------------------------------------
void TMsgSocket::Purge()
{
// small buffer to empty the socket
char Trash[512];
int Read;
if (LastTcpError!=WSAECONNRESET)
{
if (CanRead(0)) {
do
{
Read=recv(FSocket, Trash, 512, MSG_NOSIGNAL );
} while(Read==512);
}
}
}
//---------------------------------------------------------------------------
void TMsgSocket::CreateSocket()
{
DestroySocket();
LastTcpError=0;
FSocket =socket(AF_INET, SOCK_STREAM, IPPROTO_TCP );
if (FSocket!=INVALID_SOCKET)
SetSocketOptions();
else
LastTcpError =GetLastSocketError();
}
//---------------------------------------------------------------------------
void TMsgSocket::GotSocket()
{
ClientHandle=RemoteSin.sin_addr.s_addr;
// could be inherited it if wee need further actions on the socket
}
//---------------------------------------------------------------------------
void TMsgSocket::SetSocket(socket_t s)
{
FSocket=s;
if (FSocket!=INVALID_SOCKET)
{
SetSocketOptions();
GetLocal();
GetRemote();
GotSocket();
}
Connected=FSocket!=INVALID_SOCKET;
}
//---------------------------------------------------------------------------
void TMsgSocket::DestroySocket()
{
if(FSocket != INVALID_SOCKET)
{
if (shutdown(FSocket, SD_SEND)==0)
Purge();
#ifdef OS_WINDOWS
closesocket(FSocket);
#else
close(FSocket);
#endif
FSocket=INVALID_SOCKET;
}
LastTcpError=0;
}
//---------------------------------------------------------------------------
int TMsgSocket::WaitingData()
{
int result = 0;
u_long x = 0;
#ifdef OS_WINDOWS
if (ioctlsocket(FSocket, FIONREAD, &x) == 0)
result = x;
#else
if (ioctl(FSocket, FIONREAD, &x) == 0)
result = x;
#endif
if (result>MaxPacketSize)
result = MaxPacketSize;
return result;
}
//---------------------------------------------------------------------------
int TMsgSocket::WaitForData(int Size, int Timeout)
{
longword Elapsed;
// Check for connection active
if (CanRead(0) && (WaitingData()==0))
LastTcpError=WSAECONNRESET;
else
LastTcpError=0;
// Enter main loop
if (LastTcpError==0)
{
Elapsed =SysGetTick();
while((WaitingData()=(longword)(Timeout))
LastTcpError =WSAETIMEDOUT;
else
SysSleep(1);
}
}
if(LastTcpError==WSAECONNRESET)
Connected =false;
return LastTcpError;
}
//---------------------------------------------------------------------------
void TMsgSocket::SetSocketOptions()
{
int NoDelay = 1;
int KeepAlive = 1;
LastTcpError=0;
SockCheck(setsockopt(FSocket, IPPROTO_TCP, TCP_NODELAY,(char*)&NoDelay, sizeof(NoDelay)));
if (LastTcpError==0)
SockCheck(setsockopt(FSocket, SOL_SOCKET, SO_KEEPALIVE,(char*)&KeepAlive, sizeof(KeepAlive)));
}
//---------------------------------------------------------------------------
int TMsgSocket::SockCheck(int SockResult)
{
if (SockResult == (int)(SOCKET_ERROR))
LastTcpError = GetLastSocketError();
return LastTcpError;
}
//---------------------------------------------------------------------------
bool TMsgSocket::CanWrite(int Timeout)
{
timeval TimeV;
int64_t x;
fd_set FDset;
if(FSocket == INVALID_SOCKET)
return false;
TimeV.tv_usec = (Timeout % 1000) * 1000;
TimeV.tv_sec = Timeout / 1000;
FD_ZERO(&FDset);
FD_SET(FSocket, &FDset);
x = select(FSocket + 1, NULL, &FDset, NULL, &TimeV); //<-Ignore this warning in 64bit Visual Studio
if (x==(int)SOCKET_ERROR)
{
LastTcpError = GetLastSocketError();
x=0;
}
return (x > 0);
}
//---------------------------------------------------------------------------
bool TMsgSocket::CanRead(int Timeout)
{
timeval TimeV;
int64_t x;
fd_set FDset;
if(FSocket == INVALID_SOCKET)
return false;
TimeV.tv_usec = (Timeout % 1000) * 1000;
TimeV.tv_sec = Timeout / 1000;
FD_ZERO(&FDset);
FD_SET(FSocket, &FDset);
x = select(FSocket + 1, &FDset, NULL, NULL, &TimeV); //<-Ignore this warning in 64bit Visual Studio
if (x==(int)SOCKET_ERROR)
{
LastTcpError = GetLastSocketError();
x=0;
}
return (x > 0);
}
//---------------------------------------------------------------------------
#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)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
}
================================================
FILE: deps/snap7/src/sys/snap_msgsock.h
================================================
/*=============================================================================|
| 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
#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
================================================
FILE: deps/snap7/src/sys/snap_platform.h
================================================
/*=============================================================================|
| 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
# include
# if defined(_POSIX_VERSION)
# define POSIX
# endif
#endif
#ifdef OS_OSX
# include
#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 // 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
#endif
#include
#include
#include
#ifdef OS_WINDOWS
# define WIN32_LEAN_AND_MEAN
# include
# include
# include
#endif
#ifdef OS_SOLARIS
# include
# include
# include
#endif
#if defined(PLATFORM_UNIX) || defined(OS_OSX)
# include
# include
# include
# include
# include
# include
# include
#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
================================================
FILE: deps/snap7/src/sys/snap_sysutils.cpp
================================================
/*=============================================================================|
| 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 (TheTimeDestroying)
{
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();
}
//---------------------------------------------------------------------------
================================================
FILE: deps/snap7/src/sys/snap_tcpsrvr.h
================================================
/*=============================================================================|
| 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
================================================
FILE: deps/snap7/src/sys/snap_threads.cpp
================================================
/*=============================================================================|
| 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;
}
//---------------------------------------------------------------------------
================================================
FILE: deps/snap7/src/sys/snap_threads.h
================================================
/*=============================================================================|
| 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
================================================
FILE: deps/snap7/src/sys/sol_threads.h
================================================
/*=============================================================================|
| 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
#include
//---------------------------------------------------------------------------
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
================================================
FILE: deps/snap7/src/sys/unix_threads.h
================================================
/*=============================================================================|
| 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
#include
//---------------------------------------------------------------------------
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
================================================
FILE: deps/snap7/src/sys/win_threads.h
================================================
/*=============================================================================|
| 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
================================================
FILE: doc/client.md
================================================
## S7Client
- [Control functions](#control-functions)
- [Connect()](#connect)
- [ConnectTo()](#connect-to)
- [SetConnectionParams()](#set-connection-params)
- [SetConnectionType()](#set-connection-type)
- [Disconnect()](#disconnect)
- [GetParam()](#get-param)
- [SetParam()](#set-param)
- [Data I/O functions](#data-functions)
- [ReadArea()](#read-area)
- [WriteArea()](#write-area)
- [DBRead()](#dbread)
- [DBWrite()](#dbwrite)
- [ABRead()](#abread)
- [ABWrite()](#abwrite)
- [EBRead()](#ebread)
- [EBWrite()](#ebwrite)
- [MBRead()](#mbread)
- [MBWrite()](#mbwrite)
- [TMRead()](#tmread)
- [TMWrite()](#tmwrite)
- [CTRead()](#ctread)
- [CTWrite()](#ctwrite)
- [ReadMultiVars()](#read-multi-vars)
- [WriteMultiVars()](#write-multi-vars)
- [Directory function](#directory-functions)
- [ListBlocks()](#list-blocks)
- [ListBlocksOfType()](#list-blocks-of-type)
- [GetAgBlockInfo()](#get-ag-blockinfo)
- [GetPgBlockInfo()](#get-pg-blockinfo)
- [Block oriented functions](#block-functions)
- [FullUpload()](#full-upload)
- [Upload()](#upload)
- [Download()](#download)
- [Delete()](#delete)
- [DBGet()](#dbget)
- [DBFill()](#dbfill)
- [Date/Time functions](#datetime-functions)
- [GetPlcDateTime()](#get-plc-datetime)
- [SetPlcDateTime()](#set-plc-datetime)
- [SetPlcSystemDateTime()](#set-plc-system-datetime)
- [System info functions](#systeminfo-functions)
- [ReadSZL()](#read-szl)
- [ReadSZLList()](#read-szl-list)
- [GetOrderCode()](#get-order-code)
- [GetCpuInfo()](#get-cpu-info)
- [GetCpInfo()](#get-cp-info)
- [PLC control functions](#control-functions)
- [PlcHotStart()](#plc-hot-start)
- [PlcColdStart()](#plc-cold-start)
- [PlcStop()](#plc-stop)
- [CopyRamToRom()](#copy-ram-to-rom)
- [Compress()](#compress)
- [Security functions](#security-functions)
- [SetSessionPassword()](#set-session-password)
- [ClearSessionPassword()](#clear-session-password)
- [GetProtection()](#get-protection)
- [Properties](#properties)
- [ExecTime()](#exec-time)
- [LastError()](#last-error)
- [PDURequested()](#pdu-requested)
- [PDULength()](#pdu-length)
- [PlcStatus()](#plc-status)
- [Connected()](#connected)
- [ErrorText()](#error-text)
### API - Control functions
----------
#### S7Client.Connect([callback])
Connects the client to the PLC with the parameters specified in the previous call of `ConnectTo()` or `SetConnectionParams()`.
- The optional `callback` parameter will be executed after connection attempt
If `callback` is **not** set the function is **blocking** and returns `true` on success or `false` on error.
If `callback` is set the function is **non-blocking** and an `error` argument is given to the callback.
#### S7Client.ConnectTo(ip, rack, slot[, callback])
Connects the client to the hardware at `ip`, `rack`, `slot` coordinates.
- `ip` PLC/Equipment IPV4 Address ex. “192.168.1.12”
- `rack` PLC Rack number
- `slot` PLC Slot number
- The optional `callback` parameter will be executed after connection attempt
If `callback` is **not** set the function is **blocking** and returns `true` on success or `false` on error.
If `callback` is set the function is **non-blocking** and an `error` argument is given to the callback.
#### S7Client.SetConnectionParams(ip, localTSAP, remoteTSAP)
Sets internally `ip`, `localTSAP`, `remoteTSAP` coordinates.
- `ip` PLC/Equipment IPv4 address ex. “192.168.1.12”
- `localTSAP` Local TSAP (PC TSAP)
- `remoteTSAP` Remote TSAP (PLC TSAP)
Returns `true` on success or `false` on error.
#### S7Client.SetConnectionType(type)
Sets the connection resource type, i.e the way in which the Clients connects to a PLC.
- `type`
| ConnectionType | Value | Description |
|:--------------------------|:----------:|:------------|
| `S7Client.CONNTYPE_PG` | 0x01 | PG
| `S7Client.CONNTYPE_OP` | 0x02 | OP
| `S7Client.CONNTYPE_BASIC` | 0x03..0x10 | S7 Basic
#### S7Client.Disconnect()
Disconnects “gracefully” the Client from the PLC.
Returns `true` on success or `false` on error.
#### S7Client.GetParam(paramNumber)
Reads an internal Client object parameter.
- `paramNumber` One from the parameter list below
| Name | Value | Description |
|:-----------------------|:-----:|:------------|
| `S7Client.RemotePort` | 2 | Socket remote Port
| `S7Client.PingTimeout` | 3 | Client Ping timeout
| `S7Client.SendTimeout` | 4 | Socket Send timeout
| `S7Client.RecvTimeout` | 5 | Socket Recv timeout
| `S7Client.SrcRef` | 7 | ISOTcp Source reference
| `S7Client.DstRef` | 8 | ISOTcp Destination reference
| `S7Client.SrcTSap` | 9 | ISOTcp Source TSAP
| `S7Client.PDURequest` | 10 | Initial PDU length request
Returns the `parameter value` on success or `false` on error.
#### S7Client.SetParam(paramNumber, value)
Sets an internal Client object parameter.
- `paramNumber` One from the parameter list above
- `value` New parameter value
Returns `true` on success or `false` on error.
### API - Data I/O functions
----------
#### S7Client.ReadArea(area, dbNumber, start, amount, wordLen[, callback])
This is the main function to read data from a PLC. With it you can read DB, Inputs, Outputs, Merkers, Timers and Counters.
- `area` Area identifier (see table [below](#table-area))
- `dbNumber` DB number if area = S7AreaDB, otherwise ignored
- `start` Offset to start
- `amount` Amount of **words** to read
- `wordLen` Word size (see table [below](#table-wordlen))
- The optional `callback` parameter will be executed after read
If `callback` is **not** set the function is **blocking** and returns a `buffer` object on success or `false` on error.
If `callback` is set the function is **non-blocking** and an `error` and `result` argument is given to the callback.
#### S7Client.WriteArea(area, dbNumber, start, amount, wordLen, buffer[, callback])
This is the main function to write data into a PLC.
- `area` Area identifier (see table [below](#table-area))
- `dbNumber` DB number if area = S7AreaDB, otherwise ignored
- `start` Offset to start
- `amount` Amount of **words** to write
- `wordLen` Word size (see table [below](#table-wordlen))
- `buffer` User buffer
- The optional `callback` parameter will be executed after write
If `callback` is **not** set the function is **blocking** and returns `true` on success or `false` on error.
If `callback` is set the function is **non-blocking** and an `error` argument is given to the callback.
| Area | Value | Description |
|:-----------------------|:-----:|:------------|
| `S7Client.S7AreaPE` | 0x81 | Process inputs
| `S7Client.S7AreaPA` | 0x82 | Process outputs
| `S7Client.S7AreaMK` | 0x83 | Merkers
| `S7Client.S7AreaDB` | 0x84 | DB
| `S7Client.S7AreaCT` | 0x1C | Counters
| `S7Client.S7AreaTM` | 0x1D | Timers
| WordLen | Value | Description |
|:-----------------------|:-----:|:------------|
| `S7Client.S7WLBit` | 0x01 | Bit (inside a word)
| `S7Client.S7WLByte` | 0x02 | Byte (8 bit)
| `S7Client.S7WLWord` | 0x04 | Word (16 bit)
| `S7Client.S7WLDWord` | 0x06 | Double Word (32 bit)
| `S7Client.S7WLReal` | 0x08 | Real (32 bit float)
| `S7Client.S7WLCounter` | 0x1C | Counter (16 bit)
| `S7Client.S7WLTimer` | 0x1D | Timer (16 bit)
#### S7Client.DBRead(dbNumber, start, size[, callback])
This is a lean function of `ReadArea()` to read PLC DB.
It simply internally calls `ReadArea()` with `area = S7Client.S7AreaDB` and `wordLen = s7client.S7WLByte`.
- `dbNumber` DB number
- `start` Offset to start
- `size` Size to read (bytes)
- The optional `callback` parameter will be executed after read
If `callback` is **not** set the function is **blocking** and returns a `buffer` object on success or `false` on error.
If `callback` is set the function is **non-blocking** and an `error` and `result` argument is given to the callback.
#### S7Client.DBWrite(dbNumber, start, size, buffer[, callback])
This is a lean function of `WriteArea()` to write PLC DB.
It simply internally calls `WriteArea()` with `area = S7Client.S7AreaDB` and `wordLen = s7client.S7WLByte`.
- `dbNumber` DB number
- `start` Offset to start
- `size` Size to write (bytes)
- `buffer` User buffer
- The optional `callback` parameter will be executed after write
If `callback` is **not** set the function is **blocking** and returns `true` on success or `false` on error.
If `callback` is set the function is **non-blocking** and an `error` argument is given to the callback.
#### S7Client.ABRead(start, size[, callback])
This is a lean function of `ReadArea()` to read PLC process outputs.
It simply internally calls `ReadArea()` with `area = S7Client.S7AreaPA` and `wordLen = s7client.S7WLByte`.
- `start` Offset to start
- `size` Size to read (bytes)
- The optional `callback` parameter will be executed after read
If `callback` is **not** set the function is **blocking** and returns a `buffer` object on success or `false` on error.
If `callback` is set the function is **non-blocking** and an `error` and `result` argument is given to the callback.
#### S7Client.ABWrite(start, size, buffer[, callback])
This is a lean function of `WriteArea()` to write PLC process outputs.
It simply internally calls `WriteArea()` with `area = S7Client.S7AreaPA` and `wordLen = s7client.S7WLByte`.
- `start` Offset to start
- `size` Size to write (bytes)
- `buffer` User buffer
- The optional `callback` parameter will be executed after write
If `callback` is **not** set the function is **blocking** and returns `true` on success or `false` on error.
If `callback` is set the function is **non-blocking** and an `error` argument is given to the callback.
#### S7Client.EBRead(start, size[, callback])
This is a lean function of `ReadArea()` to read PLC process inputs.
It simply internally calls `ReadArea()` with `area = S7Client.S7AreaPE` and `wordLen = s7client.S7WLByte`.
- `start` Offset to start
- `size` Size to read (bytes)
- The optional `callback` parameter will be executed after read
If `callback` is **not** set the function is **blocking** and returns a `buffer` object on success or `false` on error.
If `callback` is set the function is **non-blocking** and an `error` and `result` argument is given to the callback.
#### S7Client.EBWrite(start, size, buffer[, callback])
This is a lean function of `WriteArea()` to write PLC process inputs.
It simply internally calls `WriteArea()` with `area = S7Client.S7AreaPE` and `wordLen = s7client.S7WLByte`.
- `start` Offset to start
- `size` Size to write (bytes)
- `buffer` User buffer
- The optional `callback` parameter will be executed after write
If `callback` is **not** set the function is **blocking** and returns `true` on success or `false` on error.
If `callback` is set the function is **non-blocking** and an `error` argument is given to the callback.
#### S7Client.MBRead(start, size[, callback])
This is a lean function of `ReadArea()` to read PLC Merkers.
It simply internally calls `ReadArea()` with `area = S7Client.S7AreaMK` and `wordLen = s7client.S7WLByte`.
- `start` Offset to start
- `size` Size to read (bytes)
- The optional `callback` parameter will be executed after read
If `callback` is **not** set the function is **blocking** and returns a `buffer` object on success or `false` on error.
If `callback` is set the function is **non-blocking** and an `error` and `result` argument is given to the callback.
#### S7Client.MBWrite(start, size, buffer[, callback])
This is a lean function of `WriteArea()` to write PLC Merkers.
It simply internally calls `WriteArea()` with `area = S7Client.S7AreaMK` and `wordLen = s7client.S7WLByte`.
- `start` Offset to start
- `size` Size to write (bytes)
- `buffer` User buffer
- The optional `callback` parameter will be executed after write
If `callback` is **not** set the function is **blocking** and returns `true` on success or `false` on error.
If `callback` is set the function is **non-blocking** and an `error` argument is given to the callback.
#### S7Client.TMRead(start, amount[, callback])
This is a lean function of `ReadArea()` to read PLC Timers.
It simply internally calls `ReadArea()` with `area = S7Client.S7AreaTM` and `wordLen = S7Client.S7WLTimer`.
- `start` Offset to start
- `amount` Number of timers
- The optional `callback` parameter will be executed after read
If `callback` is **not** set the function is **blocking** and returns a `buffer` object on success or `false` on error.
If `callback` is set the function is **non-blocking** and an `error` and `result` argument is given to the callback.
#### S7Client.TMWrite(start, amount, buffer[, callback])
This is a lean function of `WriteArea()` to write PLC Timers.
It simply internally calls `WriteArea()` with `area = S7Client.S7AreaTM` and `wordLen = S7Client.S7WLTimer`.
- `start` Offset to start
- `amount` Number of timers
- `buffer` User buffer
- The optional `callback` parameter will be executed after write
If `callback` is **not** set the function is **blocking** and returns `true` on success or `false` on error.
If `callback` is set the function is **non-blocking** and an `error` argument is given to the callback.
#### S7Client.CTRead(start, amount[, callback])
This is a lean function of `ReadArea()` to read PLC Counters.
It simply internally calls `ReadArea()` with `area = S7Client.S7AreaCT` and `wordLen = S7Client.S7WLCounter`.
- `start` Offset to start
- `amount` Number of counters
- The optional `callback` parameter will be executed after read
If `callback` is **not** set the function is **blocking** and returns a `buffer` object on success or `false` on error.
If `callback` is set the function is **non-blocking** and an `error` and `result` argument is given to the callback.
#### S7Client.CTWrite(start, amount, buffer[, callback])
This is a lean function of `WriteArea()` to write PLC Counters.
It simply internally calls `WriteArea()` with `area = S7Client.S7AreaCT` and `wordLen = S7Client.S7WLCounter`.
- `start` Offset to start
- `amount` Number of counters
- `buffer` User buffer
- The optional `callback` parameter will be executed after write
If `callback` is **not** set the function is **blocking** and returns `true` on success or `false` on error.
If `callback` is set the function is **non-blocking** and an `error` argument is given to the callback.
#### S7Client.ReadMultiVars(multiVars[, callback])
This is function allows to read different kind of variables from a PLC in a single call. With it you can read DB, Inputs, Outputs, Merkers, Timers and Counters.
- `multiVars` Array of objects with read information (see structure below)
- The optional `callback` parameter will be executed after read
If `callback` is **not** set the function is **blocking** and returns an `array` on success or `false` on error.
If `callback` is set the function is **non-blocking** and an `error` and `result` argument is given to the callback.
Example:
```javascript
// multiVars array structure
[
{
"Area": S7Client.S7AreaDB,
"WordLen": S7Client.S7WLByte,
"DBNumber": 1,
"Start": 0,
"Amount": 1
},
{
"Area": S7Client.S7AreaCT,
"WordLen": S7Client.S7WLCounter,
"Start": 0,
"Amount": 8
},
{
"Area": S7Client.S7AreaPA,
"WordLen": S7Client.S7WLByte,
"Start": 0,
"Amount": 16
},
...
]
// result array
[
{
"Result": 0, // Error code
"Data": ... // Buffer object or null if Result <> 0
},
...
]
```
Since could happen that some variables are read, some other not because maybe they don't exist in PLC. It is important to check the single item result.
Due the different kind of variables involved , there is no split feature available for this function, so the maximum data size must not exceed the PDU size.
The advantage of this function becomes big when you have many small non-contiguous variables to be read.
#### S7Client.WriteMultiVars(multiVars[, callback])
This is function allows to write different kind of variables into a PLC in a single call. With it you can write DB, Inputs, Outputs, Merkers, Timers and Counters.
- `multiVars` Array of objects with write information (see structure below)
- The optional `callback` parameter will be executed after write
If `callback` is **not** set the function is **blocking** and returns an `array` on success or `false` on error.
If `callback` is set the function is **non-blocking** and an `error` and `result` argument is given to the callback.
Example:
```javascript
// multiVars array structure
[
{
"Area": S7Client.S7AreaDB,
"WordLen": S7Client.S7WLByte,
"DBNumber": 1,
"Start": 0,
"Amount": 1,
"Data": buffer1 // Buffer variable
},
{
"Area": S7Client.S7AreaCT,
"WordLen": S7Client.S7WLCounter,
"Start": 0,
"Amount": 8,
"Data": buffer2 // Buffer variable
},
{
"Area": S7Client.S7AreaPA,
"WordLen": S7Client.S7WLByte,
"Start": 0,
"Amount": 16,
"Data": buffer3 // Buffer variable
},
...
]
// result array
[
{
"Result": 0 // Error code
},
...
]
```
### API - Directory functions
----------
#### S7Client.ListBlocks([callback])
This function returns an object of the AG blocks amount divided by type.
- The optional `callback` parameter will be executed after completion
If `callback` is **not** set the function is **blocking** and returns an `object` (see below) on success or `false` on error.
If `callback` is set the function is **non-blocking** and an `error` and `result` argument is given to the callback.
Example:
```javascript
{
"OBCount": 0,
"FBCount": 0,
"FCCount": 0,
"SFBCount": 0,
"SFCCount": 0,
"DBCount": 0,
"SDBCount": 0
}
```
#### S7Client.ListBlocksOfType(blockType[, callback])
This function returns an array of the AG list of a specified block type.
- `blockType` Type of block (see table below)
- The optional `callback` parameter will be executed after completion
If `callback` is **not** set the function is **blocking** and returns an `array` on success or `false` on error.
If `callback` is set the function is **non-blocking** and an `error` and `result` argument is given to the callback.
Each item of the result array will contain a block number.
| BlockType | Value | Description |
|:-----------------------|:-----:|:------------|
| `S7Client.Block_OB` | 0x38 | OB
| `S7Client.Block_DB` | 0x41 | DB
| `S7Client.Block_SDB` | 0x42 | SDB
| `S7Client.Block_FC` | 0x43 | FC
| `S7Client.Block_SFC` | 0x44 | SFC
| `S7Client.Block_FB` | 0x45 | FB
| `S7Client.Block_SFB` | 0x46 | SFB
#### S7Client.GetAgBlockInfo(blockType, blockNum[, callback])
Returns an object with detailed information about a given AG block.
This function is very useful if you need to read or write data in a DB which you do not know the size in advance (see MC7Size field)
- `blockType` Type of block (see table [above](#table-blocktype))
- `blockNum` Number of block
- The optional `callback` parameter will be executed after completion
If `callback` is **not** set the function is **blocking** and returns an `object` (see below) on success or `false` on error.
If `callback` is set the function is **non-blocking** and an `error` and `result` argument is given to the callback.
Example:
```javascript
{
"BlkType": , // Block Type (see SubBlkType table)
"BlkNumber": , // Block number
"BlkLang": , // Block Language (see LangType Table)
"BlkFlags": , // Block flags (bitmapped)
"MC7Size": , // The real size in bytes
"LoadSize": , // Load memory size
"LocalData": , // Local data
"SBBLength": , // SBB Length
"CheckSum": , // Checksum
"Version": , // Version (BCD 00)
"CodeDate": , // Code date
"IntfDate": , // Interface date
"Author": , // Author
"Family": , // Family
"Header": // Header
}
```
| SubBlockType | Value | Description |
|:-----------------------|:-----:|:------------|
| `S7Client.SubBlk_OB` | 0x08 | OB
| `S7Client.SubBlk_DB` | 0x0A | DB
| `S7Client.SubBlk_SDB` | 0x0B | SDB
| `S7Client.SubBlk_FC` | 0x0C | FC
| `S7Client.SubBlk_SFC` | 0x0D | SFC
| `S7Client.SubBlk_FB` | 0x0E | FB
| `S7Client.SubBlk_SFB` | 0x0F | SFB
| LangType | Value | Description |
|:--------------------------|:-----:|:------------|
| `S7Client.BlockLangAWL` | 0x01 | AWL
| `S7Client.BlockLangKOP` | 0x02 | KOP
| `S7Client.BlockLangFUP` | 0x03 | FUP
| `S7Client.BlockLangSCL` | 0x04 | SCL
| `S7Client.BlockLangDB` | 0x05 | DB
| `S7Client.BlockLangGRAPH` | 0x06 | GRAPH
#### S7Client.GetPgBlockInfo(buffer)
Returns detailed information about a block present in a user buffer. This function is usually used in conjunction with `FullUpload()`.
An uploaded block saved to disk, could be loaded in a user buffer and checked with this function.
- `buffer` User buffer
Returns an `object` (see [example](#example-blockinfo) above) on success or `false`on error.
### API - Block oriented functions
----------
#### S7Client.FullUpload(blockType, blockNum, size[, callback])
Uploads a block from AG. The whole block (including header and footer) is copied into the user buffer.
- `blockType` Type of block (see table [above](#table-blocktype))
- `blockNum` Number of block
- `size` Buffer size (if smaller than the data
uploaded, only `size` bytes are copied and `errCliPartialDataRead` is returned)
- The optional `callback` parameter will be executed after completion
If `callback` is **not** set the function is **blocking** and returns a `Buffer` object on success or `false` on error.
If `callback` is set the function is **non-blocking** and an `error` and `result` argument is given to the callback.
#### S7Client.Upload(blockType, blockNum[, callback])
Uploads a block body from AG. Only the block body (but header and footer) is copied into the user buffer.
- `blockType` Type of block (see table [above](#table-blocktype))
- `blockNum` Number of block
- The optional `callback` parameter will be executed after completion
If `callback` is **not** set the function is **blocking** and returns a `Buffer` object on success or `false` on error.
If `callback` is set the function is **non-blocking** and an `error` and `result` argument is given to the callback.
#### S7Client.Download(blockNum, buffer[, callback])
Downloads a block into AG. A whole block (including header and footer) must be available into the user buffer.
- `blockNum` Number of block
- `buffer` User buffer
- The optional `callback` parameter will be executed after completion
If `callback` is **not** set the function is **blocking** and returns `true` on success or `false` on error.
If `callback` is set the function is **non-blocking** and an `error` argument is given to the callback.
If the parameter `blockNum` is `-1`, the block number is not changed else the block is downloaded with the provided number (just like a “Download As…”).
#### S7Client.Delete(blockType, blockNum[, callback])
Deletes a block into AG.
!!! There is no undo function available !!!
- `blockType` Type of block (see table [above](#table-blocktype))
- `blockNum` Number of block
- The optional `callback` parameter will be executed after completion
If `callback` is **not** set the function is **blocking** and returns `true` on success or `false` on error.
If `callback` is set the function is **non-blocking** and an `error` argument is given to the callback.
#### S7Client.DBGet(dbNumber[, callback])
Uploads a DB from AG. This function is equivalent to `Upload()` with `BlockType = Block_DB` but it uses a different approach so it’s not subject to the security level set.
Only data is uploaded.
- `dbNumber` DB number
- The optional `callback` parameter will be executed after completion
If `callback` is **not** set the function is **blocking** and returns a `Buffer` object on success or `false` on error.
If `callback` is set the function is **non-blocking** and an `error` and `result` argument is given to the callback.
This function first gathers the DB size via `GetAgBlockInfo()` then calls `DBRead()`.
#### S7Client.DBFill(dbNumber, fillChar[, callback])
Fills a DB in AG with a given byte without the need of specifying its size.
- `dbNumber` DB number
- `fillChar` char or char code
- The optional `callback` parameter will be executed after completion
If `callback` is **not** set the function is **blocking** and returns `true` on success or `false` on error.
If `callback` is set the function is **non-blocking** and an `error` argument is given to the callback.
### API - Date/Time functions
----------
#### S7Client.GetPlcDateTime([callback])
Reads PLC date and time.
- The optional `callback` parameter will be executed after completion
If `callback` is **not** set the function is **blocking** and returns a javascript `Date()` object on success or `false` on error.
If `callback` is set the function is **non-blocking** and an `error` and `result` argument is given to the callback.
#### S7Client.SetPlcDateTime(dateTime[, callback])
Sets the PLC date and time.
- `dateTime`
- The optional `callback` parameter will be executed after completion
The `dateTime` argument can be a javascript `Date()` object or an object with the structure below.
```javascript
{
"year": 2015, // year
"month": 4, // months since January 0-11
"day": 3, // day of the month 1-31
"hours": 19, // hours since midnight 0-23
"minutes": 37, // minutes after the hour 0-59
"seconds": 0 // seconds after the minute 0-59
}
```
If `callback` is **not** set the function is **blocking** and returns a `true` on success or `false` on error.
If `callback` is set the function is **non-blocking** and an `error` argument is given to the callback.
#### S7Client.SetPlcSystemDateTime([callback])
Sets the PLC date and time in accord to the PC system Date/Time.
- The optional `callback` parameter will be executed after completion
If `callback` is **not** set the function is **blocking** and returns `true` on success or `false` on error.
If `callback` is set the function is **non-blocking** and an `error` argument is given to the callback.
### API - System info functions
----------
#### S7Client.ReadSZL(id, index[, callback])
Reads a partial list of given `id`and `index`.
- The optional `callback` parameter will be executed after completion
If `callback` is **not** set the function is **blocking** and returns a `buffer` on success or `false` on error.
If `callback` is set the function is **non-blocking** and an `error` and `result` argument is given to the callback.
#### S7Client.ReadSZLList([callback])
Reads the directory of the partial lists.
- The optional `callback` parameter will be executed after completion
If `callback` is **not** set the function is **blocking** and returns an `array` on success or `false` on error.
If `callback` is set the function is **non-blocking** and an `error` and `result` argument is given to the callback.
#### S7Client.GetOrderCode([callback])
Gets CPU order code and version info.
- The optional `callback` parameter will be executed after completion
If `callback` is **not** set the function is **blocking** and returns an `object` on success or `false` on error.
If `callback` is set the function is **non-blocking** and an `error` and `result` argument is given to the callback.
Example:
```javascript
{
"Code": , // Order Code
"V1": , // Version V1.V2.V3
"V2": ,
"V3":
}
```
#### S7Client.GetCpuInfo([callback])
Gets CPU module name, serial number and other info.
- The optional `callback` parameter will be executed after completion
If `callback` is **not** set the function is **blocking** and returns an `object` on success or `false` on error.
If `callback` is set the function is **non-blocking** and an `error` and `result` argument is given to the callback.
Example:
```javascript
{
"ModuleTypeName": ,
"SerialNumber": ,
"ASName": ,
"Copyright": ,
"ModuleName":
}
```
#### S7Client.GetCpInfo([callback])
Gets CP (communication processor) info.
- The optional `callback` parameter will be executed after completion
If `callback` is **not** set the function is **blocking** and returns an `object` on success or `false` on error.
If `callback` is set the function is **non-blocking** and an `error` and `result` argument is given to the callback.
Example:
```javascript
{
"MaxPduLength": ,
"MaxConnections": ,
"MaxMpiRate": ,
"MaxBusRate":
}
```
### API - PLC control functions
----------
#### S7Client.PlcHotStart([callback])
Puts the CPU in RUN mode performing an HOT START.
- The optional `callback` parameter will be executed after completion
If `callback` is **not** set the function is **blocking** and returns `true` on success or `false` on error.
If `callback` is set the function is **non-blocking** and an `error` argument is given to the callback.
#### S7Client.PlcColdStart([callback])
Puts the CPU in RUN mode performing a COLD START.
- The optional `callback` parameter will be executed after completion
If `callback` is **not** set the function is **blocking** and returns `true` on success or `false` on error.
If `callback` is set the function is **non-blocking** and an `error` argument is given to the callback.
#### S7Client.PlcStop([callback])
Puts the CPU in STOP mode.
- The optional `callback` parameter will be executed after completion
If `callback` is **not** set the function is **blocking** and returns `true` on success or `false` on error.
If `callback` is set the function is **non-blocking** and an `error` argument is given to the callback.
#### S7Client.CopyRamToRom(timeout[, callback])
Performs the Copy Ram to Rom action.
- `timeout` Maximum time expected to complete the operation (ms)
- The optional `callback` parameter will be executed after completion or on timeout
If `callback` is **not** set the function is **blocking** and returns `true` on success or `false` on error.
If `callback` is set the function is **non-blocking** and an `error` argument is given to the callback.
Not all CPUs support this operation.
The CPU must be in STOP mode.
#### S7Client.Compress(timeout[, callback])
Performs the Memory compress action.
- `timeout` Maximum time expected to complete the operation (ms)
- The optional `callback` parameter will be executed after completion or on timeout
If `callback` is **not** set the function is **blocking** and returns `true` on success or `false` on error.
If `callback` is set the function is **non-blocking** and an `error` argument is given to the callback.
### API - Security functions
----------
#### S7Client.SetSessionPassword(password[, callback])
Send the password to the PLC to meet its security level.
- `password` Password
- The optional `callback` parameter will be executed after completion
If `callback` is **not** set the function is **blocking** and returns `true` on success or `false` on error.
If `callback` is set the function is **non-blocking** and an `error` argument is given to the callback.
A `password` accepted by a PLC is an 8 chars string, a longer password will be trimmed, and a shorter one will be "right space padded".
#### S7Client.ClearSessionPassword([callback])
Clears the password set for the current session (logout).
- The optional `callback` parameter will be executed after completion
If `callback` is **not** set the function is **blocking** and returns `true` on success or `false` on error.
If `callback` is set the function is **non-blocking** and an `error` argument is given to the callback.
#### S7Client.GetProtection([callback])
Gets the CPU protection level info.
- The optional `callback` parameter will be executed after completion
If `callback` is **not** set the function is **blocking** and returns the protection object on success or `false` on error.
If `callback` is set the function is **non-blocking** and an `error` and `result` argument is given to the callback.
Example:
```javascript
{
"sch_schal": 1,
"sch_par": 0,
"sch_rel": 0,
"bart_sch": 1,
"anl_sch": 0
}
```
| S7Protection | Values | Description |
|:-------------|:--------|:------------|
| `sch_schal` | 1,2,3 | Protection level set with the mode selector
| `sch_par` | 0,1,2,3 | Password level, 0 : no password
| `sch_rel` | 0,1,2,3 | Valid protection level of the CPU
| `bart_sch` | 1,2,3,4 | Mode selector setting (1:RUN, 2:RUN-P, 3:STOP, :MRES, 0:undefined or cannot be determined)
| `anl_sch` | 0,1,2 | Startup switch setting (1:CRST, 2:WRST, 0:undefined, does not exist of cannot be determined)
### API - Properties
----------
#### S7Client.ExecTime()
Returns the last job execution time in milliseconds or `false`on error.
#### S7Client.LastError()
Returns the last job result.
#### S7Client.PDURequested()
Returns the PDU length requested by the client or `false` on error. The requested PDU length can be modified with [SetParam()](#set-param).
#### S7Client.PDULength()
Returns the PDU length negotiated between the client and the PLC during the connection or `false` on error.
It’s useful to know the PDU negotiated when we need to call `ReadMultivar()` or `WriteMultiVar()`. All other data transfer functions handle this information by themselves and split the telegrams automatically if needed.
#### S7Client.PlcStatus([callback])
Returns the CPU status (running/stopped).
- The optional `callback` parameter will be executed after completion
If `callback` is **not** set the function is **blocking** and returns the CPU status on success or `false` on error.
If `callback` is set the function is **non-blocking** and an `error` and `result` argument is given to the callback.
| Status | Value | Description |
|:------------------------------|:-----:|:------------|
| `S7Client.S7CpuStatusUnknown` | 0x00 | The CPU status is unknown
| `S7Client.S7CpuStatusRun` | 0x08 | The CPU is running
| `S7Client.S7CpuStatusStop` | 0x04 | The CPU is stopped
#### S7Client.Connected()
Returns the connection status.
#### S7Client.ErrorText(errNum)
Returns a textual explanation of a given error number.
- `errNum` Error number
================================================
FILE: doc/server.md
================================================
## S7Server
- [Administrative functions](#administrative-functions)
- [Start()](#start)
- [StartTo()](#start-to)
- [Stop()](#stop)
- [GetParam()](#get-param)
- [SetParam()](#set-param)
- [SetResourceless()](#set-resourceless)
- [Memory functions](#memory-functions)
- [RegisterArea()](#register-area)
- [UnregisterArea()](#unregister-area)
- [GetArea()](#get-area)
- [SetArea()](#set-area)
- [LockArea()](#lock-area)
- [UnlockArea()](#unlock-area)
- [Event functions](#event-functions)
- [Event 'event'](#event-event)
- [Event 'readWrite'](#event-read-write)
- [GetEventMask()](#get-event-mask)
- [SetEventMask()](#set-event-mask)
- [Miscellaneous functions](#miscellaneous-functions)
- [LastError()](#last-error)
- [EventText()](#event-text)
- [ErrorText()](#error-text)
- [ServerStatus()](#server-status)
- [ClientsCount()](#clients-count)
- [GetCpuStatus()](#get-cpu-status)
- [SetCpuStatus()](#set-cpu-status)
### API - Administrative functions
----------
#### S7Server.Start([callback])
Starts the server and binds it to the IP address specified in the previous call of `StartTo()`. If `StartTo()` was not previously called, `0.0.0.0` is assumed as IP address.
- The optional `callback` parameter will be executed after completion
If `callback` is **not** set the function is **blocking** and returns `true` on success or `false` on error.
If `callback` is set the function is **non-blocking** and an `error` argument is given to the callback.
#### S7Server.StartTo(ip[, callback])
Starts the server and binds it to the specified IP address and the IsoTCP port.
- `ip` PLC/Equipment IPV4 Address ex. “192.168.1.12”
- The optional `callback` parameter will be executed after completion
If `callback` is **not** set the function is **blocking** and returns the CPU status on success or `false` on error.
If `callback` is set the function is **non-blocking** and an `error` argument is given to the callback.
#### S7Server.Stop([callback])
Stops the server, disconnects gracefully all clients, destroys al S7 workers and unbinds the listener socket from its address.
- The optional `callback` parameter will be executed after completion
If `callback` is **not** set the function is **blocking** and returns the CPU status on success or `false` on error.
If `callback` is set the function is **non-blocking** and an `error` argument is given to the callback.
#### S7Server.GetParam(paramNumber)
Returns an internal server parameter.
- `paramNumber` One from the parameter list [below](#table-area)
| Name | Value | Description |
|:------------------------|:-----:|:------------|
| `S7Server.LocalPort` | 1 | Socket local port
| `S7Server.WorkInterval` | 6 | Socket worker interval
| `S7Server.PDURequest` | 10 | Initial PDU length request
| `S7Server.MaxClients` | 11 | Max clients allowed
Returns the `parameter value` on success or `false` on error.
#### S7Server.SetParam(paramNumber, value)
Sets an internal server parameter.
- `paramNumber` One from the parameter list [above](#table-area)
- `value` New parameter value
Returns `true` on success or `false` on error.
#### S7Server.SetResourceless(value)
Sets the server to resourceless mode.
- `value` new value
Returns `true` on success or `false` on error.
### API - Memory functions
----------
#### S7Server.RegisterArea(areaCode[, index], buffer)
Registers a memory area in the server. That memory block will be visible by the clients.
- `areaCode` Area identifier (see table [below](#table-area))
- `index` DB number if `areaCode` equals `srvAreaDB`, otherwise ignored
- `buffer` User buffer
Returns `true` on success or `false` on error.
#### S7Server.UnregisterArea(areaCode[, index])
Unregisters a memory area in the server.
- `areaCode` Area identifier (see table [below](#table-area))
- `index` DB number if `areaCode` equals `srvAreaDB`, otherwise ignored
Returns `true` on success or `false` on error.
#### S7Server.GetArea(areaCode[, index])
Gets the content of a previously registered memory area block.
- `areaCode` Area identifier (see table [below](#table-area))
- `index` DB number if `areaCode` equals `srvAreaDB`, otherwise ignored
Returns a `buffer` object.
#### S7Server.SetArea(areaCode[, index], buffer)
Sets the content of a previously registered memory area block.
- `areaCode` Area identifier (see table [below](#table-area))
- `index` DB number if `areaCode` equals `srvAreaDB`, otherwise ignored
- `buffer` Buffer object
#### S7Server.LockArea(areaCode[, index])
Locks the memory area so that a server worker thread is blocked on access attempt until the lock is released with [UnlockArea()](#unlock-area).
- `areaCode` Area identifier (see table [below](#table-area))
- `index` DB number if `areaCode` equals `srvAreaDB`, otherwise ignored
#### S7Server.UnlockArea(areaCode[, index])
Unlocks a previously locked memory area.
- `areaCode` Area identifier (see table [below](#table-area))
- `index` DB number if `areaCode` equals `srvAreaDB`, otherwise ignored
| Area | Value | Description |
|:-----------------------|:-----:|:------------|
| `S7Server.srvAreaPE` | 0 | Process inputs
| `S7Server.srvAreaPA` | 1 | Process outputs
| `S7Server.srvAreaMK` | 2 | Merkers
| `S7Server.srvAreaCT` | 3 | Counters
| `S7Server.srvAreaTM` | 4 | Timers
| `S7Server.srvAreaDB` | 5 | DB
### API - Event functions
----------
#### S7Server event: 'event'
Emitted on server events.
- `event` Event object
Event object:
```javascript
{
EvtTime; // Date
EvtSender; // Sender
EvtCode; // Event code
EvtRetCode; // Event result
EvtParam1; // Param 1 (if available)
EvtParam2; // Param 2 (if available)
EvtParam3; // Param 3 (if available)
EvtParam4; // Param 4 (if available)
}
```
Example:
```javascript
var s7server = new snap7.S7Server();
s7server.on("event", function(event) {
console.log(s7server.EventText(event));
});
s7server.StartTo('127.0.0.1');
```
#### S7Server event: 'readWrite'
Emitted on every read/write event. Only available in resourceless mode.
- `sender` IPv4 address of the sender
- `operation` Operation type
- `tagObj` Tag object
- `buffer` Buffer object
- `callback` Callback function
The server worker thread is **blocked** until `callback` is called. Therefore **calling is crucial**, to prevent a deadlock in the worker thread.
On a read event the `callback` expects a buffer as argument that is provided to the client. You can use the `buffer` argument which is an empty buffer of the correct size.
| Operation type | Value | Description |
|:--------------------------|:-----:|:---------------------|
| `S7Server.operationRead` | 0x00 | Read operation
| `S7Server.operationWrite` | 0x01 | Write operation
Tag object:
```javascript
{
Area; // Area code (DB, MK,…)
DBNumber; // DB number (if any or 0)
Start; // Offset start
Size; // Number of elements
WordLen; // Tag WordLength
}
```
Example:
```javascript
var s7server = new snap7.S7Server();
s7server.SetResourceless(true);
s7server.on("readWrite", function(sender, operation, tagObj, buffer, callback) {
console.log((operation === s7server.operationRead ? 'Read' : 'Write') + ' event from ' + sender);
console.log('Area : ' + tagObj.Area);
console.log('DBNumber : ' + tagObj.DBNumber);
console.log('Start : ' + tagObj.Start);
console.log('Size : ' + tagObj.Size);
console.log('WordLen : ' + tagObj.WordLen);
if (operation === s7server.operationRead) {
buffer.fill(255);
return callback(buffer);
} else {
console.log('Buffer : ' + buffer);
return callback();
}
});
s7server.StartTo('127.0.0.1');
```
#### S7Server.GetEventMask()
Returns the server event filter mask.
#### S7Server.SetEventMask(mask)
Sets the server event filter mask.
- `mask` Bit mask (see table [below](#table-mask))
| Event code | Value |
|:------------------------------------|:--------------:|
| `S7Server.evcAll` | 0xFFFFFFFF
| `S7Server.evcNone` | 0x00000000
| `S7Server.evcServerStarted` | 0x00000001
| `S7Server.evcServerStopped` | 0x00000002
| `S7Server.evcListenerCannotStart` | 0x00000004
| `S7Server.evcClientAdded` | 0x00000008
| `S7Server.evcClientRejected` | 0x00000010
| `S7Server.evcClientNoRoom` | 0x00000020
| `S7Server.evcClientException` | 0x00000040
| `S7Server.evcClientDisconnected` | 0x00000080
| `S7Server.evcClientTerminated` | 0x00000100
| `S7Server.evcClientsDropped` | 0x00000200
| `S7Server.evcPDUincoming` | 0x00010000
| `S7Server.evcDataRead` | 0x00020000
| `S7Server.evcDataWrite` | 0x00040000
| `S7Server.evcNegotiatePDU` | 0x00080000
| `S7Server.evcReadSZL` | 0x00100000
| `S7Server.evcClock` | 0x00200000
| `S7Server.evcUpload` | 0x00400000
| `S7Server.evcDownload` | 0x00800000
| `S7Server.evcDirectory` | 0x01000000
| `S7Server.evcSecurity` | 0x02000000
| `S7Server.evcControl` | 0x04000000
### API - Miscellaneous functions
----------
#### S7Server.LastError()
Returns the last job result.
#### S7Server.EventText(eventObj)
Returns a textual explanation of a given event.
- `eventObj` Event object (example [here](#event-object))
#### S7Server.ErrorText(errNum)
Returns a textual explanation of a given error number.
- `errNum` Error number
#### S7Server.ServerStatus()
Returns the server status. (see table [below](#table-server-status))
| Status | Value | Description |
|:----------------------|:-----:|:---------------------|
| `S7Server.SrvStopped` | 0x00 | The Server is stopped
| `S7Server.SrvRunning` | 0x01 | The Server is Running
| `S7Server.SrvError` | 0x02 | Server Error
#### S7Server.ClientsCount()
Returns the number of clients connected to the server.
#### S7Server.GetCpuStatus()
Returns the Virtual CPU status. (see table [below](#table-cpu-status))
#### S7Server.SetCpuStatus(cpuStatus)
Sets the Virtual CPU status.
- `cpuStatus` Status value (see table [below](#table-cpu-status))
| Status | Value | Description |
|:------------------------------|:-----:|:-------------------------|
| `S7Server.S7CpuStatusUnknown` | 0x00 | The CPU status is unknown
| `S7Server.S7CpuStatusRun` | 0x08 | The CPU is running
| `S7Server.S7CpuStatusStop` | 0x04 | The CPU is stopped
================================================
FILE: lib/node-snap7.js
================================================
/*
* Copyright (c) 2019, Mathias Küsel
* MIT License
*/
var events = require('events');
module.exports = snap7 = require('bindings')('node_snap7.node');
snap7.S7Client.prototype.DBRead = function (dbNumber, start, size, cb) {
return this.ReadArea(this.S7AreaDB, dbNumber, start, size, this.S7WLByte, cb);
}
snap7.S7Client.prototype.DBWrite = function (dbNumber, start, size, buf, cb) {
return this.WriteArea(this.S7AreaDB, dbNumber, start, size, this.S7WLByte, buf, cb);
}
snap7.S7Client.prototype.MBRead = function (start, size, cb) {
return this.ReadArea(this.S7AreaMK, 0, start, size, this.S7WLByte, cb);
}
snap7.S7Client.prototype.MBWrite = function (start, size, buf, cb) {
return this.WriteArea(this.S7AreaMK, 0, start, size, this.S7WLByte, buf, cb);
}
snap7.S7Client.prototype.EBRead = function (start, size, cb) {
return this.ReadArea(this.S7AreaPE, 0, start, size, this.S7WLByte, cb);
}
snap7.S7Client.prototype.EBWrite = function (start, size, buf, cb) {
return this.WriteArea(this.S7AreaPE, 0, start, size, this.S7WLByte, buf, cb);
}
snap7.S7Client.prototype.ABRead = function (start, size, cb) {
return this.ReadArea(this.S7AreaPA, 0, start, size, this.S7WLByte, cb);
}
snap7.S7Client.prototype.ABWrite = function (start, size, buf, cb) {
return this.WriteArea(this.S7AreaPA, 0, start, size, this.S7WLByte, buf, cb);
}
snap7.S7Client.prototype.TMRead = function (start, size, cb) {
return this.ReadArea(this.S7AreaTM, 0, start, size, this.S7WLTimer, cb);
}
snap7.S7Client.prototype.TMWrite = function (start, size, buf, cb) {
return this.WriteArea(this.S7AreaTM, 0, start, size, this.S7WLTimer, buf, cb);
}
snap7.S7Client.prototype.CTRead = function (start, size, cb) {
return this.ReadArea(this.S7AreaCT, 0, start, size, this.S7WLCounter, cb);
}
snap7.S7Client.prototype.CTWrite = function (start, size, buf, cb) {
return this.WriteArea(this.S7AreaCT, 0, start, size, this.S7WLCounter, buf, cb);
}
snap7.S7Server.super_ = events.EventEmitter;
Object.setPrototypeOf(snap7.S7Server.prototype, events.EventEmitter.prototype);
================================================
FILE: package.json
================================================
{
"name": "node-snap7",
"main": "./lib/node-snap7.js",
"version": "1.0.9",
"description": "Native node.js addon/wrapper for snap7",
"homepage": "https://github.com/mathiask88/node-snap7",
"repository": {
"type": "git",
"url": "git://github.com/mathiask88/node-snap7.git"
},
"keywords": [
"snap7",
"sps",
"S7",
"PLC"
],
"author": {
"name": "Mathias Küsel"
},
"engines": {
"node": "16 || 18 || 20 || 22 || 24"
},
"license": "MIT",
"readmeFilename": "README.md",
"dependencies": {
"nan": "^2.23.0",
"bindings": "^1.5.0",
"prebuild-install": "^7.1.2"
},
"devDependencies": {
"prebuild": "^13.0.1",
"prebuild-ci": "^4.0.0"
},
"scripts": {
"install": "prebuild-install || node-gyp rebuild",
"test": "prebuild-ci"
}
}
================================================
FILE: src/node_snap7.cpp
================================================
/*
* Copyright (c) 2019, Mathias Küsel
* MIT License
*/
#include
#include
namespace node_snap7 {
NAN_MODULE_INIT(InitAll) {
S7Client::Init(target);
S7Server::Init(target);
}
NODE_MODULE(node_snap7, InitAll)
} // namespace node_snap7
================================================
FILE: src/node_snap7_client.cpp
================================================
/*
* Copyright (c) 2019, Mathias Küsel
* MIT License
*/
#include
#include
#include
namespace node_snap7 {
Nan::Persistent S7Client::constructor;
NAN_MODULE_INIT(S7Client::Init) {
Nan::HandleScope scope;
v8::Local tpl;
tpl = Nan::New(S7Client::New);
v8::Local name = Nan::New("S7Client")
.ToLocalChecked();
tpl->SetClassName(name);
tpl->InstanceTemplate()->SetInternalFieldCount(1);
// Setup the prototype
// Control functions
Nan::SetPrototypeMethod(
tpl
, "Connect"
, S7Client::Connect);
Nan::SetPrototypeMethod(
tpl
, "ConnectTo"
, S7Client::ConnectTo);
Nan::SetPrototypeMethod(
tpl
, "SetConnectionParams"
, S7Client::SetConnectionParams);
Nan::SetPrototypeMethod(
tpl
, "SetConnectionType"
, S7Client::SetConnectionType);
Nan::SetPrototypeMethod(
tpl
, "Disconnect"
, S7Client::Disconnect);
Nan::SetPrototypeMethod(
tpl
, "GetParam"
, S7Client::GetParam);
Nan::SetPrototypeMethod(
tpl
, "SetParam"
, S7Client::SetParam);
// Data I/O Main functions
Nan::SetPrototypeMethod(
tpl
, "ReadArea"
, S7Client::ReadArea);
Nan::SetPrototypeMethod(
tpl
, "WriteArea"
, S7Client::WriteArea);
Nan::SetPrototypeMethod(
tpl
, "ReadMultiVars"
, S7Client::ReadMultiVars);
Nan::SetPrototypeMethod(
tpl
, "WriteMultiVars"
, S7Client::WriteMultiVars);
// Directory functions
Nan::SetPrototypeMethod(
tpl
, "ListBlocks"
, S7Client::ListBlocks);
Nan::SetPrototypeMethod(
tpl
, "GetAgBlockInfo"
, S7Client::GetAgBlockInfo);
Nan::SetPrototypeMethod(
tpl
, "GetPgBlockInfo"
, S7Client::GetPgBlockInfo);
Nan::SetPrototypeMethod(
tpl
, "ListBlocksOfType"
, S7Client::ListBlocksOfType);
// Blocks functions
Nan::SetPrototypeMethod(
tpl
, "Upload"
, S7Client::Upload);
Nan::SetPrototypeMethod(
tpl
, "FullUpload"
, S7Client::FullUpload);
Nan::SetPrototypeMethod(
tpl
, "Download"
, S7Client::Download);
Nan::SetPrototypeMethod(
tpl
, "Delete"
, S7Client::Delete);
Nan::SetPrototypeMethod(
tpl
, "DBGet"
, S7Client::DBGet);
Nan::SetPrototypeMethod(
tpl
, "DBFill"
, S7Client::DBFill);
// Date/Time functions
Nan::SetPrototypeMethod(
tpl
, "GetPlcDateTime"
, S7Client::GetPlcDateTime);
Nan::SetPrototypeMethod(
tpl
, "SetPlcDateTime"
, S7Client::SetPlcDateTime);
Nan::SetPrototypeMethod(
tpl
, "SetPlcSystemDateTime"
, S7Client::SetPlcSystemDateTime);
// System Info functions
Nan::SetPrototypeMethod(
tpl
, "GetOrderCode"
, S7Client::GetOrderCode);
Nan::SetPrototypeMethod(
tpl
, "GetCpuInfo"
, S7Client::GetCpuInfo);
Nan::SetPrototypeMethod(
tpl
, "GetCpInfo"
, S7Client::GetCpInfo);
Nan::SetPrototypeMethod(
tpl
, "ReadSZL"
, S7Client::ReadSZL);
Nan::SetPrototypeMethod(
tpl
, "ReadSZLList"
, S7Client::ReadSZLList);
// Control functions
Nan::SetPrototypeMethod(
tpl
, "PlcHotStart"
, S7Client::PlcHotStart);
Nan::SetPrototypeMethod(
tpl
, "PlcColdStart"
, S7Client::PlcColdStart);
Nan::SetPrototypeMethod(
tpl
, "PlcStop"
, S7Client::PlcStop);
Nan::SetPrototypeMethod(
tpl
, "CopyRamToRom"
, S7Client::CopyRamToRom);
Nan::SetPrototypeMethod(
tpl
, "Compress"
, S7Client::Compress);
// Security functions
Nan::SetPrototypeMethod(
tpl
, "GetProtection"
, S7Client::GetProtection);
Nan::SetPrototypeMethod(
tpl
, "SetSessionPassword"
, S7Client::SetSessionPassword);
Nan::SetPrototypeMethod(
tpl
, "ClearSessionPassword"
, S7Client::ClearSessionPassword);
// Properties
Nan::SetPrototypeMethod(
tpl
, "ExecTime"
, S7Client::ExecTime);
Nan::SetPrototypeMethod(
tpl
, "LastError"
, S7Client::LastError);
Nan::SetPrototypeMethod(
tpl
, "PDURequested"
, S7Client::PDURequested);
Nan::SetPrototypeMethod(
tpl
, "PDULength"
, S7Client::PDULength);
Nan::SetPrototypeMethod(
tpl
, "PlcStatus"
, S7Client::PlcStatus);
Nan::SetPrototypeMethod(
tpl
, "Connected"
, S7Client::Connected);
// Error to text function
Nan::SetPrototypeMethod(
tpl
, "ErrorText"
, S7Client::ErrorText);
// Error codes
Nan::SetPrototypeTemplate(
tpl
, Nan::New("errNegotiatingPDU").ToLocalChecked()
, Nan::New(errNegotiatingPDU)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("errCliInvalidParams").ToLocalChecked()
, Nan::New(errCliInvalidParams)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("errCliJobPending").ToLocalChecked()
, Nan::New(errCliJobPending)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("errCliTooManyItems").ToLocalChecked()
, Nan::New(errCliTooManyItems)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("errCliInvalidWordLen").ToLocalChecked()
, Nan::New(errCliInvalidWordLen)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("errCliPartialDataWritten").ToLocalChecked()
, Nan::New(errCliPartialDataWritten)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("errCliSizeOverPDU").ToLocalChecked()
, Nan::New(errCliSizeOverPDU)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("errCliInvalidPlcAnswer").ToLocalChecked()
, Nan::New(errCliInvalidPlcAnswer)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("errCliAddressOutOfRange").ToLocalChecked()
, Nan::New(errCliAddressOutOfRange)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("errCliInvalidTransportSize").ToLocalChecked()
, Nan::New(errCliInvalidTransportSize)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("errCliWriteDataSizeMismatch").ToLocalChecked()
, Nan::New(errCliWriteDataSizeMismatch)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("errCliItemNotAvailable").ToLocalChecked()
, Nan::New(errCliItemNotAvailable)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("errCliInvalidValue").ToLocalChecked()
, Nan::New(errCliInvalidValue)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("errCliCannotStartPLC").ToLocalChecked()
, Nan::New(errCliCannotStartPLC)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("errCliAlreadyRun").ToLocalChecked()
, Nan::New(errCliAlreadyRun)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("errCliCannotStopPLC").ToLocalChecked()
, Nan::New(errCliCannotStopPLC)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("errCliCannotCopyRamToRom").ToLocalChecked()
, Nan::New(errCliCannotCopyRamToRom)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("errCliCannotCompress").ToLocalChecked()
, Nan::New(errCliCannotCompress)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("errCliAlreadyStop").ToLocalChecked()
, Nan::New(errCliAlreadyStop)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("errCliFunNotAvailable").ToLocalChecked()
, Nan::New(errCliFunNotAvailable)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("errCliUploadSequenceFailed").ToLocalChecked()
, Nan::New(errCliUploadSequenceFailed)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("errCliInvalidDataSizeRecvd").ToLocalChecked()
, Nan::New(errCliInvalidDataSizeRecvd)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("errCliInvalidBlockType").ToLocalChecked()
, Nan::New(errCliInvalidBlockType)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("errCliInvalidBlockNumber").ToLocalChecked()
, Nan::New(errCliInvalidBlockNumber)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("errCliInvalidBlockSize").ToLocalChecked()
, Nan::New(errCliInvalidBlockSize)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("errCliDownloadSequenceFailed").ToLocalChecked()
, Nan::New(errCliDownloadSequenceFailed)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("errCliInsertRefused").ToLocalChecked()
, Nan::New(errCliInsertRefused)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("errCliDeleteRefused").ToLocalChecked()
, Nan::New(errCliDeleteRefused)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("errCliNeedPassword").ToLocalChecked()
, Nan::New(errCliNeedPassword)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("errCliInvalidPassword").ToLocalChecked()
, Nan::New(errCliInvalidPassword)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("errCliNoPasswordToSetOrClear").ToLocalChecked()
, Nan::New(errCliNoPasswordToSetOrClear)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("errCliJobTimeout").ToLocalChecked()
, Nan::New(errCliJobTimeout)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("errCliPartialDataRead").ToLocalChecked()
, Nan::New(errCliPartialDataRead)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("errCliBufferTooSmall").ToLocalChecked()
, Nan::New(errCliBufferTooSmall)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("errCliFunctionRefused").ToLocalChecked()
, Nan::New(errCliFunctionRefused)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("errCliDestroying").ToLocalChecked()
, Nan::New(errCliDestroying)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("errCliInvalidParamNumber").ToLocalChecked()
, Nan::New(errCliInvalidParamNumber)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("errCliCannotChangeParam").ToLocalChecked()
, Nan::New(errCliCannotChangeParam)
, v8::ReadOnly);
// Client Connection Type
Nan::SetPrototypeTemplate(
tpl
, Nan::New("CONNTYPE_PG").ToLocalChecked()
, Nan::New(CONNTYPE_PG)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("CONNTYPE_OP").ToLocalChecked()
, Nan::New(CONNTYPE_OP)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("CONNTYPE_BASIC").ToLocalChecked()
, Nan::New(CONNTYPE_BASIC)
, v8::ReadOnly);
// CPU Status codes
Nan::SetPrototypeTemplate(
tpl
, Nan::New("S7CpuStatusUnknown").ToLocalChecked()
, Nan::New(S7CpuStatusUnknown)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("S7CpuStatusRun").ToLocalChecked()
, Nan::New(S7CpuStatusRun)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("S7CpuStatusStop").ToLocalChecked()
, Nan::New(S7CpuStatusStop)
, v8::ReadOnly);
// Area ID
Nan::SetPrototypeTemplate(
tpl
, Nan::New("S7AreaPE").ToLocalChecked()
, Nan::New(S7AreaPE)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("S7AreaPA").ToLocalChecked()
, Nan::New(S7AreaPA)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("S7AreaMK").ToLocalChecked()
, Nan::New(S7AreaMK)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("S7AreaDB").ToLocalChecked()
, Nan::New(S7AreaDB)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("S7AreaCT").ToLocalChecked()
, Nan::New(S7AreaCT)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("S7AreaTM").ToLocalChecked()
, Nan::New(S7AreaTM)
, v8::ReadOnly);
// Word Length
Nan::SetPrototypeTemplate(
tpl
, Nan::New("S7WLBit").ToLocalChecked()
, Nan::New(S7WLBit)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("S7WLByte").ToLocalChecked()
, Nan::New(S7WLByte)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("S7WLWord").ToLocalChecked()
, Nan::New(S7WLWord)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("S7WLDWord").ToLocalChecked()
, Nan::New(S7WLDWord)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("S7WLReal").ToLocalChecked()
, Nan::New(S7WLReal)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("S7WLCounter").ToLocalChecked()
, Nan::New(S7WLCounter)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("S7WLTimer").ToLocalChecked()
, Nan::New(S7WLTimer)
, v8::ReadOnly);
// Block type
Nan::SetPrototypeTemplate(
tpl
, Nan::New("Block_OB").ToLocalChecked()
, Nan::New(Block_OB)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("Block_DB").ToLocalChecked()
, Nan::New(Block_DB)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("Block_SDB").ToLocalChecked()
, Nan::New(Block_SDB)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("Block_FC").ToLocalChecked()
, Nan::New(Block_FC)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("Block_SFC").ToLocalChecked()
, Nan::New(Block_SFC)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("Block_FB").ToLocalChecked()
, Nan::New(Block_FB)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("Block_SFB").ToLocalChecked()
, Nan::New(Block_SFB)
, v8::ReadOnly);
// Sub Block Type
Nan::SetPrototypeTemplate(
tpl
, Nan::New("SubBlk_OB").ToLocalChecked()
, Nan::New(SubBlk_OB)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("SubBlk_SDB").ToLocalChecked()
, Nan::New(SubBlk_SDB)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("SubBlk_FC").ToLocalChecked()
, Nan::New(SubBlk_FC)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("SubBlk_SFC").ToLocalChecked()
, Nan::New(SubBlk_SFC)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("SubBlk_FB").ToLocalChecked()
, Nan::New(SubBlk_FB)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("SubBlk_SFB").ToLocalChecked()
, Nan::New(SubBlk_SFB)
, v8::ReadOnly);
// Block languages
Nan::SetPrototypeTemplate(
tpl
, Nan::New("BlockLangAWL").ToLocalChecked()
, Nan::New(BlockLangAWL)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("BlockLangKOP").ToLocalChecked()
, Nan::New(BlockLangKOP)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("BlockLangFUP").ToLocalChecked()
, Nan::New(BlockLangFUP)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("BlockLangSCL").ToLocalChecked()
, Nan::New(BlockLangSCL)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("BlockLangDB").ToLocalChecked()
, Nan::New(BlockLangDB)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("BlockLangGRAPH").ToLocalChecked()
, Nan::New(BlockLangGRAPH)
, v8::ReadOnly);
// Parameter
Nan::SetPrototypeTemplate(
tpl
, Nan::New("LocalPort").ToLocalChecked()
, Nan::New(p_u16_LocalPort)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("RemotePort").ToLocalChecked()
, Nan::New(p_u16_RemotePort)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("PingTimeout").ToLocalChecked()
, Nan::New(p_i32_PingTimeout)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("SendTimeout").ToLocalChecked()
, Nan::New(p_i32_SendTimeout)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("RecvTimeout").ToLocalChecked()
, Nan::New(p_i32_RecvTimeout)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("WorkInterval").ToLocalChecked()
, Nan::New(p_i32_WorkInterval)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("SrcRef").ToLocalChecked()
, Nan::New(p_u16_SrcRef)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("DstRef").ToLocalChecked()
, Nan::New(p_u16_DstRef)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("SrcTSap").ToLocalChecked()
, Nan::New(p_u16_SrcTSap)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("PDURequest").ToLocalChecked()
, Nan::New(p_i32_PDURequest)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("MaxClients").ToLocalChecked()
, Nan::New(p_i32_MaxClients)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("BSendTimeout").ToLocalChecked()
, Nan::New(p_i32_BSendTimeout)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("BRecvTimeout").ToLocalChecked()
, Nan::New(p_i32_BRecvTimeout)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New