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 [![npm](https://img.shields.io/npm/v/node-snap7.svg?label=&logo=npm)](https://www.npmjs.com/package/node-snap7) [![Node version](https://img.shields.io/node/v/node-snap7.svg)](https://www.npmjs.com/package/node-snap7) [![Test and Release](https://github.com/mathiask88/node-snap7/actions/workflows/test-and-release.yml/badge.svg)](https://github.com/mathiask88/node-snap7/actions/workflows/test-and-release.yml) [![npm](https://img.shields.io/npm/dm/node-snap7.svg?label=dl)](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("RecoveryTime").ToLocalChecked() , Nan::New(p_u32_RecoveryTime) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("KeepAliveTime").ToLocalChecked() , Nan::New(p_u32_KeepAliveTime) , v8::ReadOnly); constructor.Reset(tpl); Nan::Set(target, name, Nan::GetFunction(tpl).ToLocalChecked()); } NAN_METHOD(S7Client::New) { if (info.IsConstructCall()) { S7Client *s7client = new S7Client(); s7client->Wrap(info.This()); info.GetReturnValue().Set(info.This()); } else { v8::Local constructorHandle; constructorHandle = Nan::New(constructor); info.GetReturnValue().Set( Nan::NewInstance(Nan::GetFunction(constructorHandle).ToLocalChecked()).ToLocalChecked()); } } S7Client::S7Client() { snap7Client = new TS7Client(); uv_mutex_init(&mutex); } S7Client::~S7Client() { snap7Client->Disconnect(); delete snap7Client; constructor.Reset(); uv_mutex_destroy(&mutex); } int S7Client::GetByteCountFromWordLen(int WordLen) { switch (WordLen) { case S7WLBit: case S7WLByte: return 1; case S7WLWord: case S7WLCounter: case S7WLTimer: return 2; case S7WLReal: case S7WLDWord: return 4; default: return 0; } } void S7Client::FreeCallback(char *data, void *hint) { delete[] data; } void S7Client::FreeCallbackSZL(char *data, void *hint) { delete reinterpret_cast(data); } // Control functions NAN_METHOD(S7Client::Connect) { S7Client *s7client = ObjectWrap::Unwrap(info.Holder()); if (!info[0]->IsFunction()) { int ret = s7client->snap7Client->Connect(); info.GetReturnValue().Set(Nan::New(ret == 0)); } else { Nan::Callback *callback = new Nan::Callback(info[0].As()); Nan::AsyncQueueWorker(new IOWorker(callback, s7client, CONNECT)); info.GetReturnValue().SetUndefined(); } } NAN_METHOD(S7Client::ConnectTo) { S7Client *s7client = ObjectWrap::Unwrap(info.Holder()); if (info.Length() < 3) { return Nan::ThrowTypeError("Wrong number of arguments"); } if (!info[0]->IsString() || !info[1]->IsInt32() || !info[2]->IsInt32()) { return Nan::ThrowTypeError("Wrong arguments"); } Nan::Utf8String *remAddress = new Nan::Utf8String(info[0]); if (!info[3]->IsFunction()) { int ret = s7client->snap7Client->ConnectTo( **remAddress , Nan::To(info[1]).FromJust() , Nan::To(info[2]).FromJust()); delete remAddress; info.GetReturnValue().Set(Nan::New(ret == 0)); } else { Nan::Callback *callback = new Nan::Callback(info[3].As()); Nan::AsyncQueueWorker(new IOWorker(callback, s7client, CONNECTTO , remAddress, Nan::To(info[1]).FromJust(), Nan::To(info[2]).FromJust())); info.GetReturnValue().SetUndefined(); } } NAN_METHOD(S7Client::SetConnectionParams) { S7Client *s7client = ObjectWrap::Unwrap(info.Holder()); if (!info[0]->IsString() || !info[1]->IsUint32() || !info[2]->IsUint32()) { return Nan::ThrowTypeError("Wrong arguments"); } Nan::Utf8String remAddress(info[0]); word LocalTSAP = Nan::To(info[1]).FromJust(); word RemoteTSAP = Nan::To(info[2]).FromJust(); int ret = s7client->snap7Client->SetConnectionParams( *remAddress , LocalTSAP , RemoteTSAP); info.GetReturnValue().Set(Nan::New(ret == 0)); } NAN_METHOD(S7Client::SetConnectionType) { S7Client *s7client = ObjectWrap::Unwrap(info.Holder()); if (!info[0]->IsUint32()) { return Nan::ThrowTypeError("Wrong arguments"); } word type = Nan::To(info[0]).FromJust(); int ret = s7client->snap7Client->SetConnectionType(type); info.GetReturnValue().Set(Nan::New(ret == 0)); } NAN_METHOD(S7Client::Disconnect) { S7Client *s7client = ObjectWrap::Unwrap(info.Holder()); int ret = s7client->snap7Client->Disconnect(); info.GetReturnValue().Set(Nan::New(ret == 0)); } NAN_METHOD(S7Client::GetParam) { S7Client *s7client = ObjectWrap::Unwrap(info.Holder()); if (!info[0]->IsInt32()) { return Nan::ThrowTypeError("Wrong arguments"); } int pData; int returnValue = s7client->snap7Client->GetParam(Nan::To(info[0]).FromJust() , &pData); if (returnValue == 0) { info.GetReturnValue().Set(Nan::New(pData)); } else { info.GetReturnValue().Set(Nan::New(returnValue)); } } NAN_METHOD(S7Client::SetParam) { S7Client *s7client = ObjectWrap::Unwrap(info.Holder()); if (!(info[0]->IsInt32() || info[1]->IsInt32())) { return Nan::ThrowTypeError("Wrong arguments"); } int pData = Nan::To(info[1]).FromJust(); int ret = s7client->snap7Client->SetParam(Nan::To(info[0]).FromJust(), &pData); info.GetReturnValue().Set(Nan::New(ret == 0)); } // Data I/O Main functions void IOWorker::Execute() { uv_mutex_lock(&s7client->mutex); switch (caller) { case CONNECTTO: returnValue = s7client->snap7Client->ConnectTo( **static_cast(pData), int1, int2); break; case CONNECT: returnValue = s7client->snap7Client->Connect(); break; case READAREA: returnValue = s7client->snap7Client->ReadArea(int1, int2, int3, int4 , int5, pData); break; case WRITEAREA: returnValue = s7client->snap7Client->WriteArea(int1, int2, int3, int4 , int5, pData); break; case READMULTI: returnValue = s7client->snap7Client->ReadMultiVars( static_cast(pData), int1); break; case WRITEMULTI: returnValue = s7client->snap7Client->WriteMultiVars( static_cast(pData), int1); break; case PLCSTATUS: returnValue = s7client->snap7Client->PlcStatus(); if ((returnValue == S7CpuStatusUnknown) || (returnValue == S7CpuStatusStop) || (returnValue == S7CpuStatusRun)) { int1 = returnValue; returnValue = 0; } break; case CLEARSESSIONPW: returnValue = s7client->snap7Client->ClearSessionPassword(); break; case SETSESSIONPW: returnValue = s7client->snap7Client->SetSessionPassword( **static_cast(pData)); break; case GETPROTECTION: returnValue = s7client->snap7Client->GetProtection( static_cast(pData)); break; case PLCSTOP: returnValue = s7client->snap7Client->PlcStop(); break; case PLCCOLDSTART: returnValue = s7client->snap7Client->PlcColdStart(); break; case PLCHOTSTART: returnValue = s7client->snap7Client->PlcHotStart(); break; case GETCPINFO: returnValue = s7client->snap7Client->GetCpInfo( static_cast(pData)); break; case GETCPUINFO: returnValue = s7client->snap7Client->GetCpuInfo( static_cast(pData)); break; case GETORDERCODE: returnValue = s7client->snap7Client->GetOrderCode( static_cast(pData)); break; case SETPLCSYSTEMDATETIME: returnValue = s7client->snap7Client->SetPlcSystemDateTime(); break; case GETPLCDATETIME: returnValue = s7client->snap7Client->GetPlcDateTime( static_cast(pData)); break; case SETPLCDATETIME: returnValue = s7client->snap7Client->SetPlcDateTime( static_cast(pData)); break; case COMPRESS: returnValue = s7client->snap7Client->Compress(int1); break; case COPYRAMTOROM: returnValue = s7client->snap7Client->CopyRamToRom(int1); break; case DBFILL: returnValue = s7client->snap7Client->DBFill(int1, int2); break; case DBGET: returnValue = s7client->snap7Client->DBGet(int1, pData, &int2); break; case DELETEBLOCK: returnValue = s7client->snap7Client->Delete(int1, int2); break; case DOWNLOAD: returnValue = s7client->snap7Client->Download(int1, pData, int2); break; case FULLUPLOAD: returnValue = s7client->snap7Client->FullUpload(int1, int2, pData, &int3); break; case UPLOAD: returnValue = s7client->snap7Client->Upload(int1, int2, pData, &int3); break; case LISTBLOCKSOFTYPE: returnValue = s7client->snap7Client->ListBlocksOfType(int1 , static_cast(pData), &int2); break; case GETAGBLOCKINFO: returnValue = s7client->snap7Client->GetAgBlockInfo(int1, int2 , static_cast(pData)); break; case LISTBLOCKS: returnValue = s7client->snap7Client->ListBlocks( static_cast(pData)); break; case READSZLLIST: returnValue = s7client->snap7Client->ReadSZLList( static_cast(pData), &int1); break; case READSZL: returnValue = s7client->snap7Client->ReadSZL(int1, int2 , static_cast(pData), &int3); break; } uv_mutex_unlock(&s7client->mutex); } void IOWorker::HandleOKCallback() { Nan::HandleScope scope; v8::Local argv1[1]; v8::Local argv2[2]; if (returnValue == 0) { argv2[0] = argv1[0] = Nan::Null(); } else { argv2[0] = argv1[0] = Nan::New(returnValue); } switch (caller) { case CONNECTTO: case SETSESSIONPW: delete static_cast(pData); callback->Call(1, argv1, async_resource); break; case CONNECT: case WRITEAREA: case CLEARSESSIONPW: case PLCSTOP: case PLCCOLDSTART: case PLCHOTSTART: case SETPLCSYSTEMDATETIME: case COPYRAMTOROM: case COMPRESS: case DBFILL: case DELETEBLOCK: case DOWNLOAD: callback->Call(1, argv1, async_resource); break; case READAREA: if (returnValue == 0) { argv2[1] = Nan::NewBuffer( static_cast(pData) , int4 * s7client->GetByteCountFromWordLen(int5) , S7Client::FreeCallback, NULL).ToLocalChecked(); } else { argv2[1] = Nan::Null(); delete[] static_cast(pData); } callback->Call(2, argv2, async_resource); break; case READMULTI: if (returnValue == 0) { argv2[1] = s7client->S7DataItemToArray(static_cast(pData) , int1, true); } else { for (int i = 0; i < int1; i++) { delete[] static_cast(static_cast(pData)[i].pdata); } delete[] static_cast(pData); argv2[1] = Nan::Null(); } callback->Call(2, argv2, async_resource); break; case WRITEMULTI: if (returnValue == 0) { argv2[1] = s7client->S7DataItemToArray(static_cast(pData) , int1, false); } else { delete[] static_cast(pData); argv2[1] = Nan::Null(); } callback->Call(2, argv2, async_resource); break; case GETPROTECTION: if (returnValue == 0) { argv2[1] = s7client->S7ProtectionToObject( static_cast(pData)); } else { argv2[1] = Nan::Null(); } delete static_cast(pData); callback->Call(2, argv2, async_resource); break; case GETCPINFO: if (returnValue == 0) { argv2[1] = s7client->S7CpInfoToObject( static_cast(pData)); } else { argv2[1] = Nan::Null(); } delete static_cast(pData); callback->Call(2, argv2, async_resource); break; case GETCPUINFO: if (returnValue == 0) { argv2[1] = s7client->S7CpuInfoToObject( static_cast(pData)); } else { argv2[1] = Nan::Null(); } delete static_cast(pData); callback->Call(2, argv2, async_resource); break; case GETORDERCODE: if (returnValue == 0) { argv2[1] = s7client->S7OrderCodeToObject( static_cast(pData)); } else { argv2[1] = Nan::Null(); } delete static_cast(pData); callback->Call(2, argv2, async_resource); break; case GETPLCDATETIME: if (returnValue == 0) { double timestamp = static_cast(mktime(static_cast(pData))); argv2[1] = Nan::New(timestamp * 1000).ToLocalChecked(); } else { argv2[1] = Nan::Null(); } delete static_cast(pData); callback->Call(2, argv2, async_resource); break; case SETPLCDATETIME: delete static_cast(pData); callback->Call(1, argv1, async_resource); break; case PLCSTATUS: if (returnValue == 0) { argv2[1] = Nan::New(int1); } else { argv2[1] = Nan::Null(); } callback->Call(2, argv2, async_resource); break; case DBGET: if (returnValue == 0) { argv2[1] = Nan::NewBuffer( static_cast(pData) , int2 , S7Client::FreeCallback , NULL).ToLocalChecked(); } else { argv2[1] = Nan::Null(); delete[] static_cast(pData); } callback->Call(2, argv2, async_resource); break; case FULLUPLOAD: case UPLOAD: if (returnValue == 0) { argv2[1] = Nan::NewBuffer( static_cast(pData) , int3 , S7Client::FreeCallback , NULL).ToLocalChecked(); } else { argv2[1] = Nan::Null(); delete[] static_cast(pData); } callback->Call(2, argv2, async_resource); break; case LISTBLOCKSOFTYPE: if (returnValue == 0) { argv2[1] = s7client->S7BlocksOfTypeToArray( static_cast(pData), int2); } else { argv2[1] = Nan::Null(); } delete[] static_cast(pData); callback->Call(2, argv2, async_resource); break; case GETAGBLOCKINFO: if (returnValue == 0) { v8::Local block_info = s7client->S7BlockInfoToObject( static_cast(pData)); argv2[1] = block_info; } else { argv2[1] = Nan::Null(); } delete static_cast(pData); callback->Call(2, argv2, async_resource); break; case LISTBLOCKS: if (returnValue == 0) { v8::Local blocks_list = s7client->S7BlocksListToObject( static_cast(pData)); argv2[1] = blocks_list; } else { argv2[1] = Nan::Null(); } delete static_cast(pData); callback->Call(2, argv2, async_resource); break; case READSZLLIST: if (returnValue == 0) { v8::Local szl_list = s7client->S7SZLListToArray( static_cast(pData), int1); argv2[1] = szl_list; } else { argv2[1] = Nan::Null(); } delete static_cast(pData); callback->Call(2, argv2, async_resource); break; case READSZL: if (returnValue == 0) { argv2[1] = Nan::NewBuffer( reinterpret_cast(static_cast(pData)) , int3 , S7Client::FreeCallbackSZL , NULL).ToLocalChecked(); } else { argv2[1] = Nan::Null(); delete static_cast(pData); } callback->Call(2, argv2, async_resource); break; } } NAN_METHOD(S7Client::ReadArea) { S7Client *s7client = ObjectWrap::Unwrap(info.Holder()); if (info.Length() < 5) return Nan::ThrowTypeError("Wrong number of Arguments"); if (!info[0]->IsInt32() || !info[1]->IsInt32() || !info[2]->IsInt32() || !info[3]->IsInt32() || !info[4]->IsInt32()) return Nan::ThrowTypeError("Wrong arguments"); int amount = Nan::To(info[3]).FromJust(); int byteCount = s7client->GetByteCountFromWordLen(Nan::To(info[4]).FromJust()); int size = amount * byteCount; char *bufferData = new char[size]; if (!info[5]->IsFunction()) { int returnValue = s7client->snap7Client->ReadArea( Nan::To(info[0]).FromJust(), Nan::To(info[1]).FromJust() , Nan::To(info[2]).FromJust(), Nan::To(info[3]).FromJust() , Nan::To(info[4]).FromJust(), bufferData); if (returnValue == 0) { v8::Local ret = Nan::NewBuffer( bufferData , size , S7Client::FreeCallback , NULL).ToLocalChecked(); info.GetReturnValue().Set(ret); } else { delete[] bufferData; info.GetReturnValue().Set(Nan::False()); } } else { Nan::Callback *callback = new Nan::Callback(info[5].As()); Nan::AsyncQueueWorker(new IOWorker(callback, s7client, READAREA , bufferData, Nan::To(info[0]).FromJust(), Nan::To(info[1]).FromJust() , Nan::To(info[2]).FromJust(), Nan::To(info[3]).FromJust(), Nan::To(info[4]).FromJust())); info.GetReturnValue().SetUndefined(); } } NAN_METHOD(S7Client::WriteArea) { S7Client *s7client = ObjectWrap::Unwrap(info.Holder()); if (info.Length() < 6) return Nan::ThrowTypeError("Wrong number of Arguments"); if (!info[0]->IsInt32() || !info[1]->IsInt32() || !info[2]->IsInt32() || !info[3]->IsInt32() || !info[4]->IsInt32() || !node::Buffer::HasInstance(info[5])) return Nan::ThrowTypeError("Wrong arguments"); if (!info[6]->IsFunction()) { info.GetReturnValue().Set(Nan::New( s7client->snap7Client->WriteArea(Nan::To(info[0]).FromJust() , Nan::To(info[1]).FromJust(), Nan::To(info[2]).FromJust() , Nan::To(info[3]).FromJust(), Nan::To(info[4]).FromJust() , node::Buffer::Data(info[5].As())) == 0)); } else { Nan::Callback *callback = new Nan::Callback(info[6].As()); Nan::AsyncQueueWorker(new IOWorker(callback, s7client, WRITEAREA , node::Buffer::Data(info[5].As()), Nan::To(info[0]).FromJust() , Nan::To(info[1]).FromJust(), Nan::To(info[2]).FromJust(), Nan::To(info[3]).FromJust() , Nan::To(info[4]).FromJust())); info.GetReturnValue().SetUndefined(); } } NAN_METHOD(S7Client::ReadMultiVars) { S7Client *s7client = ObjectWrap::Unwrap(info.Holder()); if (info.Length() < 1) { return Nan::ThrowTypeError("Wrong number of arguments"); } if (!info[0]->IsArray()) { return Nan::ThrowTypeError("Wrong arguments"); } v8::Local data_arr = v8::Local::Cast(info[0]); int len = data_arr->Length(); if (len == 0) { return Nan::ThrowTypeError("Array needs at least 1 item"); } else if (len > MaxVars) { std::stringstream err; err << "Array exceeds max variables (" << MaxVars << ") that can be transferred with ReadMultiVars()"; return Nan::ThrowTypeError(err.str().c_str()); } for (int i = 0; i < len; i++) { if (!Nan::Get(data_arr, i).ToLocalChecked()->IsObject()) { return Nan::ThrowTypeError("Wrong argument structure"); } else { v8::Local data_obj = Nan::To(Nan::Get(data_arr, i).ToLocalChecked()).ToLocalChecked(); if (!Nan::Has(data_obj, Nan::New("Area").ToLocalChecked()).FromJust() || !Nan::Has(data_obj, Nan::New("WordLen").ToLocalChecked()).FromJust() || !Nan::Has(data_obj, Nan::New("Start").ToLocalChecked()).FromJust() || !Nan::Has(data_obj, Nan::New("Amount").ToLocalChecked()).FromJust()) { return Nan::ThrowTypeError("Wrong argument structure"); } else if (!Nan::Get(data_obj, Nan::New("Area").ToLocalChecked()).ToLocalChecked()->IsInt32() || !Nan::Get(data_obj, Nan::New("WordLen").ToLocalChecked()).ToLocalChecked()->IsInt32() || !Nan::Get(data_obj, Nan::New("Start").ToLocalChecked()).ToLocalChecked()->IsInt32() || !Nan::Get(data_obj, Nan::New("Amount").ToLocalChecked()).ToLocalChecked()->IsInt32()) { return Nan::ThrowTypeError("Wrong argument structure"); } else if (Nan::To(Nan::Get(data_obj, Nan::New("Area").ToLocalChecked()).ToLocalChecked()).FromJust() == S7AreaDB) { if (!Nan::Has(data_obj, Nan::New("DBNumber").ToLocalChecked()).FromJust()) { return Nan::ThrowTypeError("Wrong argument structure"); } } else { Nan::Set(data_obj, Nan::New("DBNumber").ToLocalChecked(), Nan::New(0)); } } } PS7DataItem Items = new TS7DataItem[len]; v8::Local data_obj; int byteCount, size; for (int i = 0; i < len; i++) { data_obj = Nan::To(Nan::Get(data_arr, i).ToLocalChecked()).ToLocalChecked(); Items[i].Area = Nan::To(Nan::Get(data_obj, Nan::New("Area").ToLocalChecked()).ToLocalChecked()).FromJust(); Items[i].WordLen = Nan::To(Nan::Get(data_obj, Nan::New("WordLen").ToLocalChecked()).ToLocalChecked()).FromJust(); Items[i].DBNumber = Nan::To(Nan::Get(data_obj, Nan::New("DBNumber").ToLocalChecked()).ToLocalChecked()).FromJust(); Items[i].Start = Nan::To(Nan::Get(data_obj, Nan::New("Start").ToLocalChecked()).ToLocalChecked()).FromJust(); Items[i].Amount = Nan::To(Nan::Get(data_obj, Nan::New("Amount").ToLocalChecked()).ToLocalChecked()).FromJust(); byteCount = s7client->GetByteCountFromWordLen(Items[i].WordLen); size = Items[i].Amount * byteCount; Items[i].pdata = new char[size]; } if (!info[1]->IsFunction()) { int returnValue = s7client->snap7Client->ReadMultiVars(Items, len); if (returnValue == 0) { info.GetReturnValue().Set(s7client->S7DataItemToArray(Items, len, true)); } else { for (int i = 0; i < len; i++) { delete[] static_cast(Items[i].pdata); } delete[] Items; info.GetReturnValue().Set(Nan::False()); } } else { Nan::Callback *callback = new Nan::Callback(info[1].As()); Nan::AsyncQueueWorker(new IOWorker(callback, s7client, READMULTI , Items, len)); info.GetReturnValue().SetUndefined(); } } v8::Local S7Client::S7DataItemToArray( PS7DataItem Items , int len , bool readMulti ) { Nan::EscapableHandleScope scope; v8::Local res_arr = Nan::New(len); v8::Local res_obj; int byteCount, size; for (int i = 0; i < len; i++) { res_obj = Nan::New(); Nan::Set(res_obj, Nan::New("Result").ToLocalChecked() , Nan::New(Items[i].Result)); if (readMulti == true) { if (Items[i].Result == 0) { byteCount = S7Client::GetByteCountFromWordLen(Items[i].WordLen); size = byteCount * Items[i].Amount; Nan::Set( res_obj , Nan::New("Data").ToLocalChecked() , Nan::NewBuffer( static_cast(Items[i].pdata) , size , S7Client::FreeCallback , NULL).ToLocalChecked()); } else { delete[] static_cast(Items[i].pdata); Nan::Set(res_obj, Nan::New("Data").ToLocalChecked(), Nan::Null()); } } Nan::Set(res_arr, i, res_obj); } delete[] Items; return scope.Escape(res_arr); } NAN_METHOD(S7Client::WriteMultiVars) { S7Client *s7client = ObjectWrap::Unwrap(info.Holder()); if (info.Length() < 1) { return Nan::ThrowTypeError("Wrong number of arguments"); } if (!info[0]->IsArray()) { return Nan::ThrowTypeError("Wrong arguments"); } v8::Local data_arr = v8::Local::Cast(info[0]); int len = data_arr->Length(); if (len == 0) { return Nan::ThrowTypeError("Array needs at least 1 item"); } else if (len > MaxVars) { std::stringstream err; err << "Array exceeds max variables (" << MaxVars << ") that can be transferred with WriteMultiVars()"; return Nan::ThrowTypeError(err.str().c_str()); } for (int i = 0; i < len; i++) { if (!Nan::Get(data_arr, i).ToLocalChecked()->IsObject()) { return Nan::ThrowTypeError("Wrong argument structure"); } else { v8::Local data_obj = Nan::To(Nan::Get(data_arr, i).ToLocalChecked()).ToLocalChecked(); if (!Nan::Has(data_obj, Nan::New("Area").ToLocalChecked()).FromJust() || !Nan::Has(data_obj, Nan::New("WordLen").ToLocalChecked()).FromJust() || !Nan::Has(data_obj, Nan::New("Start").ToLocalChecked()).FromJust() || !Nan::Has(data_obj, Nan::New("Amount").ToLocalChecked()).FromJust() || !Nan::Has(data_obj, Nan::New("Data").ToLocalChecked()).FromJust()) { return Nan::ThrowTypeError("Wrong argument structure"); } else if (!Nan::Get(data_obj, Nan::New("Area").ToLocalChecked()).ToLocalChecked()->IsInt32() || !Nan::Get(data_obj, Nan::New("WordLen").ToLocalChecked()).ToLocalChecked()->IsInt32() || !Nan::Get(data_obj, Nan::New("Start").ToLocalChecked()).ToLocalChecked()->IsInt32() || !Nan::Get(data_obj, Nan::New("Amount").ToLocalChecked()).ToLocalChecked()->IsInt32() || !node::Buffer::HasInstance(Nan::Get(data_obj, Nan::New("Data").ToLocalChecked()).ToLocalChecked())) { return Nan::ThrowTypeError("Wrong argument structure"); } else if (Nan::To(Nan::Get(data_obj, Nan::New("Area").ToLocalChecked()).ToLocalChecked()).FromJust() == S7AreaDB) { if (!Nan::Has(data_obj, Nan::New("DBNumber").ToLocalChecked()).FromJust()) { return Nan::ThrowTypeError("Wrong argument structure"); } } else { Nan::Set(data_obj, Nan::New("DBNumber").ToLocalChecked(), Nan::New(0)); } } } PS7DataItem Items = new TS7DataItem[len]; v8::Local data_obj; for (int i = 0; i < len; i++) { data_obj = Nan::To(Nan::Get(data_arr, i).ToLocalChecked()).ToLocalChecked(); Items[i].Area = Nan::To(Nan::Get(data_obj, Nan::New("Area").ToLocalChecked()).ToLocalChecked()).FromJust(); Items[i].WordLen = Nan::To(Nan::Get(data_obj, Nan::New("WordLen").ToLocalChecked()).ToLocalChecked()).FromJust(); Items[i].DBNumber = Nan::To(Nan::Get(data_obj, Nan::New("DBNumber").ToLocalChecked()).ToLocalChecked()).FromJust(); Items[i].Start = Nan::To(Nan::Get(data_obj, Nan::New("Start").ToLocalChecked()).ToLocalChecked()).FromJust(); Items[i].Amount = Nan::To(Nan::Get(data_obj, Nan::New("Amount").ToLocalChecked()).ToLocalChecked()).FromJust(); Items[i].pdata = node::Buffer::Data(Nan::Get(data_obj, Nan::New("Data").ToLocalChecked()).ToLocalChecked().As()); } if (!info[1]->IsFunction()) { int returnValue = s7client->snap7Client->WriteMultiVars(Items, len); if (returnValue == 0) { info.GetReturnValue().Set(s7client->S7DataItemToArray(Items, len, false)); } else { delete[] Items; info.GetReturnValue().Set(Nan::False()); } } else { Nan::Callback *callback = new Nan::Callback(info[1].As()); Nan::AsyncQueueWorker(new IOWorker(callback, s7client, WRITEMULTI , Items, len)); info.GetReturnValue().SetUndefined(); } } // Directory functions NAN_METHOD(S7Client::ListBlocks) { S7Client *s7client = ObjectWrap::Unwrap(info.Holder()); PS7BlocksList BlocksList = new TS7BlocksList; if (!info[0]->IsFunction()) { int returnValue = s7client->snap7Client->ListBlocks(BlocksList); v8::Local blocks_list = s7client->S7BlocksListToObject( BlocksList); if (returnValue == 0) { delete BlocksList; info.GetReturnValue().Set(blocks_list); } else { delete BlocksList; info.GetReturnValue().Set(Nan::False()); } } else { Nan::Callback *callback = new Nan::Callback(info[0].As()); Nan::AsyncQueueWorker(new IOWorker(callback, s7client, LISTBLOCKS , BlocksList)); info.GetReturnValue().SetUndefined(); } } v8::Local S7Client::S7BlocksListToObject( PS7BlocksList BlocksList ) { Nan::EscapableHandleScope scope; v8::Local blocks_list = Nan::New(); Nan::Set(blocks_list, Nan::New("OBCount").ToLocalChecked() , Nan::New(BlocksList->OBCount)); Nan::Set(blocks_list, Nan::New("FBCount").ToLocalChecked() , Nan::New(BlocksList->FBCount)); Nan::Set(blocks_list, Nan::New("FCCount").ToLocalChecked() , Nan::New(BlocksList->FCCount)); Nan::Set(blocks_list, Nan::New("SFBCount").ToLocalChecked() , Nan::New(BlocksList->SFBCount)); Nan::Set(blocks_list, Nan::New("SFCCount").ToLocalChecked() , Nan::New(BlocksList->SFCCount)); Nan::Set(blocks_list, Nan::New("DBCount").ToLocalChecked() , Nan::New(BlocksList->DBCount)); Nan::Set(blocks_list, Nan::New("SDBCount").ToLocalChecked() , Nan::New(BlocksList->SDBCount)); return scope.Escape(blocks_list); } NAN_METHOD(S7Client::GetAgBlockInfo) { S7Client *s7client = ObjectWrap::Unwrap(info.Holder()); if (!info[0]->IsInt32() || !info[1]->IsInt32()) { return Nan::ThrowTypeError("Wrong arguments"); } PS7BlockInfo BlockInfo = new TS7BlockInfo; if (!info[2]->IsFunction()) { int returnValue = s7client->snap7Client->GetAgBlockInfo( Nan::To(info[0]).FromJust(), Nan::To(info[1]).FromJust(), BlockInfo); if (returnValue == 0) { v8::Local block_info = s7client->S7BlockInfoToObject( BlockInfo); delete BlockInfo; info.GetReturnValue().Set(block_info); } else { delete BlockInfo; info.GetReturnValue().Set(Nan::False()); } } else { Nan::Callback *callback = new Nan::Callback(info[2].As()); Nan::AsyncQueueWorker(new IOWorker(callback, s7client, GETAGBLOCKINFO , BlockInfo, Nan::To(info[0]).FromJust(), Nan::To(info[1]).FromJust())); info.GetReturnValue().SetUndefined(); } } NAN_METHOD(S7Client::GetPgBlockInfo) { S7Client *s7client = ObjectWrap::Unwrap(info.Holder()); if (!node::Buffer::HasInstance(info[0])) { return Nan::ThrowTypeError("Argument should be a Buffer"); } PS7BlockInfo BlockInfo = new TS7BlockInfo; int returnValue = s7client->snap7Client->GetPgBlockInfo( node::Buffer::Data(info[0].As()), BlockInfo , static_cast(node::Buffer::Length(info[0].As()))); if (returnValue == 0) { v8::Local block_info = s7client->S7BlockInfoToObject(BlockInfo); delete BlockInfo; info.GetReturnValue().Set(block_info); } else { delete BlockInfo; info.GetReturnValue().Set(Nan::False()); } } v8::Local S7Client::S7BlockInfoToObject(PS7BlockInfo BlockInfo) { Nan::EscapableHandleScope scope; v8::Local block_info = Nan::New(); Nan::Set(block_info, Nan::New("BlkType").ToLocalChecked() , Nan::New(BlockInfo->BlkType)); Nan::Set(block_info, Nan::New("BlkNumber").ToLocalChecked() , Nan::New(BlockInfo->BlkNumber)); Nan::Set(block_info, Nan::New("BlkLang").ToLocalChecked() , Nan::New(BlockInfo->BlkLang)); Nan::Set(block_info, Nan::New("BlkFlags").ToLocalChecked() , Nan::New(BlockInfo->BlkFlags)); Nan::Set(block_info, Nan::New("MC7Size").ToLocalChecked() , Nan::New(BlockInfo->MC7Size)); Nan::Set(block_info, Nan::New("LoadSize").ToLocalChecked() , Nan::New(BlockInfo->LoadSize)); Nan::Set(block_info, Nan::New("LocalData").ToLocalChecked() , Nan::New(BlockInfo->LocalData)); Nan::Set(block_info, Nan::New("SBBLength").ToLocalChecked() , Nan::New(BlockInfo->SBBLength)); Nan::Set(block_info, Nan::New("CheckSum").ToLocalChecked() , Nan::New(BlockInfo->CheckSum)); Nan::Set(block_info, Nan::New("Version").ToLocalChecked() , Nan::New(BlockInfo->Version)); Nan::Set(block_info, Nan::New("CodeDate").ToLocalChecked() , Nan::New(BlockInfo->CodeDate).ToLocalChecked()); Nan::Set(block_info, Nan::New("IntfDate").ToLocalChecked() , Nan::New(BlockInfo->IntfDate).ToLocalChecked()); Nan::Set(block_info, Nan::New("Author").ToLocalChecked() , Nan::New(BlockInfo->Author).ToLocalChecked()); Nan::Set(block_info, Nan::New("Family").ToLocalChecked() , Nan::New(BlockInfo->Family).ToLocalChecked()); Nan::Set(block_info, Nan::New("Header").ToLocalChecked() , Nan::New(BlockInfo->Header).ToLocalChecked()); return scope.Escape(block_info); } NAN_METHOD(S7Client::ListBlocksOfType) { S7Client *s7client = ObjectWrap::Unwrap(info.Holder()); if (!info[0]->IsInt32()) { return Nan::ThrowTypeError("Wrong arguments"); } int BlockNum = sizeof(TS7BlocksOfType) / sizeof(PS7BlocksOfType); PS7BlocksOfType BlockList = new TS7BlocksOfType[BlockNum]; if (!info[1]->IsFunction()) { int returnValue = s7client->snap7Client->ListBlocksOfType( Nan::To(info[0]).FromJust(), BlockList, &BlockNum); if (returnValue == 0) { v8::Local block_list = s7client->S7BlocksOfTypeToArray( BlockList, BlockNum); delete[] BlockList; info.GetReturnValue().Set(block_list); } else { delete[] BlockList; info.GetReturnValue().Set(Nan::False()); } } else { Nan::Callback *callback = new Nan::Callback(info[1].As()); Nan::AsyncQueueWorker(new IOWorker(callback, s7client, LISTBLOCKSOFTYPE , BlockList, Nan::To(info[0]).FromJust(), BlockNum)); info.GetReturnValue().SetUndefined(); } } v8::Local S7Client::S7BlocksOfTypeToArray( PS7BlocksOfType BlocksList , int count ) { Nan::EscapableHandleScope scope; v8::Local block_list = Nan::New(count); for (int i = 0; i < count; i++) { Nan::Set(block_list, i, Nan::New((*BlocksList)[i])); } return scope.Escape(block_list); } // Blocks functions NAN_METHOD(S7Client::Upload) { S7Client *s7client = ObjectWrap::Unwrap(info.Holder()); if (!info[0]->IsInt32() || !info[1]->IsInt32() || !info[2]->IsInt32()) { return Nan::ThrowTypeError("Wrong arguments"); } char *bufferData = new char[Nan::To(info[2]).FromJust()]; int size = Nan::To(info[2]).FromJust(); if (!info[3]->IsFunction()) { int returnValue = s7client->snap7Client->Upload( Nan::To(info[0]).FromJust(), Nan::To(info[1]).FromJust(), bufferData, &size); if (returnValue == 0) { v8::Local ret_buf; ret_buf = Nan::NewBuffer( bufferData , size , S7Client::FreeCallback , NULL).ToLocalChecked(); info.GetReturnValue().Set(ret_buf); } else { delete[] bufferData; info.GetReturnValue().Set(Nan::False()); } } else { Nan::Callback *callback = new Nan::Callback(info[3].As()); Nan::AsyncQueueWorker(new IOWorker(callback, s7client, UPLOAD , bufferData, Nan::To(info[0]).FromJust(), Nan::To(info[1]).FromJust(), size)); info.GetReturnValue().SetUndefined(); } } NAN_METHOD(S7Client::FullUpload) { S7Client *s7client = ObjectWrap::Unwrap(info.Holder()); if (!info[0]->IsInt32() || !info[1]->IsInt32() || !info[2]->IsInt32()) { return Nan::ThrowTypeError("Wrong arguments"); } int size = Nan::To(info[2]).FromJust(); char *bufferData = new char[size]; if (!info[3]->IsFunction()) { int returnValue = s7client->snap7Client->FullUpload( Nan::To(info[0]).FromJust(), Nan::To(info[1]).FromJust(), bufferData, &size); if (returnValue == 0) { v8::Local ret_buf; ret_buf = Nan::NewBuffer( bufferData , size , S7Client::FreeCallback , NULL).ToLocalChecked(); info.GetReturnValue().Set(ret_buf); } else { delete[] bufferData; info.GetReturnValue().Set(Nan::False()); } } else { Nan::Callback *callback = new Nan::Callback(info[3].As()); Nan::AsyncQueueWorker(new IOWorker(callback, s7client, FULLUPLOAD , bufferData, Nan::To(info[0]).FromJust(), Nan::To(info[1]).FromJust(), size)); info.GetReturnValue().SetUndefined(); } } NAN_METHOD(S7Client::Download) { S7Client *s7client = ObjectWrap::Unwrap(info.Holder()); if (!info[0]->IsInt32() || !node::Buffer::HasInstance(info[1])) { return Nan::ThrowTypeError("Wrong arguments"); } if (!info[2]->IsFunction()) { info.GetReturnValue().Set(Nan::New(s7client->snap7Client->Download( Nan::To(info[0]).FromJust(), node::Buffer::Data(info[1].As()) , static_cast(node::Buffer::Length(info[1].As()))) == 0)); } else { Nan::Callback *callback = new Nan::Callback(info[2].As()); Nan::AsyncQueueWorker(new IOWorker(callback, s7client, DOWNLOAD , node::Buffer::Data(info[1].As()), Nan::To(info[0]).FromJust() , static_cast(node::Buffer::Length(info[1].As())))); info.GetReturnValue().SetUndefined(); } } NAN_METHOD(S7Client::Delete) { S7Client *s7client = ObjectWrap::Unwrap(info.Holder()); if (!info[0]->IsInt32() || !info[1]->IsInt32()) { return Nan::ThrowTypeError("Wrong arguments"); } if (!info[2]->IsFunction()) { info.GetReturnValue().Set(Nan::New(s7client->snap7Client->Delete( Nan::To(info[0]).FromJust(), Nan::To(info[1]).FromJust()) == 0)); } else { Nan::Callback *callback = new Nan::Callback(info[2].As()); Nan::AsyncQueueWorker(new IOWorker(callback, s7client, DELETEBLOCK , Nan::To(info[0]).FromJust(), Nan::To(info[1]).FromJust())); info.GetReturnValue().SetUndefined(); } } NAN_METHOD(S7Client::DBGet) { S7Client *s7client = ObjectWrap::Unwrap(info.Holder()); if (!info[0]->IsInt32()) { return Nan::ThrowTypeError("Wrong arguments"); } int size = 65536; char *bufferData = new char[size]; if (!info[1]->IsFunction()) { int returnValue = s7client->snap7Client->DBGet( Nan::To(info[0]).FromJust(), bufferData, &size); if (returnValue == 0) { v8::Local ret_buf; ret_buf = Nan::NewBuffer( bufferData , size , S7Client::FreeCallback , NULL).ToLocalChecked(); info.GetReturnValue().Set(ret_buf); } else { delete[] bufferData; info.GetReturnValue().Set(Nan::False()); } } else { Nan::Callback *callback = new Nan::Callback(info[1].As()); Nan::AsyncQueueWorker(new IOWorker(callback, s7client, DBGET , bufferData, Nan::To(info[0]).FromJust(), size)); info.GetReturnValue().SetUndefined(); } } NAN_METHOD(S7Client::DBFill) { S7Client *s7client = ObjectWrap::Unwrap(info.Holder()); if (!info[0]->IsInt32() || !(info[1]->IsInt32() || info[1]->IsString())) { return Nan::ThrowTypeError("Wrong arguments"); } int fill; if (info[1]->IsInt32()) { fill = Nan::To(info[1]).FromJust(); } else { Nan::Utf8String fillstr(info[1]); fill = static_cast(**fillstr); } if (!info[2]->IsFunction()) { info.GetReturnValue().Set(Nan::New(s7client->snap7Client->DBFill( Nan::To(info[0]).FromJust(), fill) == 0)); } else { Nan::Callback *callback = new Nan::Callback(info[2].As()); Nan::AsyncQueueWorker(new IOWorker(callback, s7client, DBFILL , Nan::To(info[0]).FromJust(), fill)); info.GetReturnValue().SetUndefined(); } } // Date/Time functions NAN_METHOD(S7Client::GetPlcDateTime) { S7Client *s7client = ObjectWrap::Unwrap(info.Holder()); tm *DateTime = new tm; if (!info[0]->IsFunction()) { int returnValue = s7client->snap7Client->GetPlcDateTime(DateTime); double timestamp = static_cast(mktime(DateTime)); delete DateTime; if (returnValue == 0) info.GetReturnValue().Set(Nan::New(timestamp * 1000).ToLocalChecked()); else info.GetReturnValue().Set(Nan::False()); } else { Nan::Callback *callback = new Nan::Callback(info[0].As()); Nan::AsyncQueueWorker(new IOWorker(callback, s7client, GETPLCDATETIME , DateTime)); info.GetReturnValue().SetUndefined(); } } NAN_METHOD(S7Client::SetPlcDateTime) { S7Client *s7client = ObjectWrap::Unwrap(info.Holder()); if (!(info[0]->IsObject() || info[0]->IsDate())) { return Nan::ThrowTypeError("Wrong arguments"); } tm *DateTime = new tm; if (info[0]->IsDate()) { v8::Local date = v8::Local::Cast(Nan::To(info[0]).ToLocalChecked()); time_t timestamp = static_cast(Nan::To(date).FromJust() / 1000); *DateTime = *localtime(×tamp); } else { v8::Local date_time = Nan::To(info[0]).ToLocalChecked(); DateTime->tm_year = Nan::To(Nan::Get(date_time, Nan::New("year").ToLocalChecked()).ToLocalChecked()).FromJust() - 1900; DateTime->tm_mon = Nan::To(Nan::Get(date_time, Nan::New("month").ToLocalChecked()).ToLocalChecked()).FromJust(); DateTime->tm_mday = Nan::To(Nan::Get(date_time, Nan::New("day").ToLocalChecked()).ToLocalChecked()).FromJust(); DateTime->tm_hour = Nan::To(Nan::Get(date_time, Nan::New("hours").ToLocalChecked()).ToLocalChecked()).FromJust(); DateTime->tm_min = Nan::To(Nan::Get(date_time, Nan::New("minutes").ToLocalChecked()).ToLocalChecked()).FromJust(); DateTime->tm_sec = Nan::To(Nan::Get(date_time, Nan::New("seconds").ToLocalChecked()).ToLocalChecked()).FromJust(); } if (!info[1]->IsFunction()) { v8::Local ret = Nan::New( s7client->snap7Client->SetPlcDateTime(DateTime) == 0); delete DateTime; info.GetReturnValue().Set(ret); } else { Nan::Callback *callback = new Nan::Callback(info[1].As()); Nan::AsyncQueueWorker(new IOWorker(callback, s7client, SETPLCDATETIME , DateTime)); info.GetReturnValue().SetUndefined(); } } NAN_METHOD(S7Client::SetPlcSystemDateTime) { S7Client *s7client = ObjectWrap::Unwrap(info.Holder()); if (!info[0]->IsFunction()) { info.GetReturnValue().Set(Nan::New( s7client->snap7Client->SetPlcSystemDateTime() == 0)); } else { Nan::Callback *callback = new Nan::Callback(info[0].As()); Nan::AsyncQueueWorker(new IOWorker(callback, s7client, SETPLCSYSTEMDATETIME)); info.GetReturnValue().SetUndefined(); } } // System Info functions NAN_METHOD(S7Client::GetOrderCode) { S7Client *s7client = ObjectWrap::Unwrap(info.Holder()); PS7OrderCode OrderCode = new TS7OrderCode; if (!info[0]->IsFunction()) { int returnValue = s7client->snap7Client->GetOrderCode(OrderCode); if (returnValue == 0) { v8::Local order_code = s7client->S7OrderCodeToObject(OrderCode); delete OrderCode; info.GetReturnValue().Set(order_code); } else { delete OrderCode; info.GetReturnValue().Set(Nan::False()); } } else { Nan::Callback *callback = new Nan::Callback(info[0].As()); Nan::AsyncQueueWorker(new IOWorker(callback, s7client, GETORDERCODE , OrderCode)); info.GetReturnValue().SetUndefined(); } } v8::Local S7Client::S7OrderCodeToObject(PS7OrderCode OrderCode) { Nan::EscapableHandleScope scope; v8::Local order_code = Nan::New(); Nan::Set(order_code, Nan::New("Code").ToLocalChecked() , Nan::New(OrderCode->Code).ToLocalChecked()); Nan::Set(order_code, Nan::New("V1").ToLocalChecked() , Nan::New(OrderCode->V1)); Nan::Set(order_code, Nan::New("V2").ToLocalChecked() , Nan::New(OrderCode->V2)); Nan::Set(order_code, Nan::New("V3").ToLocalChecked() , Nan::New(OrderCode->V3)); return scope.Escape(order_code); } NAN_METHOD(S7Client::GetCpuInfo) { S7Client *s7client = ObjectWrap::Unwrap(info.Holder()); PS7CpuInfo CpuInfo = new TS7CpuInfo; if (!info[0]->IsFunction()) { int returnValue = s7client->snap7Client->GetCpuInfo(CpuInfo); if (returnValue == 0) { v8::Local cpu_info = s7client->S7CpuInfoToObject(CpuInfo); delete CpuInfo; info.GetReturnValue().Set(cpu_info); } else { delete CpuInfo; info.GetReturnValue().Set(Nan::False()); } } else { Nan::Callback *callback = new Nan::Callback(info[0].As()); Nan::AsyncQueueWorker(new IOWorker(callback, s7client, GETCPUINFO, CpuInfo)); info.GetReturnValue().SetUndefined(); } } v8::Local S7Client::S7CpuInfoToObject(PS7CpuInfo CpuInfo) { Nan::EscapableHandleScope scope; v8::Local cpu_info = Nan::New(); Nan::Set(cpu_info, Nan::New("ModuleTypeName").ToLocalChecked() , Nan::New(CpuInfo->ModuleTypeName).ToLocalChecked()); Nan::Set(cpu_info, Nan::New("SerialNumber").ToLocalChecked() , Nan::New(CpuInfo->SerialNumber).ToLocalChecked()); Nan::Set(cpu_info, Nan::New("ASName").ToLocalChecked() , Nan::New(CpuInfo->ASName).ToLocalChecked()); Nan::Set(cpu_info, Nan::New("Copyright").ToLocalChecked() , Nan::New(CpuInfo->Copyright).ToLocalChecked()); Nan::Set(cpu_info, Nan::New("ModuleName").ToLocalChecked() , Nan::New(CpuInfo->ModuleName).ToLocalChecked()); return scope.Escape(cpu_info); } NAN_METHOD(S7Client::GetCpInfo) { S7Client *s7client = ObjectWrap::Unwrap(info.Holder()); PS7CpInfo CpInfo = new TS7CpInfo; if (!info[0]->IsFunction()) { int returnValue = s7client->snap7Client->GetCpInfo(CpInfo); if (returnValue == 0) { v8::Local cp_info = s7client->S7CpInfoToObject(CpInfo); delete CpInfo; info.GetReturnValue().Set(cp_info); } else { delete CpInfo; info.GetReturnValue().Set(Nan::False()); } } else { Nan::Callback *callback = new Nan::Callback(info[0].As()); Nan::AsyncQueueWorker(new IOWorker(callback, s7client, GETCPINFO, CpInfo)); info.GetReturnValue().SetUndefined(); } } v8::Local S7Client::S7CpInfoToObject(PS7CpInfo CpInfo) { Nan::EscapableHandleScope scope; v8::Local cp_info = Nan::New(); Nan::Set(cp_info, Nan::New("MaxPduLength").ToLocalChecked() , Nan::New(CpInfo->MaxPduLengt)); Nan::Set(cp_info, Nan::New("MaxConnections").ToLocalChecked() , Nan::New(CpInfo->MaxConnections)); Nan::Set(cp_info, Nan::New("MaxMpiRate").ToLocalChecked() , Nan::New(CpInfo->MaxMpiRate)); Nan::Set(cp_info, Nan::New("MaxBusRate").ToLocalChecked() , Nan::New(CpInfo->MaxBusRate)); return scope.Escape(cp_info); } NAN_METHOD(S7Client::ReadSZL) { S7Client *s7client = ObjectWrap::Unwrap(info.Holder()); if (!(info[0]->IsInt32() || info[1]->IsInt32())) { return Nan::ThrowTypeError("Wrong arguments"); } PS7SZL SZL = new TS7SZL; int size = sizeof(TS7SZL); if (!info[2]->IsFunction()) { int returnValue = s7client->snap7Client->ReadSZL(Nan::To(info[0]).FromJust() , Nan::To(info[1]).FromJust(), SZL, &size); if (returnValue == 0) { v8::Local ret_buf; ret_buf = Nan::NewBuffer( reinterpret_cast(SZL) , size , S7Client::FreeCallbackSZL , NULL).ToLocalChecked(); info.GetReturnValue().Set(ret_buf); } else { delete SZL; info.GetReturnValue().Set(Nan::False()); } } else { Nan::Callback *callback = new Nan::Callback(info[2].As()); Nan::AsyncQueueWorker(new IOWorker(callback, s7client, READSZL, SZL , Nan::To(info[0]).FromJust(), Nan::To(info[1]).FromJust(), size)); info.GetReturnValue().SetUndefined(); } } NAN_METHOD(S7Client::ReadSZLList) { S7Client *s7client = ObjectWrap::Unwrap(info.Holder()); PS7SZLList SZLList = new TS7SZLList; int size = sizeof(TS7SZLList); if (!info[0]->IsFunction()) { int returnValue = s7client->snap7Client->ReadSZLList(SZLList, &size); if (returnValue == 0) { v8::Local szl_list = s7client->S7SZLListToArray(SZLList, size); delete SZLList; info.GetReturnValue().Set(szl_list); } else { delete SZLList; info.GetReturnValue().Set(Nan::False()); } } else { Nan::Callback *callback = new Nan::Callback(info[0].As()); Nan::AsyncQueueWorker(new IOWorker(callback, s7client, READSZLLIST, SZLList , size)); info.GetReturnValue().SetUndefined(); } } v8::Local S7Client::S7SZLListToArray(PS7SZLList SZLList, int count) { Nan::EscapableHandleScope scope; v8::Local szl_list = Nan::New(count); for (int i = 0; i < count; i++) { Nan::Set(szl_list, i, Nan::New((*SZLList).List[i])); } return scope.Escape(szl_list); } // Control functions NAN_METHOD(S7Client::PlcHotStart) { S7Client *s7client = ObjectWrap::Unwrap(info.Holder()); if (!info[0]->IsFunction()) { info.GetReturnValue().Set(Nan::New( s7client->snap7Client->PlcHotStart() == 0)); } else { Nan::Callback *callback = new Nan::Callback(info[0].As()); Nan::AsyncQueueWorker(new IOWorker(callback, s7client, PLCHOTSTART)); info.GetReturnValue().SetUndefined(); } } NAN_METHOD(S7Client::PlcColdStart) { S7Client *s7client = ObjectWrap::Unwrap(info.Holder()); if (!info[0]->IsFunction()) { info.GetReturnValue().Set(Nan::New( s7client->snap7Client->PlcColdStart() == 0)); } else { Nan::Callback *callback = new Nan::Callback(info[0].As()); Nan::AsyncQueueWorker(new IOWorker(callback, s7client, PLCCOLDSTART)); info.GetReturnValue().SetUndefined(); } } NAN_METHOD(S7Client::PlcStop) { S7Client *s7client = ObjectWrap::Unwrap(info.Holder()); if (!info[0]->IsFunction()) { info.GetReturnValue().Set(Nan::New( s7client->snap7Client->PlcStop() == 0)); } else { Nan::Callback *callback = new Nan::Callback(info[0].As()); Nan::AsyncQueueWorker(new IOWorker(callback, s7client, PLCSTOP)); info.GetReturnValue().SetUndefined(); } } NAN_METHOD(S7Client::CopyRamToRom) { S7Client *s7client = ObjectWrap::Unwrap(info.Holder()); if (!info[0]->IsInt32()) { return Nan::ThrowTypeError("Wrong arguments"); } if (!info[1]->IsFunction()) { info.GetReturnValue().Set(Nan::New( s7client->snap7Client->CopyRamToRom(Nan::To(info[0]).FromJust()) == 0)); } else { Nan::Callback *callback = new Nan::Callback(info[1].As()); Nan::AsyncQueueWorker(new IOWorker(callback, s7client, COPYRAMTOROM , Nan::To(info[0]).FromJust())); info.GetReturnValue().SetUndefined(); } } NAN_METHOD(S7Client::Compress) { S7Client *s7client = ObjectWrap::Unwrap(info.Holder()); if (!info[0]->IsInt32()) { return Nan::ThrowTypeError("Wrong arguments"); } if (!info[1]->IsFunction()) { info.GetReturnValue().Set(Nan::New( s7client->snap7Client->Compress(Nan::To(info[0]).FromJust()) == 0)); } else { Nan::Callback *callback = new Nan::Callback(info[1].As()); Nan::AsyncQueueWorker(new IOWorker(callback, s7client, COMPRESS , Nan::To(info[0]).FromJust())); info.GetReturnValue().SetUndefined(); } } // Security functions NAN_METHOD(S7Client::GetProtection) { S7Client *s7client = ObjectWrap::Unwrap(info.Holder()); PS7Protection S7Protection = new TS7Protection; if (!info[0]->IsFunction()) { int returnValue = s7client->snap7Client->GetProtection(S7Protection); if (returnValue == 0) { v8::Local protection = s7client->S7ProtectionToObject( S7Protection); delete S7Protection; info.GetReturnValue().Set(protection); } else { delete S7Protection; info.GetReturnValue().Set(Nan::False()); } } else { Nan::Callback *callback = new Nan::Callback(info[0].As()); Nan::AsyncQueueWorker(new IOWorker(callback, s7client, GETPROTECTION , S7Protection)); info.GetReturnValue().SetUndefined(); } } v8::Local S7Client::S7ProtectionToObject( PS7Protection S7Protection ) { Nan::EscapableHandleScope scope; v8::Local protection = Nan::New(); Nan::Set(protection, Nan::New("sch_schal").ToLocalChecked() , Nan::New(S7Protection->sch_schal)); Nan::Set(protection, Nan::New("sch_par").ToLocalChecked() , Nan::New(S7Protection->sch_par)); Nan::Set(protection, Nan::New("sch_rel").ToLocalChecked() , Nan::New(S7Protection->sch_rel)); Nan::Set(protection, Nan::New("bart_sch").ToLocalChecked() , Nan::New(S7Protection->bart_sch)); Nan::Set(protection, Nan::New("anl_sch").ToLocalChecked() , Nan::New(S7Protection->anl_sch)); return scope.Escape(protection); } NAN_METHOD(S7Client::SetSessionPassword) { S7Client *s7client = ObjectWrap::Unwrap(info.Holder()); if (!info[0]->IsString()) { return Nan::ThrowTypeError("Wrong arguments"); } Nan::Utf8String *password = new Nan::Utf8String(info[0]); if (!info[1]->IsFunction()) { v8::Local ret = Nan::New( s7client->snap7Client->SetSessionPassword(**password) == 0); delete password; info.GetReturnValue().Set(ret); } else { Nan::Callback *callback = new Nan::Callback(info[1].As()); Nan::AsyncQueueWorker(new IOWorker(callback, s7client, SETSESSIONPW , password)); info.GetReturnValue().SetUndefined(); } } NAN_METHOD(S7Client::ClearSessionPassword) { S7Client *s7client = ObjectWrap::Unwrap(info.Holder()); if (!info[0]->IsFunction()) { info.GetReturnValue().Set(Nan::New( s7client->snap7Client->ClearSessionPassword() == 0)); } else { Nan::Callback *callback = new Nan::Callback(info[0].As()); Nan::AsyncQueueWorker(new IOWorker(callback, s7client, CLEARSESSIONPW)); info.GetReturnValue().SetUndefined(); } } // Properties NAN_METHOD(S7Client::ExecTime) { S7Client *s7client = ObjectWrap::Unwrap(info.Holder()); int returnValue = s7client->snap7Client->ExecTime(); if (returnValue == errLibInvalidObject) { info.GetReturnValue().Set(Nan::False()); } else { info.GetReturnValue().Set(Nan::New(returnValue)); } } NAN_METHOD(S7Client::LastError) { S7Client *s7client = ObjectWrap::Unwrap(info.Holder()); info.GetReturnValue().Set(Nan::New( s7client->snap7Client->LastError())); } NAN_METHOD(S7Client::PDURequested) { S7Client *s7client = ObjectWrap::Unwrap(info.Holder()); int returnValue = s7client->snap7Client->PDURequested(); if (returnValue == 0) { info.GetReturnValue().Set(Nan::False()); } else { info.GetReturnValue().Set(Nan::New(returnValue)); } } NAN_METHOD(S7Client::PDULength) { S7Client *s7client = ObjectWrap::Unwrap(info.Holder()); int returnValue = s7client->snap7Client->PDULength(); if (returnValue == 0) { info.GetReturnValue().Set(Nan::False()); } else { info.GetReturnValue().Set(Nan::New(returnValue)); } } NAN_METHOD(S7Client::PlcStatus) { S7Client *s7client = ObjectWrap::Unwrap(info.Holder()); if (!info[0]->IsFunction()) { int returnValue = s7client->snap7Client->PlcStatus(); if ((returnValue == S7CpuStatusUnknown) || (returnValue == S7CpuStatusStop) || (returnValue == S7CpuStatusRun)) { info.GetReturnValue().Set(Nan::New(returnValue)); } else { info.GetReturnValue().Set(Nan::False()); } } else { Nan::Callback *callback = new Nan::Callback(info[0].As()); Nan::AsyncQueueWorker(new IOWorker(callback, s7client, PLCSTATUS)); info.GetReturnValue().SetUndefined(); } } NAN_METHOD(S7Client::Connected) { S7Client *s7client = ObjectWrap::Unwrap(info.Holder()); info.GetReturnValue().Set(Nan::New( s7client->snap7Client->Connected())); } NAN_METHOD(S7Client::ErrorText) { if (!info[0]->IsInt32()) { return Nan::ThrowTypeError("Wrong arguments"); } info.GetReturnValue().Set(Nan::New( CliErrorText(Nan::To(info[0]).FromJust()).c_str()).ToLocalChecked()); } } // namespace node_snap7 ================================================ FILE: src/node_snap7_client.h ================================================ /* * Copyright (c) 2019, Mathias Küsel * MIT License */ #ifndef SRC_NODE_SNAP7_CLIENT_H_ #define SRC_NODE_SNAP7_CLIENT_H_ #include #include #include namespace node_snap7 { enum DataIOFunction { READAREA = 1, WRITEAREA, READMULTI, WRITEMULTI , PLCSTATUS, GETPROTECTION, CLEARSESSIONPW, SETSESSIONPW, PLCSTOP , PLCCOLDSTART, PLCHOTSTART, GETCPINFO, GETCPUINFO, GETORDERCODE , SETPLCSYSTEMDATETIME, GETPLCDATETIME, COMPRESS, COPYRAMTOROM , SETPLCDATETIME, DBFILL, DBGET, DELETEBLOCK, DOWNLOAD, FULLUPLOAD , UPLOAD, LISTBLOCKSOFTYPE, GETAGBLOCKINFO, LISTBLOCKS, CONNECT , CONNECTTO, READSZLLIST, READSZL }; class S7Client : public Nan::ObjectWrap { public: S7Client(); static NAN_MODULE_INIT(Init); static NAN_METHOD(New); // Control functions static NAN_METHOD(Connect); static NAN_METHOD(ConnectTo); static NAN_METHOD(SetConnectionParams); static NAN_METHOD(SetConnectionType); static NAN_METHOD(Disconnect); static NAN_METHOD(GetParam); static NAN_METHOD(SetParam); // Data I/O Main functions static NAN_METHOD(ReadArea); static NAN_METHOD(WriteArea); static NAN_METHOD(ReadMultiVars); static NAN_METHOD(WriteMultiVars); // Directory functions static NAN_METHOD(ListBlocks); static NAN_METHOD(GetAgBlockInfo); static NAN_METHOD(GetPgBlockInfo); static NAN_METHOD(ListBlocksOfType); // Blocks functions static NAN_METHOD(Upload); static NAN_METHOD(FullUpload); static NAN_METHOD(Download); static NAN_METHOD(Delete); static NAN_METHOD(DBGet); static NAN_METHOD(DBFill); // Date/Time functions static NAN_METHOD(GetPlcDateTime); static NAN_METHOD(SetPlcDateTime); static NAN_METHOD(SetPlcSystemDateTime); // System Info functions static NAN_METHOD(GetOrderCode); static NAN_METHOD(GetCpuInfo); static NAN_METHOD(GetCpInfo); static NAN_METHOD(ReadSZL); static NAN_METHOD(ReadSZLList); // Control functions static NAN_METHOD(PlcHotStart); static NAN_METHOD(PlcColdStart); static NAN_METHOD(PlcStop); static NAN_METHOD(CopyRamToRom); static NAN_METHOD(Compress); // Security functions static NAN_METHOD(GetProtection); static NAN_METHOD(SetSessionPassword); static NAN_METHOD(ClearSessionPassword); // Properties static NAN_METHOD(ExecTime); static NAN_METHOD(LastError); static NAN_METHOD(PDURequested); static NAN_METHOD(PDULength); static NAN_METHOD(PlcStatus); static NAN_METHOD(Connected); static NAN_METHOD(ErrorText); // Internal Helper functions static int GetByteCountFromWordLen(int WordLen); v8::Local S7DataItemToArray(PS7DataItem Items, int len , bool readMulti); v8::Local S7ProtectionToObject(PS7Protection S7Protection); v8::Local S7CpInfoToObject(PS7CpInfo CpInfo); v8::Local S7CpuInfoToObject(PS7CpuInfo CpuInfo); v8::Local S7OrderCodeToObject(PS7OrderCode OrderCode); v8::Local S7BlockInfoToObject(PS7BlockInfo BlockInfo); v8::Local S7BlocksListToObject(PS7BlocksList BlocksList); v8::Local S7BlocksOfTypeToArray(PS7BlocksOfType BlocksList , int count); v8::Local S7SZLListToArray(PS7SZLList SZLList, int count); static void FreeCallback(char *data, void* hint); static void FreeCallbackSZL(char *data, void* hint); uv_mutex_t mutex; TS7Client *snap7Client; private: ~S7Client(); static Nan::Persistent constructor; }; class IOWorker : public Nan::AsyncWorker { public: // No args IOWorker(Nan::Callback *callback, S7Client *s7client, DataIOFunction caller) : Nan::AsyncWorker(callback), s7client(s7client), caller(caller) {} // 1 args IOWorker(Nan::Callback *callback, S7Client *s7client, DataIOFunction caller , void *arg1) : Nan::AsyncWorker(callback), s7client(s7client), caller(caller) , pData(arg1) {} IOWorker(Nan::Callback *callback, S7Client *s7client, DataIOFunction caller , int arg1) : Nan::AsyncWorker(callback), s7client(s7client), caller(caller) , int1(arg1) {} // 2 args IOWorker(Nan::Callback *callback, S7Client *s7client, DataIOFunction caller , void *arg1, int arg2) : Nan::AsyncWorker(callback), s7client(s7client), caller(caller) , pData(arg1), int1(arg2) {} IOWorker(Nan::Callback *callback, S7Client *s7client, DataIOFunction caller , int arg1, int arg2) : Nan::AsyncWorker(callback), s7client(s7client), caller(caller) , int1(arg1), int2(arg2) {} // 3 args IOWorker(Nan::Callback *callback, S7Client *s7client, DataIOFunction caller , void *arg1, int arg2, int arg3) : Nan::AsyncWorker(callback), s7client(s7client), caller(caller) , pData(arg1), int1(arg2), int2(arg3) {} // 4 args IOWorker(Nan::Callback *callback, S7Client *s7client, DataIOFunction caller , void *arg1, int arg2, int arg3, int arg4) : Nan::AsyncWorker(callback), s7client(s7client), caller(caller) , pData(arg1), int1(arg2), int2(arg3), int3(arg4) {} // 6 args IOWorker(Nan::Callback *callback, S7Client *s7client, DataIOFunction caller , void *arg1, int arg2, int arg3, int arg4, int arg5, int arg6) : Nan::AsyncWorker(callback), s7client(s7client), caller(caller) , pData(arg1), int1(arg2), int2(arg3), int3(arg4), int4(arg5), int5(arg6) {} ~IOWorker() {} private: void Execute(); void HandleOKCallback(); S7Client *s7client; DataIOFunction caller; void *pData; int int1, int2, int3, int4, int5, returnValue; }; } // namespace node_snap7 #endif // SRC_NODE_SNAP7_CLIENT_H_ ================================================ FILE: src/node_snap7_server.cpp ================================================ /* * Copyright (c) 2019, Mathias Küsel * MIT License */ #include namespace node_snap7 { static uv_async_t event_async_g; static uv_async_t rw_async_g; static uv_mutex_t mutex_rw; static uv_mutex_t mutex_event; static uv_sem_t sem_rw; static std::deque event_list_g; static struct rw_event_baton_t { int Sender; int Operation; TS7Tag Tag; void *pUsrData; } rw_event_baton_g; void S7API EventCallBack(void *usrPtr, PSrvEvent PEvent, int Size) { uv_mutex_lock(&mutex_event); event_list_g.push_back(*PEvent); uv_mutex_unlock(&mutex_event); uv_async_send(&event_async_g); } int S7API RWAreaCallBack(void *usrPtr, int Sender, int Operation, PS7Tag PTag , void *pUsrData ) { uv_mutex_lock(&mutex_rw); rw_event_baton_g.Sender = Sender; rw_event_baton_g.Operation = Operation; rw_event_baton_g.Tag = *PTag; rw_event_baton_g.pUsrData = pUsrData; uv_async_send(&rw_async_g); uv_sem_wait(&sem_rw); uv_mutex_unlock(&mutex_rw); return 0; } Nan::Persistent S7Server::constructor; NAN_MODULE_INIT(S7Server::Init) { Nan::HandleScope scope; v8::Local tpl; tpl = Nan::New(S7Server::New); v8::Local name = Nan::New("S7Server") .ToLocalChecked(); tpl->SetClassName(name); tpl->InstanceTemplate()->SetInternalFieldCount(1); // Setup the prototype Nan::SetPrototypeMethod( tpl , "Start" , S7Server::Start); Nan::SetPrototypeMethod( tpl , "StartTo" , S7Server::StartTo); Nan::SetPrototypeMethod( tpl , "Stop" , S7Server::Stop); Nan::SetPrototypeMethod( tpl , "SetParam" , S7Server::SetParam); Nan::SetPrototypeMethod( tpl , "GetParam" , S7Server::GetParam); Nan::SetPrototypeMethod( tpl , "SetResourceless" , S7Server::SetResourceless); Nan::SetPrototypeMethod( tpl , "RegisterArea" , S7Server::RegisterArea); Nan::SetPrototypeMethod( tpl , "UnregisterArea" , S7Server::UnregisterArea); Nan::SetPrototypeMethod( tpl , "LockArea" , S7Server::LockArea); Nan::SetPrototypeMethod( tpl , "UnlockArea" , S7Server::UnlockArea); Nan::SetPrototypeMethod( tpl , "SetArea" , S7Server::SetArea); Nan::SetPrototypeMethod( tpl , "GetArea" , S7Server::GetArea); Nan::SetPrototypeMethod( tpl , "SetEventMask" , S7Server::SetEventsMask); Nan::SetPrototypeMethod( tpl , "GetEventsMask" , S7Server::GetEventsMask); Nan::SetPrototypeMethod( tpl , "ErrorText" , S7Server::ErrorText); Nan::SetPrototypeMethod( tpl , "LastError" , S7Server::LastError); Nan::SetPrototypeMethod( tpl , "EventText" , S7Server::EventText); Nan::SetPrototypeMethod( tpl , "ServerStatus" , S7Server::ServerStatus); Nan::SetPrototypeMethod( tpl , "ClientsCount" , S7Server::ClientsCount); Nan::SetPrototypeMethod( tpl , "GetCpuStatus" , S7Server::GetCpuStatus); Nan::SetPrototypeMethod( tpl , "SetCpuStatus" , S7Server::SetCpuStatus); // Error codes Nan::SetPrototypeTemplate( tpl , Nan::New("errSrvCannotStart").ToLocalChecked() , Nan::New(errSrvCannotStart) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("errSrvDBNullPointer").ToLocalChecked() , Nan::New(errSrvDBNullPointer) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("errSrvAreaAlreadyExists").ToLocalChecked() , Nan::New(errSrvAreaAlreadyExists) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("errSrvUnknownArea").ToLocalChecked() , Nan::New(errSrvUnknownArea) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("errSrvInvalidParams").ToLocalChecked() , Nan::New(errSrvInvalidParams) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("errSrvTooManyDB").ToLocalChecked() , Nan::New(errSrvTooManyDB) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("errSrvInvalidParamNumber").ToLocalChecked() , Nan::New(errSrvInvalidParamNumber) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("errSrvCannotChangeParam").ToLocalChecked() , Nan::New(errSrvCannotChangeParam) , v8::ReadOnly); // Server area IDs Nan::SetPrototypeTemplate( tpl , Nan::New("srvAreaPE").ToLocalChecked() , Nan::New(srvAreaPE) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("srvAreaPA").ToLocalChecked() , Nan::New(srvAreaPA) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("srvAreaMK").ToLocalChecked() , Nan::New(srvAreaMK) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("srvAreaCT").ToLocalChecked() , Nan::New(srvAreaCT) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("srvAreaTM").ToLocalChecked() , Nan::New(srvAreaTM) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("srvAreaDB").ToLocalChecked() , Nan::New(srvAreaDB) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("operationWrite").ToLocalChecked() , Nan::New(OperationWrite) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("operationRead").ToLocalChecked() , Nan::New(OperationRead) , v8::ReadOnly); // TCP server event codes Nan::SetPrototypeTemplate( tpl , Nan::New("evcServerStarted").ToLocalChecked() , Nan::New(evcServerStarted) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evcServerStopped").ToLocalChecked() , Nan::New(evcServerStopped) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evcListenerCannotStart").ToLocalChecked() , Nan::New(evcListenerCannotStart) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evcClientAdded").ToLocalChecked() , Nan::New(evcClientAdded) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evcClientRejected").ToLocalChecked() , Nan::New(evcClientRejected) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evcClientNoRoom").ToLocalChecked() , Nan::New(evcClientNoRoom) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evcClientException").ToLocalChecked() , Nan::New(evcClientException) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evcClientDisconnected").ToLocalChecked() , Nan::New(evcClientDisconnected) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evcClientTerminated").ToLocalChecked() , Nan::New(evcClientTerminated) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evcClientsDropped").ToLocalChecked() , Nan::New(evcClientsDropped) , v8::ReadOnly); // S7 server event codes Nan::SetPrototypeTemplate( tpl , Nan::New("evcPDUincoming").ToLocalChecked() , Nan::New(evcPDUincoming) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evcDataRead").ToLocalChecked() , Nan::New(evcDataRead) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evcDataWrite").ToLocalChecked() , Nan::New(evcDataWrite) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evcNegotiatePDU").ToLocalChecked() , Nan::New(evcNegotiatePDU) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evcReadSZL").ToLocalChecked() , Nan::New(evcReadSZL) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evcClock").ToLocalChecked() , Nan::New(evcClock) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evcUpload").ToLocalChecked() , Nan::New(evcUpload) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evcDownload").ToLocalChecked() , Nan::New(evcDownload) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evcDirectory").ToLocalChecked() , Nan::New(evcDirectory) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evcSecurity").ToLocalChecked() , Nan::New(evcSecurity) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evcControl").ToLocalChecked() , Nan::New(evcControl) , v8::ReadOnly); // Masks to enable/disable all events Nan::SetPrototypeTemplate( tpl , Nan::New("evcAll").ToLocalChecked() , Nan::New(evcAll) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evcNone").ToLocalChecked() , Nan::New(evcNone) , v8::ReadOnly); // Event subcodes Nan::SetPrototypeTemplate( tpl , Nan::New("evsUnknown").ToLocalChecked() , Nan::New(evsUnknown) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evsStartUpload").ToLocalChecked() , Nan::New(evsStartUpload) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evsStartDownload").ToLocalChecked() , Nan::New(evsStartDownload) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evsGetBlockList").ToLocalChecked() , Nan::New(evsGetBlockList) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evsStartListBoT").ToLocalChecked() , Nan::New(evsStartListBoT) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evsListBoT").ToLocalChecked() , Nan::New(evsListBoT) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evsGetBlockInfo").ToLocalChecked() , Nan::New(evsGetBlockInfo) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evsGetClock").ToLocalChecked() , Nan::New(evsGetClock) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evsSetClock").ToLocalChecked() , Nan::New(evsSetClock) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evsSetPassword").ToLocalChecked() , Nan::New(evsSetPassword) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evsClrPassword").ToLocalChecked() , Nan::New(evsClrPassword) , v8::ReadOnly); // Event params : functions group Nan::SetPrototypeTemplate( tpl , Nan::New("grProgrammer").ToLocalChecked() , Nan::New(grProgrammer) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("grCyclicData").ToLocalChecked() , Nan::New(grCyclicData) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("grBlocksInfo").ToLocalChecked() , Nan::New(grBlocksInfo) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("grSZL").ToLocalChecked() , Nan::New(grSZL) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("grPassword").ToLocalChecked() , Nan::New(grPassword) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("grBSend").ToLocalChecked() , Nan::New(grBSend) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("grClock").ToLocalChecked() , Nan::New(grClock) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("grSecurity").ToLocalChecked() , Nan::New(grSecurity) , v8::ReadOnly); // Event params : control codes Nan::SetPrototypeTemplate( tpl , Nan::New("CodeControlUnknown").ToLocalChecked() , Nan::New(CodeControlUnknown) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("CodeControlColdStart").ToLocalChecked() , Nan::New(CodeControlColdStart) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("CodeControlWarmStart").ToLocalChecked() , Nan::New(CodeControlWarmStart) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("CodeControlStop").ToLocalChecked() , Nan::New(CodeControlStop) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("CodeControlCompress").ToLocalChecked() , Nan::New(CodeControlCompress) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("CodeControlCpyRamRom").ToLocalChecked() , Nan::New(CodeControlCpyRamRom) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("CodeControlInsDel").ToLocalChecked() , Nan::New(CodeControlInsDel) , v8::ReadOnly); // Event results Nan::SetPrototypeTemplate( tpl , Nan::New("evrNoError").ToLocalChecked() , Nan::New(evrNoError) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evrFragmentRejected").ToLocalChecked() , Nan::New(evrFragmentRejected) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evrMalformedPDU").ToLocalChecked() , Nan::New(evrMalformedPDU) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evrSparseBytes").ToLocalChecked() , Nan::New(evrSparseBytes) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evrCannotHandlePDU").ToLocalChecked() , Nan::New(evrCannotHandlePDU) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evrNotImplemented").ToLocalChecked() , Nan::New(evrNotImplemented) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evrErrException").ToLocalChecked() , Nan::New(evrErrException) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evrErrAreaNotFound").ToLocalChecked() , Nan::New(evrErrAreaNotFound) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evrErrOutOfRange").ToLocalChecked() , Nan::New(evrErrOutOfRange) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evrErrOverPDU").ToLocalChecked() , Nan::New(evrErrOverPDU) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evrErrTransportSize").ToLocalChecked() , Nan::New(evrErrTransportSize) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evrInvalidGroupUData").ToLocalChecked() , Nan::New(evrInvalidGroupUData) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evrInvalidSZL").ToLocalChecked() , Nan::New(evrInvalidSZL) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evrDataSizeMismatch").ToLocalChecked() , Nan::New(evrDataSizeMismatch) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evrCannotUpload").ToLocalChecked() , Nan::New(evrCannotUpload) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evrCannotDownload").ToLocalChecked() , Nan::New(evrCannotDownload) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evrUploadInvalidID").ToLocalChecked() , Nan::New(evrUploadInvalidID) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evrResNotFound").ToLocalChecked() , Nan::New(evrResNotFound) , v8::ReadOnly); // Server parameter Nan::SetPrototypeTemplate( tpl , Nan::New("LocalPort").ToLocalChecked() , Nan::New(p_u16_LocalPort) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("WorkInterval").ToLocalChecked() , Nan::New(p_i32_WorkInterval) , 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); // 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); // Server status codes Nan::SetPrototypeTemplate( tpl , Nan::New("SrvStopped").ToLocalChecked() , Nan::New(0) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("SrvRunning").ToLocalChecked() , Nan::New(1) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("SrvError").ToLocalChecked() , Nan::New(2) , v8::ReadOnly); constructor.Reset(tpl); Nan::Set(target, name, Nan::GetFunction(tpl).ToLocalChecked()); } NAN_METHOD(S7Server::New) { if (info.IsConstructCall()) { S7Server *s7Server = new S7Server(info.This()); s7Server->Wrap(info.This()); info.GetReturnValue().Set(info.This()); } else { v8::Local constructorHandle; constructorHandle = Nan::New(constructor); info.GetReturnValue().Set( Nan::NewInstance(Nan::GetFunction(constructorHandle).ToLocalChecked()).ToLocalChecked()); } } S7Server::S7Server(v8::Local resource) : async_resource("S7Server:emit", resource) { lastError = 0; snap7Server = new TS7Server(); event_async_g.data = rw_async_g.data = this; uv_async_init(uv_default_loop(), &event_async_g, S7Server::HandleEvent); uv_async_init(uv_default_loop(), &rw_async_g, S7Server::HandleReadWriteEvent); uv_unref(reinterpret_cast(&event_async_g)); uv_unref(reinterpret_cast(&rw_async_g)); uv_mutex_init(&mutex); uv_mutex_init(&mutex_rw); uv_mutex_init(&mutex_event); uv_sem_init(&sem_rw, 0); snap7Server->SetEventsCallback(&EventCallBack, NULL); } S7Server::~S7Server() { snap7Server->Stop(); delete snap7Server; constructor.Reset(); uv_close(reinterpret_cast(&event_async_g), 0); uv_close(reinterpret_cast(&rw_async_g), 0); uv_sem_destroy(&sem_rw); uv_mutex_destroy(&mutex_event); uv_mutex_destroy(&mutex_rw); uv_mutex_destroy(&mutex); } int S7Server::GetByteCountFromWordLen(int WordLen) { switch (WordLen) { case S7WLBit: case S7WLByte: return 1; case S7WLWord: case S7WLCounter: case S7WLTimer: return 2; case S7WLReal: case S7WLDWord: return 4; default: return 0; } } NAN_METHOD(S7Server::RWBufferCallback) { Nan::HandleScope scope; if (rw_event_baton_g.Operation == OperationRead) { if (!node::Buffer::HasInstance(info[0])) { return Nan::ThrowTypeError("Wrong argument"); } int byteCount, size; byteCount = S7Server::GetByteCountFromWordLen(rw_event_baton_g.Tag.WordLen); size = byteCount * rw_event_baton_g.Tag.Size; if (node::Buffer::Length(info[0].As()) < size) { return Nan::ThrowTypeError("Buffer length too small"); } memcpy( rw_event_baton_g.pUsrData , node::Buffer::Data(info[0].As()) , size); } uv_sem_post(&sem_rw); } #if NODE_VERSION_AT_LEAST(0, 11, 13) void S7Server::HandleEvent(uv_async_t* handle) { #else void S7Server::HandleEvent(uv_async_t* handle, int status) { #endif Nan::HandleScope scope; S7Server *s7server = static_cast(handle->data); uv_mutex_lock(&mutex_event); while (!event_list_g.empty()) { PSrvEvent Event = &event_list_g.front(); in_addr sin; sin.s_addr = Event->EvtSender; double time = static_cast(Event->EvtTime * 1000); v8::Local event_obj = Nan::New(); Nan::Set(event_obj, Nan::New("EvtTime").ToLocalChecked() , Nan::New(time).ToLocalChecked()); Nan::Set(event_obj, Nan::New("EvtSender").ToLocalChecked() , Nan::New(inet_ntoa(sin)).ToLocalChecked()); Nan::Set(event_obj, Nan::New("EvtCode").ToLocalChecked() , Nan::New(Event->EvtCode)); Nan::Set(event_obj, Nan::New("EvtRetCode").ToLocalChecked() , Nan::New(Event->EvtRetCode)); Nan::Set(event_obj, Nan::New("EvtParam1").ToLocalChecked() , Nan::New(Event->EvtParam1)); Nan::Set(event_obj, Nan::New("EvtParam2").ToLocalChecked() , Nan::New(Event->EvtParam2)); Nan::Set(event_obj, Nan::New("EvtParam3").ToLocalChecked() , Nan::New(Event->EvtParam3)); Nan::Set(event_obj, Nan::New("EvtParam4").ToLocalChecked() , Nan::New(Event->EvtParam4)); v8::Local argv[2] = { Nan::New("event").ToLocalChecked(), event_obj }; s7server->async_resource.runInAsyncScope(s7server->handle(), "emit", 2, argv); event_list_g.pop_front(); } uv_mutex_unlock(&mutex_event); } #if NODE_VERSION_AT_LEAST(0, 11, 13) void S7Server::HandleReadWriteEvent(uv_async_t* handle) { #else void S7Server::HandleReadWriteEvent(uv_async_t* handle, int status) { #endif Nan::HandleScope scope; S7Server *s7server = static_cast(handle->data); in_addr sin; sin.s_addr = rw_event_baton_g.Sender; v8::Local rw_tag_obj = Nan::New(); Nan::Set(rw_tag_obj, Nan::New("Area").ToLocalChecked() , Nan::New(rw_event_baton_g.Tag.Area)); Nan::Set(rw_tag_obj, Nan::New("DBNumber").ToLocalChecked() , Nan::New(rw_event_baton_g.Tag.DBNumber)); Nan::Set(rw_tag_obj, Nan::New("Start").ToLocalChecked() , Nan::New(rw_event_baton_g.Tag.Start)); Nan::Set(rw_tag_obj, Nan::New("Size").ToLocalChecked() , Nan::New(rw_event_baton_g.Tag.Size)); Nan::Set(rw_tag_obj, Nan::New("WordLen").ToLocalChecked() , Nan::New(rw_event_baton_g.Tag.WordLen)); int byteCount, size; byteCount = S7Server::GetByteCountFromWordLen(rw_event_baton_g.Tag.WordLen); size = byteCount * rw_event_baton_g.Tag.Size; v8::Local buffer; if (rw_event_baton_g.Operation == OperationWrite) { buffer = Nan::CopyBuffer( static_cast(rw_event_baton_g.pUsrData), size).ToLocalChecked(); } else { buffer = Nan::NewBuffer(size).ToLocalChecked(); memset(node::Buffer::Data(buffer), 0, size); } v8::Local argv[6] = { Nan::New("readWrite").ToLocalChecked(), Nan::New(inet_ntoa(sin)).ToLocalChecked(), Nan::New(rw_event_baton_g.Operation), rw_tag_obj, buffer, Nan::New(S7Server::RWBufferCallback) }; s7server->async_resource.runInAsyncScope(s7server->handle(), "emit", 6, argv); } void IOWorkerServer::Execute() { uv_mutex_lock(&s7server->mutex); switch (caller) { case STARTTO: ret = s7server->snap7Server->StartTo( **static_cast(pData)); if (ret == 0) { uv_ref(reinterpret_cast(&event_async_g)); } break; case START: ret = s7server->snap7Server->Start(); if (ret == 0) { uv_ref(reinterpret_cast(&event_async_g)); } break; case STOP: ret = s7server->snap7Server->Stop(); if (ret == 0) { uv_unref(reinterpret_cast(&event_async_g)); } break; } uv_mutex_unlock(&s7server->mutex); } void IOWorkerServer::HandleOKCallback() { Nan::HandleScope scope; v8::Local argv1[1]; v8::Local argv2[2]; if (ret == 0) { argv2[0] = argv1[0] = Nan::Null(); } else { argv2[0] = argv1[0] = Nan::New(ret); } switch (caller) { case STARTTO: delete static_cast(pData); callback->Call(1, argv1, async_resource); break; case START: case STOP: callback->Call(1, argv1, async_resource); break; } } NAN_METHOD(S7Server::Start) { S7Server *s7server = ObjectWrap::Unwrap(info.Holder()); if (!info[0]->IsFunction()) { int ret = s7server->snap7Server->Start(); if (ret == 0) { uv_ref(reinterpret_cast(&event_async_g)); } s7server->lastError = ret; info.GetReturnValue().Set(Nan::New(ret == 0)); } else { Nan::Callback *callback = new Nan::Callback(info[0].As()); Nan::AsyncQueueWorker(new IOWorkerServer(callback, s7server, START)); info.GetReturnValue().SetUndefined(); } } NAN_METHOD(S7Server::StartTo) { S7Server *s7server = ObjectWrap::Unwrap(info.Holder()); if (info.Length() < 1) { return Nan::ThrowTypeError("Wrong number of arguments"); } if (!info[0]->IsString()) { return Nan::ThrowTypeError("Wrong arguments"); } Nan::Utf8String *address = new Nan::Utf8String(info[0]); if (!info[1]->IsFunction()) { int ret = s7server->snap7Server->StartTo(**address); delete address; if (ret == 0) { uv_ref(reinterpret_cast(&event_async_g)); } s7server->lastError = ret; info.GetReturnValue().Set(Nan::New(ret == 0)); } else { Nan::Callback *callback = new Nan::Callback(info[1].As()); Nan::AsyncQueueWorker(new IOWorkerServer(callback, s7server, STARTTO , address)); info.GetReturnValue().SetUndefined(); } } NAN_METHOD(S7Server::Stop) { S7Server *s7server = ObjectWrap::Unwrap(info.Holder()); if (!info[0]->IsFunction()) { int ret = s7server->snap7Server->Stop(); if (ret == 0) { uv_unref(reinterpret_cast(&event_async_g)); } s7server->lastError = ret; info.GetReturnValue().Set(Nan::New(ret == 0)); } else { Nan::Callback *callback = new Nan::Callback(info[0].As()); Nan::AsyncQueueWorker(new IOWorkerServer(callback, s7server, STOP)); info.GetReturnValue().SetUndefined(); } } NAN_METHOD(S7Server::SetResourceless) { S7Server *s7server = ObjectWrap::Unwrap(info.Holder()); if (!info[0]->IsBoolean()) { return Nan::ThrowTypeError("Wrong arguments"); } bool resourceless = Nan::To(info[0]).FromJust(); int ret; if (resourceless) { ret = s7server->snap7Server->SetRWAreaCallback(&RWAreaCallBack, NULL); } else { ret = s7server->snap7Server->SetRWAreaCallback(NULL, NULL); } s7server->lastError = ret; info.GetReturnValue().Set(Nan::New(ret == 0)); } NAN_METHOD(S7Server::GetParam) { S7Server *s7server = ObjectWrap::Unwrap(info.Holder()); if (!info[0]->IsInt32()) { return Nan::ThrowTypeError("Wrong arguments"); } int pData; int ret = s7server->snap7Server->GetParam(Nan::To(info[0]).FromJust() , &pData); s7server->lastError = ret; info.GetReturnValue().Set(Nan::New(ret == 0)); } NAN_METHOD(S7Server::SetParam) { S7Server *s7server = ObjectWrap::Unwrap(info.Holder()); if (!(info[0]->IsInt32() || info[1]->IsInt32())) { return Nan::ThrowTypeError("Wrong arguments"); } int pData = Nan::To(info[1]).FromJust(); int ret = s7server->snap7Server->SetParam(Nan::To(info[0]).FromJust(), &pData); s7server->lastError = ret; info.GetReturnValue().Set(Nan::New(ret == 0)); } NAN_METHOD(S7Server::GetEventsMask) { S7Server *s7server = ObjectWrap::Unwrap(info.Holder()); int ret = s7server->snap7Server->GetEventsMask(); info.GetReturnValue().Set(Nan::New(ret)); } NAN_METHOD(S7Server::SetEventsMask) { S7Server *s7server = ObjectWrap::Unwrap(info.Holder()); if (!info[0]->IsUint32()) { return Nan::ThrowTypeError("Wrong arguments"); } s7server->snap7Server->SetEventsMask(Nan::To(info[0]).FromJust()); info.GetReturnValue().SetUndefined(); } NAN_METHOD(S7Server::RegisterArea) { S7Server *s7server = ObjectWrap::Unwrap(info.Holder()); if (!info[0]->IsInt32()) { return Nan::ThrowTypeError("Wrong arguments"); } int index; char *pBuffer; size_t len; int area = Nan::To(info[0]).FromJust(); if (area == srvAreaDB) { if (!info[1]->IsInt32() || !node::Buffer::HasInstance(info[2])) { return Nan::ThrowTypeError("Wrong arguments"); } index = Nan::To(info[1]).FromJust(); len = node::Buffer::Length(info[2].As()); pBuffer = node::Buffer::Data(info[2].As()); } else if (!node::Buffer::HasInstance(info[1])) { return Nan::ThrowTypeError("Wrong arguments"); } else { index = 0; len = node::Buffer::Length(info[1].As()); pBuffer = node::Buffer::Data(info[1].As()); } if (len > 0xFFFF) { return Nan::ThrowRangeError("Max area buffer size is 65535"); } word size = static_cast(len); char *data = new char[size]; memcpy(data, pBuffer, size); int ret = s7server->snap7Server->RegisterArea(area, index, data, size); s7server->lastError = ret; if (ret == 0) { s7server->area2buffer[area][index].pBuffer = data; s7server->area2buffer[area][index].size = size; } else { delete[] data; } info.GetReturnValue().Set(Nan::New(ret == 0)); } NAN_METHOD(S7Server::UnregisterArea) { S7Server *s7server = ObjectWrap::Unwrap(info.Holder()); if (!info[0]->IsInt32()) { return Nan::ThrowTypeError("Wrong arguments"); } int index = 0; int area = Nan::To(info[0]).FromJust(); if (area == srvAreaDB) { if (!info[1]->IsInt32()) { return Nan::ThrowTypeError("Wrong arguments"); } index = Nan::To(info[1]).FromJust(); } int ret = s7server->snap7Server->UnregisterArea(area, index); s7server->lastError = ret; if (ret == 0) { delete[] s7server->area2buffer[area][index].pBuffer; s7server->area2buffer[area].erase(index); } info.GetReturnValue().Set(Nan::New(ret == 0)); } NAN_METHOD(S7Server::SetArea) { S7Server *s7server = ObjectWrap::Unwrap(info.Holder()); if (!info[0]->IsInt32()) { return Nan::ThrowTypeError("Wrong arguments"); } int area = Nan::To(info[0]).FromJust(); if (!s7server->area2buffer.count(area)) { return Nan::ThrowError("Unknown area"); } int index; char *pBuffer; size_t len; if (area == srvAreaDB) { if (!info[1]->IsInt32() || !node::Buffer::HasInstance(info[2])) { return Nan::ThrowTypeError("Wrong arguments"); } index = Nan::To(info[1]).FromJust(); if (!s7server->area2buffer[area].count(index)) { return Nan::ThrowError("DB index not found"); } len = node::Buffer::Length(info[2].As()); pBuffer = node::Buffer::Data(info[2].As()); } else { index = 0; if (node::Buffer::HasInstance(info[1])) { len = node::Buffer::Length(info[1].As()); pBuffer = node::Buffer::Data(info[1].As()); } else if (node::Buffer::HasInstance(info[2])) { len = node::Buffer::Length(info[2].As()); pBuffer = node::Buffer::Data(info[2].As()); } else { return Nan::ThrowTypeError("Wrong arguments"); } } if (len != s7server->area2buffer[area][index].size) { return Nan::ThrowError("Wrong buffer length"); } s7server->snap7Server->LockArea(area, index); memcpy( s7server->area2buffer[area][index].pBuffer , pBuffer, s7server->area2buffer[area][index].size); s7server->snap7Server->UnlockArea(area, index); info.GetReturnValue().SetUndefined(); } NAN_METHOD(S7Server::GetArea) { S7Server *s7server = ObjectWrap::Unwrap(info.Holder()); if (!info[0]->IsInt32()) { return Nan::ThrowTypeError("Wrong arguments"); } int index = 0; int area = Nan::To(info[0]).FromJust(); if (!s7server->area2buffer.count(area)) { return Nan::ThrowError("Unknown area"); } if (area == srvAreaDB) { if (!info[1]->IsInt32()) { return Nan::ThrowTypeError("Wrong arguments"); } index = Nan::To(info[1]).FromJust(); if (!s7server->area2buffer[area].count(index)) { return Nan::ThrowError("DB index not found"); } } s7server->snap7Server->LockArea(area, index); v8::Local buffer = Nan::CopyBuffer( s7server->area2buffer[area][index].pBuffer , s7server->area2buffer[area][index].size).ToLocalChecked(); s7server->snap7Server->UnlockArea(area, index); info.GetReturnValue().Set(buffer); } NAN_METHOD(S7Server::LockArea) { S7Server *s7server = ObjectWrap::Unwrap(info.Holder()); if (!info[0]->IsInt32()) { return Nan::ThrowTypeError("Wrong arguments"); } int index = 0; int area = Nan::To(info[0]).FromJust(); if (area == srvAreaDB) { if (!info[1]->IsInt32()) { return Nan::ThrowTypeError("Wrong arguments"); } index = Nan::To(info[1]).FromJust(); } int ret = s7server->snap7Server->LockArea(area, index); s7server->lastError = ret; info.GetReturnValue().Set(Nan::New(ret == 0)); } NAN_METHOD(S7Server::UnlockArea) { S7Server *s7server = ObjectWrap::Unwrap(info.Holder()); if (!info[0]->IsInt32()) { return Nan::ThrowTypeError("Wrong arguments"); } int index = 0; int area = Nan::To(info[0]).FromJust(); if (area == srvAreaDB) { if (!info[1]->IsInt32()) { return Nan::ThrowTypeError("Wrong arguments"); } index = Nan::To(info[1]).FromJust(); } int ret = s7server->snap7Server->UnlockArea(area, index); s7server->lastError = ret; info.GetReturnValue().Set(Nan::New(ret == 0)); } NAN_METHOD(S7Server::ServerStatus) { S7Server *s7server = ObjectWrap::Unwrap(info.Holder()); int ret = s7server->snap7Server->ServerStatus(); if ((ret == 0) || (ret == 1) || (ret == 2)) { s7server->lastError = 0; info.GetReturnValue().Set(Nan::New(ret)); } else { s7server->lastError = ret; info.GetReturnValue().Set(Nan::False()); } } NAN_METHOD(S7Server::ClientsCount) { S7Server *s7server = ObjectWrap::Unwrap(info.Holder()); int ret = s7server->snap7Server->ClientsCount(); info.GetReturnValue().Set(Nan::New(ret)); } NAN_METHOD(S7Server::GetCpuStatus) { S7Server *s7server = ObjectWrap::Unwrap(info.Holder()); int ret = s7server->snap7Server->GetCpuStatus(); if ((ret == S7CpuStatusUnknown) || (ret == S7CpuStatusStop) || (ret == S7CpuStatusRun)) { s7server->lastError = 0; info.GetReturnValue().Set(Nan::New(ret)); } else { s7server->lastError = ret; info.GetReturnValue().Set(Nan::False()); } } NAN_METHOD(S7Server::SetCpuStatus) { S7Server *s7server = ObjectWrap::Unwrap(info.Holder()); if (!info[0]->IsInt32()) { return Nan::ThrowTypeError("Wrong arguments"); } int ret = s7server->snap7Server->SetCpuStatus(Nan::To(info[0]).FromJust()); s7server->lastError = ret; info.GetReturnValue().Set(Nan::New(ret == 0)); } NAN_METHOD(S7Server::ErrorText) { if (!info[0]->IsInt32()) { return Nan::ThrowTypeError("Wrong arguments"); } info.GetReturnValue().Set(Nan::New( SrvErrorText(Nan::To(info[0]).FromJust()).c_str()).ToLocalChecked()); } NAN_METHOD(S7Server::EventText) { TSrvEvent SrvEvent; if (!info[0]->IsObject()) { return Nan::ThrowTypeError("Wrong arguments"); } v8::Local event_obj = v8::Local::Cast(info[0]); if (!Nan::Has(event_obj, Nan::New("EvtTime").ToLocalChecked()).FromJust() || !Nan::Has(event_obj, Nan::New("EvtSender").ToLocalChecked()).FromJust() || !Nan::Has(event_obj, Nan::New("EvtCode").ToLocalChecked()).FromJust() || !Nan::Has(event_obj, Nan::New("EvtRetCode").ToLocalChecked()).FromJust() || !Nan::Has(event_obj, Nan::New("EvtParam1").ToLocalChecked()).FromJust() || !Nan::Has(event_obj, Nan::New("EvtParam2").ToLocalChecked()).FromJust() || !Nan::Has(event_obj, Nan::New("EvtParam3").ToLocalChecked()).FromJust() || !Nan::Has(event_obj, Nan::New("EvtParam4").ToLocalChecked()).FromJust()) { return Nan::ThrowTypeError("Wrong argument structure"); } if (!Nan::Get(event_obj, Nan::New("EvtTime").ToLocalChecked()).ToLocalChecked()->IsDate() || !Nan::Get(event_obj, Nan::New("EvtSender").ToLocalChecked()).ToLocalChecked()->IsString() || !Nan::Get(event_obj, Nan::New("EvtCode").ToLocalChecked()).ToLocalChecked()->IsUint32() || !Nan::Get(event_obj, Nan::New("EvtRetCode").ToLocalChecked()).ToLocalChecked()->IsInt32() || !Nan::Get(event_obj, Nan::New("EvtParam1").ToLocalChecked()).ToLocalChecked()->IsInt32() || !Nan::Get(event_obj, Nan::New("EvtParam2").ToLocalChecked()).ToLocalChecked()->IsInt32() || !Nan::Get(event_obj, Nan::New("EvtParam3").ToLocalChecked()).ToLocalChecked()->IsInt32() || !Nan::Get(event_obj, Nan::New("EvtParam4").ToLocalChecked()).ToLocalChecked()->IsInt32()) { return Nan::ThrowTypeError("Wrong argument types"); } Nan::Utf8String *remAddress = new Nan::Utf8String( Nan::Get( event_obj , Nan::New("EvtSender").ToLocalChecked()).ToLocalChecked()); SrvEvent.EvtTime = static_cast(Nan::To(v8::Local::Cast(Nan::Get(event_obj, Nan::New("EvtTime").ToLocalChecked()).ToLocalChecked())).FromJust() / 1000); SrvEvent.EvtSender = inet_addr(**remAddress); SrvEvent.EvtCode = Nan::To(Nan::Get(event_obj, Nan::New("EvtCode").ToLocalChecked()).ToLocalChecked()).FromJust(); SrvEvent.EvtRetCode = Nan::To(Nan::Get(event_obj, Nan::New("EvtRetCode").ToLocalChecked()).ToLocalChecked()).FromJust(); SrvEvent.EvtParam1 = Nan::To(Nan::Get(event_obj, Nan::New("EvtParam1").ToLocalChecked()).ToLocalChecked()).FromJust(); SrvEvent.EvtParam2 = Nan::To(Nan::Get(event_obj, Nan::New("EvtParam2").ToLocalChecked()).ToLocalChecked()).FromJust(); SrvEvent.EvtParam3 = Nan::To(Nan::Get(event_obj, Nan::New("EvtParam3").ToLocalChecked()).ToLocalChecked()).FromJust(); SrvEvent.EvtParam4 = Nan::To(Nan::Get(event_obj, Nan::New("EvtParam4").ToLocalChecked()).ToLocalChecked()).FromJust(); delete remAddress; info.GetReturnValue().Set(Nan::New( SrvEventText(&SrvEvent).c_str()).ToLocalChecked()); } NAN_METHOD(S7Server::LastError) { S7Server *s7server = ObjectWrap::Unwrap(info.Holder()); info.GetReturnValue().Set(Nan::New(s7server->lastError)); } } // namespace node_snap7 ================================================ FILE: src/node_snap7_server.h ================================================ /* * Copyright (c) 2019, Mathias Küsel * MIT License */ #ifndef SRC_NODE_SNAP7_SERVER_H_ #define SRC_NODE_SNAP7_SERVER_H_ #include #include #include #include #include #include namespace node_snap7 { enum ServerIOFunction { START = 1, STARTTO, STOP }; typedef struct { char* pBuffer; word size; }TBufferInfo; class S7Server : public Nan::ObjectWrap { public: explicit S7Server(v8::Local resource); static NAN_MODULE_INIT(Init); static NAN_METHOD(New); static NAN_METHOD(Start); static NAN_METHOD(StartTo); static NAN_METHOD(Stop); static NAN_METHOD(SetResourceless); static NAN_METHOD(GetParam); static NAN_METHOD(SetParam); static NAN_METHOD(GetEventsMask); static NAN_METHOD(SetEventsMask); static NAN_METHOD(RegisterArea); static NAN_METHOD(UnregisterArea); static NAN_METHOD(SetArea); static NAN_METHOD(GetArea); static NAN_METHOD(LockArea); static NAN_METHOD(UnlockArea); static NAN_METHOD(ServerStatus); static NAN_METHOD(ClientsCount); static NAN_METHOD(GetCpuStatus); static NAN_METHOD(SetCpuStatus); static NAN_METHOD(ErrorText); static NAN_METHOD(EventText); static NAN_METHOD(LastError); static int GetByteCountFromWordLen(int WordLen); #if NODE_VERSION_AT_LEAST(0, 11, 13) static void HandleEvent(uv_async_t* handle); #else static void HandleEvent(uv_async_t* handle, int status); #endif #if NODE_VERSION_AT_LEAST(0, 11, 13) static void HandleReadWriteEvent(uv_async_t* handle); #else static void HandleReadWriteEvent(uv_async_t* handle, int status); #endif static NAN_METHOD(RWBufferCallback); uv_mutex_t mutex; TS7Server *snap7Server; std::map > area2buffer; int lastError; Nan::AsyncResource async_resource; private: ~S7Server(); static Nan::Persistent constructor; }; class IOWorkerServer : public Nan::AsyncWorker { public: // No args IOWorkerServer(Nan::Callback *callback, S7Server *s7server, ServerIOFunction caller) : Nan::AsyncWorker(callback), s7server(s7server), caller(caller) {} // 1 args IOWorkerServer(Nan::Callback *callback, S7Server *s7server, ServerIOFunction caller , void *arg1) : Nan::AsyncWorker(callback), s7server(s7server), caller(caller) , pData(arg1) {} ~IOWorkerServer() {} private: void Execute(); void HandleOKCallback(); S7Server *s7server; ServerIOFunction caller; void *pData; int ret; }; } // namespace node_snap7 #endif // SRC_NODE_SNAP7_SERVER_H_ ================================================ FILE: src/snap7.cpp ================================================ /*=============================================================================| | PROJECT SNAP7 1.4.0 | |==============================================================================| | Copyright (C) 2013, 2014 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/ | |==============================================================================| | | | C++ Snap 7 classes Implementation | | | |=============================================================================*/ #include "snap7.h" //============================================================================== // CLIENT //============================================================================== TS7Client::TS7Client() { Client=Cli_Create(); } //--------------------------------------------------------------------------- TS7Client::~TS7Client() { Cli_Destroy(&Client); } //--------------------------------------------------------------------------- int TS7Client::Connect() { return Cli_Connect(Client); } //--------------------------------------------------------------------------- int TS7Client::ConnectTo(const char *RemAddress, int Rack, int Slot) { return Cli_ConnectTo(Client, RemAddress, Rack, Slot); } //--------------------------------------------------------------------------- int TS7Client::SetConnectionParams(const char *RemAddress, word LocalTSAP, word RemoteTSAP) { return Cli_SetConnectionParams(Client, RemAddress, LocalTSAP, RemoteTSAP); } //--------------------------------------------------------------------------- int TS7Client::SetConnectionType(word ConnectionType) { return Cli_SetConnectionType(Client, ConnectionType); } //--------------------------------------------------------------------------- int TS7Client::Disconnect() { return Cli_Disconnect(Client); } //--------------------------------------------------------------------------- int TS7Client::GetParam(int ParamNumber, void *pValue) { return Cli_GetParam(Client, ParamNumber, pValue); } //--------------------------------------------------------------------------- int TS7Client::SetParam(int ParamNumber, void *pValue) { return Cli_SetParam(Client, ParamNumber, pValue); } //--------------------------------------------------------------------------- int TS7Client::ReadArea(int Area, int DBNumber, int Start, int Amount, int WordLen, void *pUsrData) { return Cli_ReadArea(Client, Area, DBNumber, Start, Amount, WordLen, pUsrData); } //--------------------------------------------------------------------------- int TS7Client::WriteArea(int Area, int DBNumber, int Start, int Amount, int WordLen, void *pUsrData) { return Cli_WriteArea(Client, Area, DBNumber, Start, Amount, WordLen, pUsrData); } //--------------------------------------------------------------------------- int TS7Client::ReadMultiVars(PS7DataItem Item, int ItemsCount) { return Cli_ReadMultiVars(Client, Item, ItemsCount); } //--------------------------------------------------------------------------- int TS7Client::WriteMultiVars(PS7DataItem Item, int ItemsCount) { return Cli_WriteMultiVars(Client, Item, ItemsCount); } //--------------------------------------------------------------------------- int TS7Client::DBRead(int DBNumber, int Start, int Size, void *pUsrData) { return Cli_DBRead(Client, DBNumber, Start, Size, pUsrData); } //--------------------------------------------------------------------------- int TS7Client::DBWrite(int DBNumber, int Start, int Size, void *pUsrData) { return Cli_DBWrite(Client, DBNumber, Start, Size, pUsrData); } //--------------------------------------------------------------------------- int TS7Client::MBRead(int Start, int Size, void *pUsrData) { return Cli_MBRead(Client, Start, Size, pUsrData); } //--------------------------------------------------------------------------- int TS7Client::MBWrite(int Start, int Size, void *pUsrData) { return Cli_MBWrite(Client, Start, Size, pUsrData); } //--------------------------------------------------------------------------- int TS7Client::EBRead(int Start, int Size, void *pUsrData) { return Cli_EBRead(Client, Start, Size, pUsrData); } //--------------------------------------------------------------------------- int TS7Client::EBWrite(int Start, int Size, void *pUsrData) { return Cli_EBWrite(Client, Start, Size, pUsrData); } //--------------------------------------------------------------------------- int TS7Client::ABRead(int Start, int Size, void *pUsrData) { return Cli_ABRead(Client, Start, Size, pUsrData); } //--------------------------------------------------------------------------- int TS7Client::ABWrite(int Start, int Size, void *pUsrData) { return Cli_ABWrite(Client, Start, Size, pUsrData); } //--------------------------------------------------------------------------- int TS7Client::TMRead(int Start, int Amount, void *pUsrData) { return Cli_TMRead(Client, Start, Amount, pUsrData); } //--------------------------------------------------------------------------- int TS7Client::TMWrite(int Start, int Amount, void *pUsrData) { return Cli_TMWrite(Client, Start, Amount, pUsrData); } //--------------------------------------------------------------------------- int TS7Client::CTRead(int Start, int Amount, void *pUsrData) { return Cli_CTRead(Client, Start, Amount, pUsrData); } //--------------------------------------------------------------------------- int TS7Client::CTWrite(int Start, int Amount, void *pUsrData) { return Cli_CTWrite(Client, Start, Amount, pUsrData); } //--------------------------------------------------------------------------- int TS7Client::ListBlocks(PS7BlocksList pUsrData) { return Cli_ListBlocks(Client, pUsrData); } //--------------------------------------------------------------------------- int TS7Client::GetAgBlockInfo(int BlockType, int BlockNum, PS7BlockInfo pUsrData) { return Cli_GetAgBlockInfo(Client, BlockType, BlockNum, pUsrData); } //--------------------------------------------------------------------------- int TS7Client::GetPgBlockInfo(void *pBlock, PS7BlockInfo pUsrData, int Size) { return Cli_GetPgBlockInfo(Client, pBlock, pUsrData, Size); } //--------------------------------------------------------------------------- int TS7Client::ListBlocksOfType(int BlockType, TS7BlocksOfType *pUsrData, int *ItemsCount) { return Cli_ListBlocksOfType(Client, BlockType, pUsrData, ItemsCount); } //--------------------------------------------------------------------------- int TS7Client::Upload(int BlockType, int BlockNum, void *pUsrData, int *Size) { return Cli_Upload(Client, BlockType, BlockNum, pUsrData, Size); } //--------------------------------------------------------------------------- int TS7Client::FullUpload(int BlockType, int BlockNum, void *pUsrData, int *Size) { return Cli_FullUpload(Client, BlockType, BlockNum, pUsrData, Size); } //--------------------------------------------------------------------------- int TS7Client::Download(int BlockNum, void *pUsrData, int Size) { return Cli_Download(Client, BlockNum, pUsrData, Size); } //--------------------------------------------------------------------------- int TS7Client::Delete(int BlockType, int BlockNum) { return Cli_Delete(Client, BlockType, BlockNum); } //--------------------------------------------------------------------------- int TS7Client::DBGet(int DBNumber, void *pUsrData, int *Size) { return Cli_DBGet(Client, DBNumber, pUsrData, Size); } //--------------------------------------------------------------------------- int TS7Client::DBFill(int DBNumber, int FillChar) { return Cli_DBFill(Client, DBNumber, FillChar); } //--------------------------------------------------------------------------- int TS7Client::GetPlcDateTime(tm *DateTime) { return Cli_GetPlcDateTime(Client, DateTime); } //--------------------------------------------------------------------------- int TS7Client::SetPlcDateTime(tm *DateTime) { return Cli_SetPlcDateTime(Client, DateTime); } //--------------------------------------------------------------------------- int TS7Client::SetPlcSystemDateTime() { return Cli_SetPlcSystemDateTime(Client); } //--------------------------------------------------------------------------- int TS7Client::GetOrderCode(PS7OrderCode pUsrData) { return Cli_GetOrderCode(Client, pUsrData); } //--------------------------------------------------------------------------- int TS7Client::GetCpuInfo(PS7CpuInfo pUsrData) { return Cli_GetCpuInfo(Client, pUsrData); } //--------------------------------------------------------------------------- int TS7Client::GetCpInfo(PS7CpInfo pUsrData) { return Cli_GetCpInfo(Client, pUsrData); } //--------------------------------------------------------------------------- int TS7Client::ReadSZL(int ID, int Index, PS7SZL pUsrData, int *Size) { return Cli_ReadSZL(Client, ID, Index, pUsrData, Size); } //--------------------------------------------------------------------------- int TS7Client::ReadSZLList(PS7SZLList pUsrData, int *ItemsCount) { return Cli_ReadSZLList(Client, pUsrData, ItemsCount); } //--------------------------------------------------------------------------- int TS7Client::PlcHotStart() { return Cli_PlcHotStart(Client); } //--------------------------------------------------------------------------- int TS7Client::PlcColdStart() { return Cli_PlcColdStart(Client); } //--------------------------------------------------------------------------- int TS7Client::PlcStop() { return Cli_PlcStop(Client); } //--------------------------------------------------------------------------- int TS7Client::CopyRamToRom(int Timeout) { return Cli_CopyRamToRom(Client, Timeout); } //--------------------------------------------------------------------------- int TS7Client::Compress(int Timeout) { return Cli_Compress(Client, Timeout); } //--------------------------------------------------------------------------- int TS7Client::GetProtection(PS7Protection pUsrData) { return Cli_GetProtection(Client, pUsrData); } //--------------------------------------------------------------------------- int TS7Client::SetSessionPassword(char *Password) { return Cli_SetSessionPassword(Client, Password); } //--------------------------------------------------------------------------- int TS7Client::ClearSessionPassword() { return Cli_ClearSessionPassword(Client); } //--------------------------------------------------------------------------- int TS7Client::ExecTime() { int Time; int Result = Cli_GetExecTime(Client, &Time); if (Result==0) return Time; else return Result; } //--------------------------------------------------------------------------- int TS7Client::LastError() { int LastError; int Result =Cli_GetLastError(Client, &LastError); if (Result==0) return LastError; else return Result; } //--------------------------------------------------------------------------- int TS7Client::PDULength() { int Requested, Negotiated; if (Cli_GetPduLength(Client, &Requested, &Negotiated)==0) return Negotiated; else return 0; } //--------------------------------------------------------------------------- int TS7Client::PDURequested() { int Requested, Negotiated; if (Cli_GetPduLength(Client, &Requested, &Negotiated)==0) return Requested; else return 0; } //--------------------------------------------------------------------------- int TS7Client::PlcStatus() { int Status; int Result = Cli_GetPlcStatus(Client, &Status); if (Result==0) return Status; else return Result; } //--------------------------------------------------------------------------- bool TS7Client::Connected() { int ClientStatus; if (Cli_GetConnected(Client ,&ClientStatus)==0) return ClientStatus!=0; else return false; } //--------------------------------------------------------------------------- int TS7Client::SetAsCallback(pfn_CliCompletion pCompletion, void *usrPtr) { return Cli_SetAsCallback(Client, pCompletion, usrPtr); } //--------------------------------------------------------------------------- bool TS7Client::CheckAsCompletion(int *opResult) { return Cli_CheckAsCompletion(Client ,opResult)==JobComplete; } //--------------------------------------------------------------------------- int TS7Client::WaitAsCompletion(longword Timeout) { return Cli_WaitAsCompletion(Client, Timeout); } //--------------------------------------------------------------------------- int TS7Client::AsReadArea(int Area, int DBNumber, int Start, int Amount, int WordLen, void *pUsrData) { return Cli_AsReadArea(Client, Area, DBNumber, Start, Amount, WordLen, pUsrData); } //--------------------------------------------------------------------------- int TS7Client::AsWriteArea(int Area, int DBNumber, int Start, int Amount, int WordLen, void *pUsrData) { return Cli_AsWriteArea(Client, Area, DBNumber, Start, Amount, WordLen, pUsrData); } //--------------------------------------------------------------------------- int TS7Client::AsListBlocksOfType(int BlockType, PS7BlocksOfType pUsrData, int *ItemsCount) { return Cli_AsListBlocksOfType(Client, BlockType, pUsrData, ItemsCount); } //--------------------------------------------------------------------------- int TS7Client::AsReadSZL(int ID, int Index, PS7SZL pUsrData, int *Size) { return Cli_AsReadSZL(Client, ID, Index, pUsrData, Size); } //--------------------------------------------------------------------------- int TS7Client::AsReadSZLList(PS7SZLList pUsrData, int *ItemsCount) { return Cli_AsReadSZLList(Client, pUsrData, ItemsCount); } //--------------------------------------------------------------------------- int TS7Client::AsUpload(int BlockType, int BlockNum, void *pUsrData, int *Size) { return Cli_AsUpload(Client, BlockType, BlockNum, pUsrData, Size); } //--------------------------------------------------------------------------- int TS7Client::AsFullUpload(int BlockType, int BlockNum, void *pUsrData, int *Size) { return Cli_AsFullUpload(Client, BlockType, BlockNum, pUsrData, Size); } //--------------------------------------------------------------------------- int TS7Client::AsDownload(int BlockNum, void *pUsrData, int Size) { return Cli_AsDownload(Client, BlockNum, pUsrData, Size); } //--------------------------------------------------------------------------- int TS7Client::AsCopyRamToRom(int Timeout) { return Cli_AsCopyRamToRom(Client, Timeout); } //--------------------------------------------------------------------------- int TS7Client::AsCompress(int Timeout) { return Cli_AsCompress(Client, Timeout); } //--------------------------------------------------------------------------- int TS7Client::AsDBRead(int DBNumber, int Start, int Size, void *pUsrData) { return Cli_AsDBRead(Client, DBNumber, Start, Size, pUsrData); } //--------------------------------------------------------------------------- int TS7Client::AsDBWrite(int DBNumber, int Start, int Size, void *pUsrData) { return Cli_AsDBWrite(Client, DBNumber, Start, Size, pUsrData); } //--------------------------------------------------------------------------- int TS7Client::AsMBRead(int Start, int Size, void *pUsrData) { return Cli_AsMBRead(Client, Start, Size, pUsrData); } //--------------------------------------------------------------------------- int TS7Client::AsMBWrite(int Start, int Size, void *pUsrData) { return Cli_AsMBWrite(Client, Start, Size, pUsrData); } //--------------------------------------------------------------------------- int TS7Client::AsEBRead(int Start, int Size, void *pUsrData) { return Cli_AsEBRead(Client, Start, Size, pUsrData); } //--------------------------------------------------------------------------- int TS7Client::AsEBWrite(int Start, int Size, void *pUsrData) { return Cli_AsEBWrite(Client, Start, Size, pUsrData); } //--------------------------------------------------------------------------- int TS7Client::AsABRead(int Start, int Size, void *pUsrData) { return Cli_AsABRead(Client, Start, Size, pUsrData); } //--------------------------------------------------------------------------- int TS7Client::AsABWrite(int Start, int Size, void *pUsrData) { return Cli_AsABWrite(Client, Start, Size, pUsrData); } //--------------------------------------------------------------------------- int TS7Client::AsTMRead(int Start, int Amount, void *pUsrData) { return Cli_AsTMRead(Client, Start, Amount, pUsrData); } //--------------------------------------------------------------------------- int TS7Client::AsTMWrite(int Start, int Amount, void *pUsrData) { return Cli_AsTMWrite(Client, Start, Amount, pUsrData); } //--------------------------------------------------------------------------- int TS7Client::AsCTRead(int Start, int Amount, void *pUsrData) { return Cli_AsCTRead(Client, Start, Amount, pUsrData); } //--------------------------------------------------------------------------- int TS7Client::AsCTWrite(int Start, int Amount, void *pUsrData) { return Cli_AsCTWrite(Client, Start, Amount, pUsrData); } //--------------------------------------------------------------------------- int TS7Client::AsDBGet(int DBNumber, void *pUsrData, int *Size) { return Cli_AsDBGet(Client, DBNumber, pUsrData, Size); } //--------------------------------------------------------------------------- int TS7Client::AsDBFill(int DBNumber, int FillChar) { return Cli_AsDBFill(Client, DBNumber, FillChar); } //============================================================================== // SERVER //============================================================================== TS7Server::TS7Server() { Server=Srv_Create(); } //--------------------------------------------------------------------------- TS7Server::~TS7Server() { Srv_Destroy(&Server); } //--------------------------------------------------------------------------- int TS7Server::Start() { return Srv_Start(Server); } //--------------------------------------------------------------------------- int TS7Server::StartTo(const char *Address) { return Srv_StartTo(Server, Address); } //--------------------------------------------------------------------------- int TS7Server::Stop() { return Srv_Stop(Server); } //--------------------------------------------------------------------------- int TS7Server::GetParam(int ParamNumber, void *pValue) { return Srv_GetParam(Server, ParamNumber, pValue); } //--------------------------------------------------------------------------- int TS7Server::SetParam(int ParamNumber, void *pValue) { return Srv_SetParam(Server, ParamNumber, pValue); } //--------------------------------------------------------------------------- int TS7Server::SetEventsCallback(pfn_SrvCallBack PCallBack, void *UsrPtr) { return Srv_SetEventsCallback(Server, PCallBack, UsrPtr); } //--------------------------------------------------------------------------- int TS7Server::SetReadEventsCallback(pfn_SrvCallBack PCallBack, void *UsrPtr) { return Srv_SetReadEventsCallback(Server, PCallBack, UsrPtr); } //--------------------------------------------------------------------------- int TS7Server::SetRWAreaCallback(pfn_RWAreaCallBack PCallBack, void *UsrPtr) { return Srv_SetRWAreaCallback(Server, PCallBack, UsrPtr); } //--------------------------------------------------------------------------- bool TS7Server::PickEvent(TSrvEvent *pEvent) { int EvtReady; if (Srv_PickEvent(Server, pEvent, &EvtReady)==0) return EvtReady!=0; else return false; } //--------------------------------------------------------------------------- void TS7Server::ClearEvents() { Srv_ClearEvents(Server); } //--------------------------------------------------------------------------- longword TS7Server::GetEventsMask() { longword Mask; int Result = Srv_GetMask(Server, mkEvent, &Mask); if (Result==0) return Mask; else return 0; } //--------------------------------------------------------------------------- longword TS7Server::GetLogMask() { longword Mask; int Result = Srv_GetMask(Server, mkLog, &Mask); if (Result==0) return Mask; else return 0; } //--------------------------------------------------------------------------- void TS7Server::SetEventsMask(longword Mask) { Srv_SetMask(Server, mkEvent, Mask); } //--------------------------------------------------------------------------- void TS7Server::SetLogMask(longword Mask) { Srv_SetMask(Server, mkLog, Mask); } //--------------------------------------------------------------------------- int TS7Server::RegisterArea(int AreaCode, word Index, void *pUsrData, word Size) { return Srv_RegisterArea(Server, AreaCode, Index, pUsrData, Size); } //--------------------------------------------------------------------------- int TS7Server::UnregisterArea(int AreaCode, word Index) { return Srv_UnregisterArea(Server, AreaCode, Index); } //--------------------------------------------------------------------------- int TS7Server::LockArea(int AreaCode, word Index) { return Srv_LockArea(Server, AreaCode, Index); } //--------------------------------------------------------------------------- int TS7Server::UnlockArea(int AreaCode, word Index) { return Srv_UnlockArea(Server, AreaCode, Index); } //--------------------------------------------------------------------------- int TS7Server::ServerStatus() { int ServerStatus, CpuStatus, ClientsCount; int Result =Srv_GetStatus(Server, &ServerStatus, &CpuStatus, &ClientsCount); if (Result==0) return ServerStatus; else return Result; } //--------------------------------------------------------------------------- int TS7Server::GetCpuStatus() { int ServerStatus, CpuStatus, ClientsCount; int Result =Srv_GetStatus(Server, &ServerStatus, &CpuStatus, &ClientsCount); if (Result==0) return CpuStatus; else return Result; } //--------------------------------------------------------------------------- int TS7Server::ClientsCount() { int ServerStatus, CpuStatus, ClientsCount; int Result =Srv_GetStatus(Server, &ServerStatus, &CpuStatus, &ClientsCount); if (Result==0) return ClientsCount; else return Result; } //--------------------------------------------------------------------------- int TS7Server::SetCpuStatus(int Status) { return Srv_SetCpuStatus(Server, Status); } //============================================================================== // PARTNER //============================================================================== TS7Partner::TS7Partner(bool Active) { Partner=Par_Create(int(Active)); } //--------------------------------------------------------------------------- TS7Partner::~TS7Partner() { Par_Destroy(&Partner); } //--------------------------------------------------------------------------- int TS7Partner::GetParam(int ParamNumber, void *pValue) { return Par_GetParam(Partner, ParamNumber, pValue); } //--------------------------------------------------------------------------- int TS7Partner::SetParam(int ParamNumber, void *pValue) { return Par_SetParam(Partner, ParamNumber, pValue); } //--------------------------------------------------------------------------- int TS7Partner::Start() { return Par_Start(Partner); } //--------------------------------------------------------------------------- int TS7Partner::StartTo(const char *LocalAddress, const char *RemoteAddress, int LocalTSAP, int RemoteTSAP) { return Par_StartTo(Partner, LocalAddress, RemoteAddress, LocalTSAP, RemoteTSAP); } //--------------------------------------------------------------------------- int TS7Partner::Stop() { return Par_Stop(Partner); } //--------------------------------------------------------------------------- int TS7Partner::BSend(longword R_ID, void *pUsrData, int Size) { return Par_BSend(Partner, R_ID, pUsrData, Size); } //--------------------------------------------------------------------------- int TS7Partner::AsBSend(longword R_ID, void *pUsrData, int Size) { return Par_AsBSend(Partner, R_ID, pUsrData, Size); } //--------------------------------------------------------------------------- bool TS7Partner::CheckAsBSendCompletion(int *opResult) { return Par_CheckAsBSendCompletion(Partner ,opResult)==JobComplete; } //--------------------------------------------------------------------------- int TS7Partner::WaitAsBSendCompletion(longword Timeout) { return Par_WaitAsBSendCompletion(Partner, Timeout); } //--------------------------------------------------------------------------- int TS7Partner::SetSendCallback(pfn_ParSendCompletion pCompletion, void *usrPtr) { return Par_SetSendCallback(Partner, pCompletion, usrPtr); } //--------------------------------------------------------------------------- int TS7Partner::BRecv(longword *R_ID, void *pUsrData, int *Size, longword Timeout) { return Par_BRecv(Partner, R_ID, pUsrData, Size, Timeout); } //--------------------------------------------------------------------------- bool TS7Partner::CheckAsBRecvCompletion(int *opResult, longword *R_ID, void *pUsrData, int *Size) { return Par_CheckAsBRecvCompletion(Partner, opResult, R_ID, pUsrData, Size) == JobComplete; } //--------------------------------------------------------------------------- int TS7Partner::SetRecvCallback(pfn_ParRecvCallBack pCallback, void *usrPtr) { return Par_SetRecvCallback(Partner, pCallback, usrPtr); } //--------------------------------------------------------------------------- int TS7Partner::Status() { int ParStatus; int Result = Par_GetStatus(Partner, &ParStatus); if (Result==0) return ParStatus; else return Result; } //--------------------------------------------------------------------------- int TS7Partner::LastError() { int Error; int Result = Par_GetLastError(Partner, &Error); if (Result==0) return Error; else return Result; } //--------------------------------------------------------------------------- int TS7Partner::GetTimes(longword *SendTime, longword *RecvTime) { return Par_GetTimes(Partner, SendTime, RecvTime); } //--------------------------------------------------------------------------- int TS7Partner::GetStats(longword *BytesSent, longword *BytesRecv, longword *ErrSend, longword *ErrRecv) { return Par_GetStats(Partner, BytesSent, BytesRecv, ErrSend, ErrRecv); } //--------------------------------------------------------------------------- bool TS7Partner::Linked() { return Status()==par_linked; } //============================================================================== // Text routines //============================================================================== TextString CliErrorText(int Error) { char text[TextLen]; Cli_ErrorText(Error, text, TextLen); return TextString(text); } //--------------------------------------------------------------------------- TextString SrvErrorText(int Error) { char text[TextLen]; Srv_ErrorText(Error, text, TextLen); return TextString(text); } //--------------------------------------------------------------------------- TextString ParErrorText(int Error) { char text[TextLen]; Par_ErrorText(Error, text, TextLen); return TextString(text); } //--------------------------------------------------------------------------- TextString SrvEventText(TSrvEvent *Event) { char text[TextLen]; Srv_EventText(Event, text, TextLen); return TextString(text); } ================================================ FILE: src/snap7.h ================================================ /*=============================================================================| | PROJECT SNAP7 1.4.0 | |==============================================================================| | Copyright (C) 2013, 2014 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/ | |==============================================================================| | | | C/C++ Snap 7 classes/Imports definitions | | | |=============================================================================*/ #ifndef snap7_h #define snap7_h //--------------------------------------------------------------------------- // Platform detection //--------------------------------------------------------------------------- #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) # define _USE_32BIT_TIME_T #endif #if defined(unix) || defined(__unix__) || defined(__unix) # define PLATFORM_UNIX #endif #if defined(__SVR4) || defined(__svr4__) # define OS_SOLARIS #endif #if BSD>=0 # define OS_BSD #endif #if defined(__APPLE__) # define OS_OSX #endif #if defined(PLATFORM_UNIX) || defined(OS_OSX) # include # if defined(_POSIX_VERSION) # define POSIX # endif #endif //--------------------------------------------------------------------------- // C++ Library //--------------------------------------------------------------------------- #ifdef __cplusplus #include #include // 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 extern "C" { #endif //--------------------------------------------------------------------------- // C exact length types //--------------------------------------------------------------------------- #ifndef __cplusplus #ifdef OS_BSD # include # include #endif #ifdef OS_OSX # include # include #endif #ifdef OS_SOLARIS # include # include #endif #if defined(_UINTPTR_T_DEFINED) # include # include #endif #if !defined(_UINTPTR_T_DEFINED) && !defined(OS_SOLARIS) && !defined(OS_BSD) && !defined(OS_OSX) typedef unsigned char uint8_t; // 8 bit unsigned integer typedef unsigned short uint16_t; // 16 bit unsigned integer typedef unsigned int uint32_t; // 32 bit unsigned integer typedef unsigned long uintptr_t;// 64 bit unsigned integer #endif #endif #ifdef OS_WINDOWS # define S7API __stdcall #else # define S7API #endif #pragma pack(1) //****************************************************************************** // COMMON //****************************************************************************** // Exact length types regardless of platform/processor typedef uint8_t byte; typedef uint16_t word; typedef uint32_t longword; typedef byte *pbyte; typedef word *pword; typedef uintptr_t S7Object; // multi platform/processor object reference // DON'T CONFUSE IT WITH AN OLE OBJECT, IT'S SIMPLY // AN INTEGER VALUE (32 OR 64 BIT) USED AS HANDLE. #ifndef __cplusplus typedef struct { int tm_sec; int tm_min; int tm_hour; int tm_mday; int tm_mon; int tm_year; int tm_wday; int tm_yday; int tm_isdst; }tm; typedef int bool; #define false 0; #define true 1; #endif const int errLibInvalidParam = -1; const int errLibInvalidObject = -2; // CPU status #define S7CpuStatusUnknown 0x00 #define S7CpuStatusRun 0x08 #define S7CpuStatusStop 0x04 // ISO Errors const longword errIsoConnect = 0x00010000; // Connection error const longword errIsoDisconnect = 0x00020000; // Disconnect error const longword errIsoInvalidPDU = 0x00030000; // Bad format const longword errIsoInvalidDataSize = 0x00040000; // Bad Datasize passed to send/recv buffer is invalid const longword errIsoNullPointer = 0x00050000; // Null passed as pointer const longword errIsoShortPacket = 0x00060000; // A short packet received const longword errIsoTooManyFragments = 0x00070000; // Too many packets without EoT flag const longword errIsoPduOverflow = 0x00080000; // The sum of fragments data exceded maximum packet size const longword errIsoSendPacket = 0x00090000; // An error occurred during send const longword errIsoRecvPacket = 0x000A0000; // An error occurred during recv const longword errIsoInvalidParams = 0x000B0000; // Invalid TSAP params const longword errIsoResvd_1 = 0x000C0000; // Unassigned const longword errIsoResvd_2 = 0x000D0000; // Unassigned const longword errIsoResvd_3 = 0x000E0000; // Unassigned const longword errIsoResvd_4 = 0x000F0000; // Unassigned // Tag Struct typedef struct{ int Area; int DBNumber; int Start; int Size; int WordLen; }TS7Tag, *PS7Tag; //------------------------------------------------------------------------------ // PARAMS LIST //------------------------------------------------------------------------------ const int p_u16_LocalPort = 1; const int p_u16_RemotePort = 2; const int p_i32_PingTimeout = 3; const int p_i32_SendTimeout = 4; const int p_i32_RecvTimeout = 5; const int p_i32_WorkInterval = 6; const int p_u16_SrcRef = 7; const int p_u16_DstRef = 8; const int p_u16_SrcTSap = 9; const int p_i32_PDURequest = 10; const int p_i32_MaxClients = 11; const int p_i32_BSendTimeout = 12; const int p_i32_BRecvTimeout = 13; const int p_u32_RecoveryTime = 14; const int p_u32_KeepAliveTime = 15; // Client/Partner Job status const int JobComplete = 0; const int JobPending = 1; //****************************************************************************** // CLIENT //****************************************************************************** // Error codes const longword errNegotiatingPDU = 0x00100000; const longword errCliInvalidParams = 0x00200000; const longword errCliJobPending = 0x00300000; const longword errCliTooManyItems = 0x00400000; const longword errCliInvalidWordLen = 0x00500000; const longword errCliPartialDataWritten = 0x00600000; const longword errCliSizeOverPDU = 0x00700000; const longword errCliInvalidPlcAnswer = 0x00800000; const longword errCliAddressOutOfRange = 0x00900000; const longword errCliInvalidTransportSize = 0x00A00000; const longword errCliWriteDataSizeMismatch = 0x00B00000; const longword errCliItemNotAvailable = 0x00C00000; const longword errCliInvalidValue = 0x00D00000; const longword errCliCannotStartPLC = 0x00E00000; const longword errCliAlreadyRun = 0x00F00000; const longword errCliCannotStopPLC = 0x01000000; const longword errCliCannotCopyRamToRom = 0x01100000; const longword errCliCannotCompress = 0x01200000; const longword errCliAlreadyStop = 0x01300000; const longword errCliFunNotAvailable = 0x01400000; const longword errCliUploadSequenceFailed = 0x01500000; const longword errCliInvalidDataSizeRecvd = 0x01600000; const longword errCliInvalidBlockType = 0x01700000; const longword errCliInvalidBlockNumber = 0x01800000; const longword errCliInvalidBlockSize = 0x01900000; const longword errCliDownloadSequenceFailed = 0x01A00000; const longword errCliInsertRefused = 0x01B00000; const longword errCliDeleteRefused = 0x01C00000; const longword errCliNeedPassword = 0x01D00000; const longword errCliInvalidPassword = 0x01E00000; const longword errCliNoPasswordToSetOrClear = 0x01F00000; const longword errCliJobTimeout = 0x02000000; const longword errCliPartialDataRead = 0x02100000; const longword errCliBufferTooSmall = 0x02200000; const longword errCliFunctionRefused = 0x02300000; const longword errCliDestroying = 0x02400000; const longword errCliInvalidParamNumber = 0x02500000; const longword errCliCannotChangeParam = 0x02600000; const int MaxVars = 20; // Max vars that can be transferred with MultiRead/MultiWrite // Client Connection Type const word CONNTYPE_PG = 0x0001; // Connect to the PLC as a PG const word CONNTYPE_OP = 0x0002; // Connect to the PLC as an OP const word CONNTYPE_BASIC = 0x0003; // Basic connection // Area ID const byte S7AreaPE = 0x81; const byte S7AreaPA = 0x82; const byte S7AreaMK = 0x83; const byte S7AreaDB = 0x84; const byte S7AreaCT = 0x1C; const byte S7AreaTM = 0x1D; // Word Length const int S7WLBit = 0x01; const int S7WLByte = 0x02; const int S7WLWord = 0x04; const int S7WLDWord = 0x06; const int S7WLReal = 0x08; const int S7WLCounter = 0x1C; const int S7WLTimer = 0x1D; // Block type const byte Block_OB = 0x38; const byte Block_DB = 0x41; const byte Block_SDB = 0x42; const byte Block_FC = 0x43; const byte Block_SFC = 0x44; const byte Block_FB = 0x45; const byte Block_SFB = 0x46; // Sub Block Type const byte SubBlk_OB = 0x08; const byte SubBlk_DB = 0x0A; const byte SubBlk_SDB = 0x0B; const byte SubBlk_FC = 0x0C; const byte SubBlk_SFC = 0x0D; const byte SubBlk_FB = 0x0E; const byte SubBlk_SFB = 0x0F; // Block languages const byte BlockLangAWL = 0x01; const byte BlockLangKOP = 0x02; const byte BlockLangFUP = 0x03; const byte BlockLangSCL = 0x04; const byte BlockLangDB = 0x05; const byte BlockLangGRAPH = 0x06; // Read/Write Multivars typedef struct{ int Area; int WordLen; int Result; int DBNumber; int Start; int Amount; void *pdata; } TS7DataItem, *PS7DataItem; //typedef int TS7ResultItems[MaxVars]; //typedef TS7ResultItems *PS7ResultItems; // List Blocks typedef struct { int OBCount; int FBCount; int FCCount; int SFBCount; int SFCCount; int DBCount; int SDBCount; } TS7BlocksList, *PS7BlocksList; // Blocks info typedef struct { int BlkType; // Block Type (OB, DB) int BlkNumber; // Block number int BlkLang; // Block Language int BlkFlags; // Block flags int MC7Size; // The real size in bytes int LoadSize; // Load memory size int LocalData; // Local data int SBBLength; // SBB Length int CheckSum; // Checksum int Version; // Block version // Chars info char CodeDate[11]; // Code date char IntfDate[11]; // Interface date char Author[9]; // Author char Family[9]; // Family char Header[9]; // Header } TS7BlockInfo, *PS7BlockInfo ; typedef word TS7BlocksOfType[0x2000]; typedef TS7BlocksOfType *PS7BlocksOfType; // Order code typedef struct { char Code[21]; byte V1; byte V2; byte V3; } TS7OrderCode, *PS7OrderCode; // CPU Info typedef struct { char ModuleTypeName[33]; char SerialNumber[25]; char ASName[25]; char Copyright[27]; char ModuleName[25]; } TS7CpuInfo, *PS7CpuInfo; // CP Info typedef struct { int MaxPduLengt; int MaxConnections; int MaxMpiRate; int MaxBusRate; } TS7CpInfo, *PS7CpInfo; // See §33.1 of "System Software for S7-300/400 System and Standard Functions" // and see SFC51 description too typedef struct { word LENTHDR; word N_DR; } SZL_HEADER, *PSZL_HEADER; typedef struct { SZL_HEADER Header; byte Data[0x4000-4]; } TS7SZL, *PS7SZL; // SZL List of available SZL IDs : same as SZL but List items are big-endian adjusted typedef struct { SZL_HEADER Header; word List[0x2000-2]; } TS7SZLList, *PS7SZLList; // See §33.19 of "System Software for S7-300/400 System and Standard Functions" typedef struct { word sch_schal; word sch_par; word sch_rel; word bart_sch; word anl_sch; } TS7Protection, *PS7Protection; // Client completion callback typedef void (S7API *pfn_CliCompletion) (void *usrPtr, int opCode, int opResult); //------------------------------------------------------------------------------ // Import prototypes //------------------------------------------------------------------------------ S7Object S7API Cli_Create(); void S7API Cli_Destroy(S7Object *Client); int S7API Cli_ConnectTo(S7Object Client, const char *Address, int Rack, int Slot); int S7API Cli_SetConnectionParams(S7Object Client, const char *Address, word LocalTSAP, word RemoteTSAP); int S7API Cli_SetConnectionType(S7Object Client, word ConnectionType); int S7API Cli_Connect(S7Object Client); int S7API Cli_Disconnect(S7Object Client); int S7API Cli_GetParam(S7Object Client, int ParamNumber, void *pValue); int S7API Cli_SetParam(S7Object Client, int ParamNumber, void *pValue); int S7API Cli_SetAsCallback(S7Object Client, pfn_CliCompletion pCompletion, void *usrPtr); // Data I/O main functions int S7API Cli_ReadArea(S7Object Client, int Area, int DBNumber, int Start, int Amount, int WordLen, void *pUsrData); int S7API Cli_WriteArea(S7Object Client, int Area, int DBNumber, int Start, int Amount, int WordLen, void *pUsrData); int S7API Cli_ReadMultiVars(S7Object Client, PS7DataItem Item, int ItemsCount); int S7API Cli_WriteMultiVars(S7Object Client, PS7DataItem Item, int ItemsCount); // Data I/O Lean functions int S7API Cli_DBRead(S7Object Client, int DBNumber, int Start, int Size, void *pUsrData); int S7API Cli_DBWrite(S7Object Client, int DBNumber, int Start, int Size, void *pUsrData); int S7API Cli_MBRead(S7Object Client, int Start, int Size, void *pUsrData); int S7API Cli_MBWrite(S7Object Client, int Start, int Size, void *pUsrData); int S7API Cli_EBRead(S7Object Client, int Start, int Size, void *pUsrData); int S7API Cli_EBWrite(S7Object Client, int Start, int Size, void *pUsrData); int S7API Cli_ABRead(S7Object Client, int Start, int Size, void *pUsrData); int S7API Cli_ABWrite(S7Object Client, int Start, int Size, void *pUsrData); int S7API Cli_TMRead(S7Object Client, int Start, int Amount, void *pUsrData); int S7API Cli_TMWrite(S7Object Client, int Start, int Amount, void *pUsrData); int S7API Cli_CTRead(S7Object Client, int Start, int Amount, void *pUsrData); int S7API Cli_CTWrite(S7Object Client, int Start, int Amount, void *pUsrData); // Directory functions int S7API Cli_ListBlocks(S7Object Client, TS7BlocksList *pUsrData); int S7API Cli_GetAgBlockInfo(S7Object Client, int BlockType, int BlockNum, TS7BlockInfo *pUsrData); int S7API Cli_GetPgBlockInfo(S7Object Client, void *pBlock, TS7BlockInfo *pUsrData, int Size); int S7API Cli_ListBlocksOfType(S7Object Client, int BlockType, TS7BlocksOfType *pUsrData, int *ItemsCount); // Blocks functions int S7API Cli_Upload(S7Object Client, int BlockType, int BlockNum, void *pUsrData, int *Size); int S7API Cli_FullUpload(S7Object Client, int BlockType, int BlockNum, void *pUsrData, int *Size); int S7API Cli_Download(S7Object Client, int BlockNum, void *pUsrData, int Size); int S7API Cli_Delete(S7Object Client, int BlockType, int BlockNum); int S7API Cli_DBGet(S7Object Client, int DBNumber, void *pUsrData, int *Size); int S7API Cli_DBFill(S7Object Client, int DBNumber, int FillChar); // Date/Time functions int S7API Cli_GetPlcDateTime(S7Object Client, tm *DateTime); int S7API Cli_SetPlcDateTime(S7Object Client, tm *DateTime); int S7API Cli_SetPlcSystemDateTime(S7Object Client); // System Info functions int S7API Cli_GetOrderCode(S7Object Client, TS7OrderCode *pUsrData); int S7API Cli_GetCpuInfo(S7Object Client, TS7CpuInfo *pUsrData); int S7API Cli_GetCpInfo(S7Object Client, TS7CpInfo *pUsrData); int S7API Cli_ReadSZL(S7Object Client, int ID, int Index, TS7SZL *pUsrData, int *Size); int S7API Cli_ReadSZLList(S7Object Client, TS7SZLList *pUsrData, int *ItemsCount); // Control functions int S7API Cli_PlcHotStart(S7Object Client); int S7API Cli_PlcColdStart(S7Object Client); int S7API Cli_PlcStop(S7Object Client); int S7API Cli_CopyRamToRom(S7Object Client, int Timeout); int S7API Cli_Compress(S7Object Client, int Timeout); int S7API Cli_GetPlcStatus(S7Object Client, int *Status); // Security functions int S7API Cli_GetProtection(S7Object Client, TS7Protection *pUsrData); int S7API Cli_SetSessionPassword(S7Object Client, char *Password); int S7API Cli_ClearSessionPassword(S7Object Client); // Low level int S7API Cli_IsoExchangeBuffer(S7Object Client, void *pUsrData, int *Size); // Misc int S7API Cli_GetExecTime(S7Object Client, int *Time); int S7API Cli_GetLastError(S7Object Client, int *LastError); int S7API Cli_GetPduLength(S7Object Client, int *Requested, int *Negotiated); int S7API Cli_ErrorText(int Error, char *Text, int TextLen); // 1.1.0 int S7API Cli_GetConnected(S7Object Client, int *Connected); //------------------------------------------------------------------------------ // Async functions //------------------------------------------------------------------------------ int S7API Cli_AsReadArea(S7Object Client, int Area, int DBNumber, int Start, int Amount, int WordLen, void *pUsrData); int S7API Cli_AsWriteArea(S7Object Client, int Area, int DBNumber, int Start, int Amount, int WordLen, void *pUsrData); int S7API Cli_AsDBRead(S7Object Client, int DBNumber, int Start, int Size, void *pUsrData); int S7API Cli_AsDBWrite(S7Object Client, int DBNumber, int Start, int Size, void *pUsrData); int S7API Cli_AsMBRead(S7Object Client, int Start, int Size, void *pUsrData); int S7API Cli_AsMBWrite(S7Object Client, int Start, int Size, void *pUsrData); int S7API Cli_AsEBRead(S7Object Client, int Start, int Size, void *pUsrData); int S7API Cli_AsEBWrite(S7Object Client, int Start, int Size, void *pUsrData); int S7API Cli_AsABRead(S7Object Client, int Start, int Size, void *pUsrData); int S7API Cli_AsABWrite(S7Object Client, int Start, int Size, void *pUsrData); int S7API Cli_AsTMRead(S7Object Client, int Start, int Amount, void *pUsrData); int S7API Cli_AsTMWrite(S7Object Client, int Start, int Amount, void *pUsrData); int S7API Cli_AsCTRead(S7Object Client, int Start, int Amount, void *pUsrData); int S7API Cli_AsCTWrite(S7Object Client, int Start, int Amount, void *pUsrData); int S7API Cli_AsListBlocksOfType(S7Object Client, int BlockType, TS7BlocksOfType *pUsrData, int *ItemsCount); int S7API Cli_AsReadSZL(S7Object Client, int ID, int Index, TS7SZL *pUsrData, int *Size); int S7API Cli_AsReadSZLList(S7Object Client, TS7SZLList *pUsrData, int *ItemsCount); int S7API Cli_AsUpload(S7Object Client, int BlockType, int BlockNum, void *pUsrData, int *Size); int S7API Cli_AsFullUpload(S7Object Client, int BlockType, int BlockNum, void *pUsrData, int *Size); int S7API Cli_AsDownload(S7Object Client, int BlockNum, void *pUsrData, int Size); int S7API Cli_AsCopyRamToRom(S7Object Client, int Timeout); int S7API Cli_AsCompress(S7Object Client, int Timeout); int S7API Cli_AsDBGet(S7Object Client, int DBNumber, void *pUsrData, int *Size); int S7API Cli_AsDBFill(S7Object Client, int DBNumber, int FillChar); int S7API Cli_CheckAsCompletion(S7Object Client, int *opResult); int S7API Cli_WaitAsCompletion(S7Object Client, int Timeout); //****************************************************************************** // SERVER //****************************************************************************** const int OperationRead = 0; const int OperationWrite = 1; const int mkEvent = 0; const int mkLog = 1; // Server Area ID (use with Register/unregister - Lock/unlock Area) const int srvAreaPE = 0; const int srvAreaPA = 1; const int srvAreaMK = 2; const int srvAreaCT = 3; const int srvAreaTM = 4; const int srvAreaDB = 5; // Errors const longword errSrvCannotStart = 0x00100000; // Server cannot start const longword errSrvDBNullPointer = 0x00200000; // Passed null as PData const longword errSrvAreaAlreadyExists = 0x00300000; // Area Re-registration const longword errSrvUnknownArea = 0x00400000; // Unknown area const longword errSrvInvalidParams = 0x00500000; // Invalid param(s) supplied const longword errSrvTooManyDB = 0x00600000; // Cannot register DB const longword errSrvInvalidParamNumber = 0x00700000; // Invalid param (srv_get/set_param) const longword errSrvCannotChangeParam = 0x00800000; // Cannot change because running // TCP Server Event codes const longword evcServerStarted = 0x00000001; const longword evcServerStopped = 0x00000002; const longword evcListenerCannotStart = 0x00000004; const longword evcClientAdded = 0x00000008; const longword evcClientRejected = 0x00000010; const longword evcClientNoRoom = 0x00000020; const longword evcClientException = 0x00000040; const longword evcClientDisconnected = 0x00000080; const longword evcClientTerminated = 0x00000100; const longword evcClientsDropped = 0x00000200; const longword evcReserved_00000400 = 0x00000400; // actually unused const longword evcReserved_00000800 = 0x00000800; // actually unused const longword evcReserved_00001000 = 0x00001000; // actually unused const longword evcReserved_00002000 = 0x00002000; // actually unused const longword evcReserved_00004000 = 0x00004000; // actually unused const longword evcReserved_00008000 = 0x00008000; // actually unused // S7 Server Event Code const longword evcPDUincoming = 0x00010000; const longword evcDataRead = 0x00020000; const longword evcDataWrite = 0x00040000; const longword evcNegotiatePDU = 0x00080000; const longword evcReadSZL = 0x00100000; const longword evcClock = 0x00200000; const longword evcUpload = 0x00400000; const longword evcDownload = 0x00800000; const longword evcDirectory = 0x01000000; const longword evcSecurity = 0x02000000; const longword evcControl = 0x04000000; const longword evcReserved_08000000 = 0x08000000; // actually unused const longword evcReserved_10000000 = 0x10000000; // actually unused const longword evcReserved_20000000 = 0x20000000; // actually unused const longword evcReserved_40000000 = 0x40000000; // actually unused const longword evcReserved_80000000 = 0x80000000; // actually unused // Masks to enable/disable all events const longword evcAll = 0xFFFFFFFF; const longword evcNone = 0x00000000; // Event SubCodes const word evsUnknown = 0x0000; const word evsStartUpload = 0x0001; const word evsStartDownload = 0x0001; const word evsGetBlockList = 0x0001; const word evsStartListBoT = 0x0002; const word evsListBoT = 0x0003; const word evsGetBlockInfo = 0x0004; const word evsGetClock = 0x0001; const word evsSetClock = 0x0002; const word evsSetPassword = 0x0001; const word evsClrPassword = 0x0002; // Event Params : functions group const word grProgrammer = 0x0041; const word grCyclicData = 0x0042; const word grBlocksInfo = 0x0043; const word grSZL = 0x0044; const word grPassword = 0x0045; const word grBSend = 0x0046; const word grClock = 0x0047; const word grSecurity = 0x0045; // Event Params : control codes const word CodeControlUnknown = 0x0000; const word CodeControlColdStart = 0x0001; const word CodeControlWarmStart = 0x0002; const word CodeControlStop = 0x0003; const word CodeControlCompress = 0x0004; const word CodeControlCpyRamRom = 0x0005; const word CodeControlInsDel = 0x0006; // Event Result const word evrNoError = 0x0000; const word evrFragmentRejected = 0x0001; const word evrMalformedPDU = 0x0002; const word evrSparseBytes = 0x0003; const word evrCannotHandlePDU = 0x0004; const word evrNotImplemented = 0x0005; const word evrErrException = 0x0006; const word evrErrAreaNotFound = 0x0007; const word evrErrOutOfRange = 0x0008; const word evrErrOverPDU = 0x0009; const word evrErrTransportSize = 0x000A; const word evrInvalidGroupUData = 0x000B; const word evrInvalidSZL = 0x000C; const word evrDataSizeMismatch = 0x000D; const word evrCannotUpload = 0x000E; const word evrCannotDownload = 0x000F; const word evrUploadInvalidID = 0x0010; const word evrResNotFound = 0x0011; typedef struct{ 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; // Server Events callback typedef void (S7API *pfn_SrvCallBack)(void *usrPtr, PSrvEvent PEvent, int Size); // Server Read/Write callback typedef int(S7API *pfn_RWAreaCallBack)(void *usrPtr, int Sender, int Operation, PS7Tag PTag, void *pUsrData); S7Object S7API Srv_Create(); void S7API Srv_Destroy(S7Object *Server); int S7API Srv_GetParam(S7Object Server, int ParamNumber, void *pValue); int S7API Srv_SetParam(S7Object Server, int ParamNumber, void *pValue); int S7API Srv_StartTo(S7Object Server, const char *Address); int S7API Srv_Start(S7Object Server); int S7API Srv_Stop(S7Object Server); int S7API Srv_RegisterArea(S7Object Server, int AreaCode, word Index, void *pUsrData, int Size); int S7API Srv_UnregisterArea(S7Object Server, int AreaCode, word Index); int S7API Srv_LockArea(S7Object Server, int AreaCode, word Index); int S7API Srv_UnlockArea(S7Object Server, int AreaCode, word Index); int S7API Srv_GetStatus(S7Object Server, int *ServerStatus, int *CpuStatus, int *ClientsCount); int S7API Srv_SetCpuStatus(S7Object Server, int CpuStatus); int S7API Srv_ClearEvents(S7Object Server); int S7API Srv_PickEvent(S7Object Server, TSrvEvent *pEvent, int *EvtReady); int S7API Srv_GetMask(S7Object Server, int MaskKind, longword *Mask); int S7API Srv_SetMask(S7Object Server, int MaskKind, longword Mask); int S7API Srv_SetEventsCallback(S7Object Server, pfn_SrvCallBack pCallback, void *usrPtr); int S7API Srv_SetReadEventsCallback(S7Object Server, pfn_SrvCallBack pCallback, void *usrPtr); int S7API Srv_SetRWAreaCallback(S7Object Server, pfn_RWAreaCallBack pCallback, void *usrPtr); int S7API Srv_EventText(TSrvEvent *Event, char *Text, int TextLen); int S7API Srv_ErrorText(int Error, char *Text, int TextLen); //****************************************************************************** // PARTNER //****************************************************************************** // Status const int par_stopped = 0; // stopped const int par_connecting = 1; // running and active connecting const int par_waiting = 2; // running and waiting for a connection const int par_linked = 3; // running and connected : linked const int par_sending = 4; // sending data const int par_receiving = 5; // receiving data const int par_binderror = 6; // error starting passive server // Errors const longword errParAddressInUse = 0x00200000; const longword errParNoRoom = 0x00300000; const longword errServerNoRoom = 0x00400000; const longword errParInvalidParams = 0x00500000; const longword errParNotLinked = 0x00600000; const longword errParBusy = 0x00700000; const longword errParFrameTimeout = 0x00800000; const longword errParInvalidPDU = 0x00900000; const longword errParSendTimeout = 0x00A00000; const longword errParRecvTimeout = 0x00B00000; const longword errParSendRefused = 0x00C00000; const longword errParNegotiatingPDU = 0x00D00000; const longword errParSendingBlock = 0x00E00000; const longword errParRecvingBlock = 0x00F00000; const longword errParBindError = 0x01000000; const longword errParDestroying = 0x01100000; const longword errParInvalidParamNumber = 0x01200000; // Invalid param (par_get/set_param) const longword errParCannotChangeParam = 0x01300000; // Cannot change because running const longword errParBufferTooSmall = 0x01400000; // Raised by LabVIEW wrapper // Brecv Data incoming Callback typedef void (S7API *pfn_ParRecvCallBack)(void * usrPtr, int opResult, longword R_ID, void *pData, int Size); // BSend Completion Callback typedef void (S7API *pfn_ParSendCompletion)(void * usrPtr, int opResult); S7Object S7API Par_Create(int Active); void S7API Par_Destroy(S7Object *Partner); int S7API Par_GetParam(S7Object Partner, int ParamNumber, void *pValue); int S7API Par_SetParam(S7Object Partner, int ParamNumber, void *pValue); int S7API Par_StartTo(S7Object Partner, const char *LocalAddress, const char *RemoteAddress, word LocTsap, word RemTsap); int S7API Par_Start(S7Object Partner); int S7API Par_Stop(S7Object Partner); // BSend int S7API Par_BSend(S7Object Partner, longword R_ID, void *pUsrData, int Size); int S7API Par_AsBSend(S7Object Partner, longword R_ID, void *pUsrData, int Size); int S7API Par_CheckAsBSendCompletion(S7Object Partner, int *opResult); int S7API Par_WaitAsBSendCompletion(S7Object Partner, longword Timeout); int S7API Par_SetSendCallback(S7Object Partner, pfn_ParSendCompletion pCompletion, void *usrPtr); // BRecv int S7API Par_BRecv(S7Object Partner, longword *R_ID, void *pData, int *Size, longword Timeout); int S7API Par_CheckAsBRecvCompletion(S7Object Partner, int *opResult, longword *R_ID, void *pData, int *Size); int S7API Par_SetRecvCallback(S7Object Partner, pfn_ParRecvCallBack pCompletion, void *usrPtr); // Stat int S7API Par_GetTimes(S7Object Partner, longword *SendTime, longword *RecvTime); int S7API Par_GetStats(S7Object Partner, longword *BytesSent, longword *BytesRecv, longword *SendErrors, longword *RecvErrors); int S7API Par_GetLastError(S7Object Partner, int *LastError); int S7API Par_GetStatus(S7Object Partner, int *Status); int S7API Par_ErrorText(int Error, char *Text, int TextLen); #pragma pack() #ifdef __cplusplus } #endif // __cplusplus #ifdef __cplusplus //****************************************************************************** // CLIENT CLASS DEFINITION //****************************************************************************** class TS7Client { private: S7Object Client; public: TS7Client(); ~TS7Client(); // Control functions int Connect(); int ConnectTo(const char *RemAddress, int Rack, int Slot); int SetConnectionParams(const char *RemAddress, word LocalTSAP, word RemoteTSAP); int SetConnectionType(word ConnectionType); int Disconnect(); int GetParam(int ParamNumber, void *pValue); int SetParam(int ParamNumber, void *pValue); // Data I/O Main functions int ReadArea(int Area, int DBNumber, int Start, int Amount, int WordLen, void *pUsrData); int WriteArea(int Area, int DBNumber, int Start, int Amount, int WordLen, void *pUsrData); int ReadMultiVars(PS7DataItem Item, int ItemsCount); int WriteMultiVars(PS7DataItem Item, int ItemsCount); // Data I/O Lean functions int DBRead(int DBNumber, int Start, int Size, void *pUsrData); int DBWrite(int DBNumber, int Start, int Size, void *pUsrData); int MBRead(int Start, int Size, void *pUsrData); int MBWrite(int Start, int Size, void *pUsrData); int EBRead(int Start, int Size, void *pUsrData); int EBWrite(int Start, int Size, void *pUsrData); int ABRead(int Start, int Size, void *pUsrData); int ABWrite(int Start, int Size, void *pUsrData); int TMRead(int Start, int Amount, void *pUsrData); int TMWrite(int Start, int Amount, void *pUsrData); int CTRead(int Start, int Amount, void *pUsrData); int CTWrite(int Start, int Amount, void *pUsrData); // Directory functions int ListBlocks(PS7BlocksList pUsrData); int GetAgBlockInfo(int BlockType, int BlockNum, PS7BlockInfo pUsrData); int GetPgBlockInfo(void *pBlock, PS7BlockInfo pUsrData, int Size); int ListBlocksOfType(int BlockType, TS7BlocksOfType *pUsrData, int *ItemsCount); // Blocks functions int Upload(int BlockType, int BlockNum, void *pUsrData, int *Size); int FullUpload(int BlockType, int BlockNum, void *pUsrData, int *Size); int Download(int BlockNum, void *pUsrData, int Size); int Delete(int BlockType, int BlockNum); int DBGet(int DBNumber, void *pUsrData, int *Size); int DBFill(int DBNumber, int FillChar); // Date/Time functions int GetPlcDateTime(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); // Security functions int GetProtection(PS7Protection pUsrData); int SetSessionPassword(char *Password); int ClearSessionPassword(); // Properties int ExecTime(); int LastError(); int PDURequested(); int PDULength(); int PlcStatus(); bool Connected(); // Async functions int SetAsCallback(pfn_CliCompletion pCompletion, void *usrPtr); bool CheckAsCompletion(int *opResult); int WaitAsCompletion(longword Timeout); int AsReadArea(int Area, int DBNumber, int Start, int Amount, int WordLen, void *pUsrData); int AsWriteArea(int Area, int DBNumber, int Start, int Amount, int WordLen, void *pUsrData); int AsListBlocksOfType(int BlockType, PS7BlocksOfType pUsrData, int *ItemsCount); int AsReadSZL(int ID, int Index, PS7SZL pUsrData, int *Size); int AsReadSZLList(PS7SZLList pUsrData, int *ItemsCount); int AsUpload(int BlockType, int BlockNum, void *pUsrData, int *Size); int AsFullUpload(int BlockType, int BlockNum, void *pUsrData, int *Size); int AsDownload(int BlockNum, void *pUsrData, int Size); int AsCopyRamToRom(int Timeout); int AsCompress(int Timeout); int AsDBRead(int DBNumber, int Start, int Size, void *pUsrData); int AsDBWrite(int DBNumber, int Start, int Size, void *pUsrData); int AsMBRead(int Start, int Size, void *pUsrData); int AsMBWrite(int Start, int Size, void *pUsrData); int AsEBRead(int Start, int Size, void *pUsrData); int AsEBWrite(int Start, int Size, void *pUsrData); int AsABRead(int Start, int Size, void *pUsrData); int AsABWrite(int Start, int Size, void *pUsrData); int AsTMRead(int Start, int Amount, void *pUsrData); int AsTMWrite(int Start, int Amount, void *pUsrData); int AsCTRead(int Start, int Amount, void *pUsrData); int AsCTWrite(int Start, int Amount, void *pUsrData); int AsDBGet(int DBNumber, void *pUsrData, int *Size); int AsDBFill(int DBNumber, int FillChar); }; typedef TS7Client *PS7Client; //****************************************************************************** // SERVER CLASS DEFINITION //****************************************************************************** class TS7Server { private: S7Object Server; public: TS7Server(); ~TS7Server(); // Control int Start(); int StartTo(const char *Address); int Stop(); int GetParam(int ParamNumber, void *pValue); int SetParam(int ParamNumber, void *pValue); // Events int SetEventsCallback(pfn_SrvCallBack PCallBack, void *UsrPtr); int SetReadEventsCallback(pfn_SrvCallBack PCallBack, void *UsrPtr); int SetRWAreaCallback(pfn_RWAreaCallBack PCallBack, void *UsrPtr); bool PickEvent(TSrvEvent *pEvent); void ClearEvents(); longword GetEventsMask(); longword GetLogMask(); void SetEventsMask(longword Mask); void SetLogMask(longword Mask); // Resources int RegisterArea(int AreaCode, word Index, void *pUsrData, word Size); int UnregisterArea(int AreaCode, word Index); int LockArea(int AreaCode, word Index); int UnlockArea(int AreaCode, word Index); // Properties int ServerStatus(); int GetCpuStatus(); int SetCpuStatus(int Status); int ClientsCount(); }; typedef TS7Server *PS7Server; //****************************************************************************** // PARTNER CLASS DEFINITION //****************************************************************************** class TS7Partner { private: S7Object Partner; // Partner Handle public: TS7Partner(bool Active); ~TS7Partner(); // Control int GetParam(int ParamNumber, void *pValue); int SetParam(int ParamNumber, void *pValue); int Start(); int StartTo(const char *LocalAddress, const char *RemoteAddress, int LocalTSAP, int RemoteTSAP); int Stop(); // Data I/O functions : BSend int BSend(longword R_ID, void *pUsrData, int Size); int AsBSend(longword R_ID, void *pUsrData, int Size); bool CheckAsBSendCompletion(int *opResult); int WaitAsBSendCompletion(longword Timeout); int SetSendCallback(pfn_ParSendCompletion pCompletion, void *usrPtr); // Data I/O functions : BRecv int BRecv(longword *R_ID, void *pUsrData, int *Size, longword Timeout); bool CheckAsBRecvCompletion(int *opResult, longword *R_ID, void *pUsrData, int *Size); int SetRecvCallback(pfn_ParRecvCallBack pCallback, void *usrPtr); // Properties int Status(); int LastError(); int GetTimes(longword *SendTime, longword *RecvTime); int GetStats(longword *BytesSent, longword *BytesRecv, longword *ErrSend, longword *ErrRecv); bool Linked(); }; typedef TS7Partner *PS7Partner; //****************************************************************************** // TEXT ROUTINES // Only for C++, for pure C use xxx_ErrorText() which uses *char //****************************************************************************** #define TextLen 1024 // String type // Here we define generic TextString (by default mapped onto std::string). // So you can change it if needed (Unicodestring, Ansistring etc...) typedef std::string TextString; TextString CliErrorText(int Error); TextString SrvErrorText(int Error); TextString ParErrorText(int Error); TextString SrvEventText(TSrvEvent *Event); #endif // __cplusplus #endif // snap7_h