[
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ngithub: fbarresi\n"
  },
  {
    "path": ".gitignore",
    "content": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n##\n## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore\n\n# User-specific files\n*.suo\n*.user\n*.userosscache\n*.sln.docstates\n\n# User-specific files (MonoDevelop/Xamarin Studio)\n*.userprefs\n\n# Build results\n[Dd]ebug/\n[Dd]ebugPublic/\n[Rr]elease/\n[Rr]eleases/\nx64/\nx86/\nbld/\n[Bb]in/\n[Oo]bj/\n[Ll]og/\n\n# Visual Studio 2015 cache/options directory\n.vs/\n# Uncomment if you have tasks that create the project's static files in wwwroot\n#wwwroot/\n\n# MSTest test Results\n[Tt]est[Rr]esult*/\n[Bb]uild[Ll]og.*\n\n# NUNIT\n*.VisualState.xml\nTestResult.xml\n\n# Build Results of an ATL Project\n[Dd]ebugPS/\n[Rr]eleasePS/\ndlldata.c\n\n# .NET Core\nproject.lock.json\nproject.fragment.lock.json\nartifacts/\n**/Properties/launchSettings.json\n\n*_i.c\n*_p.c\n*_i.h\n*.ilk\n*.meta\n*.obj\n*.pch\n*.pdb\n*.pgc\n*.pgd\n*.rsp\n*.sbr\n*.tlb\n*.tli\n*.tlh\n*.tmp\n*.tmp_proj\n*.log\n*.vspscc\n*.vssscc\n.builds\n*.pidb\n*.svclog\n*.scc\n\n# Chutzpah Test files\n_Chutzpah*\n\n# Visual C++ cache files\nipch/\n*.aps\n*.ncb\n*.opendb\n*.opensdf\n*.sdf\n*.cachefile\n*.VC.db\n*.VC.VC.opendb\n\n# Visual Studio profiler\n*.psess\n*.vsp\n*.vspx\n*.sap\n\n# TFS 2012 Local Workspace\n$tf/\n\n# Guidance Automation Toolkit\n*.gpState\n\n# ReSharper is a .NET coding add-in\n_ReSharper*/\n*.[Rr]e[Ss]harper\n*.DotSettings.user\n\n# JustCode is a .NET coding add-in\n.JustCode\n\n# TeamCity is a build add-in\n_TeamCity*\n\n# DotCover is a Code Coverage Tool\n*.dotCover\n\n# Visual Studio code coverage results\n*.coverage\n*.coveragexml\n\n# NCrunch\n_NCrunch_*\n.*crunch*.local.xml\nnCrunchTemp_*\n\n# MightyMoose\n*.mm.*\nAutoTest.Net/\n\n# Web workbench (sass)\n.sass-cache/\n\n# Installshield output folder\n[Ee]xpress/\n\n# DocProject is a documentation generator add-in\nDocProject/buildhelp/\nDocProject/Help/*.HxT\nDocProject/Help/*.HxC\nDocProject/Help/*.hhc\nDocProject/Help/*.hhk\nDocProject/Help/*.hhp\nDocProject/Help/Html2\nDocProject/Help/html\n\n# Click-Once directory\npublish/\n\n# Publish Web Output\n*.[Pp]ublish.xml\n*.azurePubxml\n# TODO: Comment the next line if you want to checkin your web deploy settings\n# but database connection strings (with potential passwords) will be unencrypted\n*.pubxml\n*.publishproj\n\n# Microsoft Azure Web App publish settings. Comment the next line if you want to\n# checkin your Azure Web App publish settings, but sensitive information contained\n# in these scripts will be unencrypted\nPublishScripts/\n\n# NuGet Packages\n*.nupkg\n# The packages folder can be ignored because of Package Restore\n**/packages/*\n# except build/, which is used as an MSBuild target.\n!**/packages/build/\n# Uncomment if necessary however generally it will be regenerated when needed\n#!**/packages/repositories.config\n# NuGet v3's project.json files produces more ignorable files\n*.nuget.props\n*.nuget.targets\n\n# Microsoft Azure Build Output\ncsx/\n*.build.csdef\n\n# Microsoft Azure Emulator\necf/\nrcf/\n\n# Windows Store app package directories and files\nAppPackages/\nBundleArtifacts/\nPackage.StoreAssociation.xml\n_pkginfo.txt\n\n# Visual Studio cache files\n# files ending in .cache can be ignored\n*.[Cc]ache\n# but keep track of directories ending in .cache\n!*.[Cc]ache/\n\n# Others\nClientBin/\n~$*\n*~\n*.dbmdl\n*.dbproj.schemaview\n*.jfm\n*.pfx\n*.publishsettings\norleans.codegen.cs\n\n# Since there are multiple workflows, uncomment next line to ignore bower_components\n# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)\n#bower_components/\n\n# RIA/Silverlight projects\nGenerated_Code/\n\n# Backup & report files from converting an old project file\n# to a newer Visual Studio version. Backup files are not needed,\n# because we have git ;-)\n_UpgradeReport_Files/\nBackup*/\nUpgradeLog*.XML\nUpgradeLog*.htm\n\n# SQL Server files\n*.mdf\n*.ldf\n*.ndf\n\n# Business Intelligence projects\n*.rdl.data\n*.bim.layout\n*.bim_*.settings\n\n# Microsoft Fakes\nFakesAssemblies/\n\n# GhostDoc plugin setting file\n*.GhostDoc.xml\n\n# Node.js Tools for Visual Studio\n.ntvs_analysis.dat\nnode_modules/\n\n# Typescript v1 declaration files\ntypings/\n\n# Visual Studio 6 build log\n*.plg\n\n# Visual Studio 6 workspace options file\n*.opt\n\n# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)\n*.vbw\n\n# Visual Studio LightSwitch build output\n**/*.HTMLClient/GeneratedArtifacts\n**/*.DesktopClient/GeneratedArtifacts\n**/*.DesktopClient/ModelManifest.xml\n**/*.Server/GeneratedArtifacts\n**/*.Server/ModelManifest.xml\n_Pvt_Extensions\n\n# Paket dependency manager\n.paket/paket.exe\npaket-files/\n\n# FAKE - F# Make\n.fake/\n\n# JetBrains Rider\n.idea/\n*.sln.iml\n\n# CodeRush\n.cr/\n\n# Python Tools for Visual Studio (PTVS)\n__pycache__/\n*.pyc\n\n# Cake - Uncomment if you are using it\n# tools/**\n# !tools/packages.config\n\n# Telerik's JustMock configuration file\n*.jmconfig\n\n# BizTalk build output\n*.btp.cs\n*.btm.cs\n*.odx.cs\n*.xsd.cs\n\nrun_tests_and_coverage.bat\ncoverage/"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Change Log\nAll notable changed to this project will be documented in this file.\n\n## [1.1.84] - 11.05.2023\n### Added\n### Changed\n### Fixed\n- Fixed ReadSZL [#36](https://github.com/fbarresi/Sharp7/issues/36)\n\n## [1.1.82] - 18.05.2022\n### Added\n### Changed\n### Fixed\n- Fixed string length check into SetStringAt [#28](https://github.com/fbarresi/Sharp7/issues/28)\n\n## [1.1.81] - 18.05.2022\n### Added\n### Changed\n### Fixed\n- Removed obsolete SetBitAt  [#27](https://github.com/fbarresi/Sharp7/issues/27)\n\n## [1.1.80] - 18.05.2022\n### Added\n### Changed\n### Fixed\n- Fixed casting in GetIntAt [#29](https://github.com/fbarresi/Sharp7/issues/29)\n\n## [1.1.79] - 09.02.2021\n### Added\n- Constant for no errors `S7Consts.ResultOK`\n### Changed\n### Fixed\n\n## [1.1.78] - 04.02.2021\n### Added\n- Property `PLCIpAddress`\n- Overload of `ToString` for S7Client\n- Property `Name` as constructor param in S7Client\n### Changed\n### Fixed\n\n\n## [1.1.75] - 03.09.2020\n### Added\n### Changed\n- CHANGELOG.md\n- README.md\n### Fixed\n- [#18](https://github.com/fbarresi/Sharp7/issues/18)\n\t- New overloaded extension method signatures for SetBitAt\n\t- Removed not necessary casting to short for GetIntAt\n\t- Added overloads for S7 `Time_Of_Day` functions\n\t- Added more tests\n\t- made old methods obsolete\n\n## [1.1.71] - 14.08.2020\n### Added\n- CHANGELOG.md\n### Changed\n- README.md\n- Referenced changelog into nuget release notes\n### Fixed\n\n## [1.1.69] - 11.06.2020\n### Added\n### Changed\n- README.md\n### Fixed\n\n## [1.1.68] - 11.06.2020\n### Added\n- Added enums and methods overloads for S7Wordlength and S7Area (#11)\n### Changed\n- README.md\n- Changed properties to expression body solution wide\n- Changed S7 calls to extension methods\n- Usage of overloaded methods with enums instead of constants\n### Fixed\n- Check connection on socket close\n- Null propagation on disconnect method\n- Soved usage ob obsolete constants\n\n## [1.1.63] - 06.05.2020\n### Added\n### Changed\n### Fixed\n- style and security enhancement\n\n## [1.1.62] - 06.05.2020\n### Added\n### Changed\n### Fixed\n- Unused exception handling\n\n## [1.1.61] - 06.05.2020\n### Added\n### Changed\n### Fixed\n- Usage of Timeouts from [philfontaine/Sharp7@fb01cc0](https://github.com/philfontaine/Sharp7@fb01cc0)\n\n## [1.1.60] - 06.05.2020\n### Added\n### Changed\n### Fixed\n- connection check into overload of SendPacket (#8)\n\n## [1.1.59] - 06.05.2020\n### Added\n- Added unit tests\n### Changed\n- Created extension methods from S7\n### Fixed\n- Fixed naming rules\n\n## [1.0.50] - 17.11.2019\n### Added\n### Changed\n- README.md\n### Fixed\n\n## [1.0.49] - 17.11.2019\n### Added\n### Changed\n- README.md\n### Fixed\n\n## [1.0.48] - 17.11.2019\n### Added\n### Changed\n- README.md\n### Fixed\n\n## [1.0.25] - 02.04.2019\n### Added\n- Added nuget package description\n### Changed\n### Fixed\n\n## [1.0.22] - 17.01.2019\n### Added\n- Added debug symbols to Nuget\n### Changed\n### Fixed\n\n## [1.0.18] - 21.11.2018\n### Added\n### Changed\n- Migrate solution to project SDK (#2)\n### Fixed\n\n## [1.0.0] - 21.01.2018\n### Added\n- imported initial project from source forge\n### Changed\n### Fixed"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2018 Federico Barresi\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# ![Sharp7](https://raw.githubusercontent.com/fbarresi/sharp7/master/doc/images/logo.jpg)\n\n[![Build status](https://ci.appveyor.com/api/projects/status/2i77qfjjq8aep50b?svg=true)](https://ci.appveyor.com/project/fbarresi/sharp7)\n[![Codacy Badge](https://api.codacy.com/project/badge/Grade/4ff75e759a66416a84052769a71b70c6)](https://www.codacy.com/manual/fbarresi/Sharp7?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=fbarresi/Sharp7&amp;utm_campaign=Badge_Grade)\n[![codecov](https://codecov.io/gh/fbarresi/Sharp7/branch/master/graph/badge.svg)](https://codecov.io/gh/fbarresi/Sharp7)\n![Licence](https://img.shields.io/github/license/fbarresi/sharp7.svg)\n[![Nuget Version](https://img.shields.io/nuget/v/Sharp7.svg)](https://www.nuget.org/packages/Sharp7/)\n\nNuget package for Sharp7 - The multi-platform Ethernet S7 PLC communication suite\n\nSharp7 is a C# port of [Snap7](http://snap7.sourceforge.net) library\n\nFor usage and documentation you can visit the [official page](http://snap7.sourceforge.net)\nor read the [Wiki](https://github.com/fbarresi/Sharp7/wiki).\n\n# Changelog\nSee the changelog [here](https://github.com/fbarresi/Sharp7/blob/master/CHANGELOG.md)\n\n# How to install\n\n## Package Manager or dotnet CLI\n```\nPM> Install-Package Sharp7\n```\nor\n```\n> dotnet add package Sharp7\n```\n\n# Do you need more power?\n\nTry [Sharp7Reactive](https://github.com/evopro-ag/Sharp7Reactive)\n\n# Get Started\n\n## Supported Targets\n- S7 300/400/WinAC CPU (fully supported)\n- S7 1200/1500 CPU\n- CP (Communication processor - 343/443/IE)\n\n## S7 1200/1500 Notes\n\nAn external equipment can access to S71200/1500 CPU using the S7 'base' protocol, only working as an HMI, i.e. only basic data transfer are allowed.\n\nAll other PG operations (control/directory/etc..) must follow the extended protocol, not implemented yet.\n\nParticularly **to access a DB in S71500 some additional setting plc-side are needed**.\n\n- Only global DBs can be accessed.\n\n- The optimized block access must be turned off.\n\n![DB_props](http://snap7.sourceforge.net/snap7_client_file/db_1500.bmp)\n\n- The access level must be “full” and the “connection mechanism” must allow GET/PUT.\n\n![DB_sec](http://snap7.sourceforge.net/snap7_client_file/cpu_1500.bmp)\n\n"
  },
  {
    "path": "Sharp7/MsgSocket.cs",
    "content": "﻿using System;\nusing System.Threading;\nusing System.Net.Sockets;\n\nnamespace Sharp7\n{\n\n    class MsgSocket\n    {\n        private Socket TCPSocket;\n        private int _ReadTimeout = 2000;\n        private int _WriteTimeout = 2000;\n        private int _ConnectTimeout = 1000;\n        private int LastError;\n        public MsgSocket()\n        {\n        }\n\n        ~MsgSocket()\n        {\n            Close();\n        }\n\n        public void Close()\n        {\n            if (TCPSocket != null)\n            {\n                TCPSocket.Dispose();\n                TCPSocket = null;\n            }\n        }\n\n        private void CreateSocket()\n        {\n            TCPSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);\n            TCPSocket.NoDelay = true;\n        }\n\n        private void TCPPing(string Host, int Port)\n        {\n            // To Ping the PLC an Asynchronous socket is used rather then an ICMP packet.\n            // This allows the use also across Internet and Firewalls (obviously the port must be opened)           \n            LastError = 0;\n            Socket PingSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);\n            try\n            {\n\n                IAsyncResult result = PingSocket.BeginConnect(Host, Port, null, null);\n                bool success = result.AsyncWaitHandle.WaitOne(_ConnectTimeout, true);\n\n                if (!success)\n                {\n                    LastError = S7Consts.errTCPConnectionFailed;\n                }\n            }\n            catch\n            {\n                LastError = S7Consts.errTCPConnectionFailed;\n            }\n\n            PingSocket.Close();\n        }\n\n        public int Connect(string Host, int Port)\n        {\n            LastError = 0;\n            if (!Connected)\n            { \n                TCPPing(Host, Port);\n                if (LastError == 0)\n                try\n                {\n                        CreateSocket();\n                        TCPSocket.Connect(Host, Port);\n                }\n                catch\n                {\n                        LastError = S7Consts.errTCPConnectionFailed;\n                }\n            }\n            return LastError;\n        }\n\n        private int WaitForData(int Size, int Timeout)\n        {\n            bool Expired = false;\n            int SizeAvail;\n            int Elapsed = Environment.TickCount;\n            LastError = 0;\n            try\n            {\n                SizeAvail = TCPSocket.Available;\n                while ((SizeAvail < Size) && (!Expired))\n                {\n                    Thread.Sleep(2);\n                    SizeAvail = TCPSocket.Available;\n                    Expired = Environment.TickCount - Elapsed > Timeout;\n                    // If timeout we clean the buffer\n                    if (Expired && (SizeAvail > 0))\n                    {\n                        try\n                        {\n                            byte[] Flush = new byte[SizeAvail];\n                            TCPSocket.Receive(Flush, 0, SizeAvail, SocketFlags.None);\n                        }\n                        catch\n                        {\n                            LastError = S7Consts.errTCPDataReceive;\n                        }\n                    }\n                }\n            }\n            catch\n            {\n                LastError = S7Consts.errTCPDataReceive;\n            }\n            if (Expired)\n            {\n                LastError = S7Consts.errTCPDataReceive;\n            }\n            return LastError;\n        }\n\n        public int Receive(byte[] Buffer, int Start, int Size)\n        {\n\n            int BytesRead = 0;\n            LastError = WaitForData(Size, _ReadTimeout);\n            if (LastError == 0)\n            {\n                try\n                {\n                    BytesRead = TCPSocket.Receive(Buffer, Start, Size, SocketFlags.None);\n                }\n                catch\n                {\n                    LastError = S7Consts.errTCPDataReceive;\n                }\n                if (BytesRead == 0) // Connection Reset by the peer\n                {\n                    LastError = S7Consts.errTCPDataReceive;\n                    Close();\n                }\n            }\n            return LastError;\n        }\n\n        public int Send(byte[] Buffer, int Size)\n        {\n            LastError = 0;\n            try\n            {\n                TCPSocket.Send(Buffer, Size, SocketFlags.None);\n            }\n            catch\n            {\n                LastError = S7Consts.errTCPDataSend;\n                Close();\n            }\n            return LastError;\n        }\n\n        public bool Connected => (TCPSocket != null) && (TCPSocket.Connected);\n\n        public int ReadTimeout\n        {\n            get => _ReadTimeout;\n            set => _ReadTimeout = value;\n        }\n\n        public int WriteTimeout\n        {\n            get => _WriteTimeout;\n            set => _WriteTimeout = value;\n        }\n        public int ConnectTimeout\n        {\n            get => _ConnectTimeout;\n            set => _ConnectTimeout = value;\n        }\n    }   \n}\n"
  },
  {
    "path": "Sharp7/S7.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\n\nnamespace Sharp7\n{\n    public static class S7\n    {\n        #region [Help Functions]\n\n        private static Int64\n            bias = 621355968000000000; // \"decimicros\" between 0001-01-01 00:00:00 and 1970-01-01 00:00:00\n\n        private static int BCDtoByte(byte B)\n        {\n            return ((B >> 4) * 10) + (B & 0x0F);\n        }\n\n        private static byte ByteToBCD(int value)\n        {\n            return (byte) (((value / 10) << 4) | (value % 10));\n        }\n\n        public static int DataSizeByte(this int wordLength)\n        {\n            switch (wordLength)\n            {\n                case (int)S7WordLength.Bit: return 1; // S7 sends 1 byte per bit\n                case (int)S7WordLength.Byte: return 1;\n                case (int)S7WordLength.Char: return 1;\n                case (int)S7WordLength.Word: return 2;\n                case (int)S7WordLength.DWord: return 4;\n                case (int)S7WordLength.Int: return 2;\n                case (int)S7WordLength.DInt: return 4;\n                case (int)S7WordLength.Real: return 4;\n                case (int)S7WordLength.Counter: return 2;\n                case (int)S7WordLength.Timer: return 2;\n                default: return 0;\n            }\n        }\n\n        #region Get/Set the bit at Pos.Bit\n\n        public static bool GetBitAt(this byte[] buffer, int pos, int bit)\n        {\n            byte[] Mask = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};\n            if (bit < 0) bit = 0;\n            if (bit > 7) bit = 7;\n            return (buffer[pos] & Mask[bit]) != 0;\n        }\n\n        public static void SetBitAt(this byte[] buffer, int pos, int bit, bool value)\n        {\n            byte[] Mask = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};\n            if (bit < 0)\n            {\n                bit = 0;\n            }\n\n            if (bit > 7)\n            {\n                bit = 7;\n            }\n\n            if (value)\n            {\n                buffer[pos] = (byte) (buffer[pos] | Mask[bit]);\n            }\n            else\n            {\n                buffer[pos] = (byte) (buffer[pos] & ~Mask[bit]);\n            }\n            \n        }\n\n        #endregion\n\n        #region Get/Set 8 bit signed value (S7 SInt) -128..127\n\n        public static int GetSIntAt(this byte[] buffer, int pos)\n        {\n            int value = buffer[pos];\n            if (value < 128)\n                return value;\n                \n            return (value - 256);\n        }\n\n        public static void SetSIntAt(this byte[] buffer, int pos, int value)\n        {\n            if (value < -128) value = -128;\n            if (value > 127) value = 127;\n            buffer[pos] = (byte) value;\n        }\n\n        #endregion\n\n        #region Get/Set 16 bit signed value (S7 int) -32768..32767\n\n        public static short GetIntAt(this byte[] buffer, int pos)\n        {\n            return (short)((buffer[pos] << 8) | buffer[pos + 1]);\n        }\n\n        public static void SetIntAt(this byte[] buffer, int pos, Int16 value)\n        {\n            buffer[pos] = (byte) (value >> 8);\n            buffer[pos + 1] = (byte) (value & 0x00FF);\n        }\n\n        #endregion\n\n        #region Get/Set 32 bit signed value (S7 DInt) -2147483648..2147483647\n\n        public static int GetDIntAt(this byte[] buffer, int pos)\n        {\n            int result;\n            result = buffer[pos];\n            result <<= 8;\n            result += buffer[pos + 1];\n            result <<= 8;\n            result += buffer[pos + 2];\n            result <<= 8;\n            result += buffer[pos + 3];\n            return result;\n        }\n\n        public static void SetDIntAt(this byte[] buffer, int pos, int value)\n        {\n            buffer[pos + 3] = (byte) (value & 0xFF);\n            buffer[pos + 2] = (byte) ((value >> 8) & 0xFF);\n            buffer[pos + 1] = (byte) ((value >> 16) & 0xFF);\n            buffer[pos] = (byte) ((value >> 24) & 0xFF);\n        }\n\n        #endregion\n\n        #region Get/Set 64 bit signed value (S7 LInt) -9223372036854775808..9223372036854775807\n\n        public static Int64 GetLIntAt(this byte[] buffer, int pos)\n        {\n            Int64 result;\n            result = buffer[pos];\n            result <<= 8;\n            result += buffer[pos + 1];\n            result <<= 8;\n            result += buffer[pos + 2];\n            result <<= 8;\n            result += buffer[pos + 3];\n            result <<= 8;\n            result += buffer[pos + 4];\n            result <<= 8;\n            result += buffer[pos + 5];\n            result <<= 8;\n            result += buffer[pos + 6];\n            result <<= 8;\n            result += buffer[pos + 7];\n            return result;\n        }\n\n        public static void SetLIntAt(this byte[] buffer, int pos, Int64 value)\n        {\n            buffer[pos + 7] = (byte) (value & 0xFF);\n            buffer[pos + 6] = (byte) ((value >> 8) & 0xFF);\n            buffer[pos + 5] = (byte) ((value >> 16) & 0xFF);\n            buffer[pos + 4] = (byte) ((value >> 24) & 0xFF);\n            buffer[pos + 3] = (byte) ((value >> 32) & 0xFF);\n            buffer[pos + 2] = (byte) ((value >> 40) & 0xFF);\n            buffer[pos + 1] = (byte) ((value >> 48) & 0xFF);\n            buffer[pos] = (byte) ((value >> 56) & 0xFF);\n        }\n\n        #endregion\n\n        #region Get/Set 8 bit unsigned value (S7 USInt) 0..255\n\n        public static byte GetUSIntAt(this byte[] buffer, int pos)\n        {\n            return buffer[pos];\n        }\n\n        public static void SetUSIntAt(this byte[] buffer, int pos, byte value)\n        {\n            buffer[pos] = value;\n        }\n\n        #endregion\n\n        #region Get/Set 16 bit unsigned value (S7 UInt) 0..65535\n\n        public static UInt16 GetUIntAt(this byte[] buffer, int pos)\n        {\n            return (UInt16) ((buffer[pos] << 8) | buffer[pos + 1]);\n        }\n\n        public static void SetUIntAt(this byte[] buffer, int pos, UInt16 value)\n        {\n            buffer[pos] = (byte) (value >> 8);\n            buffer[pos + 1] = (byte) (value & 0x00FF);\n        }\n\n        #endregion\n\n        #region Get/Set 32 bit unsigned value (S7 UDInt) 0..4294967296\n\n        public static UInt32 GetUDIntAt(this byte[] buffer, int pos)\n        {\n            UInt32 result;\n            result = buffer[pos];\n            result <<= 8;\n            result |= buffer[pos + 1];\n            result <<= 8;\n            result |= buffer[pos + 2];\n            result <<= 8;\n            result |= buffer[pos + 3];\n            return result;\n        }\n\n        public static void SetUDIntAt(this byte[] buffer, int pos, UInt32 value)\n        {\n            buffer[pos + 3] = (byte) (value & 0xFF);\n            buffer[pos + 2] = (byte) ((value >> 8) & 0xFF);\n            buffer[pos + 1] = (byte) ((value >> 16) & 0xFF);\n            buffer[pos] = (byte) ((value >> 24) & 0xFF);\n        }\n\n        #endregion\n\n        #region Get/Set 64 bit unsigned value (S7 ULint) 0..18446744073709551616\n\n        public static UInt64 GetULIntAt(this byte[] buffer, int pos)\n        {\n            UInt64 result;\n            result = buffer[pos];\n            result <<= 8;\n            result |= buffer[pos + 1];\n            result <<= 8;\n            result |= buffer[pos + 2];\n            result <<= 8;\n            result |= buffer[pos + 3];\n            result <<= 8;\n            result |= buffer[pos + 4];\n            result <<= 8;\n            result |= buffer[pos + 5];\n            result <<= 8;\n            result |= buffer[pos + 6];\n            result <<= 8;\n            result |= buffer[pos + 7];\n            return result;\n        }\n\n        public static void SetULintAt(this byte[] buffer, int pos, UInt64 value)\n        {\n            buffer[pos + 7] = (byte) (value & 0xFF);\n            buffer[pos + 6] = (byte) ((value >> 8) & 0xFF);\n            buffer[pos + 5] = (byte) ((value >> 16) & 0xFF);\n            buffer[pos + 4] = (byte) ((value >> 24) & 0xFF);\n            buffer[pos + 3] = (byte) ((value >> 32) & 0xFF);\n            buffer[pos + 2] = (byte) ((value >> 40) & 0xFF);\n            buffer[pos + 1] = (byte) ((value >> 48) & 0xFF);\n            buffer[pos] = (byte) ((value >> 56) & 0xFF);\n        }\n\n        #endregion\n\n        #region Get/Set 8 bit word (S7 Byte) 16#00..16#FF\n\n        public static byte GetByteAt(this byte[] buffer, int pos)\n        {\n            return buffer[pos];\n        }\n\n        public static void SetByteAt(this byte[] buffer, int pos, byte value)\n        {\n            buffer[pos] = value;\n        }\n\n        #endregion\n\n        #region Get/Set 16 bit word (S7 Word) 16#0000..16#FFFF\n\n        public static UInt16 GetWordAt(this byte[] buffer, int pos)\n        {\n            return GetUIntAt(buffer, pos);\n        }\n\n        public static void SetWordAt(this byte[] buffer, int pos, UInt16 value)\n        {\n            SetUIntAt(buffer, pos, value);\n        }\n\n        #endregion\n\n        #region Get/Set 32 bit word (S7 DWord) 16#00000000..16#FFFFFFFF\n\n        public static UInt32 GetDWordAt(this byte[] buffer, int pos)\n        {\n            return GetUDIntAt(buffer, pos);\n        }\n\n        public static void SetDWordAt(this byte[] buffer, int pos, UInt32 value)\n        {\n            SetUDIntAt(buffer, pos, value);\n        }\n\n        #endregion\n\n        #region Get/Set 64 bit word (S7 LWord) 16#0000000000000000..16#FFFFFFFFFFFFFFFF\n\n        public static UInt64 GetLWordAt(this byte[] buffer, int pos)\n        {\n            return GetULIntAt(buffer, pos);\n        }\n\n        public static void SetLWordAt(this byte[] buffer, int pos, UInt64 value)\n        {\n            SetULintAt(buffer, pos, value);\n        }\n\n        #endregion\n\n        #region Get/Set 32 bit floating point number (S7 Real) (Range of Single)\n\n        public static Single GetRealAt(this byte[] buffer, int pos)\n        {\n            UInt32 value = GetUDIntAt(buffer, pos);\n            byte[] bytes = BitConverter.GetBytes(value);\n            return BitConverter.ToSingle(bytes, 0);\n        }\n\n        public static void SetRealAt(this byte[] buffer, int pos, Single value)\n        {\n            byte[] FloatArray = BitConverter.GetBytes(value);\n            buffer[pos] = FloatArray[3];\n            buffer[pos + 1] = FloatArray[2];\n            buffer[pos + 2] = FloatArray[1];\n            buffer[pos + 3] = FloatArray[0];\n        }\n\n        #endregion\n\n        #region Get/Set 64 bit floating point number (S7 LReal) (Range of Double)\n\n        public static Double GetLRealAt(this byte[] buffer, int pos)\n        {\n            UInt64 value = GetULIntAt(buffer, pos);\n            byte[] bytes = BitConverter.GetBytes(value);\n            return BitConverter.ToDouble(bytes, 0);\n        }\n\n        public static void SetLRealAt(this byte[] buffer, int pos, Double value)\n        {\n            byte[] FloatArray = BitConverter.GetBytes(value);\n            buffer[pos] = FloatArray[7];\n            buffer[pos + 1] = FloatArray[6];\n            buffer[pos + 2] = FloatArray[5];\n            buffer[pos + 3] = FloatArray[4];\n            buffer[pos + 4] = FloatArray[3];\n            buffer[pos + 5] = FloatArray[2];\n            buffer[pos + 6] = FloatArray[1];\n            buffer[pos + 7] = FloatArray[0];\n        }\n\n        #endregion\n\n        #region Get/Set DateTime (S7 DATE_AND_TIME)\n\n        public static DateTime GetDateTimeAt(this byte[] buffer, int pos)\n        {\n            int Year, Month, Day, Hour, Min, Sec, MSec;\n\n            Year = BCDtoByte(buffer[pos]);\n            if (Year < 90)\n                Year += 2000;\n            else\n                Year += 1900;\n\n            Month = BCDtoByte(buffer[pos + 1]);\n            Day = BCDtoByte(buffer[pos + 2]);\n            Hour = BCDtoByte(buffer[pos + 3]);\n            Min = BCDtoByte(buffer[pos + 4]);\n            Sec = BCDtoByte(buffer[pos + 5]);\n            MSec = (BCDtoByte(buffer[pos + 6]) * 10) + (BCDtoByte(buffer[pos + 7]) / 10);\n            try\n            {\n                return new DateTime(Year, Month, Day, Hour, Min, Sec, MSec);\n            }\n            catch (System.ArgumentOutOfRangeException)\n            {\n                return new DateTime(0);\n            }\n        }\n\n        public static void SetDateTimeAt(this byte[] buffer, int pos, DateTime value)\n        {\n            int Year = value.Year;\n            int Month = value.Month;\n            int Day = value.Day;\n            int Hour = value.Hour;\n            int Min = value.Minute;\n            int Sec = value.Second;\n            int Dow = (int) value.DayOfWeek + 1;\n            // MSecH = First two digits of miliseconds \n            int MsecH = value.Millisecond / 10;\n            // MSecL = Last digit of miliseconds\n            int MsecL = value.Millisecond % 10;\n            if (Year > 1999)\n                Year -= 2000;\n\n            buffer[pos] = ByteToBCD(Year);\n            buffer[pos + 1] = ByteToBCD(Month);\n            buffer[pos + 2] = ByteToBCD(Day);\n            buffer[pos + 3] = ByteToBCD(Hour);\n            buffer[pos + 4] = ByteToBCD(Min);\n            buffer[pos + 5] = ByteToBCD(Sec);\n            buffer[pos + 6] = ByteToBCD(MsecH);\n            buffer[pos + 7] = ByteToBCD(MsecL * 10 + Dow);\n        }\n\n        #endregion\n\n        #region Get/Set DATE (S7 DATE)\n\n        public static DateTime GetDateAt(this byte[] buffer, int pos)\n        {\n            try\n            {\n                return new DateTime(1990, 1, 1).AddDays(GetIntAt(buffer, pos));\n            }\n            catch (System.ArgumentOutOfRangeException)\n            {\n                return new DateTime(0);\n            }\n        }\n\n        public static void SetDateAt(this byte[] buffer, int pos, DateTime value)\n        {\n            SetIntAt(buffer, pos, (Int16) (value - new DateTime(1990, 1, 1)).Days);\n        }\n\n        #endregion\n\n        #region Get/Set TOD (S7 TIME_OF_DAY)\n\n        [Obsolete(\"Use GetTODAsDateTimeAt or GetTODAsTimeSpanAt instead\")]\n        public static DateTime GetTODAt(this byte[] buffer, int pos)\n        {\n            return buffer.GetTODAsDateTimeAt(pos);\n        }\n        \n        public static DateTime GetTODAsDateTimeAt(this byte[] buffer, int pos)\n        {\n            try\n            {\n                return new DateTime(0).AddMilliseconds(buffer.GetDIntAt(pos));\n            }\n            catch (ArgumentOutOfRangeException)\n            {\n                return new DateTime(0);\n            }\n        }\n\n        public static void SetTODAt(this byte[] buffer, int pos, DateTime value)\n        {\n            TimeSpan Time = value.TimeOfDay;\n            SetDIntAt(buffer, pos, (Int32) Math.Round(Time.TotalMilliseconds));\n        }\n        \n        public static TimeSpan GetTODAsTimeSpanAt(this byte[] buffer, int pos)\n        {\n            try\n            {\n                return TimeSpan.FromMilliseconds(buffer.GetDIntAt(pos));\n            }\n            catch (ArgumentOutOfRangeException)\n            {\n                return TimeSpan.Zero;\n            }\n        }\n\n        public static void SetTODAt(this byte[] buffer, int pos, TimeSpan value)\n        {\n            SetDIntAt(buffer, pos, (Int32) Math.Round(value.TotalMilliseconds));\n        }\n\n        #endregion\n\n        #region Get/Set LTOD (S7 1500 LONG TIME_OF_DAY)\n\n        [Obsolete(\"Use GetLTODAsDateTimeAt or GetLTODAsTimeSpanAt instead\")]\n        public static DateTime GetLTODAt(this byte[] buffer, int pos)\n        {\n            return buffer.GetLTODAsDateTimeAt(pos);\n        }\n        \n        public static DateTime GetLTODAsDateTimeAt(this byte[] buffer, int pos)\n        {\n            // .NET Tick = 100 ns, S71500 Tick = 1 ns\n            try\n            {\n                return new DateTime(Math.Abs(GetLIntAt(buffer, pos) / 100));\n            }\n            catch (System.ArgumentOutOfRangeException)\n            {\n                return new DateTime(0);\n            }\n        }\n\n        public static void SetLTODAt(this byte[] buffer, int pos, DateTime value)\n        {\n            TimeSpan Time = value.TimeOfDay;\n            SetLIntAt(buffer, pos, (Int64) Time.Ticks * 100);\n        }\n\n        public static TimeSpan GetLTODAsTimeSpanAt(this byte[] buffer, int pos)\n        {\n            try\n            {\n                return TimeSpan.FromTicks(Math.Abs(GetLIntAt(buffer, pos) / 100));\n            }\n            catch (System.ArgumentOutOfRangeException)\n            {\n                return TimeSpan.Zero;\n            }\n        }\n\n        public static void SetLTODAt(this byte[] buffer, int pos, TimeSpan value)\n        {\n            SetLIntAt(buffer, pos, (Int64) value.Ticks * 100);\n        }\n        \n        #endregion\n\n        #region GET/SET LDT (S7 1500 Long Date and Time)\n\n        public static DateTime GetLDTAt(this byte[] buffer, int pos)\n        {\n            try\n            {\n                return new DateTime((GetLIntAt(buffer, pos) / 100) + bias);\n            }\n            catch (System.ArgumentOutOfRangeException)\n            {\n                return new DateTime(0);\n            }\n        }\n\n        public static void SetLDTAt(this byte[] buffer, int pos, DateTime value)\n        {\n            SetLIntAt(buffer, pos, (value.Ticks - bias) * 100);\n        }\n\n        #endregion\n\n        #region Get/Set DTL (S71200/1500 Date and Time)\n\n        // Thanks to Johan Cardoen for GetDTLAt\n        public static DateTime GetDTLAt(this byte[] buffer, int pos)\n        {\n            int Year, Month, Day, Hour, Min, Sec, MSec;\n\n            Year = buffer[pos] * 256 + buffer[pos + 1];\n            Month = buffer[pos + 2];\n            Day = buffer[pos + 3];\n            Hour = buffer[pos + 5];\n            Min = buffer[pos + 6];\n            Sec = buffer[pos + 7];\n            MSec = (int) GetUDIntAt(buffer, pos + 8) / 1000000;\n\n            try\n            {\n                return new DateTime(Year, Month, Day, Hour, Min, Sec, MSec);\n            }\n            catch (System.ArgumentOutOfRangeException)\n            {\n                return new DateTime(0);\n            }\n        }\n\n        public static void SetDTLAt(this byte[] buffer, int pos, DateTime value)\n        {\n            short Year = (short) value.Year;\n            byte Month = (byte) value.Month;\n            byte Day = (byte) value.Day;\n            byte Hour = (byte) value.Hour;\n            byte Min = (byte) value.Minute;\n            byte Sec = (byte) value.Second;\n            byte Dow = (byte) (value.DayOfWeek + 1);\n\n            Int32 NanoSecs = value.Millisecond * 1000000;\n\n            var bytes_short = BitConverter.GetBytes(Year);\n\n            buffer[pos] = bytes_short[1];\n            buffer[pos + 1] = bytes_short[0];\n            buffer[pos + 2] = Month;\n            buffer[pos + 3] = Day;\n            buffer[pos + 4] = Dow;\n            buffer[pos + 5] = Hour;\n            buffer[pos + 6] = Min;\n            buffer[pos + 7] = Sec;\n            SetDIntAt(buffer, pos + 8, NanoSecs);\n        }\n\n        #endregion\n\n        #region Get/Set String (S7 String)\n\n        // Thanks to Pablo Agirre \n        public static string GetStringAt(this byte[] buffer, int pos)\n        {\n            int size = (int) buffer[pos + 1];\n            return Encoding.UTF8.GetString(buffer, pos + 2, size);\n        }\n\n        public static void SetStringAt(this byte[] buffer, int pos, int MaxLen, string value)\n        {\n            int length = value.Length;\n            // checking current length against MaxLen\n            if (length > MaxLen) length = MaxLen;\n            buffer[pos] = (byte) MaxLen;\n            buffer[pos + 1] = (byte) length;\n            Encoding.UTF8.GetBytes(value, 0, length, buffer, pos + 2);\n        }\n\n        #endregion\n\n        #region Get/Set Array of char (S7 ARRAY OF CHARS)\n\n        public static string GetCharsAt(this byte[] buffer, int pos, int Size)\n        {\n            return Encoding.UTF8.GetString(buffer, pos, Size);\n        }\n\n        public static void SetCharsAt(this byte[] buffer, int pos, string value)\n        {\n            int MaxLen = buffer.Length - pos;\n            // Truncs the string if there's no room enough        \n            if (MaxLen > value.Length) MaxLen = value.Length;\n            Encoding.UTF8.GetBytes(value, 0, MaxLen, buffer, pos);\n        }\n\n        #endregion\n\n        #region Get/Set Counter\n\n        public static int GetCounter(this ushort value)\n        {\n            return BCDtoByte((byte) value) * 100 + BCDtoByte((byte) (value >> 8));\n        }\n\n        public static int GetCounterAt(this ushort[] buffer, int Index)\n        {\n            return GetCounter(buffer[Index]);\n        }\n\n        public static ushort ToCounter(this int value)\n        {\n            return (ushort) (ByteToBCD(value / 100) + (ByteToBCD(value % 100) << 8));\n        }\n\n        public static void SetCounterAt(this ushort[] buffer, int pos, int value)\n        {\n            buffer[pos] = ToCounter(value);\n        }\n\n        #endregion\n\n        #region Get/Set Timer\n\n        public static S7Timer GetS7TimerAt(this byte[] buffer, int pos)\n        {\n            return new S7Timer(new List<byte>(buffer).GetRange(pos, 12).ToArray());\n        }\n\n        public static void SetS7TimespanAt(this byte[] buffer, int pos, TimeSpan value)\n        {\n            SetDIntAt(buffer, pos, (Int32) value.TotalMilliseconds);\n        }\n\n        public static TimeSpan GetS7TimespanAt(this byte[] buffer, int pos)\n        {\n            if (buffer.Length < pos + 4)\n            {\n                return new TimeSpan();\n            }\n\n            Int32 a;\n            a = buffer[pos + 0];\n            a <<= 8;\n            a += buffer[pos + 1];\n            a <<= 8;\n            a += buffer[pos + 2];\n            a <<= 8;\n            a += buffer[pos + 3];\n            TimeSpan sp = new TimeSpan(0, 0, 0, 0, a);\n\n            return sp;\n        }\n\n        #endregion\n\n        #endregion [Help Functions]\n    }\n}"
  },
  {
    "path": "Sharp7/S7Area.cs",
    "content": "﻿namespace Sharp7\n{\n    public enum S7Area\n    {\n        PE = 0x81,\n        PA = 0x82,\n        MK = 0x83,\n        DB = 0x84,\n        CT = 0x1C,\n        TM = 0x1D,\n    }\n}"
  },
  {
    "path": "Sharp7/S7Client.cs",
    "content": "﻿using System;\nusing System.Linq;\nusing System.Runtime.InteropServices;\n\nnamespace Sharp7\n{\n\tpublic class S7Client\n\t{\n\t\t#region [Constants and TypeDefs]\n\n\t\t// Block type\n\t\tpublic const int Block_OB  = 0x38;\n\t\tpublic const int Block_DB  = 0x41;\n\t\tpublic const int Block_SDB = 0x42;\n\t\tpublic const int Block_FC  = 0x43;\n\t\tpublic const int Block_SFC = 0x44;\n\t\tpublic const int Block_FB  = 0x45;\n\t\tpublic const int Block_SFB = 0x46;\n\n\t\t// Sub Block Type \n\t\tpublic const byte SubBlk_OB  = 0x08;\n\t\tpublic const byte SubBlk_DB  = 0x0A;\n\t\tpublic const byte SubBlk_SDB = 0x0B;\n\t\tpublic const byte SubBlk_FC  = 0x0C;\n\t\tpublic const byte SubBlk_SFC = 0x0D;\n\t\tpublic const byte SubBlk_FB  = 0x0E;\n\t\tpublic const byte SubBlk_SFB = 0x0F;\n\n\t\t// Block languages\n\t\tpublic const byte BlockLangAWL   = 0x01;\n\t\tpublic const byte BlockLangKOP   = 0x02;\n\t\tpublic const byte BlockLangFUP   = 0x03;\n\t\tpublic const byte BlockLangSCL   = 0x04;\n\t\tpublic const byte BlockLangDB    = 0x05;\n\t\tpublic const byte BlockLangGRAPH = 0x06;\n\n\t\t// Max number of vars (multiread/write)\n\t\tpublic static readonly int MaxVars = 20;\n        \n\t\t// Result transport size\n\t\tconst byte TS_ResBit   = 0x03;\n\t\tconst byte TS_ResByte  = 0x04;\n\t\tconst byte TS_ResInt   = 0x05;\n\t\tconst byte TS_ResReal  = 0x07;\n\t\tconst byte TS_ResOctet = 0x09;\n\n\t\tconst ushort Code7Ok                    = 0x0000;\n\t\tconst ushort Code7AddressOutOfRange     = 0x0005;\n\t\tconst ushort Code7InvalidTransportSize  = 0x0006;\n\t\tconst ushort Code7WriteDataSizeMismatch = 0x0007;\n\t\tconst ushort Code7ResItemNotAvailable   = 0x000A;\n\t\tconst ushort Code7ResItemNotAvailable1  = 0xD209;\n\t\tconst ushort Code7InvalidValue          = 0xDC01;\n\t\tconst ushort Code7NeedPassword          = 0xD241;\n\t\tconst ushort Code7InvalidPassword       = 0xD602;\n\t\tconst ushort Code7NoPasswordToClear     = 0xD604;\n\t\tconst ushort Code7NoPasswordToSet       = 0xD605;\n\t\tconst ushort Code7FunNotAvailable       = 0x8104;\n\t\tconst ushort Code7DataOverPDU           = 0x8500;\n\n\t\t// Client Connection Type\n\t\tpublic static readonly UInt16 CONNTYPE_PG    = 0x01;  // Connect to the PLC as a PG\n\t\tpublic static readonly UInt16 CONNTYPE_OP    = 0x02;  // Connect to the PLC as an OP\n\t\tpublic static readonly UInt16 CONNTYPE_BASIC = 0x03;  // Basic connection \n\n\t\tpublic int _LastError = 0;\n\n\t\tpublic struct S7DataItem\n\t\t{\n\t\t\tpublic int Area;\n\t\t\tpublic int WordLen;\n\t\t\tpublic int Result;\n\t\t\tpublic int DBNumber;\n\t\t\tpublic int Start;\n\t\t\tpublic int Amount;\n\t\t\tpublic IntPtr pData;\n\t\t}\n\n\t\t// Order Code + Version\n\t\tpublic struct S7OrderCode\n\t\t{\n\t\t\tpublic string Code; // such as \"6ES7 151-8AB01-0AB0\"\n\t\t\tpublic byte V1;     // Version 1st digit\n\t\t\tpublic byte V2;     // Version 2nd digit\n\t\t\tpublic byte V3;     // Version 3th digit\n\t\t};\n\n\t\t// CPU Info\n\t\tpublic struct S7CpuInfo\n\t\t{\n\t\t\tpublic string ModuleTypeName;\n\t\t\tpublic string SerialNumber;\n\t\t\tpublic string ASName;\n\t\t\tpublic string Copyright;\n\t\t\tpublic string ModuleName;\n\t\t}\n\n\t\tpublic struct S7CpInfo\n\t\t{\n\t\t\tpublic int MaxPduLength;\n\t\t\tpublic int MaxConnections;\n\t\t\tpublic int MaxMpiRate;\n\t\t\tpublic int MaxBusRate;\n\t\t};\n\n\t\t// Block List\n\t\t[StructLayout(LayoutKind.Sequential, Pack = 1)]\n\t\tpublic struct S7BlocksList\n\t\t{\n\t\t\tpublic Int32 OBCount;\n\t\t\tpublic Int32 FBCount;\n\t\t\tpublic Int32 FCCount;\n\t\t\tpublic Int32 SFBCount;\n\t\t\tpublic Int32 SFCCount;\n\t\t\tpublic Int32 DBCount;\n\t\t\tpublic Int32 SDBCount;\n\t\t};\n\n\t\t// Managed Block Info\n\t\tpublic struct S7BlockInfo\n\t\t{\n\t\t\tpublic int BlkType;\n\t\t\tpublic int BlkNumber;\n\t\t\tpublic int BlkLang;\n\t\t\tpublic int BlkFlags;\n\t\t\tpublic int MC7Size;  // The real size in bytes\n\t\t\tpublic int LoadSize;\n\t\t\tpublic int LocalData;\n\t\t\tpublic int SBBLength;\n\t\t\tpublic int CheckSum;\n\t\t\tpublic int Version;\n\t\t\t// Chars info\n\t\t\tpublic string CodeDate;\n\t\t\tpublic string IntfDate;\n\t\t\tpublic string Author;\n\t\t\tpublic string Family;\n\t\t\tpublic string Header;\n\t\t};\n\n\t\t// See §33.1 of \"System Software for S7-300/400 System and Standard Functions\"\n\t\t// and see SFC51 description too\n\t\t[StructLayout(LayoutKind.Sequential, Pack = 1)]\n\t\tpublic struct SZL_HEADER\n\t\t{\n\t\t\tpublic UInt16 LENTHDR;\n\t\t\tpublic UInt16 N_DR;\n\t\t};\n\n\t\t[StructLayout(LayoutKind.Sequential, Pack = 1)]\n\t\tpublic struct S7SZL\n\t\t{\n\t\t\tpublic SZL_HEADER Header;\n\t\t\t[MarshalAs(UnmanagedType.ByValArray)]\n\t\t\tpublic byte[] Data;\n\t\t};\n\n\t\t// SZL List of available SZL IDs : same as SZL but List items are big-endian adjusted\n\t\t[StructLayout(LayoutKind.Sequential, Pack = 1)]\n\t\tpublic struct S7SZLList\n\t\t{\n\t\t\tpublic SZL_HEADER Header;\n\t\t\t[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x2000 - 2)]\n\t\t\tpublic UInt16[] Data;\n\t\t};\n\n\t\t// S7 Protection\n\t\t// See §33.19 of \"System Software for S7-300/400 System and Standard Functions\"\n\t\tpublic struct S7Protection  \n\t\t{\n\t\t\tpublic ushort sch_schal;\n\t\t\tpublic ushort sch_par;\n\t\t\tpublic ushort sch_rel;\n\t\t\tpublic ushort bart_sch;\n\t\t\tpublic ushort anl_sch;\n\t\t};\n\n\t\t#endregion\n\n\t\t#region [S7 Telegrams]\n\n\t\t// ISO Connection Request telegram (contains also ISO Header and COTP Header)\n\t\tbyte[] ISO_CR = {\n\t\t\t// TPKT (RFC1006 Header)\n\t\t\t0x03, // RFC 1006 ID (3) \n\t\t\t0x00, // Reserved, always 0\n\t\t\t0x00, // High part of packet lenght (entire frame, payload and TPDU included)\n\t\t\t0x16, // Low part of packet lenght (entire frame, payload and TPDU included)\n\t\t\t// COTP (ISO 8073 Header)\n\t\t\t0x11, // PDU Size Length\n\t\t\t0xE0, // CR - Connection Request ID\n\t\t\t0x00, // Dst Reference HI\n\t\t\t0x00, // Dst Reference LO\n\t\t\t0x00, // Src Reference HI\n\t\t\t0x01, // Src Reference LO\n\t\t\t0x00, // Class + Options Flags\n\t\t\t0xC0, // PDU Max Length ID\n\t\t\t0x01, // PDU Max Length HI\n\t\t\t0x0A, // PDU Max Length LO\n\t\t\t0xC1, // Src TSAP Identifier\n\t\t\t0x02, // Src TSAP Length (2 bytes)\n\t\t\t0x01, // Src TSAP HI (will be overwritten)\n\t\t\t0x00, // Src TSAP LO (will be overwritten)\n\t\t\t0xC2, // Dst TSAP Identifier\n\t\t\t0x02, // Dst TSAP Length (2 bytes)\n\t\t\t0x01, // Dst TSAP HI (will be overwritten)\n\t\t\t0x02  // Dst TSAP LO (will be overwritten)\n\t\t};\n\n\t\t// TPKT + ISO COTP Header (Connection Oriented Transport Protocol)\n\t\tbyte[] TPKT_ISO = { // 7 bytes\n\t\t\t0x03,0x00,\n\t\t\t0x00,0x1f,      // Telegram Length (Data Size + 31 or 35)\n\t\t\t0x02,0xf0,0x80  // COTP (see above for info)\n\t\t};\n\n\t\t// S7 PDU Negotiation Telegram (contains also ISO Header and COTP Header)\n\t\tbyte[] S7_PN = {\n\t\t\t0x03, 0x00, 0x00, 0x19, \n\t\t\t0x02, 0xf0, 0x80, // TPKT + COTP (see above for info)\n\t\t\t0x32, 0x01, 0x00, 0x00, \n\t\t\t0x04, 0x00, 0x00, 0x08, \n\t\t\t0x00, 0x00, 0xf0, 0x00, \n\t\t\t0x00, 0x01, 0x00, 0x01, \n\t\t\t0x00, 0x1e        // PDU Length Requested = HI-LO Here Default 480 bytes\n\t\t};\n        \n\t\t// S7 Read/Write Request Header (contains also ISO Header and COTP Header)\n\t\tbyte[] S7_RW = { // 31-35 bytes\n\t\t\t0x03,0x00, \n\t\t\t0x00,0x1f,       // Telegram Length (Data Size + 31 or 35)\n\t\t\t0x02,0xf0, 0x80, // COTP (see above for info)\n\t\t\t0x32,            // S7 Protocol ID \n\t\t\t0x01,            // Job Type\n\t\t\t0x00,0x00,       // Redundancy identification\n\t\t\t0x05,0x00,       // PDU Reference\n\t\t\t0x00,0x0e,       // Parameters Length\n\t\t\t0x00,0x00,       // Data Length = Size(bytes) + 4      \n\t\t\t0x04,            // Function 4 Read Var, 5 Write Var  \n\t\t\t0x01,            // Items count\n\t\t\t0x12,            // Var spec.\n\t\t\t0x0a,            // Length of remaining bytes\n\t\t\t0x10,            // Syntax ID \n\t\t\t(byte)S7WordLength.Byte,  // Transport Size idx=22                       \n\t\t\t0x00,0x00,       // Num Elements                          \n\t\t\t0x00,0x00,       // DB Number (if any, else 0)            \n\t\t\t0x84,            // Area Type                            \n\t\t\t0x00,0x00,0x00,  // Area Offset                     \n\t\t\t// WR area\n\t\t\t0x00,            // Reserved \n\t\t\t0x04,            // Transport size\n\t\t\t0x00,0x00,       // Data Length * 8 (if not bit or timer or counter) \n\t\t};\n\t\tprivate static int Size_RD = 31; // Header Size when Reading \n\t\tprivate static int Size_WR = 35; // Header Size when Writing\n\n\t\t// S7 Variable MultiRead Header\n\t\tbyte[] S7_MRD_HEADER = {\n\t\t\t0x03,0x00, \n\t\t\t0x00,0x1f,       // Telegram Length \n\t\t\t0x02,0xf0, 0x80, // COTP (see above for info)\n\t\t\t0x32,            // S7 Protocol ID \n\t\t\t0x01,            // Job Type\n\t\t\t0x00,0x00,       // Redundancy identification\n\t\t\t0x05,0x00,       // PDU Reference\n\t\t\t0x00,0x0e,       // Parameters Length\n\t\t\t0x00,0x00,       // Data Length = Size(bytes) + 4      \n\t\t\t0x04,            // Function 4 Read Var, 5 Write Var  \n\t\t\t0x01             // Items count (idx 18)\n\t\t};\n\n\t\t// S7 Variable MultiRead Item\n\t\tbyte[] S7_MRD_ITEM = {\n\t\t\t0x12,            // Var spec.\n\t\t\t0x0a,            // Length of remaining bytes\n\t\t\t0x10,            // Syntax ID \n\t\t\t(byte)S7WordLength.Byte,  // Transport Size idx=3                   \n\t\t\t0x00,0x00,       // Num Elements                          \n\t\t\t0x00,0x00,       // DB Number (if any, else 0)            \n\t\t\t0x84,            // Area Type                            \n\t\t\t0x00,0x00,0x00   // Area Offset                     \n\t\t};\n\n\t\t// S7 Variable MultiWrite Header\n\t\tbyte[] S7_MWR_HEADER = {\n\t\t\t0x03,0x00,\n\t\t\t0x00,0x1f,       // Telegram Length \n\t\t\t0x02,0xf0, 0x80, // COTP (see above for info)\n\t\t\t0x32,            // S7 Protocol ID \n\t\t\t0x01,            // Job Type\n\t\t\t0x00,0x00,       // Redundancy identification\n\t\t\t0x05,0x00,       // PDU Reference\n\t\t\t0x00,0x0e,       // Parameters Length (idx 13)\n\t\t\t0x00,0x00,       // Data Length = Size(bytes) + 4 (idx 15)     \n\t\t\t0x05,            // Function 5 Write Var  \n\t\t\t0x01             // Items count (idx 18)\n\t\t};\n\n\t\t// S7 Variable MultiWrite Item (Param)\n\t\tbyte[] S7_MWR_PARAM = {\n\t\t\t0x12,            // Var spec.\n\t\t\t0x0a,            // Length of remaining bytes\n\t\t\t0x10,            // Syntax ID \n\t\t\t(byte)S7WordLength.Byte,  // Transport Size idx=3                      \n\t\t\t0x00,0x00,       // Num Elements                          \n\t\t\t0x00,0x00,       // DB Number (if any, else 0)            \n\t\t\t0x84,            // Area Type                            \n\t\t\t0x00,0x00,0x00,  // Area Offset                     \n\t\t};\n\n\t\t// SZL First telegram request   \n\t\tbyte[] S7_SZL_FIRST = {\n\t\t\t0x03, 0x00, 0x00, 0x21,\n\t\t\t0x02, 0xf0, 0x80, 0x32,\n\t\t\t0x07, 0x00, 0x00,\n\t\t\t0x05, 0x00, // Sequence out\n\t\t\t0x00, 0x08, 0x00,\n\t\t\t0x08, 0x00, 0x01, 0x12,\n\t\t\t0x04, 0x11, 0x44, 0x01,\n\t\t\t0x00, 0xff, 0x09, 0x00,\n\t\t\t0x04,\n\t\t\t0x00, 0x00, // ID (29)\n\t\t\t0x00, 0x00  // Index (31)\n\t\t};\n\n\t\t// SZL Next telegram request \n\t\tbyte[] S7_SZL_NEXT = {\n\t\t\t0x03, 0x00, 0x00, 0x21,\n\t\t\t0x02, 0xf0, 0x80, 0x32,\n\t\t\t0x07, 0x00, 0x00, 0x06,\n\t\t\t0x00, 0x00, 0x0c, 0x00,\n\t\t\t0x04, 0x00, 0x01, 0x12,\n\t\t\t0x08, 0x12, 0x44, 0x01,\n\t\t\t0x01, // Sequence\n\t\t\t0x00, 0x00, 0x00, 0x00,\n\t\t\t0x0a, 0x00, 0x00, 0x00\n\t\t};\n\n\t\t// Get Date/Time request\n\t\tbyte[] S7_GET_DT = {\n\t\t\t0x03, 0x00, 0x00, 0x1d,\n\t\t\t0x02, 0xf0, 0x80, 0x32,\n\t\t\t0x07, 0x00, 0x00, 0x38,\n\t\t\t0x00, 0x00, 0x08, 0x00,\n\t\t\t0x04, 0x00, 0x01, 0x12,\n\t\t\t0x04, 0x11, 0x47, 0x01,\n\t\t\t0x00, 0x0a, 0x00, 0x00,\n\t\t\t0x00\n\t\t};\n\n\t\t// Set Date/Time command\n\t\tbyte[] S7_SET_DT = {\n\t\t\t0x03, 0x00, 0x00, 0x27,\n\t\t\t0x02, 0xf0, 0x80, 0x32,\n\t\t\t0x07, 0x00, 0x00, 0x89,\n\t\t\t0x03, 0x00, 0x08, 0x00,\n\t\t\t0x0e, 0x00, 0x01, 0x12,\n\t\t\t0x04, 0x11, 0x47, 0x02,\n\t\t\t0x00, 0xff, 0x09, 0x00,\n\t\t\t0x0a, 0x00,\n\t\t\t0x19, // Hi part of Year (idx=30)\n\t\t\t0x13, // Lo part of Year\n\t\t\t0x12, // Month\n\t\t\t0x06, // Day\n\t\t\t0x17, // Hour\n\t\t\t0x37, // Min\n\t\t\t0x13, // Sec\n\t\t\t0x00, 0x01 // ms + Day of week   \n\t\t};\n\n\t\t// S7 Set Session Password \n\t\tbyte[] S7_SET_PWD = {\n\t\t\t0x03, 0x00, 0x00, 0x25,\n\t\t\t0x02, 0xf0, 0x80, 0x32,\n\t\t\t0x07, 0x00, 0x00, 0x27,\n\t\t\t0x00, 0x00, 0x08, 0x00,\n\t\t\t0x0c, 0x00, 0x01, 0x12,\n\t\t\t0x04, 0x11, 0x45, 0x01,\n\t\t\t0x00, 0xff, 0x09, 0x00,\n\t\t\t0x08, \n\t\t\t// 8 Char Encoded Password\n\t\t\t0x00, 0x00, 0x00, 0x00,\n\t\t\t0x00, 0x00, 0x00, 0x00\n\t\t};\n\n\t\t// S7 Clear Session Password \n\t\tbyte[] S7_CLR_PWD = {\n\t\t\t0x03, 0x00, 0x00, 0x1d,\n\t\t\t0x02, 0xf0, 0x80, 0x32,\n\t\t\t0x07, 0x00, 0x00, 0x29,\n\t\t\t0x00, 0x00, 0x08, 0x00,\n\t\t\t0x04, 0x00, 0x01, 0x12,\n\t\t\t0x04, 0x11, 0x45, 0x02,\n\t\t\t0x00, 0x0a, 0x00, 0x00,\n\t\t\t0x00\n\t\t};\n\n\t\t// S7 STOP request\n\t\tbyte[] S7_STOP = {\n\t\t\t0x03, 0x00, 0x00, 0x21,\n\t\t\t0x02, 0xf0, 0x80, 0x32,\n\t\t\t0x01, 0x00, 0x00, 0x0e,\n\t\t\t0x00, 0x00, 0x10, 0x00,\n\t\t\t0x00, 0x29, 0x00, 0x00,\n\t\t\t0x00, 0x00, 0x00, 0x09,\n\t\t\t0x50, 0x5f, 0x50, 0x52,\n\t\t\t0x4f, 0x47, 0x52, 0x41,\n\t\t\t0x4d\n\t\t};\n\n\t\t// S7 HOT Start request\n\t\tbyte[] S7_HOT_START = {\n\t\t\t0x03, 0x00, 0x00, 0x25,\n\t\t\t0x02, 0xf0, 0x80, 0x32,\n\t\t\t0x01, 0x00, 0x00, 0x0c,\n\t\t\t0x00, 0x00, 0x14, 0x00,\n\t\t\t0x00, 0x28, 0x00, 0x00,\n\t\t\t0x00, 0x00, 0x00, 0x00,\n\t\t\t0xfd, 0x00, 0x00, 0x09,\n\t\t\t0x50, 0x5f, 0x50, 0x52,\n\t\t\t0x4f, 0x47, 0x52, 0x41,\n\t\t\t0x4d\n\t\t};\n\n\t\t// S7 COLD Start request\n\t\tbyte[] S7_COLD_START = {\n\t\t\t0x03, 0x00, 0x00, 0x27,\n\t\t\t0x02, 0xf0, 0x80, 0x32,\n\t\t\t0x01, 0x00, 0x00, 0x0f,\n\t\t\t0x00, 0x00, 0x16, 0x00,\n\t\t\t0x00, 0x28, 0x00, 0x00,\n\t\t\t0x00, 0x00, 0x00, 0x00,\n\t\t\t0xfd, 0x00, 0x02, 0x43,\n\t\t\t0x20, 0x09, 0x50, 0x5f,\n\t\t\t0x50, 0x52, 0x4f, 0x47,\n\t\t\t0x52, 0x41, 0x4d\n\t\t};\n\t\tconst byte pduStart          = 0x28;   // CPU start\n\t\tconst byte pduStop           = 0x29;   // CPU stop\n\t\tconst byte pduAlreadyStarted = 0x02;   // CPU already in run mode\n\t\tconst byte pduAlreadyStopped = 0x07;   // CPU already in stop mode\n\n\t\t// S7 Get PLC Status \n\t\tbyte[] S7_GET_STAT = {\n\t\t\t0x03, 0x00, 0x00, 0x21,\n\t\t\t0x02, 0xf0, 0x80, 0x32,\n\t\t\t0x07, 0x00, 0x00, 0x2c,\n\t\t\t0x00, 0x00, 0x08, 0x00,\n\t\t\t0x08, 0x00, 0x01, 0x12,\n\t\t\t0x04, 0x11, 0x44, 0x01,\n\t\t\t0x00, 0xff, 0x09, 0x00,\n\t\t\t0x04, 0x04, 0x24, 0x00,\n\t\t\t0x00\n\t\t};\n\n\t\t// S7 Get Block Info Request Header (contains also ISO Header and COTP Header)\n\t\tbyte[] S7_BI = {\n\t\t\t0x03, 0x00, 0x00, 0x25, \n\t\t\t0x02, 0xf0, 0x80, 0x32, \n\t\t\t0x07, 0x00, 0x00, 0x05, \n\t\t\t0x00, 0x00, 0x08, 0x00, \n\t\t\t0x0c, 0x00, 0x01, 0x12, \n\t\t\t0x04, 0x11, 0x43, 0x03, \n\t\t\t0x00, 0xff, 0x09, 0x00, \n\t\t\t0x08, 0x30, \n\t\t\t0x41, // Block Type\n\t\t\t0x30, 0x30, 0x30, 0x30, 0x30, // ASCII Block Number\n\t\t\t0x41 \n\t\t};    \n\n\t\t#endregion\n\n\t\t#region [Internals]\n\n\t\t// Defaults\n\t\tprivate static int ISOTCP = 102; // ISOTCP Port\n\t\tprivate static int MinPduSize = 16;\n\t\tprivate static int MinPduSizeToRequest = 240;\n\t\tprivate static int MaxPduSizeToRequest = 960;\n\t\tprivate static int DefaultTimeout = 2000;\n\t\tprivate static int IsoHSize = 7; // TPKT+COTP Header Size\n\n\t\t// Properties\n\t\tprivate int _PDULength = 0;\n\t\tprivate int _PduSizeRequested = 480;\n\t\tprivate int _PLCPort = ISOTCP;\n\n\t\t// Privates\n\t\tprivate string IPAddress;\n\t\tprivate byte LocalTSAP_HI;\n\t\tprivate byte LocalTSAP_LO;\n\t\tprivate byte RemoteTSAP_HI;\n\t\tprivate byte RemoteTSAP_LO;\n\t\tprivate byte LastPDUType;\n\t\tprivate ushort ConnType = CONNTYPE_PG;\n\t\tprivate byte[] PDU = new byte[2048];\n\t\tprivate MsgSocket Socket = null;\n\t\tprivate int Time_ms = 0;\n\n\t\tprivate void CreateSocket()\n\t\t{\n\t\t\tSocket = new MsgSocket();\n\t\t\tSocket.ConnectTimeout = DefaultTimeout;\n\t\t\tSocket.ReadTimeout = DefaultTimeout;\n\t\t\tSocket.WriteTimeout = DefaultTimeout;\n\t\t}\n\n\t\tprivate int TCPConnect()\n\t\t{           \n\t\t\tif (_LastError==0)\n\t\t\t{\n\t\t\t\ttry\n\t\t\t\t{\n\t\t\t\t\t_LastError=Socket.Connect(IPAddress, _PLCPort);\n\t\t\t\t}\n\t\t\t\tcatch\n\t\t\t\t{\n\t\t\t\t\t_LastError = S7Consts.errTCPConnectionFailed;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn _LastError;\n\t\t}\n       \n\t\tprivate void RecvPacket(byte[] Buffer, int Start, int Size)\n\t\t{\n\t\t\tif (Connected)\n\t\t\t\t_LastError = Socket.Receive(Buffer, Start, Size);\n\t\t\telse\n\t\t\t\t_LastError = S7Consts.errTCPNotConnected;\n\t\t}\n\n\t\tprivate void SendPacket(byte[] Buffer, int Len)\n\t\t{\n\t\t\tif (Connected)\n\t\t\t\t_LastError = Socket.Send(Buffer, Len);\n\t\t\telse\n\t\t\t\t_LastError = S7Consts.errTCPNotConnected;\n\t\t}\n\n\t\tprivate void SendPacket(byte[] Buffer)\n\t\t{\n\t\t\tSendPacket(Buffer, Buffer.Length);\n\t\t}\n\n\t\tprivate int RecvIsoPacket()\n\t\t{\n\t\t\tBoolean Done = false;\n\t\t\tint Size = 0;\n\t\t\twhile ((_LastError == 0) && !Done)\n\t\t\t{\n\t\t\t\t// Get TPKT (4 bytes)\n\t\t\t\tRecvPacket(PDU, 0, 4);\n\t\t\t\tif (_LastError == 0)\n\t\t\t\t{\n\t\t\t\t\tSize = PDU.GetWordAt(2);\n\t\t\t\t\t// Check 0 bytes Data Packet (only TPKT+COTP = 7 bytes)\n\t\t\t\t\tif (Size == IsoHSize)\n\t\t\t\t\t\tRecvPacket(PDU, 4, 3); // Skip remaining 3 bytes and Done is still false\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tif ((Size > _PduSizeRequested + IsoHSize) || (Size < MinPduSize))\n\t\t\t\t\t\t\t_LastError = S7Consts.errIsoInvalidPDU;\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tDone = true; // a valid Length !=7 && >16 && <247\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (_LastError == 0)\n\t\t\t{\n\t\t\t\tRecvPacket(PDU, 4, 3); // Skip remaining 3 COTP bytes\n\t\t\t\tLastPDUType = PDU[5];   // Stores PDU Type, we need it \n\t\t\t\t// Receives the S7 Payload          \n\t\t\t\tRecvPacket(PDU, 7, Size - IsoHSize);\n\t\t\t}\n\n\t\t\tif (_LastError == 0)\n\t\t\t{\n\t\t\t\treturn Size;\n\t\t\t}\n\t\t\t\t\n\t\t\treturn 0;\n\t\t}\n\n\t\tprivate int ISOConnect()\n\t\t{\n\t\t\tint Size;\n\t\t\tISO_CR[16] = LocalTSAP_HI;\n\t\t\tISO_CR[17] = LocalTSAP_LO;\n\t\t\tISO_CR[20] = RemoteTSAP_HI;\n\t\t\tISO_CR[21] = RemoteTSAP_LO;\n\n\t\t\t// Sends the connection request telegram      \n\t\t\tSendPacket(ISO_CR);\n\t\t\tif (_LastError == 0)\n\t\t\t{\n\t\t\t\t// Gets the reply (if any)\n\t\t\t\tSize = RecvIsoPacket();\n\t\t\t\tif (_LastError == 0)\n\t\t\t\t{\n\t\t\t\t\tif (Size == 22)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (LastPDUType != (byte)0xD0) // 0xD0 = CC Connection confirm\n\t\t\t\t\t\t\t_LastError = S7Consts.errIsoConnect;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\t_LastError = S7Consts.errIsoInvalidPDU;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn _LastError;\n\t\t}\n\n\t\tprivate int NegotiatePduLength()\n\t\t{\n\t\t\tint Length;\n\t\t\t// Set PDU Size Requested\n\t\t\tS7_PN.SetWordAt(23, (ushort)_PduSizeRequested);\n\t\t\t// Sends the connection request telegram\n\t\t\tSendPacket(S7_PN);\n\t\t\tif (_LastError == 0)\n\t\t\t{\n\t\t\t\tLength = RecvIsoPacket();\n\t\t\t\tif (_LastError == 0)\n\t\t\t\t{\n\t\t\t\t\t// check S7 Error\n\t\t\t\t\tif ((Length == 27) && (PDU[17] == 0) && (PDU[18] == 0))  // 20 = size of Negotiate Answer\n\t\t\t\t\t{\n\t\t\t\t\t\t// Get PDU Size Negotiated\n\t\t\t\t\t\t_PDULength = PDU.GetWordAt(25);\n\t\t\t\t\t\tif (_PDULength <= 0)\n\t\t\t\t\t\t\t_LastError = S7Consts.errCliNegotiatingPDU;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\t_LastError = S7Consts.errCliNegotiatingPDU;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn _LastError;\n\t\t}\n\n\t\tprivate int CpuError(ushort Error)\n\t\t{\n\t\t\tswitch(Error)\n\t\t\t{\n\t\t\t\tcase 0                          : return 0;\n\t\t\t\tcase Code7AddressOutOfRange     : return S7Consts.errCliAddressOutOfRange;\n\t\t\t\tcase Code7InvalidTransportSize  : return S7Consts.errCliInvalidTransportSize;\n\t\t\t\tcase Code7WriteDataSizeMismatch : return S7Consts.errCliWriteDataSizeMismatch;\n\t\t\t\tcase Code7ResItemNotAvailable   :\n\t\t\t\tcase Code7ResItemNotAvailable1  : return S7Consts.errCliItemNotAvailable;\n\t\t\t\tcase Code7DataOverPDU           : return S7Consts.errCliSizeOverPDU;\n\t\t\t\tcase Code7InvalidValue          : return S7Consts.errCliInvalidValue;\n\t\t\t\tcase Code7FunNotAvailable       : return S7Consts.errCliFunNotAvailable;\n\t\t\t\tcase Code7NeedPassword          : return S7Consts.errCliNeedPassword;\n\t\t\t\tcase Code7InvalidPassword       : return S7Consts.errCliInvalidPassword;\n\t\t\t\tcase Code7NoPasswordToSet       :\n\t\t\t\tcase Code7NoPasswordToClear     : return S7Consts.errCliNoPasswordToSetOrClear;\n\t\t\t\tdefault:\n\t\t\t\t\treturn S7Consts.errCliFunctionRefused;\n\t\t\t};\n\t\t}\n\n\t\t#endregion\n\n\t\t#region [Class Control]\n\n\t\tpublic S7Client(string name) : this()\n\t\t{\n\t\t\tName = name;\n\t\t}\n\n\t\tpublic string Name { get; }\n\n\t\tpublic S7Client()\n\t\t{\n\t\t\tCreateSocket();\n\t\t}\n\n\t\t~S7Client()\n\t\t{\n\t\t\tDisconnect();\n\t\t}\n\n\t\tpublic override string ToString()\n\t\t{ \n\t\t\treturn $\"PLC {Name ?? string.Empty}@{PLCIpAddress ?? \"0.0.0.0\"}\";\n\t\t}\n\n\t\tpublic int Connect()\n\t\t{\n\t\t\t_LastError = 0;\n\t\t\tTime_ms = 0;\n\t\t\tint Elapsed = Environment.TickCount;\n\t\t\tif (!Connected)\n\t\t\t{\n\t\t\t\tTCPConnect(); // First stage : TCP Connection\n\t\t\t\tif (_LastError == 0) \n\t\t\t\t{\n\t\t\t\t\tISOConnect(); // Second stage : ISOTCP (ISO 8073) Connection\n\t\t\t\t\tif (_LastError == 0) \n\t\t\t\t\t{\n\t\t\t\t\t\t_LastError = NegotiatePduLength(); // Third stage : S7 PDU negotiation\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (_LastError != 0)\n\t\t\t\tDisconnect();\n\t\t\telse\n\t\t\t\tTime_ms = Environment.TickCount - Elapsed;\n\n\t\t\treturn _LastError;\n\t\t}\n\n\t\tpublic int ConnectTo(string Address, int Rack, int Slot)\n\t\t{\n\t\t\tUInt16 RemoteTSAP = (UInt16)((ConnType << 8) + (Rack * 0x20) + Slot);\n\t\t\tSetConnectionParams(Address, 0x0100, RemoteTSAP);\n\t\t\treturn Connect();\n\t\t}\n\n\t\tpublic int SetConnectionParams(string Address, ushort LocalTSAP, ushort RemoteTSAP)\n\t\t{\n\t\t\tint LocTSAP = LocalTSAP & 0x0000FFFF;\n\t\t\tint RemTSAP = RemoteTSAP & 0x0000FFFF;\n\t\t\tIPAddress = Address;\n\t\t\tLocalTSAP_HI = (byte)(LocTSAP >> 8);\n\t\t\tLocalTSAP_LO = (byte)(LocTSAP & 0x00FF);\n\t\t\tRemoteTSAP_HI = (byte)(RemTSAP >> 8);\n\t\t\tRemoteTSAP_LO = (byte)(RemTSAP & 0x00FF);\n\t\t\treturn 0;\n\t\t}\n\n\t\tpublic int SetConnectionType(ushort ConnectionType)\n\t\t{\n\t\t\tConnType = ConnectionType;\n\t\t\treturn 0;\n\t\t}\n\n\t\tpublic int Disconnect()\n\t\t{\n\t\t\tSocket?.Close();\n\t\t\treturn 0;\n\t\t}\n\n\t\tpublic int GetParam(Int32 ParamNumber, ref int Value)\n\t\t{\n\t\t\tint Result = 0;\n\t\t\tswitch (ParamNumber)\n\t\t\t{\n\t\t\t\tcase S7Consts.p_u16_RemotePort:\n\t\t\t\t{\n\t\t\t\t\tValue = PLCPort;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase S7Consts.p_i32_PingTimeout:\n\t\t\t\t{\n\t\t\t\t\tValue = ConnTimeout;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase S7Consts.p_i32_SendTimeout:\n\t\t\t\t{\n\t\t\t\t\tValue = SendTimeout;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase S7Consts.p_i32_RecvTimeout:\n\t\t\t\t{\n\t\t\t\t\tValue = RecvTimeout;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase S7Consts.p_i32_PDURequest:\n\t\t\t\t{\n\t\t\t\t\tValue = PduSizeRequested;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t{\n\t\t\t\t\tResult = S7Consts.errCliInvalidParamNumber;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn Result;\n\t\t}\n\n\t\t// Set Properties for compatibility with Snap7.net.cs\n\t\tpublic int SetParam(Int32 ParamNumber, ref int Value)\n\t\t{\n\t\t\tint Result = 0;\n\t\t\tswitch(ParamNumber)\n\t\t\t{\n\t\t\t\tcase S7Consts.p_u16_RemotePort:\n\t\t\t\t{\n\t\t\t\t\tPLCPort = Value;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase S7Consts.p_i32_PingTimeout:\n\t\t\t\t{\n\t\t\t\t\tConnTimeout = Value;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase S7Consts.p_i32_SendTimeout:\n\t\t\t\t{\n\t\t\t\t\tSendTimeout = Value;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase S7Consts.p_i32_RecvTimeout:\n\t\t\t\t{\n\t\t\t\t\tRecvTimeout = Value;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase S7Consts.p_i32_PDURequest:\n\t\t\t\t{\n\t\t\t\t\tPduSizeRequested = Value;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t{\n\t\t\t\t\tResult = S7Consts.errCliInvalidParamNumber;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn Result; \n\t\t}\n\n\t\tpublic delegate void S7CliCompletion(IntPtr usrPtr, int opCode, int opResult);\n\t\tpublic int SetAsCallBack(S7CliCompletion Completion, IntPtr usrPtr)\n\t\t{\n\t\t\treturn S7Consts.errCliFunctionNotImplemented;\n\t\t}\n\n\t\t#endregion\n\n\t\t#region [Data I/O main functions]\n\n\t\tpublic int ReadArea(S7Area Area, int DBNumber, int Start, int Amount, S7WordLength WordLen, byte[] Buffer)\n\t\t{\n\t\t\treturn ReadArea((int)Area, DBNumber, Start, Amount, (int)WordLen, Buffer);\n\t\t}\n\n\t\tpublic int ReadArea(S7Area Area, int DBNumber, int Start, int Amount, S7WordLength WordLen, byte[] Buffer, ref int BytesRead)\n\t\t{\n\t\t\treturn ReadArea((int)Area, DBNumber, Start, Amount, (int)WordLen, Buffer, ref BytesRead);\n\t\t}\n\t\tpublic int ReadArea(int Area, int DBNumber, int Start, int Amount, int WordLen, byte[] Buffer)\n\t\t{\n\t\t\tint BytesRead = 0;\n\t\t\treturn ReadArea(Area, DBNumber, Start, Amount, WordLen, Buffer, ref BytesRead);\n\t\t}\n\n\t\tpublic int ReadArea(int Area, int DBNumber, int Start, int Amount, int WordLen, byte[] Buffer, ref int BytesRead)\n\t\t{\n\t\t\tint Address;\n\t\t\tint NumElements;\n\t\t\tint MaxElements;\n\t\t\tint TotElements;\n\t\t\tint SizeRequested;\n\t\t\tint Length;\n\t\t\tint Offset = 0;\n\t\t\tint WordSize = 1;\n\n\t\t\t_LastError = 0;\n\t\t\tTime_ms = 0;\n\t\t\tint Elapsed = Environment.TickCount;\n\t\t\t// Some adjustment\n\t\t\tif (Area == (int)S7Area.CT)\n\t\t\t\tWordLen = (int)S7WordLength.Counter;\n\t\t\tif (Area == (int)S7Area.TM)\n\t\t\t\tWordLen = (int)S7WordLength.Timer;\n\n\t\t\t// Calc Word size          \n\t\t\tWordSize = WordLen.DataSizeByte();\n\t\t\tif (WordSize == 0)\n\t\t\t\treturn S7Consts.errCliInvalidWordLen;\n\n\t\t\tif (WordLen == (int)S7WordLength.Bit)\n\t\t\t\tAmount = 1;  // Only 1 bit can be transferred at time\n\t\t\telse\n\t\t\t{\n\t\t\t\tif ((WordLen != (int)S7WordLength.Counter) && (WordLen != (int)S7WordLength.Timer))\n\t\t\t\t{\n\t\t\t\t\tAmount = Amount * WordSize;\n\t\t\t\t\tWordSize = 1;\n\t\t\t\t\tWordLen = (int)S7WordLength.Byte;\n\t\t\t\t}\n\t\t\t}        \n\n\t\t\tMaxElements = (_PDULength - 18) / WordSize; // 18 = Reply telegram header\n\t\t\tTotElements = Amount;\n\n\t\t\twhile ((TotElements > 0) && (_LastError == 0))\n\t\t\t{\n\t\t\t\tNumElements = TotElements;\n\t\t\t\tif (NumElements > MaxElements)\n\t\t\t\t\tNumElements = MaxElements;\n\n\t\t\t\tSizeRequested = NumElements * WordSize;\n\n\t\t\t\t// Setup the telegram\n\t\t\t\tArray.Copy(S7_RW, 0, PDU, 0, Size_RD);\n\t\t\t\t// Set DB Number\n\t\t\t\tPDU[27] = (byte)Area;\n\t\t\t\t// Set Area\n\t\t\t\tif (Area == (int)S7Area.DB)\n\t\t\t\t\tPDU.SetWordAt(25, (ushort)DBNumber);\n\n\t\t\t\t// Adjusts Start and word length\n\t\t\t\tif ((WordLen == (int)S7WordLength.Bit) || (WordLen == (int)S7WordLength.Counter) || (WordLen == (int)S7WordLength.Timer))\n\t\t\t\t{\n\t\t\t\t\tAddress = Start;\n\t\t\t\t\tPDU[22] = (byte)WordLen;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tAddress = Start << 3;\n\n\t\t\t\t// Num elements\n\t\t\t\tPDU.SetWordAt(23, (ushort)NumElements);\n\n\t\t\t\t// Address into the PLC (only 3 bytes)           \n\t\t\t\tPDU[30] = (byte)(Address & 0x0FF);\n\t\t\t\tAddress = Address >> 8;\n\t\t\t\tPDU[29] = (byte)(Address & 0x0FF);\n\t\t\t\tAddress = Address >> 8;\n\t\t\t\tPDU[28] = (byte)(Address & 0x0FF);\n\n\t\t\t\tSendPacket(PDU, Size_RD);\n\t\t\t\tif (_LastError == 0)\n\t\t\t\t{\n\t\t\t\t\tLength = RecvIsoPacket();\n\t\t\t\t\tif (_LastError == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (Length<25)\n\t\t\t\t\t\t\t_LastError = S7Consts.errIsoInvalidDataSize;\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (PDU[21] != 0xFF)\n\t\t\t\t\t\t\t\t_LastError = CpuError(PDU[21]);\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tArray.Copy(PDU, 25, Buffer, Offset, SizeRequested);\n\t\t\t\t\t\t\t\tOffset += SizeRequested;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tTotElements -= NumElements;\n\t\t\t\tStart += NumElements * WordSize;\n\t\t\t}\n\n\t\t\tif (_LastError == 0)\n\t\t\t{\n\t\t\t\tBytesRead = Offset;\n\t\t\t\tTime_ms = Environment.TickCount - Elapsed;\n\t\t\t}\n\t\t\telse\n\t\t\t\tBytesRead = 0;\n\t\t\treturn _LastError;\n\t\t}\n\n\t\tpublic int WriteArea(S7Area Area, int DBNumber, int Start, int Amount, S7WordLength WordLen, byte[] Buffer)\n\t\t{\n\t\t\tint BytesWritten = 0;\n\t\t\treturn WriteArea((int) Area, DBNumber, Start, Amount, (int) WordLen, Buffer, ref BytesWritten);\n\t\t}\n\n\t\tpublic int WriteArea(S7Area Area, int DBNumber, int Start, int Amount, S7WordLength WordLen, byte[] Buffer, ref int BytesWritten)\n\t\t{\n\t\t\treturn WriteArea((int) Area, DBNumber, Start, Amount, (int) WordLen, Buffer, ref BytesWritten);\n\t\t}\t\t\n\t\tpublic int WriteArea(int Area, int DBNumber, int Start, int Amount, int WordLen, byte[] Buffer)\n\t\t{\n\t\t\tint BytesWritten = 0;\n\t\t\treturn WriteArea(Area, DBNumber, Start, Amount, WordLen, Buffer, ref BytesWritten);\n\t\t}\n\n\t\tpublic int WriteArea(int Area, int DBNumber, int Start, int Amount, int WordLen, byte[] Buffer, ref int BytesWritten)\n\t\t{\n\t\t\tint Address;\n\t\t\tint NumElements;\n\t\t\tint MaxElements;\n\t\t\tint TotElements;\n\t\t\tint DataSize;\n\t\t\tint IsoSize;\n\t\t\tint Length;\n\t\t\tint Offset = 0;\n\t\t\tint WordSize = 1;\n\n\t\t\t_LastError = 0;\n\t\t\tTime_ms = 0;\n\t\t\tint Elapsed = Environment.TickCount;\n\t\t\t// Some adjustment\n\t\t\tif (Area == (int)S7Area.CT)\n\t\t\t\tWordLen = (int)S7WordLength.Counter;\n\t\t\tif (Area == (int)S7Area.TM)\n\t\t\t\tWordLen = (int)S7WordLength.Timer;\n\n\t\t\t// Calc Word size          \n\t\t\tWordSize = WordLen.DataSizeByte();\n\t\t\tif (WordSize == 0)\n\t\t\t\treturn S7Consts.errCliInvalidWordLen;\n\n\t\t\tif (WordLen == (int)S7WordLength.Bit) // Only 1 bit can be transferred at time\n\t\t\t\tAmount = 1;\n\t\t\telse\n\t\t\t{\n\t\t\t\tif ((WordLen != (int)S7WordLength.Counter) && (WordLen != (int)S7WordLength.Timer))\n\t\t\t\t{\n\t\t\t\t\tAmount = Amount * WordSize;\n\t\t\t\t\tWordSize = 1;\n\t\t\t\t\tWordLen = (int)S7WordLength.Byte;\n\t\t\t\t}\n\t\t\t}        \n\n\t\t\tMaxElements = (_PDULength - 35) / WordSize; // 35 = Reply telegram header\n\t\t\tTotElements = Amount;\n\n\t\t\twhile ((TotElements > 0) && (_LastError == 0))\n\t\t\t{\n\t\t\t\tNumElements = TotElements;\n\t\t\t\tif (NumElements > MaxElements)\n\t\t\t\t\tNumElements = MaxElements;\n\n\t\t\t\tDataSize = NumElements * WordSize;\n\t\t\t\tIsoSize = Size_WR + DataSize;\n\n\t\t\t\t// Setup the telegram\n\t\t\t\tArray.Copy(S7_RW, 0, PDU, 0, Size_WR);\n\t\t\t\t// Whole telegram Size\n\t\t\t\tPDU.SetWordAt(2, (ushort)IsoSize);\n\t\t\t\t// Data Length\n\t\t\t\tLength = DataSize + 4;\n\t\t\t\tPDU.SetWordAt(15, (ushort)Length);\n\t\t\t\t// Function\n\t\t\t\tPDU[17] = (byte)0x05;\n\t\t\t\t// Set DB Number\n\t\t\t\tPDU[27] = (byte)Area;\n\t\t\t\tif (Area == (int)S7Area.DB)\n\t\t\t\t\tPDU.SetWordAt(25, (ushort)DBNumber);\n\n\n\t\t\t\t// Adjusts Start and word length\n\t\t\t\tif ((WordLen == (int)S7WordLength.Bit) || (WordLen == (int)S7WordLength.Counter) || (WordLen == (int)S7WordLength.Timer))\n\t\t\t\t{\n\t\t\t\t\tAddress = Start;\n\t\t\t\t\tLength = DataSize;\n\t\t\t\t\tPDU[22] = (byte)WordLen;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tAddress = Start << 3;\n\t\t\t\t\tLength = DataSize << 3;\n\t\t\t\t}\n\n\t\t\t\t// Num elements\n\t\t\t\tPDU.SetWordAt(23, (ushort)NumElements);\n\t\t\t\t// Address into the PLC\n\t\t\t\tPDU[30] = (byte)(Address & 0x0FF);\n\t\t\t\tAddress = Address >> 8;\n\t\t\t\tPDU[29] = (byte)(Address & 0x0FF);\n\t\t\t\tAddress = Address >> 8;\n\t\t\t\tPDU[28] = (byte)(Address & 0x0FF);\n\n\t\t\t\t// Transport Size\n\t\t\t\tswitch (WordLen)\n\t\t\t\t{\n\t\t\t\t\tcase (int)S7WordLength.Bit:\n\t\t\t\t\t\tPDU[32] = TS_ResBit;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase (int)S7WordLength.Counter:\n\t\t\t\t\tcase (int)S7WordLength.Timer:\n\t\t\t\t\t\tPDU[32] = TS_ResOctet;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tPDU[32] = TS_ResByte; // byte/word/dword etc.\n\t\t\t\t\t\tbreak;\n\t\t\t\t};\n\t\t\t\t// Length\n\t\t\t\tPDU.SetWordAt(33, (ushort)Length);\n\n\t\t\t\t// Copies the Data\n\t\t\t\tArray.Copy(Buffer, Offset, PDU, 35, DataSize);\n\n\t\t\t\tSendPacket(PDU, IsoSize);\n\t\t\t\tif (_LastError == 0)\n\t\t\t\t{\n\t\t\t\t\tLength = RecvIsoPacket();\n\t\t\t\t\tif (_LastError == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (Length == 22)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (PDU[21] != (byte)0xFF)\n\t\t\t\t\t\t\t\t_LastError = CpuError(PDU[21]);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\t_LastError = S7Consts.errIsoInvalidPDU;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tOffset += DataSize;\n\t\t\t\tTotElements -= NumElements;\n\t\t\t\tStart += NumElements * WordSize;\n\t\t\t}\n\n\t\t\tif (_LastError == 0)\n\t\t\t{\n\t\t\t\tBytesWritten = Offset;\n\t\t\t\tTime_ms = Environment.TickCount - Elapsed;\n\t\t\t}\n\t\t\telse\n\t\t\t\tBytesWritten = 0;\n\n\t\t\treturn _LastError;\n\t\t}\n\n\t\tpublic int ReadMultiVars(S7DataItem[] Items, int ItemsCount)\n\t\t{\n\t\t\tint Offset;\n\t\t\tint Length;\n\t\t\tint ItemSize;\n\t\t\tbyte[] S7Item = new byte[12];\n\t\t\tbyte[] S7ItemRead = new byte[1024]; \n            \n\t\t\t_LastError = 0;\n\t\t\tTime_ms = 0;\n\t\t\tint Elapsed = Environment.TickCount;\n\n\t\t\t// Checks items\n\t\t\tif (ItemsCount > MaxVars)\n\t\t\t\treturn S7Consts.errCliTooManyItems;\n            \n\t\t\t// Fills Header\n\t\t\tArray.Copy(S7_MRD_HEADER, 0, PDU, 0, S7_MRD_HEADER.Length);\n\t\t\tPDU.SetWordAt(13, (ushort)(ItemsCount * S7Item.Length + 2));\n\t\t\tPDU[18] = (byte)ItemsCount;\n\t\t\t// Fills the Items\n\t\t\tOffset = 19;\n\t\t\tfor (int c = 0; c < ItemsCount; c++)\n\t\t\t{\n\t\t\t\tArray.Copy(S7_MRD_ITEM, S7Item, S7Item.Length);\n\t\t\t\tS7Item[3] = (byte)Items[c].WordLen;\n\t\t\t\tS7Item.SetWordAt(4, (ushort)Items[c].Amount);\n\t\t\t\tif (Items[c].Area == (int)S7Area.DB)\n\t\t\t\t\tS7Item.SetWordAt(6, (ushort)Items[c].DBNumber);\n\t\t\t\tS7Item[8] = (byte)Items[c].Area;\n                \n\t\t\t\t// Address into the PLC\n\t\t\t\tint Address = Items[c].Start;\n\t\t\t\tS7Item[11] = (byte)(Address & 0x0FF);\n\t\t\t\tAddress = Address >> 8;\n\t\t\t\tS7Item[10] = (byte)(Address & 0x0FF);\n\t\t\t\tAddress = Address >> 8;\n\t\t\t\tS7Item[09] = (byte)(Address & 0x0FF);\n\n\t\t\t\tArray.Copy(S7Item, 0, PDU, Offset, S7Item.Length);\n\t\t\t\tOffset += S7Item.Length;\n\t\t\t}\n\n\t\t\tif (Offset > _PDULength)\n\t\t\t\treturn S7Consts.errCliSizeOverPDU;\n\n\t\t\tPDU.SetWordAt(2, (ushort)Offset); // Whole size\n\t\t\tSendPacket(PDU, Offset);\n            \n\t\t\tif (_LastError != 0)\n\t\t\t\treturn _LastError;\n\t\t\t// Get Answer\n\t\t\tLength = RecvIsoPacket();\n\t\t\tif (_LastError != 0)\n\t\t\t\treturn _LastError;\n\t\t\t// Check ISO Length\n\t\t\tif (Length < 22)\n\t\t\t{\n\t\t\t\t_LastError = S7Consts.errIsoInvalidPDU; // PDU too Small\n\t\t\t\treturn _LastError;\n\t\t\t}\n\t\t\t// Check Global Operation Result\n\t\t\t_LastError = CpuError(PDU.GetWordAt(17));\n\t\t\tif (_LastError != 0)\n\t\t\t\treturn _LastError;\n\t\t\t// Get true ItemsCount\n\t\t\tint ItemsRead = PDU.GetByteAt(20);\n\t\t\tif ((ItemsRead != ItemsCount) || (ItemsRead>MaxVars))\n\t\t\t{\n\t\t\t\t_LastError = S7Consts.errCliInvalidPlcAnswer;\n\t\t\t\treturn _LastError;\n\t\t\t}\n\t\t\t// Get Data\n\t\t\tOffset = 21;           \n\t\t\tfor (int c = 0; c < ItemsCount; c++)\n\t\t\t{\n\t\t\t\t// Get the Item\n\t\t\t\tArray.Copy(PDU, Offset, S7ItemRead, 0, Length-Offset);\n\t\t\t\tif (S7ItemRead[0] == 0xff)\n\t\t\t\t{\n\t\t\t\t\tItemSize = (int)S7ItemRead.GetWordAt(2);\n\t\t\t\t\tif ((S7ItemRead[1] != TS_ResOctet) && (S7ItemRead[1] != TS_ResReal) && (S7ItemRead[1] != TS_ResBit))\n\t\t\t\t\t\tItemSize = ItemSize >> 3;\n\t\t\t\t\tMarshal.Copy(S7ItemRead, 4, Items[c].pData, ItemSize);\n\t\t\t\t\tItems[c].Result = 0;\n\t\t\t\t\tif (ItemSize % 2 != 0)\n\t\t\t\t\t\tItemSize++; // Odd size are rounded\n\t\t\t\t\tOffset = Offset + 4 + ItemSize;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tItems[c].Result = CpuError(S7ItemRead[0]);\n\t\t\t\t\tOffset += 4; // Skip the Item header                           \n\t\t\t\t}\n\t\t\t}         \n\t\t\tTime_ms = Environment.TickCount - Elapsed;\n\t\t\treturn _LastError;\n\t\t}\n\n\t\tpublic int WriteMultiVars(S7DataItem[] Items, int ItemsCount)\n\t\t{\n\t\t\tint Offset;\n\t\t\tint ParLength;\n\t\t\tint DataLength;\n\t\t\tint ItemDataSize;\n\t\t\tbyte[] S7ParItem = new byte[S7_MWR_PARAM.Length];\n\t\t\tbyte[] S7DataItem = new byte[1024];\n\n\t\t\t_LastError = 0;\n\t\t\tTime_ms = 0;\n\t\t\tint Elapsed = Environment.TickCount;\n\n\t\t\t// Checks items\n\t\t\tif (ItemsCount > MaxVars)\n\t\t\t\treturn S7Consts.errCliTooManyItems;\n\t\t\t// Fills Header\n\t\t\tArray.Copy(S7_MWR_HEADER, 0, PDU, 0, S7_MWR_HEADER.Length);\n\t\t\tParLength = ItemsCount * S7_MWR_PARAM.Length + 2;\n\t\t\tPDU.SetWordAt(13, (ushort)ParLength);\n\t\t\tPDU[18] = (byte)ItemsCount;\n\t\t\t// Fills Params\n\t\t\tOffset = S7_MWR_HEADER.Length;\n\t\t\tfor (int c=0; c<ItemsCount; c++)\n\t\t\t{\n\t\t\t\tArray.Copy(S7_MWR_PARAM, 0, S7ParItem, 0, S7_MWR_PARAM.Length);\n\t\t\t\tS7ParItem[3] = (byte)Items[c].WordLen;\n\t\t\t\tS7ParItem[8] = (byte)Items[c].Area;\n\t\t\t\tS7ParItem.SetWordAt(4, (ushort)Items[c].Amount);\n\t\t\t\tS7ParItem.SetWordAt(6, (ushort)Items[c].DBNumber);\n\t\t\t\t// Address into the PLC\n\t\t\t\tint Address = Items[c].Start;\n\t\t\t\tS7ParItem[11] = (byte)(Address & 0x0FF);\n\t\t\t\tAddress = Address >> 8;\n\t\t\t\tS7ParItem[10] = (byte)(Address & 0x0FF);\n\t\t\t\tAddress = Address >> 8;\n\t\t\t\tS7ParItem[09] = (byte)(Address & 0x0FF);\n\t\t\t\tArray.Copy(S7ParItem, 0, PDU, Offset, S7ParItem.Length);\n\t\t\t\tOffset += S7_MWR_PARAM.Length;\n\t\t\t}\n\t\t\t// Fills Data\n\t\t\tDataLength = 0;\n\t\t\tfor (int c = 0; c < ItemsCount; c++)\n\t\t\t{\n\t\t\t\tS7DataItem[0] = 0x00;\n\t\t\t\tswitch (Items[c].WordLen)\n\t\t\t\t{\n\t\t\t\t\tcase (int)S7WordLength.Bit:\n\t\t\t\t\t\tS7DataItem[1] = TS_ResBit;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase (int)S7WordLength.Counter:\n\t\t\t\t\tcase (int)S7WordLength.Timer:\n\t\t\t\t\t\tS7DataItem[1] = TS_ResOctet;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tS7DataItem[1] = TS_ResByte; // byte/word/dword etc.\n\t\t\t\t\t\tbreak;\n\t\t\t\t};\n\t\t\t\tif ((Items[c].WordLen==(int)S7WordLength.Timer) || (Items[c].WordLen == (int)S7WordLength.Counter))\n\t\t\t\t\tItemDataSize = Items[c].Amount * 2;\n\t\t\t\telse\n\t\t\t\t\tItemDataSize = Items[c].Amount;\n\n\t\t\t\tif ((S7DataItem[1] != TS_ResOctet) && (S7DataItem[1] != TS_ResBit))\n\t\t\t\t\tS7DataItem.SetWordAt(2, (ushort)(ItemDataSize*8));\n\t\t\t\telse\n\t\t\t\t\tS7DataItem.SetWordAt(2, (ushort)ItemDataSize);\n\n\t\t\t\tMarshal.Copy(Items[c].pData, S7DataItem, 4, ItemDataSize);\n\t\t\t\tif (ItemDataSize % 2 != 0)\n\t\t\t\t{\n\t\t\t\t\tS7DataItem[ItemDataSize+4] = 0x00;\n\t\t\t\t\tItemDataSize++;\n\t\t\t\t}\n\t\t\t\tArray.Copy(S7DataItem, 0, PDU, Offset, ItemDataSize+4);\n\t\t\t\tOffset = Offset + ItemDataSize + 4;\n\t\t\t\tDataLength = DataLength + ItemDataSize + 4;\n\t\t\t}\n\n\t\t\t// Checks the size\n\t\t\tif (Offset > _PDULength)\n\t\t\t\treturn S7Consts.errCliSizeOverPDU;\n\n\t\t\tPDU.SetWordAt(2, (ushort)Offset); // Whole size\n\t\t\tPDU.SetWordAt(15, (ushort)DataLength); // Whole size\n\t\t\tSendPacket(PDU, Offset);\n\n\t\t\tRecvIsoPacket();\n\t\t\tif (_LastError==0)\n\t\t\t{\n\t\t\t\t// Check Global Operation Result\n\t\t\t\t_LastError = CpuError(PDU.GetWordAt(17));\n\t\t\t\tif (_LastError != 0)\n\t\t\t\t\treturn _LastError;\n\t\t\t\t// Get true ItemsCount\n\t\t\t\tint ItemsWritten = PDU.GetByteAt(20);\n\t\t\t\tif ((ItemsWritten != ItemsCount) || (ItemsWritten > MaxVars))\n\t\t\t\t{\n\t\t\t\t\t_LastError = S7Consts.errCliInvalidPlcAnswer;\n\t\t\t\t\treturn _LastError;\n\t\t\t\t}\n\n\t\t\t\tfor (int c=0; c<ItemsCount; c++)\n\t\t\t\t{\n\t\t\t\t\tif (PDU[c + 21] == 0xFF)\n\t\t\t\t\t\tItems[c].Result = 0;\n\t\t\t\t\telse\n\t\t\t\t\t\tItems[c].Result = CpuError((ushort)PDU[c + 21]);\n\t\t\t\t}\n\t\t\t\tTime_ms = Environment.TickCount - Elapsed;\n\t\t\t}\n\t\t\treturn _LastError;\n\t\t}\n\n\t\t#endregion\n\n\t\t#region [Data I/O lean functions]\n\n\t\tpublic int DBRead(int DBNumber, int Start, int Size, byte[] Buffer)\n\t\t{\n\t\t\treturn ReadArea(S7Area.DB, DBNumber, Start, Size, S7WordLength.Byte, Buffer);\n\t\t}\n\n\t\tpublic int DBWrite(int DBNumber, int Start, int Size, byte[] Buffer)\n\t\t{\n\t\t\treturn WriteArea(S7Area.DB, DBNumber, Start, Size, S7WordLength.Byte, Buffer);\n\t\t}\n\n\t\tpublic int MBRead(int Start, int Size, byte[] Buffer)\n\t\t{\n\t\t\treturn ReadArea(S7Area.MK, 0, Start, Size, S7WordLength.Byte, Buffer);\n\t\t}\n\n\t\tpublic int MBWrite(int Start, int Size, byte[] Buffer)\n\t\t{\n\t\t\treturn WriteArea(S7Area.MK, 0, Start, Size, S7WordLength.Byte, Buffer);\n\t\t}\n\n\t\tpublic int EBRead(int Start, int Size, byte[] Buffer)\n\t\t{\n\t\t\treturn ReadArea(S7Area.PE, 0, Start, Size, S7WordLength.Byte, Buffer);\n\t\t}\n\n\t\tpublic int EBWrite(int Start, int Size, byte[] Buffer)\n\t\t{\n\t\t\treturn WriteArea(S7Area.PE, 0, Start, Size, S7WordLength.Byte, Buffer);\n\t\t}\n\n\t\tpublic int ABRead(int Start, int Size, byte[] Buffer)\n\t\t{\n\t\t\treturn ReadArea(S7Area.PA, 0, Start, Size, S7WordLength.Byte, Buffer);\n\t\t}\n\n\t\tpublic int ABWrite(int Start, int Size, byte[] Buffer)\n\t\t{\n\t\t\treturn WriteArea(S7Area.PA, 0, Start, Size, S7WordLength.Byte, Buffer);\n\t\t}\n\n\t\tpublic int TMRead(int Start, int Amount, ushort[] Buffer)\n\t\t{\n\t\t\tbyte[] sBuffer = new byte[Amount * 2];\n\t\t\tint Result = ReadArea(S7Area.TM, 0, Start, Amount, S7WordLength.Timer, sBuffer);\n\t\t\tif (Result == 0)\n\t\t\t{\n\t\t\t\tfor (int c = 0; c < Amount; c++)\n\t\t\t\t{\n\t\t\t\t\tBuffer[c] = (ushort)((sBuffer[c * 2 + 1] << 8) + (sBuffer[c * 2]));\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn Result;\n\t\t}\n\n\t\tpublic int TMWrite(int Start, int Amount, ushort[] Buffer)\n\t\t{\n\t\t\tbyte[] sBuffer = new byte[Amount * 2];\n\t\t\tfor (int c = 0; c < Amount; c++)\n\t\t\t{\n\t\t\t\tsBuffer[c * 2 + 1] = (byte)((Buffer[c] & 0xFF00) >> 8);\n\t\t\t\tsBuffer[c * 2] = (byte)(Buffer[c] & 0x00FF);\n\t\t\t}\n\t\t\treturn WriteArea(S7Area.TM, 0, Start, Amount, S7WordLength.Timer, sBuffer);\n\t\t}\n\n\t\tpublic int CTRead(int Start, int Amount, ushort[] Buffer)\n\t\t{\n\t\t\tbyte[] sBuffer = new byte[Amount * 2];\n\t\t\tint Result = ReadArea(S7Area.CT, 0, Start, Amount, S7WordLength.Counter, sBuffer);\n\t\t\tif (Result==0)\n\t\t\t{\n\t\t\t\tfor (int c=0; c<Amount; c++)\n\t\t\t\t{\n\t\t\t\t\tBuffer[c] = (ushort)((sBuffer[c * 2 + 1] << 8) + (sBuffer[c * 2]));\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn Result;\n\t\t}\n\n\t\tpublic int CTWrite(int Start, int Amount, ushort[] Buffer)\n\t\t{\n\t\t\tbyte[] sBuffer = new byte[Amount * 2];\n\t\t\tfor (int c = 0; c < Amount; c++)\n\t\t\t{\n\t\t\t\tsBuffer[c * 2 + 1] = (byte)((Buffer[c] & 0xFF00)>>8);\n\t\t\t\tsBuffer[c * 2]= (byte)(Buffer[c] & 0x00FF);\n\t\t\t}\n\t\t\treturn WriteArea(S7Area.CT, 0, Start, Amount, S7WordLength.Counter, sBuffer);\n\t\t}\n\n\t\t#endregion\n\n\t\t#region [Directory functions]\n\n\t\tpublic int ListBlocks(ref S7BlocksList List)\n\t\t{\n\t\t\treturn S7Consts.errCliFunctionNotImplemented;\n\t\t}\n\n\t\tprivate string SiemensTimestamp(long EncodedDate)\n\t\t{\n\t\t\tDateTime DT = new DateTime(1984, 1, 1).AddSeconds(EncodedDate*86400);\n#if WINDOWS_UWP || NETFX_CORE || CORE_CLR\n            return DT.ToString(System.Globalization.DateTimeFormatInfo.CurrentInfo.ShortDatePattern);\n#else\n\t\t\treturn DT.ToShortDateString();\n#endif\n\t\t}\n\n\t\tpublic int GetAgBlockInfo(int BlockType, int BlockNum, ref S7BlockInfo Info)\n\t\t{\n\t\t\t_LastError = 0;\n\t\t\tTime_ms = 0;\n\t\t\tint Elapsed = Environment.TickCount;\n\n\t\t\tS7_BI[30] = (byte)BlockType;\n\t\t\t// Block Number\n\t\t\tS7_BI[31] = (byte)((BlockNum / 10000) + 0x30);\n\t\t\tBlockNum = BlockNum % 10000;\n\t\t\tS7_BI[32] = (byte)((BlockNum / 1000) + 0x30);\n\t\t\tBlockNum = BlockNum % 1000;\n\t\t\tS7_BI[33] = (byte)((BlockNum / 100) + 0x30);\n\t\t\tBlockNum = BlockNum % 100;\n\t\t\tS7_BI[34] = (byte)((BlockNum / 10) + 0x30);\n\t\t\tBlockNum = BlockNum % 10;\n\t\t\tS7_BI[35] = (byte)((BlockNum / 1) + 0x30);\n\n\t\t\tSendPacket(S7_BI);\n\n\t\t\tif (_LastError == 0)\n\t\t\t{\n\t\t\t\tint Length = RecvIsoPacket();\n\t\t\t\tif (Length > 32) // the minimum expected\n\t\t\t\t{\n\t\t\t\t\tushort Result = PDU.GetWordAt(27);\n\t\t\t\t\tif (Result == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tInfo.BlkFlags= PDU[42];\n\t\t\t\t\t\tInfo.BlkLang = PDU[43];\n\t\t\t\t\t\tInfo.BlkType = PDU[44];\n\t\t\t\t\t\tInfo.BlkNumber = PDU.GetWordAt(45);\n\t\t\t\t\t\tInfo.LoadSize = PDU.GetDIntAt(47);\n\t\t\t\t\t\tInfo.CodeDate = SiemensTimestamp(PDU.GetWordAt(59));\n\t\t\t\t\t\tInfo.IntfDate = SiemensTimestamp(PDU.GetWordAt(65)); \n\t\t\t\t\t\tInfo.SBBLength = PDU.GetWordAt(67);\n\t\t\t\t\t\tInfo.LocalData = PDU.GetWordAt(71);\n\t\t\t\t\t\tInfo.MC7Size = PDU.GetWordAt(73);\n\t\t\t\t\t\tInfo.Author = PDU.GetCharsAt(75, 8).Trim(new char[]{(char)0});\n\t\t\t\t\t\tInfo.Family = PDU.GetCharsAt(83, 8).Trim(new char[]{(char)0});\n\t\t\t\t\t\tInfo.Header = PDU.GetCharsAt(91, 8).Trim(new char[]{(char)0}); \n\t\t\t\t\t\tInfo.Version = PDU[99];\n\t\t\t\t\t\tInfo.CheckSum = PDU.GetWordAt(101);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\t_LastError = CpuError(Result);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\t_LastError = S7Consts.errIsoInvalidPDU;\n\t\t\t}\n\t\t\tif (_LastError == 0)\n\t\t\t\tTime_ms = Environment.TickCount - Elapsed;\n\n\t\t\treturn _LastError;\n            \n\t\t}\n\n\t\tpublic int GetPgBlockInfo(ref S7BlockInfo Info, byte[] Buffer, int Size)\n\t\t{\n\t\t\treturn S7Consts.errCliFunctionNotImplemented;\n\t\t}\n\n\t\tpublic int ListBlocksOfType(int BlockType, ushort[] List, ref int ItemsCount)\n\t\t{\n\t\t\treturn S7Consts.errCliFunctionNotImplemented;\n\t\t}\n\n\t\t#endregion\n\n\t\t#region [Blocks functions]\n\n\t\tpublic int Upload(int BlockType, int BlockNum, byte[] UsrData, ref int Size)\n\t\t{\n\t\t\treturn S7Consts.errCliFunctionNotImplemented;\n\t\t}\n\n\t\tpublic int FullUpload(int BlockType, int BlockNum, byte[] UsrData, ref int Size)\n\t\t{\n\t\t\treturn S7Consts.errCliFunctionNotImplemented;\n\t\t}\n\n\t\tpublic int Download(int BlockNum, byte[] UsrData, int Size)\n\t\t{\n\t\t\treturn S7Consts.errCliFunctionNotImplemented;\n\t\t}\n\n\t\tpublic int Delete(int BlockType, int BlockNum)\n\t\t{\n\t\t\treturn S7Consts.errCliFunctionNotImplemented;\n\t\t}\n\n\t\tpublic int DBGet(int DBNumber, byte[] UsrData, ref int Size)\n\t\t{\n\t\t\tS7BlockInfo BI = new S7BlockInfo();\n\t\t\tint Elapsed = Environment.TickCount;\n\t\t\tTime_ms = 0;\n\n\t\t\t_LastError = GetAgBlockInfo(Block_DB, DBNumber, ref BI);\n\n\t\t\tif (_LastError==0)\n\t\t\t{\n\t\t\t\tint DBSize = BI.MC7Size;\n\t\t\t\tif (DBSize <= UsrData.Length)\n\t\t\t\t{\n\t\t\t\t\tSize = DBSize;\n\t\t\t\t\t_LastError = DBRead(DBNumber, 0, DBSize, UsrData);\n\t\t\t\t\tif (_LastError == 0)\n\t\t\t\t\t\tSize = DBSize;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\t_LastError = S7Consts.errCliBufferTooSmall;                  \n\t\t\t}\n\t\t\tif (_LastError == 0)\n\t\t\t\tTime_ms = Environment.TickCount - Elapsed;\n\t\t\treturn _LastError;\n\t\t}\n\n\t\tpublic int DBFill(int DBNumber, int FillChar)\n\t\t{\n\t\t\tS7BlockInfo BI = new S7BlockInfo();\n\t\t\tint Elapsed = Environment.TickCount;\n\t\t\tTime_ms = 0;\n            \n\t\t\t_LastError = GetAgBlockInfo(Block_DB, DBNumber, ref BI);\n            \n\t\t\tif (_LastError == 0)\n\t\t\t{\n\t\t\t\tbyte[] Buffer = new byte[BI.MC7Size];\n\t\t\t\tfor (int c = 0; c < BI.MC7Size; c++)\n\t\t\t\t\tBuffer[c] = (byte)FillChar;\n\t\t\t\t_LastError = DBWrite(DBNumber, 0, BI.MC7Size, Buffer);\n\t\t\t}\n\t\t\tif (_LastError == 0)\n\t\t\t\tTime_ms = Environment.TickCount - Elapsed;\n\t\t\treturn _LastError;\n\t\t}\n\n\t\t#endregion\n\n\t\t#region [Date/Time functions]\n\n\t\tpublic int GetPlcDateTime(ref DateTime DT)\n\t\t{\n\t\t\tint Length;\n\t\t\t_LastError = 0;\n\t\t\tTime_ms = 0;\n\t\t\tint Elapsed = Environment.TickCount;\n\n\t\t\tSendPacket(S7_GET_DT);\n\t\t\tif (_LastError == 0)\n\t\t\t{\n\t\t\t\tLength = RecvIsoPacket();\n\t\t\t\tif (Length > 30) // the minimum expected\n\t\t\t\t{\n\t\t\t\t\tif ((PDU.GetWordAt(27) == 0) && (PDU[29] == 0xFF))\n\t\t\t\t\t{\n\t\t\t\t\t\tDT = PDU.GetDateTimeAt(35);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\t_LastError = S7Consts.errCliInvalidPlcAnswer;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\t_LastError = S7Consts.errIsoInvalidPDU;\n\t\t\t}\n\n\t\t\tif(_LastError==0)\n\t\t\t\tTime_ms = Environment.TickCount - Elapsed;\n\n\t\t\treturn _LastError;\n\t\t}\n\n\t\tpublic int SetPlcDateTime(DateTime DT)\n\t\t{\n\t\t\tint Length;\n\t\t\t_LastError = 0;\n\t\t\tTime_ms = 0;\n\t\t\tint Elapsed = Environment.TickCount;\n\n\t\t\tS7_SET_DT.SetDateTimeAt(31, DT);\n\t\t\tSendPacket(S7_SET_DT);\n\t\t\tif (_LastError == 0)\n\t\t\t{\n\t\t\t\tLength = RecvIsoPacket();\n\t\t\t\tif (Length > 30) // the minimum expected\n\t\t\t\t{\n\t\t\t\t\tif (PDU.GetWordAt(27) != 0)\n\t\t\t\t\t\t_LastError = S7Consts.errCliInvalidPlcAnswer;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\t_LastError = S7Consts.errIsoInvalidPDU;\n\t\t\t}\n\t\t\tif (_LastError == 0)\n\t\t\t\tTime_ms = Environment.TickCount - Elapsed;\n\n\t\t\treturn _LastError;\n\t\t}\n\n\t\tpublic int SetPlcSystemDateTime()\n\t\t{\n\t\t\treturn SetPlcDateTime(DateTime.Now);\n\t\t}\n\n\t\t#endregion\n\n\t\t#region [System Info functions]\n\n\t\tpublic int GetOrderCode(ref S7OrderCode Info)\n\t\t{\n\t\t\tS7SZL SZL = new S7SZL();\n\t\t\tint Size = 1024;\n\t\t\tSZL.Data = new byte[Size];\n\t\t\tint Elapsed = Environment.TickCount;\n\t\t\t_LastError = ReadSZL(0x0011, 0x000, ref SZL, ref Size);\n\t\t\tif (_LastError == 0)\n\t\t\t{\n\t\t\t\tInfo.Code = SZL.Data.GetCharsAt(2, 20);\n\t\t\t\tInfo.V1 = SZL.Data[Size - 3];\n\t\t\t\tInfo.V2 = SZL.Data[Size - 2];\n\t\t\t\tInfo.V3 = SZL.Data[Size - 1];\n\t\t\t}\n\t\t\tif (_LastError == 0)\n\t\t\t\tTime_ms = Environment.TickCount - Elapsed;\n\t\t\treturn _LastError;\n\t\t}\n\n\t\tpublic int GetCpuInfo(ref S7CpuInfo Info)\n\t\t{\n\t\t\tS7SZL SZL = new S7SZL();\n\t\t\tint Size = 1024;\n\t\t\tSZL.Data = new byte[Size];\n\t\t\tint Elapsed = Environment.TickCount;\n\t\t\t_LastError = ReadSZL(0x001C, 0x000, ref SZL, ref Size);\n\t\t\tif (_LastError == 0)\n\t\t\t{\n\t\t\t\tInfo.ModuleTypeName = SZL.Data.GetCharsAt(172, 32);\n\t\t\t\tInfo.SerialNumber = SZL.Data.GetCharsAt(138, 24);\n\t\t\t\tInfo.ASName = SZL.Data.GetCharsAt(2, 24);\n\t\t\t\tInfo.Copyright = SZL.Data.GetCharsAt(104, 26);\n\t\t\t\tInfo.ModuleName = SZL.Data.GetCharsAt(36, 24);\n\t\t\t}\n\t\t\tif (_LastError == 0)\n\t\t\t\tTime_ms = Environment.TickCount - Elapsed;\n\t\t\treturn _LastError;\n\t\t}\n\n\t\tpublic int GetCpInfo(ref S7CpInfo Info)\n\t\t{\n\t\t\tS7SZL SZL = new S7SZL();\n\t\t\tint Size = 1024;\n\t\t\tSZL.Data = new byte[Size];\n\t\t\tint Elapsed = Environment.TickCount;\n\t\t\t_LastError = ReadSZL(0x0131, 0x001, ref SZL, ref Size);\n\t\t\tif (_LastError == 0)\n\t\t\t{\n\t\t\t\tInfo.MaxPduLength = PDU.GetIntAt(2);\n\t\t\t\tInfo.MaxConnections = PDU.GetIntAt(4);\n\t\t\t\tInfo.MaxMpiRate = PDU.GetDIntAt(6);\n\t\t\t\tInfo.MaxBusRate = PDU.GetDIntAt(10);\n\t\t\t}\n\t\t\tif (_LastError == 0)\n\t\t\t\tTime_ms = Environment.TickCount - Elapsed;\n\t\t\treturn _LastError;\n\t\t}\n\n\t\tpublic int ReadSZL(int ID, int Index, ref S7SZL SZL, ref int Size)\n\t\t{\n\t\t\tint Length;\n\t\t\tint DataSZL;\n\t\t\tint Offset = 0;\n\t\t\tbool Done = false;\n\t\t\tbool First = true;\n\t\t\tbyte Seq_in = 0x00;\n\t\t\tushort Seq_out = 0x0000;\n\n\t\t\t_LastError = 0;\n\t\t\tTime_ms = 0;\n\t\t\tint Elapsed = Environment.TickCount;\n\t\t\tSZL.Header.LENTHDR = 0;\n\n\t\t\tdo\n\t\t\t{\n\t\t\t\tif (First)\n\t\t\t\t{\n\t\t\t\t\tS7_SZL_FIRST.SetWordAt(11, ++Seq_out);\n\t\t\t\t\tS7_SZL_FIRST.SetWordAt(29, (ushort)ID);\n\t\t\t\t\tS7_SZL_FIRST.SetWordAt(31, (ushort)Index);\n\t\t\t\t\tSendPacket(S7_SZL_FIRST);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tS7_SZL_NEXT.SetWordAt(11, ++Seq_out);\n\t\t\t\t\tS7_SZL_NEXT[24] = (byte)Seq_in;\n\t\t\t\t\tSendPacket(S7_SZL_NEXT);\n\t\t\t\t}\n\t\t\t\tif (_LastError != 0)\n\t\t\t\t\treturn _LastError;\n\n\t\t\t\tLength = RecvIsoPacket();\n\t\t\t\tif (_LastError == 0)\n\t\t\t\t{\n\t\t\t\t\tif (First)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (Length > 32) // the minimum expected\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif ((PDU.GetWordAt(27) == 0) && (PDU[29] == (byte)0xFF))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// Gets Amount of this slice\n\t\t\t\t\t\t\t\tDataSZL = PDU.GetWordAt(31) - 8; // Skips extra params (ID, Index ...)\n\t\t\t\t\t\t\t\tDone = PDU[26] == 0x00;\n\t\t\t\t\t\t\t\tSeq_in = (byte)PDU[24]; // Slice sequence\n\t\t\t\t\t\t\t\tSZL.Header.LENTHDR = PDU.GetWordAt(37);\n\t\t\t\t\t\t\t\tSZL.Header.N_DR = PDU.GetWordAt(39);\n\t\t\t\t\t\t\t\tArray.Copy(PDU, 41, SZL.Data, Offset, DataSZL);\n\t\t\t\t\t\t\t\t//                                SZL.Copy(PDU, 41, Offset, DataSZL);\n\t\t\t\t\t\t\t\tOffset += DataSZL;\n\t\t\t\t\t\t\t\tSZL.Header.LENTHDR += SZL.Header.LENTHDR;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t_LastError = S7Consts.errCliInvalidPlcAnswer;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\t_LastError = S7Consts.errIsoInvalidPDU;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tif (Length > 32) // the minimum expected\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif ((PDU.GetWordAt(27) == 0) && (PDU[29] == (byte)0xFF))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// Gets Amount of this slice\n\t\t\t\t\t\t\t\tDataSZL = PDU.GetWordAt(31);\n\t\t\t\t\t\t\t\tDone = PDU[26] == 0x00;\n\t\t\t\t\t\t\t\tSeq_in = (byte)PDU[24]; // Slice sequence\n\t\t\t\t\t\t\t\tArray.Copy(PDU, 37, SZL.Data, Offset, DataSZL);\n\t\t\t\t\t\t\t\tOffset += DataSZL;\n\t\t\t\t\t\t\t\tSZL.Header.LENTHDR += SZL.Header.LENTHDR;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t_LastError = S7Consts.errCliInvalidPlcAnswer;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\t_LastError = S7Consts.errIsoInvalidPDU;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tFirst = false;\n\t\t\t}\n\t\t\twhile (!Done && (_LastError == 0));\n\t\t\tif (_LastError==0)\n\t\t\t{\n\t\t\t\tSize = SZL.Header.LENTHDR;\n\t\t\t\tTime_ms = Environment.TickCount - Elapsed;\n\t\t\t}\n\t\t\treturn _LastError;\n\t\t}\n\n\t\tpublic int ReadSZLList(ref S7SZLList List, ref Int32 ItemsCount)\n\t\t{\n\t\t\treturn S7Consts.errCliFunctionNotImplemented;\n\t\t}\n\n\t\t#endregion\n\n\t\t#region [Control functions]\n\n\t\tpublic int PlcHotStart()\n\t\t{\n\t\t\t_LastError = 0;\n\t\t\tint Elapsed = Environment.TickCount;\n\n\t\t\tSendPacket(S7_HOT_START);\n\t\t\tif (_LastError == 0)\n\t\t\t{\n\t\t\t\tint Length = RecvIsoPacket();\n\t\t\t\tif (Length > 18) // 18 is the minimum expected\n\t\t\t\t{\n\t\t\t\t\tif (PDU[19] != pduStart)\n\t\t\t\t\t\t_LastError = S7Consts.errCliCannotStartPLC;\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tif (PDU[20] == pduAlreadyStarted)\n\t\t\t\t\t\t\t_LastError = S7Consts.errCliAlreadyRun;\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\t_LastError = S7Consts.errCliCannotStartPLC;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\t_LastError = S7Consts.errIsoInvalidPDU;\n\t\t\t}\n\t\t\tif (_LastError == 0)\n\t\t\t\tTime_ms = Environment.TickCount - Elapsed;\n\t\t\treturn _LastError;\n\t\t}\n\n\t\tpublic int PlcColdStart()\n\t\t{\n\t\t\t_LastError = 0;\n\t\t\tint Elapsed = Environment.TickCount;\n\n\t\t\tSendPacket(S7_COLD_START);\n\t\t\tif (_LastError == 0)\n\t\t\t{\n\t\t\t\tint Length = RecvIsoPacket();\n\t\t\t\tif (Length > 18) // 18 is the minimum expected\n\t\t\t\t{\n\t\t\t\t\tif (PDU[19] != pduStart)\n\t\t\t\t\t\t_LastError = S7Consts.errCliCannotStartPLC;\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tif (PDU[20] == pduAlreadyStarted)\n\t\t\t\t\t\t\t_LastError = S7Consts.errCliAlreadyRun;\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\t_LastError = S7Consts.errCliCannotStartPLC;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\t_LastError = S7Consts.errIsoInvalidPDU;\n\t\t\t}\n\t\t\tif (_LastError == 0)\n\t\t\t\tTime_ms = Environment.TickCount - Elapsed;\n\t\t\treturn _LastError;\n\t\t}\n\n\t\tpublic int PlcStop()\n\t\t{\n\t\t\t_LastError = 0;\n\t\t\tint Elapsed = Environment.TickCount;\n\n\t\t\tSendPacket(S7_STOP);\n\t\t\tif (_LastError == 0)\n\t\t\t{\n\t\t\t\tint Length = RecvIsoPacket();\n\t\t\t\tif (Length > 18) // 18 is the minimum expected\n\t\t\t\t{\n\t\t\t\t\tif (PDU[19]!=pduStop)\n\t\t\t\t\t\t_LastError = S7Consts.errCliCannotStopPLC;\n\t\t\t\t\telse\n\t\t\t\t\t{ \n\t\t\t\t\t\tif (PDU[20]== pduAlreadyStopped)\n\t\t\t\t\t\t\t_LastError = S7Consts.errCliAlreadyStop;\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\t_LastError = S7Consts.errCliCannotStopPLC;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\t_LastError = S7Consts.errIsoInvalidPDU;\n\t\t\t}\n\t\t\tif (_LastError == 0)\n\t\t\t\tTime_ms = Environment.TickCount - Elapsed;\n\t\t\treturn _LastError;\n\t\t}\n\n\t\tpublic int PlcCopyRamToRom(UInt32 Timeout)\n\t\t{\n\t\t\treturn S7Consts.errCliFunctionNotImplemented;\n\t\t}\n\n\t\tpublic int PlcCompress(UInt32 Timeout)\n\t\t{\n\t\t\treturn S7Consts.errCliFunctionNotImplemented;\n\t\t}\n\n\t\tpublic int PlcGetStatus(ref Int32 Status)\n\t\t{\n\t\t\t_LastError = 0;\n\t\t\tint Elapsed = Environment.TickCount;\n\n\t\t\tSendPacket(S7_GET_STAT);\n\t\t\tif (_LastError == 0)\n\t\t\t{\n\t\t\t\tint Length = RecvIsoPacket();\n\t\t\t\tif (Length > 30) // the minimum expected\n\t\t\t\t{\n\t\t\t\t\tushort Result = PDU.GetWordAt(27);\n\t\t\t\t\tif (Result == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tswitch (PDU[44])\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcase S7Consts.S7CpuStatusUnknown:\n\t\t\t\t\t\t\tcase S7Consts.S7CpuStatusRun:\n\t\t\t\t\t\t\tcase S7Consts.S7CpuStatusStop:\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tStatus = PDU[44];\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// Since RUN status is always 0x08 for all CPUs and CPs, STOP status\n\t\t\t\t\t\t\t\t// sometime can be coded as 0x03 (especially for old cpu...)\n\t\t\t\t\t\t\t\tStatus = S7Consts.S7CpuStatusStop;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\t_LastError = CpuError(Result);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\t_LastError = S7Consts.errIsoInvalidPDU;\n\t\t\t}\n\t\t\tif (_LastError == 0)\n\t\t\t\tTime_ms = Environment.TickCount - Elapsed;\n\t\t\treturn _LastError;\n\t\t}\n\n\t\t#endregion\n\n\t\t#region [Security functions]\n\t\tpublic int SetSessionPassword(string Password)\n\t\t{\n\t\t\tbyte[] pwd = { 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 };\n\t\t\tint Length;\n\t\t\t_LastError = 0;\n\t\t\tint Elapsed = Environment.TickCount;\n\t\t\t// Encodes the Password\n\t\t\tpwd.SetCharsAt(0, Password);\n\t\t\tpwd[0] = (byte)(pwd[0] ^ 0x55);\n\t\t\tpwd[1] = (byte)(pwd[1] ^ 0x55);\n\t\t\tfor (int c = 2; c < 8; c++)\n\t\t\t{\n\t\t\t\tpwd[c] = (byte)(pwd[c] ^ 0x55 ^ pwd[c - 2]);\n\t\t\t}\n\t\t\tArray.Copy(pwd, 0, S7_SET_PWD, 29, 8);\n\t\t\t// Sends the telegrem\n\t\t\tSendPacket(S7_SET_PWD);\n\t\t\tif (_LastError == 0)\n\t\t\t{\n\t\t\t\tLength = RecvIsoPacket();\n\t\t\t\tif (Length > 32) // the minimum expected\n\t\t\t\t{\n\t\t\t\t\tushort Result = PDU.GetWordAt(27);\n\t\t\t\t\tif (Result != 0)\n\t\t\t\t\t\t_LastError = CpuError(Result);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\t_LastError = S7Consts.errIsoInvalidPDU;\n\t\t\t}\n\t\t\tif (_LastError == 0)\n\t\t\t\tTime_ms = Environment.TickCount - Elapsed;\n\t\t\treturn _LastError;\n\t\t}\n\n\t\tpublic int ClearSessionPassword()\n\t\t{\n\t\t\tint Length;\n\t\t\t_LastError = 0;\n\t\t\tint Elapsed = Environment.TickCount;\n\t\t\tSendPacket(S7_CLR_PWD);\n\t\t\tif (_LastError == 0)\n\t\t\t{\n\t\t\t\tLength = RecvIsoPacket();\n\t\t\t\tif (Length > 30) // the minimum expected\n\t\t\t\t{\n\t\t\t\t\tushort Result = PDU.GetWordAt(27);\n\t\t\t\t\tif (Result != 0)\n\t\t\t\t\t\t_LastError = CpuError(Result);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\t_LastError = S7Consts.errIsoInvalidPDU;\n\t\t\t}\n\t\t\treturn _LastError;\n\t\t}\n\n\t\tpublic int GetProtection(ref S7Protection Protection)\n\t\t{\n\t\t\tS7Client.S7SZL SZL = new S7Client.S7SZL();\n\t\t\tint Size = 256;\n\t\t\tSZL.Data = new byte[Size];\n\t\t\t_LastError = ReadSZL(0x0232, 0x0004, ref SZL, ref Size);\n\t\t\tif (_LastError == 0)\n\t\t\t{\n\t\t\t\tProtection.sch_schal = SZL.Data.GetWordAt(2);\n\t\t\t\tProtection.sch_par = SZL.Data.GetWordAt(4);\n\t\t\t\tProtection.sch_rel = SZL.Data.GetWordAt(6);\n\t\t\t\tProtection.bart_sch = SZL.Data.GetWordAt(8);\n\t\t\t\tProtection.anl_sch = SZL.Data.GetWordAt(10);\n\t\t\t}\n\t\t\treturn _LastError;\n\t\t}\n\t\t#endregion\n\n\t\t#region [Low Level]\n\n\t\tpublic int IsoExchangeBuffer(byte[] Buffer, ref Int32 Size)\n\t\t{\n\t\t\t_LastError = 0;\n\t\t\tTime_ms = 0;\n\t\t\tint Elapsed = Environment.TickCount;\n\t\t\tArray.Copy(TPKT_ISO, 0, PDU, 0, TPKT_ISO.Length);\n\t\t\tPDU.SetWordAt(2, (ushort)(Size + TPKT_ISO.Length));\n\t\t\ttry\n\t\t\t{\n\t\t\t\tArray.Copy(Buffer, 0, PDU, TPKT_ISO.Length, Size);\n\t\t\t}\n\t\t\tcatch\n\t\t\t{\n\t\t\t\treturn S7Consts.errIsoInvalidPDU;\n\t\t\t}\n\t\t\tSendPacket(PDU, TPKT_ISO.Length + Size);\n\t\t\tif (_LastError==0)\n\t\t\t{\n\t\t\t\tint Length=RecvIsoPacket();\n\t\t\t\tif (_LastError==0)\n\t\t\t\t{\n\t\t\t\t\tArray.Copy(PDU, TPKT_ISO.Length, Buffer, 0, Length - TPKT_ISO.Length);\n\t\t\t\t\tSize = Length - TPKT_ISO.Length;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (_LastError == 0)\n\t\t\t\tTime_ms = Environment.TickCount - Elapsed;\n\t\t\telse\n\t\t\t\tSize = 0;\n\t\t\treturn _LastError;\n\t\t}\n\n\t\t#endregion\n\n\t\t#region [Async functions (not implemented)]\n\n\t\tpublic int AsReadArea(int Area, int DBNumber, int Start, int Amount, int WordLen, byte[] Buffer)\n\t\t{\n\t\t\treturn S7Consts.errCliFunctionNotImplemented;\n\t\t}\n\n\t\tpublic int AsWriteArea(int Area, int DBNumber, int Start, int Amount, int WordLen, byte[] Buffer)\n\t\t{\n\t\t\treturn S7Consts.errCliFunctionNotImplemented;\n\t\t}\n\n\t\tpublic int AsDBRead(int DBNumber, int Start, int Size, byte[] Buffer)\n\t\t{\n\t\t\treturn S7Consts.errCliFunctionNotImplemented;\n\t\t}\n\n\t\tpublic int AsDBWrite(int DBNumber, int Start, int Size, byte[] Buffer)\n\t\t{\n\t\t\treturn S7Consts.errCliFunctionNotImplemented;\n\t\t}\n\n\t\tpublic int AsMBRead(int Start, int Size, byte[] Buffer)\n\t\t{\n\t\t\treturn S7Consts.errCliFunctionNotImplemented;\n\t\t}\n\n\t\tpublic int AsMBWrite(int Start, int Size, byte[] Buffer)\n\t\t{\n\t\t\treturn S7Consts.errCliFunctionNotImplemented;\n\t\t}\n\n\t\tpublic int AsEBRead(int Start, int Size, byte[] Buffer)\n\t\t{\n\t\t\treturn S7Consts.errCliFunctionNotImplemented;\n\t\t}\n\n\t\tpublic int AsEBWrite(int Start, int Size, byte[] Buffer)\n\t\t{\n\t\t\treturn S7Consts.errCliFunctionNotImplemented;\n\t\t}\n\n\t\tpublic int AsABRead(int Start, int Size, byte[] Buffer)\n\t\t{\n\t\t\treturn S7Consts.errCliFunctionNotImplemented;\n\t\t}\n\n\t\tpublic int AsABWrite(int Start, int Size, byte[] Buffer)\n\t\t{\n\t\t\treturn S7Consts.errCliFunctionNotImplemented;\n\t\t}\n\n\t\tpublic int AsTMRead(int Start, int Amount, ushort[] Buffer)\n\t\t{\n\t\t\treturn S7Consts.errCliFunctionNotImplemented;\n\t\t}\n\n\t\tpublic int AsTMWrite(int Start, int Amount, ushort[] Buffer)\n\t\t{\n\t\t\treturn S7Consts.errCliFunctionNotImplemented;\n\t\t}\n\n\t\tpublic int AsCTRead(int Start, int Amount, ushort[] Buffer)\n\t\t{\n\t\t\treturn S7Consts.errCliFunctionNotImplemented;\n\t\t}\n\n\t\tpublic int AsCTWrite(int Start, int Amount, ushort[] Buffer)\n\t\t{\n\t\t\treturn S7Consts.errCliFunctionNotImplemented;\n\t\t}\n\n\t\tpublic int AsListBlocksOfType(int BlockType, ushort[] List)\n\t\t{\n\t\t\treturn S7Consts.errCliFunctionNotImplemented;\n\t\t}\n\n\t\tpublic int AsReadSZL(int ID, int Index, ref S7SZL Data, ref Int32 Size)\n\t\t{\n\t\t\treturn S7Consts.errCliFunctionNotImplemented;\n\t\t}\n\n\t\tpublic int AsReadSZLList(ref S7SZLList List, ref Int32 ItemsCount)\n\t\t{\n\t\t\treturn S7Consts.errCliFunctionNotImplemented;\n\t\t}\n\n\t\tpublic int AsUpload(int BlockType, int BlockNum, byte[] UsrData, ref int Size)\n\t\t{\n\t\t\treturn S7Consts.errCliFunctionNotImplemented;\n\t\t}\n\n\t\tpublic int AsFullUpload(int BlockType, int BlockNum, byte[] UsrData, ref int Size)\n\t\t{\n\t\t\treturn S7Consts.errCliFunctionNotImplemented;\n\t\t}\n\n\t\tpublic int ASDownload(int BlockNum, byte[] UsrData, int Size)\n\t\t{\n\t\t\treturn S7Consts.errCliFunctionNotImplemented;\n\t\t}\n\n\t\tpublic int AsPlcCopyRamToRom(UInt32 Timeout)\n\t\t{\n\t\t\treturn S7Consts.errCliFunctionNotImplemented;\n\t\t}\n\n\t\tpublic int AsPlcCompress(UInt32 Timeout)\n\t\t{\n\t\t\treturn S7Consts.errCliFunctionNotImplemented;\n\t\t}\n\n\t\tpublic int AsDBGet(int DBNumber, byte[] UsrData, ref int Size)\n\t\t{\n\t\t\treturn S7Consts.errCliFunctionNotImplemented;\n\t\t}\n\n\t\tpublic int AsDBFill(int DBNumber, int FillChar)\n\t\t{\n\t\t\treturn S7Consts.errCliFunctionNotImplemented;\n\t\t}\n\n\t\tpublic bool CheckAsCompletion(ref int opResult)\n\t\t{\n\t\t\topResult = 0;\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic int WaitAsCompletion(int Timeout)\n\t\t{\n\t\t\treturn S7Consts.errCliFunctionNotImplemented;\n\t\t}\n\n\t\t#endregion\n\n\t\t#region [Info Functions / Properties]\n\n\t\tpublic string ErrorText(int Error)\n\t\t{\n\t\t\tswitch (Error)\n\t\t\t{\n\t\t\t\tcase 0: return \"OK\";\n\t\t\t\tcase S7Consts.errTCPSocketCreation: return \"SYS: Error creating the Socket\";\n\t\t\t\tcase S7Consts.errTCPConnectionTimeout: return \"TCP: Connection Timeout\";\n\t\t\t\tcase S7Consts.errTCPConnectionFailed: return \"TCP: Connection Error\";\n\t\t\t\tcase S7Consts.errTCPReceiveTimeout: return \"TCP: Data receive Timeout\";\n\t\t\t\tcase S7Consts.errTCPDataReceive: return \"TCP: Error receiving Data\";\n\t\t\t\tcase S7Consts.errTCPSendTimeout: return \"TCP: Data send Timeout\";\n\t\t\t\tcase S7Consts.errTCPDataSend: return \"TCP: Error sending Data\";\n\t\t\t\tcase S7Consts.errTCPConnectionReset: return \"TCP: Connection reset by the Peer\";\n\t\t\t\tcase S7Consts.errTCPNotConnected: return \"CLI: Client not connected\";\n\t\t\t\tcase S7Consts.errTCPUnreachableHost: return \"TCP: Unreachable host\";\n\t\t\t\tcase S7Consts.errIsoConnect: return \"ISO: Connection Error\";\n\t\t\t\tcase S7Consts.errIsoInvalidPDU: return \"ISO: Invalid PDU received\";\n\t\t\t\tcase S7Consts.errIsoInvalidDataSize: return \"ISO: Invalid Buffer passed to Send/Receive\";\n\t\t\t\tcase S7Consts.errCliNegotiatingPDU: return \"CLI: Error in PDU negotiation\";\n\t\t\t\tcase S7Consts.errCliInvalidParams: return \"CLI: Invalid param(s) supplied\";\n\t\t\t\tcase S7Consts.errCliJobPending: return \"CLI: Job pending\";\n\t\t\t\tcase S7Consts.errCliTooManyItems: return \"CLI: Too many items (>20) in multi read/write\";\n\t\t\t\tcase S7Consts.errCliInvalidWordLen: return \"CLI: Invalid WordLength\";\n\t\t\t\tcase S7Consts.errCliPartialDataWritten: return \"CLI: Partial data written\";\n\t\t\t\tcase S7Consts.errCliSizeOverPDU: return \"CPU: Total data exceeds the PDU size\";\n\t\t\t\tcase S7Consts.errCliInvalidPlcAnswer: return \"CLI: Invalid CPU answer\";\n\t\t\t\tcase S7Consts.errCliAddressOutOfRange: return \"CPU: Address out of range\";\n\t\t\t\tcase S7Consts.errCliInvalidTransportSize: return \"CPU: Invalid Transport size\";\n\t\t\t\tcase S7Consts.errCliWriteDataSizeMismatch: return \"CPU: Data size mismatch\";\n\t\t\t\tcase S7Consts.errCliItemNotAvailable: return \"CPU: Item not available\";\n\t\t\t\tcase S7Consts.errCliInvalidValue: return \"CPU: Invalid value supplied\";\n\t\t\t\tcase S7Consts.errCliCannotStartPLC: return \"CPU: Cannot start PLC\";\n\t\t\t\tcase S7Consts.errCliAlreadyRun: return \"CPU: PLC already RUN\";\n\t\t\t\tcase S7Consts.errCliCannotStopPLC: return \"CPU: Cannot stop PLC\";\n\t\t\t\tcase S7Consts.errCliCannotCopyRamToRom: return \"CPU: Cannot copy RAM to ROM\";\n\t\t\t\tcase S7Consts.errCliCannotCompress: return \"CPU: Cannot compress\";\n\t\t\t\tcase S7Consts.errCliAlreadyStop: return \"CPU: PLC already STOP\";\n\t\t\t\tcase S7Consts.errCliFunNotAvailable: return \"CPU: Function not available\";\n\t\t\t\tcase S7Consts.errCliUploadSequenceFailed: return \"CPU: Upload sequence failed\";\n\t\t\t\tcase S7Consts.errCliInvalidDataSizeRecvd: return \"CLI: Invalid data size received\";\n\t\t\t\tcase S7Consts.errCliInvalidBlockType: return \"CLI: Invalid block type\";\n\t\t\t\tcase S7Consts.errCliInvalidBlockNumber: return \"CLI: Invalid block number\";\n\t\t\t\tcase S7Consts.errCliInvalidBlockSize: return \"CLI: Invalid block size\";\n\t\t\t\tcase S7Consts.errCliNeedPassword: return \"CPU: Function not authorized for current protection level\";\n\t\t\t\tcase S7Consts.errCliInvalidPassword: return \"CPU: Invalid password\";\n\t\t\t\tcase S7Consts.errCliNoPasswordToSetOrClear: return \"CPU: No password to set or clear\";\n\t\t\t\tcase S7Consts.errCliJobTimeout: return \"CLI: Job Timeout\";\n\t\t\t\tcase S7Consts.errCliFunctionRefused: return \"CLI: Function refused by CPU (Unknown error)\";\n\t\t\t\tcase S7Consts.errCliPartialDataRead: return \"CLI: Partial data read\";\n\t\t\t\tcase S7Consts.errCliBufferTooSmall: return \"CLI: The buffer supplied is too small to accomplish the operation\";\n\t\t\t\tcase S7Consts.errCliDestroying: return \"CLI: Cannot perform (destroying)\";\n\t\t\t\tcase S7Consts.errCliInvalidParamNumber: return \"CLI: Invalid Param Number\";\n\t\t\t\tcase S7Consts.errCliCannotChangeParam: return \"CLI: Cannot change this param now\";\n\t\t\t\tcase S7Consts.errCliFunctionNotImplemented: return \"CLI: Function not implemented\";\n\t\t\t\tdefault: return \"CLI: Unknown error (0x\" + Convert.ToString(Error, 16) + \")\";\n\t\t\t};\n\t\t}\n\n\t\tpublic int LastError()\n\t\t{\n\t\t\treturn _LastError;\n\t\t}\n\n\t\tpublic int RequestedPduLength()\n\t\t{\n\t\t\treturn _PduSizeRequested;\n\t\t}\n\n\t\tpublic int NegotiatedPduLength()\n\t\t{\n\t\t\treturn _PDULength;\n\t\t}\n\n\t\tpublic int ExecTime()\n\t\t{\n\t\t\treturn Time_ms;\n\t\t}\n\n\t\tpublic int ExecutionTime => Time_ms;\n\n\t\tpublic int PduSizeNegotiated => _PDULength;\n\n\t\tpublic int PduSizeRequested\n\t\t{\n\t\t\tget => _PduSizeRequested;\n\t\t\tset\n\t\t\t{\n\t\t\t\tif (value < MinPduSizeToRequest)\n\t\t\t\t\tvalue = MinPduSizeToRequest;\n\t\t\t\tif (value > MaxPduSizeToRequest)\n\t\t\t\t\tvalue = MaxPduSizeToRequest;\n\t\t\t\t_PduSizeRequested = value;       \n\t\t\t}\n\t\t}\n\n\t\tpublic string PLCIpAddress => IPAddress;\n\n\t\tpublic int PLCPort\n\t\t{\n\t\t\tget => _PLCPort;\n\t\t\tset => _PLCPort = value;\n\t\t}\n\n\t\tpublic int ConnTimeout\n\t\t{\n\t\t\tget => Socket.ConnectTimeout;\n\t\t\tset => Socket.ConnectTimeout = value;\n\t\t}\n\n\t\tpublic int RecvTimeout\n\t\t{\n\t\t\tget => Socket.ReadTimeout;\n\t\t\tset => Socket.ReadTimeout = value;\n\t\t}\n\n\t\tpublic int SendTimeout\n\t\t{\n\t\t\tget => Socket.WriteTimeout;\n\t\t\tset => Socket.WriteTimeout = value;\n\t\t}\n\n\t\tpublic bool Connected => (Socket != null) && (Socket.Connected);\n\n\t\t#endregion\n\t}\n}"
  },
  {
    "path": "Sharp7/S7Consts.cs",
    "content": "﻿using System;\nusing System.Linq;\nusing System.Runtime.InteropServices;\n\nnamespace Sharp7\n{\n\tpublic static class S7Consts\n\t{\n\t\t#region [Exported Consts]\n\t\t// Error codes\n\t\t//------------------------------------------------------------------------------\n\t\t//                                     ERRORS                 \n\t\t//------------------------------------------------------------------------------\n\t\tpublic const int ResultOK                     = 0x00000000;\n\t\tpublic const int errTCPSocketCreation         = 0x00000001;\n\t\tpublic const int errTCPConnectionTimeout      = 0x00000002;\n\t\tpublic const int errTCPConnectionFailed       = 0x00000003;\n\t\tpublic const int errTCPReceiveTimeout         = 0x00000004;\n\t\tpublic const int errTCPDataReceive            = 0x00000005;\n\t\tpublic const int errTCPSendTimeout            = 0x00000006;\n\t\tpublic const int errTCPDataSend               = 0x00000007;\n\t\tpublic const int errTCPConnectionReset        = 0x00000008;\n\t\tpublic const int errTCPNotConnected           = 0x00000009;\n\t\tpublic const int errTCPUnreachableHost        = 0x00002751;\n\n\t\tpublic const int errIsoConnect                = 0x00010000; // Connection error\n\t\tpublic const int errIsoInvalidPDU             = 0x00030000; // Bad format\n\t\tpublic const int errIsoInvalidDataSize        = 0x00040000; // Bad Datasize passed to send/recv : buffer is invalid\n\n\t\tpublic const int errCliNegotiatingPDU         = 0x00100000;\n\t\tpublic const int errCliInvalidParams          = 0x00200000;\n\t\tpublic const int errCliJobPending             = 0x00300000;\n\t\tpublic const int errCliTooManyItems           = 0x00400000;\n\t\tpublic const int errCliInvalidWordLen         = 0x00500000;\n\t\tpublic const int errCliPartialDataWritten     = 0x00600000;\n\t\tpublic const int errCliSizeOverPDU            = 0x00700000;\n\t\tpublic const int errCliInvalidPlcAnswer       = 0x00800000;\n\t\tpublic const int errCliAddressOutOfRange      = 0x00900000;\n\t\tpublic const int errCliInvalidTransportSize   = 0x00A00000;\n\t\tpublic const int errCliWriteDataSizeMismatch  = 0x00B00000;\n\t\tpublic const int errCliItemNotAvailable       = 0x00C00000;\n\t\tpublic const int errCliInvalidValue           = 0x00D00000;\n\t\tpublic const int errCliCannotStartPLC         = 0x00E00000;\n\t\tpublic const int errCliAlreadyRun             = 0x00F00000;\n\t\tpublic const int errCliCannotStopPLC          = 0x01000000;\n\t\tpublic const int errCliCannotCopyRamToRom     = 0x01100000;\n\t\tpublic const int errCliCannotCompress         = 0x01200000;\n\t\tpublic const int errCliAlreadyStop            = 0x01300000;\n\t\tpublic const int errCliFunNotAvailable        = 0x01400000;\n\t\tpublic const int errCliUploadSequenceFailed   = 0x01500000;\n\t\tpublic const int errCliInvalidDataSizeRecvd   = 0x01600000;\n\t\tpublic const int errCliInvalidBlockType       = 0x01700000;\n\t\tpublic const int errCliInvalidBlockNumber     = 0x01800000;\n\t\tpublic const int errCliInvalidBlockSize       = 0x01900000;\n\t\tpublic const int errCliNeedPassword           = 0x01D00000;\n\t\tpublic const int errCliInvalidPassword        = 0x01E00000;\n\t\tpublic const int errCliNoPasswordToSetOrClear = 0x01F00000;\n\t\tpublic const int errCliJobTimeout             = 0x02000000;\n\t\tpublic const int errCliPartialDataRead        = 0x02100000;\n\t\tpublic const int errCliBufferTooSmall         = 0x02200000;\n\t\tpublic const int errCliFunctionRefused        = 0x02300000;\n\t\tpublic const int errCliDestroying             = 0x02400000;\n\t\tpublic const int errCliInvalidParamNumber     = 0x02500000;\n\t\tpublic const int errCliCannotChangeParam      = 0x02600000;\n\t\tpublic const int errCliFunctionNotImplemented = 0x02700000;\n\t\t//------------------------------------------------------------------------------\n\t\t//        PARAMS LIST FOR COMPATIBILITY WITH Snap7.net.cs           \n\t\t//------------------------------------------------------------------------------\n\t\tpublic const Int32 p_u16_LocalPort     = 1;  // Not applicable here\n\t\tpublic const Int32 p_u16_RemotePort    = 2;\n\t\tpublic const Int32 p_i32_PingTimeout   = 3;\n\t\tpublic const Int32 p_i32_SendTimeout   = 4;\n\t\tpublic const Int32 p_i32_RecvTimeout   = 5;\n\t\tpublic const Int32 p_i32_WorkInterval  = 6;  // Not applicable here\n\t\tpublic const Int32 p_u16_SrcRef        = 7;  // Not applicable here\n\t\tpublic const Int32 p_u16_DstRef        = 8;  // Not applicable here\n\t\tpublic const Int32 p_u16_SrcTSap       = 9;  // Not applicable here\n\t\tpublic const Int32 p_i32_PDURequest    = 10;\n\t\tpublic const Int32 p_i32_MaxClients    = 11; // Not applicable here\n\t\tpublic const Int32 p_i32_BSendTimeout  = 12; // Not applicable here\n\t\tpublic const Int32 p_i32_BRecvTimeout  = 13; // Not applicable here\n\t\tpublic const Int32 p_u32_RecoveryTime  = 14; // Not applicable here\n\t\tpublic const Int32 p_u32_KeepAliveTime = 15; // Not applicable here\n\t\t// Area ID\n\t\t[Obsolete(\"Use enum S7Area.PE instead\")]public const byte S7AreaPE = 0x81;\n\t\t[Obsolete(\"Use enum S7Area.PA instead\")]public const byte S7AreaPA = 0x82;\n\t\t[Obsolete(\"Use enum S7Area.MK instead\")]public const byte S7AreaMK = 0x83;\n\t\t[Obsolete(\"Use enum S7Area.DB instead\")]public const byte S7AreaDB = 0x84;\n\t\t[Obsolete(\"Use enum S7Area.CT instead\")]public const byte S7AreaCT = 0x1C;\n\t\t[Obsolete(\"Use enum S7Area.TM instead\")]public const byte S7AreaTM = 0x1D;\n\t\t// Word Length\n\t\t[Obsolete(\"Use enum S7WordLength.Bit instead\")]public const int S7WLBit     = 0x01;\n\t\t[Obsolete(\"Use enum S7WordLength.Byte instead\")]public const int S7WLByte    = 0x02;\n\t\t[Obsolete(\"Use enum S7WordLength.Char instead\")]public const int S7WLChar    = 0x03;\n\t\t[Obsolete(\"Use enum S7WordLength.Word instead\")]public const int S7WLWord    = 0x04;\n\t\t[Obsolete(\"Use enum S7WordLength.Int instead\")]public const int S7WLInt     = 0x05;\n\t\t[Obsolete(\"Use enum S7WordLength.DWord instead\")]public const int S7WLDWord   = 0x06;\n\t\t[Obsolete(\"Use enum S7WordLength.DInt instead\")]public const int S7WLDInt    = 0x07;\n\t\t[Obsolete(\"Use enum S7WordLength.Real instead\")]public const int S7WLReal    = 0x08;\n\t\t[Obsolete(\"Use enum S7WordLength.Counter instead\")]public const int S7WLCounter = 0x1C;\n\t\t[Obsolete(\"Use enum S7WordLength.Timer instead\")]public const int S7WLTimer   = 0x1D;\n\t\t// PLC Status\n\t\tpublic const int S7CpuStatusUnknown = 0x00;\n\t\tpublic const int S7CpuStatusRun     = 0x08;\n\t\tpublic const int S7CpuStatusStop    = 0x04;\n\n\t\t[StructLayout(LayoutKind.Sequential, Pack = 1)]\n\t\tpublic struct S7Tag\n\t\t{\n\t\t\tpublic Int32 Area;\n\t\t\tpublic Int32 DBNumber;\n\t\t\tpublic Int32 Start;\n\t\t\tpublic Int32 Elements;\n\t\t\tpublic Int32 WordLen;\n\t\t}\n\t\t#endregion\n\t}\n}"
  },
  {
    "path": "Sharp7/S7MultiVar.cs",
    "content": "﻿using System;\nusing System.Linq;\nusing System.Runtime.InteropServices;\n\nnamespace Sharp7\n{\n\tpublic class S7MultiVar\n\t{\n\t\t#region [MultiRead/Write Helper]\n\t\tprivate S7Client FClient;\n\t\tprivate GCHandle[] Handles = new GCHandle[S7Client.MaxVars];\n\t\tprivate int Count;\n\t\tprivate S7Client.S7DataItem[] Items = new S7Client.S7DataItem[S7Client.MaxVars];\n\n\n\t\tpublic int[] Results { get; } = new int[S7Client.MaxVars];\n\n\t\tprivate bool AdjustWordLength(int Area, ref int WordLen, ref int Amount, ref int Start)\n\t\t{\n\t\t\t// Calc Word size          \n\t\t\tint WordSize = WordLen.DataSizeByte();\n\t\t\tif (WordSize == 0)\n\t\t\t\treturn false;\n\n\t\t\tif (Area == (int)S7Area.CT)\n\t\t\t\tWordLen = (int)S7WordLength.Counter;\n\t\t\tif (Area == (int)S7Area.TM)\n\t\t\t\tWordLen = (int)S7WordLength.Timer;\n\n\t\t\tif (WordLen == (int)S7WordLength.Bit)\n\t\t\t\tAmount = 1;  // Only 1 bit can be transferred at time\n\t\t\telse\n\t\t\t{\n\t\t\t\tif ((WordLen != (int)S7WordLength.Counter) && (WordLen != (int)S7WordLength.Timer))\n\t\t\t\t{\n\t\t\t\t\tAmount = Amount * WordSize;\n\t\t\t\t\tStart = Start * 8;\n\t\t\t\t\tWordLen = (int)S7WordLength.Byte;\n\t\t\t\t}\n\t\t\t}   \n\t\t\treturn true;\n\t\t}\n\n\t\tpublic S7MultiVar(S7Client Client)\n\t\t{\n\t\t\tFClient = Client;\n\t\t\tfor (int c = 0; c < S7Client.MaxVars; c++)\n\t\t\t\tResults[c] = S7Consts.errCliItemNotAvailable;\n\t\t}\n\t\t~S7MultiVar()\n\t\t{\n\t\t\tClear();\n\t\t}\n\n\t\tpublic bool Add<T>(S7Consts.S7Tag Tag, ref T[] Buffer, int Offset)\n\t\t{\n\t\t\treturn Add(Tag.Area, Tag.WordLen, Tag.DBNumber, Tag.Start, Tag.Elements, ref Buffer, Offset);\n\t\t}\n\n\t\tpublic bool Add<T>(S7Consts.S7Tag Tag, ref T[] Buffer)\n\t\t{\n\t\t\treturn Add(Tag.Area, Tag.WordLen, Tag.DBNumber, Tag.Start, Tag.Elements, ref Buffer);\n\t\t}\n\n\t\tpublic bool Add<T>(Int32 Area, Int32 WordLen, Int32 DBNumber, Int32 Start, Int32 Amount, ref T[] Buffer)\n\t\t{\n\t\t\treturn Add(Area, WordLen, DBNumber, Start, Amount, ref Buffer, 0);\n\t\t}\n\n\t\tpublic bool Add<T>(Int32 Area, Int32 WordLen, Int32 DBNumber, Int32 Start, Int32 Amount, ref T[] Buffer, int Offset)\n\t\t{\n\t\t\tif (Count < S7Client.MaxVars)\n\t\t\t{\n\t\t\t\tif (AdjustWordLength(Area, ref WordLen, ref Amount, ref Start))\n\t\t\t\t{\n\t\t\t\t\tItems[Count].Area = Area;\n\t\t\t\t\tItems[Count].WordLen = WordLen;\n\t\t\t\t\tItems[Count].Result = (int)S7Consts.errCliItemNotAvailable;\n\t\t\t\t\tItems[Count].DBNumber = DBNumber;\n\t\t\t\t\tItems[Count].Start = Start;\n\t\t\t\t\tItems[Count].Amount = Amount;\n\t\t\t\t\tGCHandle handle = GCHandle.Alloc(Buffer, GCHandleType.Pinned);\n\n\t\t\t\t\tif (IntPtr.Size == 4)\n\t\t\t\t\t\tItems[Count].pData = (IntPtr)(handle.AddrOfPinnedObject().ToInt32() + Offset * Marshal.SizeOf(typeof(T)));\n\t\t\t\t\telse\n\t\t\t\t\t\tItems[Count].pData = (IntPtr)(handle.AddrOfPinnedObject().ToInt64() + Offset * Marshal.SizeOf(typeof(T)));\n\n\t\t\t\t\tHandles[Count] = handle;\n\t\t\t\t\tCount++;\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic int Read()\n\t\t{\n\t\t\tint FunctionResult;\n\t\t\tint GlobalResult;\n\t\t\ttry\n\t\t\t{\n\t\t\t\tif (Count > 0)\n\t\t\t\t{\n\t\t\t\t\tFunctionResult = FClient.ReadMultiVars(Items, Count);\n\t\t\t\t\tif (FunctionResult == 0)\n\t\t\t\t\t\tfor (int c = 0; c < S7Client.MaxVars; c++)\n\t\t\t\t\t\t\tResults[c] = Items[c].Result;\n\t\t\t\t\tGlobalResult = FunctionResult;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tGlobalResult = S7Consts.errCliFunctionRefused;\n\t\t\t}\n\t\t\tfinally\n\t\t\t{\n\t\t\t\tClear(); // handles are no more needed and MUST be freed\n\t\t\t}\n\t\t\treturn GlobalResult;\n\t\t}\n\n\t\tpublic int Write()\n\t\t{\n\t\t\tint FunctionResult;\n\t\t\tint GlobalResult;\n\t\t\ttry\n\t\t\t{\n\t\t\t\tif (Count > 0)\n\t\t\t\t{\n\t\t\t\t\tFunctionResult = FClient.WriteMultiVars(Items, Count);\n\t\t\t\t\tif (FunctionResult == 0)\n\t\t\t\t\t\tfor (int c = 0; c < S7Client.MaxVars; c++)\n\t\t\t\t\t\t\tResults[c] = Items[c].Result;\n\t\t\t\t\tGlobalResult = FunctionResult;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tGlobalResult = S7Consts.errCliFunctionRefused;\n\t\t\t}\n\t\t\tfinally\n\t\t\t{\n\t\t\t\tClear(); // handles are no more needed and MUST be freed\n\t\t\t}\n\t\t\treturn GlobalResult;\n\t\t}\n\n\t\tpublic void Clear()\n\t\t{\n\t\t\tfor (int c = 0; c < Count; c++)\n\t\t\t{\n\t\t\t\tif (Handles[c] != null)\n\t\t\t\t\tHandles[c].Free();\n\t\t\t}\n\t\t\tCount = 0;\n\t\t}\n\t\t#endregion\n\t}\n}"
  },
  {
    "path": "Sharp7/S7Timer.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace Sharp7\n{\n\tpublic class S7Timer\n\t{\n\t\t#region S7Timer\n\t\tTimeSpan pt;\n\t\tTimeSpan et;\n\t\tbool input ;\n\t\tbool q;\n\t\tpublic S7Timer(byte[] buff, int position)\n\t\t{\n\t\t\tif (position + 12 < buff.Length)\n\t\t\t{\n\t\t\t\tSetTimer(new List<byte>(buff).GetRange(position, 12).ToArray());\n\t\t\t}\n\t\t}\n\n\t\tpublic S7Timer(byte[] buff)\n\t\t{\n\t\t\tSetTimer(buff);\n\t\t}\n\n\t\tprivate void SetTimer(byte[] buff)\n\t\t{\n\t\t\tif (buff.Length != 12)\n\t\t\t{\n\t\t\t\tthis.pt = new TimeSpan(0);\n\t\t\t\tthis.et = new TimeSpan(0);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tInt32 resPT;\n\t\t\t\tresPT = buff[0]; resPT <<= 8;\n\t\t\t\tresPT += buff[1]; resPT <<= 8;\n\t\t\t\tresPT += buff[2]; resPT <<= 8;\n\t\t\t\tresPT += buff[3];\n\t\t\t\tthis.pt = new TimeSpan(0, 0, 0, 0, resPT);\n\n\t\t\t\tInt32 resET;\n\t\t\t\tresET = buff[4]; resET <<= 8;\n\t\t\t\tresET += buff[5]; resET <<= 8;\n\t\t\t\tresET += buff[6]; resET <<= 8;\n\t\t\t\tresET += buff[7];\n\t\t\t\tthis.et = new TimeSpan(0, 0, 0, 0, resET);\n\n\t\t\t\tthis.input = (buff[8] & 0x01) == 0x01;\n\t\t\t\tthis.q = (buff[8] & 0x02) == 0x02;\n\t\t\t}\n\t\t}\n\t\tpublic TimeSpan PT => pt;\n\n\t\tpublic TimeSpan ET => et;\n\n\t\tpublic bool IN => input;\n\n\t\tpublic bool Q => q;\n\n\t\t#endregion\n\t}\n}"
  },
  {
    "path": "Sharp7/S7WordLength.cs",
    "content": "﻿namespace Sharp7\n{\n    public enum S7WordLength\n    {\n        Bit     = 0x01,\n        Byte    = 0x02,\n        Char    = 0x03,\n        Word    = 0x04,\n        Int     = 0x05,\n        DWord   = 0x06,\n        DInt    = 0x07,\n        Real    = 0x08,\n        Counter = 0x1C,\n        Timer   = 0x1D,\n    }\n}"
  },
  {
    "path": "Sharp7/Sharp7.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFrameworks>net40;netstandard2.0</TargetFrameworks>\n    <AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>\n    <IncludeSymbols>true</IncludeSymbols>\n    <SymbolPackageFormat>snupkg</SymbolPackageFormat>\n    <Authors>Federico Barresi</Authors>\n    <Description>The multi-platform Ethernet S7 PLC communication suite</Description>\n    <GeneratePackageOnBuild>true</GeneratePackageOnBuild>\n    <PackageProjectUrl>https://github.com/fbarresi/Sharp7</PackageProjectUrl>\n    <PackageLicenseUrl>https://raw.githubusercontent.com/fbarresi/Sharp7/master/LICENSE</PackageLicenseUrl>\n    <PackageTags>snap7 s7 simatic siemens</PackageTags>\n    <Company />\n    <Version>1.0.0</Version>\n    <PackageIconUrl>https://raw.githubusercontent.com/fbarresi/Sharp7/master/doc/images/logo.jpg</PackageIconUrl>\n    <PackageReleaseNotes>https://github.com/fbarresi/Sharp7/blob/master/CHANGELOG.md</PackageReleaseNotes>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "Sharp7.Tests/ClientTest.cs",
    "content": "using System;\nusing Shouldly;\nusing Xunit;\n\nnamespace Sharp7.Tests\n{\n    public class ClientTest : ServerClientTestBase\n    {\n\n        [Fact]\n        public void ClientIsNotNull()\n        {\n            Client.ShouldNotBeNull();\n        }\n\n        [Fact]\n        public void ServerIsNotNull()\n        {\n            Server.ShouldNotBeNull();\n        }\n\n        [Fact]\n        public void Timeout()\n        {\n            Client.ConnTimeout.ShouldBe(2000);\n        }\n\n        [Fact]\n        public void Connected()\n        {\n            Client.Connected.ShouldBe(true);\n        }\n\n        [Fact]\n        public void Port()\n        {\n            Client.PLCPort.ShouldBe(102);\n        }\n\n        [Fact]\n        public void ReadWriteDb()\n        {\n            var bytes = new byte[] { 1, 2, 3 };\n            var index = 3;\n            Server.RegisterArea(S7Server.SrvAreaDB, index, ref bytes, bytes.Length);\n\n            var buffer = new byte[bytes.Length];\n            var rc = Client.DBRead(index, 0, bytes.Length, buffer);\n\n            //test read\n            rc.ShouldBe(Sharp7.S7Consts.ResultOK);\n            buffer.ShouldBe(bytes);\n\n            buffer = new byte[] { 3, 2, 1 };\n            rc = Client.DBWrite(index, 0, bytes.Length, buffer);\n\n            //test write\n            rc.ShouldBe(Sharp7.S7Consts.ResultOK);\n            bytes.ShouldBe(buffer);\n        }\n\n        [Fact]\n        public void ReadWriteAb()\n        {\n            var bytes = new byte[] { 1, 2, 3 };\n            Server.RegisterArea(S7Server.SrvAreaPa, 0, ref bytes, bytes.Length);\n\n            var buffer = new byte[bytes.Length];\n            var rc = Client.ABRead(0, bytes.Length, buffer);\n\n            //test read\n            rc.ShouldBe(Sharp7.S7Consts.ResultOK);\n            buffer.ShouldBe(bytes);\n\n            buffer = new byte[] { 3, 2, 1 };\n            rc = Client.ABWrite(0, bytes.Length, buffer);\n\n            //test write\n            rc.ShouldBe(Sharp7.S7Consts.ResultOK);\n            bytes.ShouldBe(buffer);\n        }\n\n        [Fact]\n        public void ReadWriteCt()\n        {\n            var bytes = new byte[] { 0,1,2,3,4,5,6,7,8};\n            var index = 3;\n            Server.RegisterArea(S7Server.SrvAreaCt, index, ref bytes, bytes.Length/2);\n\n            var buffer = new ushort[2];\n            var rc = Client.CTRead(0, 2, buffer);\n\n            //test read\n            rc.ShouldBe(Sharp7.S7Consts.ResultOK);\n            buffer.ShouldBe(new ushort[]{0x0100,0x0302});\n\n            buffer = new ushort[] {0x0403, 0x0201 };\n            rc = Client.CTWrite(0, 2, buffer);\n\n            //test write\n            rc.ShouldBe(Sharp7.S7Consts.ResultOK);\n            bytes.ShouldBe(new byte[] { 3, 4, 1, 2, 4, 5, 6, 7, 8 });\n        }\n\n        [Fact]\n        public void ReadWriteMb()\n        {\n            var bytes = new byte[] { 0, 1, 2};\n            Server.RegisterArea(S7Server.SrvAreaMk, 0, ref bytes, bytes.Length);\n\n            var buffer = new byte[bytes.Length];\n            var rc = Client.MBRead(0,bytes.Length,buffer);\n\n            //test read\n            rc.ShouldBe(Sharp7.S7Consts.ResultOK);\n            buffer.ShouldBe(bytes);\n\n            buffer = new byte[] { 3, 2, 1 };\n            rc = Client.MBWrite(0, bytes.Length, buffer);\n\n            //test write\n            rc.ShouldBe(Sharp7.S7Consts.ResultOK);\n            bytes.ShouldBe(buffer);\n        }\n\n        [Fact]\n        public void ReadWriteTm()\n        {\n            var bytes = new byte[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};\n            var index = 5;\n            Server.RegisterArea(S7Server.SrvAreaTm, index, ref bytes, bytes.Length / 2);\n\n            var buffer = new ushort[2];\n            var rc = Client.TMRead(0, 2, buffer);\n\n            //test read\n            rc.ShouldBe(Sharp7.S7Consts.ResultOK);\n            buffer.ShouldBe(new ushort[] { 0x0100, 0x0302 });\n\n            buffer = new ushort[] { 0x0403, 0x0201 };\n            rc = Client.TMWrite(0, 2, buffer);\n\n            //test write\n            rc.ShouldBe(Sharp7.S7Consts.ResultOK);\n            bytes.ShouldBe(new byte[] {3, 4, 1, 2, 4, 5, 6, 7, 8, 9, 10, 11});\n        }\n\n        [Fact]\n        public void ReadWriteEb()\n        {\n            var bytes = new byte[] { 0, 1, 2 };\n            Server.RegisterArea(S7Server.SrvAreaPe, 0, ref bytes, bytes.Length);\n\n            var buffer = new byte[bytes.Length];\n            var rc = Client.EBRead(0, bytes.Length, buffer);\n\n            //test read\n            rc.ShouldBe(Sharp7.S7Consts.ResultOK);\n            buffer.ShouldBe(bytes);\n\n            buffer = new byte[] { 3, 2, 1 };\n            rc = Client.EBWrite(0, bytes.Length, buffer);\n\n            //test write\n            rc.ShouldBe(Sharp7.S7Consts.ResultOK);\n            bytes.ShouldBe(buffer);\n        }\n\n        [Fact]\n        public void Multivars()\n        {\n            var bytes = new byte[] { 1, 2, 3,4,5,6,7,8,9,0 };\n            var index = 30;\n            Server.RegisterArea(S7Server.SrvAreaDB, index, ref bytes, bytes.Length);\n\n            var buffer = new byte[bytes.Length];\n            var multivar = new S7MultiVar(Client);\n            multivar.ShouldNotBeNull();\n            \n            multivar.Add(new Sharp7.S7Consts.S7Tag(){Area = (int)S7Area.DB, DBNumber = index, Elements = 2,Start = 0, WordLen = 2}, ref buffer).ShouldBe(true);\n\n            multivar.Read().ShouldBe(Sharp7.S7Consts.ResultOK);\n            multivar.Add(new Sharp7.S7Consts.S7Tag() { Area = (int)S7Area.DB, DBNumber = index, Elements = 2, Start = 0, WordLen = 2 }, ref buffer).ShouldBe(true);\n\n            multivar.Write().ShouldBe(Sharp7.S7Consts.ResultOK);\n            \n        }\n    }\n}\n"
  },
  {
    "path": "Sharp7.Tests/ClientWithoutServer.cs",
    "content": "using System;\nusing System.Linq;\nusing Shouldly;\nusing Xunit;\n\nnamespace Sharp7.Tests\n{\n    public class ClientWithoutServer\n    {\n        private S7Client client;\n\n        public ClientWithoutServer()\n        {\n            client = new S7Client();\n        }\n\n        public void Dispose()\n        {\n            client.Disconnect();\n        }\n\n        [Fact]\n        public void CannotConnectTest()\n        {\n            var rc = client.ConnectTo(\"127.0.1.2\", 0, 2);\n            rc.ShouldBe(Sharp7.S7Consts.errTCPConnectionFailed);\n        }\n\n        [Fact]\n        public void GetLastErrorTest()\n        {\n            var rc = client.LastError();\n            rc.ShouldBe(0);\n        }\n\n        [Fact]\n        public void GetRequestedPduTest()\n        {\n            var rc = client.RequestedPduLength();\n            rc.ShouldBe(480);\n            client.PduSizeRequested.ShouldBe(480);\n        }\n\n        [Fact]\n        public void GetNegotiatedPduTest()\n        {\n            var rc = client.NegotiatedPduLength();\n            rc.ShouldBe(0);\n            client.PduSizeNegotiated.ShouldBe(0);\n        }\n\n        [Fact]\n        public void SetPlcPortTest()\n        {\n            client.PLCPort = 104;\n            client.PLCPort.ShouldBe(104);\n        }\n\n        [Fact]\n        public void SetPduRequestedTest()\n        {\n            client.PduSizeRequested = 239;\n            client.PduSizeRequested.ShouldBe(240);\n            client.PduSizeRequested = 961;\n            client.PduSizeRequested.ShouldBe(960);\n            client.PduSizeRequested = 481;\n            client.PduSizeRequested.ShouldBe(481);\n        }\n\n        [Fact]\n        public void SetTimeoutTest()\n        {\n            client.ConnTimeout = 239;\n            client.ConnTimeout.ShouldBe(239);\n\n            client.RecvTimeout = 239;\n            client.RecvTimeout.ShouldBe(239);\n\n            client.SendTimeout = 239;\n            client.SendTimeout.ShouldBe(239);\n        }\n\n        [Fact]\n        public void GetExecTimeTest()\n        {\n            client.ExecutionTime.ShouldBe(client.ExecutionTime);\n        }\n\n        [Theory]\n        [InlineData(1, 0)]\n        [InlineData(2, 102)]\n        [InlineData(3, 2000)]\n        [InlineData(4, 2000)]\n        [InlineData(5, 2000)]\n        [InlineData(6, 0)]\n        [InlineData(7, 0)]\n        [InlineData(8, 0)]\n        [InlineData(9, 0)]\n        [InlineData(10, 480)]\n        [InlineData(11, 0)]\n        [InlineData(12, 0)]\n        [InlineData(13, 0)]\n        [InlineData(14, 0)]\n        [InlineData(15, 0)]\n        public void GetParameterTest(int parameterNumber, int expected)\n        {\n            int value = -1;\n            var result = client.GetParam(parameterNumber, ref value);\n            if(result == 0)\n                value.ShouldBe(expected);\n            else\n                result.ShouldBe(0x02500000);\n        }\n\n        [Theory]\n        [InlineData(1, 0)]\n        [InlineData(2, 103)]\n        [InlineData(3, 2001)]\n        [InlineData(4, 2001)]\n        [InlineData(5, 2001)]\n        [InlineData(6, 0)]\n        [InlineData(7, 0)]\n        [InlineData(8, 0)]\n        [InlineData(9, 0)]\n        [InlineData(10, 482)]\n        [InlineData(11, 0)]\n        [InlineData(12, 0)]\n        [InlineData(13, 0)]\n        [InlineData(14, 0)]\n        [InlineData(15, 0)]\n        public void SetParameterTest(int parameterNumber, int newValue)\n        {\n            var result = client.SetParam(parameterNumber, ref newValue);\n            if (result == 0)\n            {\n                int readValue = -1;\n                client.GetParam(parameterNumber, ref readValue);\n                readValue.ShouldBe(newValue);\n            }\n            else\n                result.ShouldBe(0x02500000);\n        }\n    }\n}"
  },
  {
    "path": "Sharp7.Tests/PropertiesTests.cs",
    "content": "﻿using Shouldly;\nusing Xunit;\n\nnamespace Sharp7.Tests\n{\n    public class PropertiesTests\n    {\n        [Fact]\n        public void PlcHasNoName()\n        {\n            var client = new S7Client();\n            client.Name.ShouldBeNull();\n            string.IsNullOrEmpty(client.Name).ShouldBeTrue();\n        }\n\n        [Fact]\n        public void PlcHasAName()\n        {\n            var name = \"test\";\n            var client = new S7Client(name);\n            client.Name.ShouldNotBeNull();\n            string.IsNullOrEmpty(client.Name).ShouldBeFalse();\n            client.Name.ShouldBe(name);\n        }\n        \n        [Fact]\n        public void PlcHasIp()\n        {\n            var ip = \"10.10.10.10\";\n            var client = new S7Client();\n            client.SetConnectionParams(ip, 0, 0);\n            client.PLCIpAddress.ShouldNotBeNull();\n            string.IsNullOrEmpty(client.PLCIpAddress).ShouldBeFalse();\n            client.PLCIpAddress.ShouldBe(ip);\n        }\n        \n        [Fact]\n        public void PlcHasNoIp()\n        {\n            var client = new S7Client();\n            client.PLCIpAddress.ShouldBeNull();\n            string.IsNullOrEmpty(client.PLCIpAddress).ShouldBeTrue();\n        }\n        \n        [Fact]\n        public void PlcToString()\n        {\n            var client = new S7Client();\n            client.ToString().ShouldBe(\"PLC @0.0.0.0\");\n        }\n        \n        [Fact]\n        public void PlcToStringWithName()\n        {\n            var client = new S7Client(\"Test\");\n            client.ToString().ShouldBe(\"PLC Test@0.0.0.0\");\n        }\n        \n        [Fact]\n        public void PlcToStringWithNameAndIp()\n        {\n            var client = new S7Client(\"Test\");\n            client.SetConnectionParams(\"1.2.3.4\", 0, 0);\n            client.ToString().ShouldBe(\"PLC Test@1.2.3.4\");\n        }\n    }\n}"
  },
  {
    "path": "Sharp7.Tests/S7Server.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Runtime.InteropServices;\nusing System.Text;\n\nnamespace Sharp7.Tests\n{\n    internal class S7Consts\n    {\n        public const string S7LibName = \"snap7.dll\";\n    }\n    public class S7Server\n    {\n        #region [Constants, private vars and TypeDefs]\n\n        private const int MsgTextLen = 1024;\n        private const int MkEvent = 0;\n        private const int MkLog = 1;\n\n        // Server Area ID  (use with Register/unregister - Lock/unlock Area)\n        public static readonly int SrvAreaPe = 0;\n        public static readonly int SrvAreaPa = 1;\n        public static readonly int SrvAreaMk = 2;\n        public static readonly int SrvAreaCt = 3;\n        public static readonly int SrvAreaTm = 4;\n        public static readonly int SrvAreaDB = 5;\n\n        // S7 Server Event Code\n        public static readonly uint EvcPdUincoming = 0x00010000;\n        public static readonly uint EvcDataRead = 0x00020000;\n        public static readonly uint EvcDataWrite = 0x00040000;\n        public static readonly uint EvcNegotiatePdu = 0x00080000;\n        public static readonly uint EvcReadSzl = 0x00100000;\n        public static readonly uint EvcClock = 0x00200000;\n        public static readonly uint EvcUpload = 0x00400000;\n        public static readonly uint EvcDownload = 0x00800000;\n        public static readonly uint EvcDirectory = 0x01000000;\n        public static readonly uint EvcSecurity = 0x02000000;\n        public static readonly uint EvcControl = 0x04000000;\n\n        [StructLayout(LayoutKind.Sequential, Pack = 1)]\n        public struct USrvEvent\n        {\n            public IntPtr EvtTime;   // It's platform dependent (32 or 64 bit)\n            public Int32 EvtSender;\n            public UInt32 EvtCode;\n            public ushort EvtRetCode;\n            public ushort EvtParam1;\n            public ushort EvtParam2;\n            public ushort EvtParam3;\n            public ushort EvtParam4;\n        }\n\n        [StructLayout(LayoutKind.Sequential, Pack = 1)]\n        public struct S7Tag\n        {\n            public Int32 Area;\n            public Int32 DBNumber;\n            public Int32 Start;\n            public Int32 Elements;\n            public Int32 WordLen;\n        }\n\n        private Dictionary<Int32, GCHandle> hArea;\n\n        private IntPtr server;\n\n        #endregion\n\n        #region [Class Control]\n\n        [DllImport(S7Consts.S7LibName)]\n        private static extern IntPtr Srv_Create();\n        /// <summary>\n        /// Create an instace of S7Server\n        /// </summary>\n        public S7Server()\n        {\n            server = Srv_Create();\n            hArea = new Dictionary<int, GCHandle>();\n        }\n\n        [DllImport(S7Consts.S7LibName)]\n        private static extern int Srv_Destroy(ref IntPtr server);\n        /// <summary>\n        /// Destroy the S7Server and free the memory\n        /// </summary>\n        ~S7Server()\n        {\n            foreach (var item in hArea)\n            {\n                GCHandle handle = item.Value;\n                if (handle != null)\n                    handle.Free();\n            }\n            Srv_Destroy(ref server);\n        }\n\n        [DllImport(S7Consts.S7LibName)]\n        private static extern int Srv_StartTo(IntPtr server, [MarshalAs(UnmanagedType.LPStr)] string address);\n        /// <summary>\n        /// Start the server to a specific Address\n        /// </summary>\n        /// <param name=\"address\">Address for adapter selection</param>\n        /// <returns>0: No errors. Otherwise see errorcodes</returns>\n        public int StartTo(string address)\n        {\n            return Srv_StartTo(server, address);\n        }\n\n        [DllImport(S7Consts.S7LibName)]\n        private static extern int Srv_Start(IntPtr server);\n        /// <summary>\n        /// start the server\n        /// </summary>\n        /// <returns>0: No errors. Otherwise see errorcodes</returns>\n        public int Start()\n        {\n            return Srv_Start(server);\n        }\n\n        [DllImport(S7Consts.S7LibName)]\n        private static extern int Srv_Stop(IntPtr server);\n        /// <summary>\n        /// Stop the server\n        /// </summary>\n        /// <returns>0: No errors. Otherwise see errorcodes</returns>\n        public int Stop()\n        {\n            return Srv_Stop(server);\n        }\n\n        #endregion\n\n        #region [Data Areas functions]\n\n        [DllImport(S7Consts.S7LibName)]\n        private static extern int Srv_RegisterArea(IntPtr server, Int32 areaCode, Int32 index, IntPtr pUsrData, Int32 size);\n        /// <summary>\n        /// Register a PLC Area\n        /// </summary>\n        /// <typeparam name=\"T\"></typeparam>\n        /// <param name=\"areaCode\">Code for area identification (e.g. S7Server.SrvAreaDB)</param>\n        /// <param name=\"index\">Area index</param>\n        /// <param name=\"pUsrData\">Content of the area by reference</param>\n        /// <param name=\"size\">Allocation size</param>\n        /// <returns>0: No errors. Otherwise see errorcodes</returns>\n        public int RegisterArea<T>(Int32 areaCode, Int32 index, ref T pUsrData, Int32 size)\n        {\n            Int32 areaUid = (areaCode << 16) + index;\n            GCHandle handle = GCHandle.Alloc(pUsrData, GCHandleType.Pinned);\n            int result = Srv_RegisterArea(server, areaCode, index, handle.AddrOfPinnedObject(), size);\n            if (result == 0)\n                hArea.Add(areaUid, handle);\n            else\n                handle.Free();\n            return result;\n        }\n\n        [DllImport(S7Consts.S7LibName)]\n        private static extern int Srv_UnregisterArea(IntPtr server, Int32 areaCode, Int32 index);\n        /// <summary>\n        /// Unregister a PLC area\n        /// </summary>\n        /// <param name=\"areaCode\">Code for area identification (e.g. S7Server.SrvAreaDB)</param>\n        /// <param name=\"index\">Area index</param>\n        /// <returns>0: No errors. Otherwise see errorcodes</returns>\n        public int UnregisterArea(Int32 areaCode, Int32 index)\n        {\n            int result = Srv_UnregisterArea(server, areaCode, index);\n            if (result == 0)\n            {\n                Int32 areaUid = (areaCode << 16) + index;\n                if (hArea.ContainsKey(areaUid)) // should be always true\n                {\n                    GCHandle handle = hArea[areaUid];\n                    if (handle != null) // should be always true\n                        handle.Free();\n                    hArea.Remove(areaUid);\n                }\n            }\n            return result;\n        }\n\n        [DllImport(S7Consts.S7LibName)]\n        private static extern int Srv_LockArea(IntPtr server, Int32 areaCode, Int32 index);\n        /// <summary>\n        /// Lock a memory area\n        /// </summary>\n        /// <param name=\"areaCode\">Code for area identification (e.g. S7Server.SrvAreaDB)</param>\n        /// <param name=\"index\">Area index</param>\n        /// <returns>0: No errors. Otherwise see errorcodes</returns>\n        public int LockArea(Int32 areaCode, Int32 index)\n        {\n            return Srv_LockArea(server, areaCode, index);\n        }\n\n        [DllImport(S7Consts.S7LibName)]\n        private static extern int Srv_UnlockArea(IntPtr server, Int32 areaCode, Int32 index);\n        /// <summary>\n        /// Unlock a memory area\n        /// </summary>\n        /// <param name=\"areaCode\">Code for area identification (e.g. S7Server.SrvAreaDB)</param>\n        /// <param name=\"index\">Area index</param>\n        /// <returns>0: No errors. Otherwise see errorcodes</returns>\n        public int UnlockArea(Int32 areaCode, Int32 index)\n        {\n            return Srv_UnlockArea(server, areaCode, index);\n        }\n\n        #endregion\n\n        #region [Notification functions (Events)]\n\n        [StructLayout(LayoutKind.Sequential, Pack = 1)]\n        public struct RwBuffer\n        {\n            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1024)] // A telegram cannot exceed PDU size (960 bytes)\n            public byte[] Data;\n        }\n        /// <summary>\n        /// Callback delegate\n        /// </summary>\n        /// <param name=\"usrPtr\">User pointer passed back</param>\n        /// <param name=\"Event\">Event information structure</param>\n        /// <param name=\"size\">Size</param>\n        public delegate void SrvCallback(IntPtr usrPtr, ref USrvEvent Event, int size);\n        /// <summary>\n        /// Callback delegate for RW operation\n        /// </summary>\n        /// <param name=\"usrPtr\">User pointer passed back</param>\n        /// <param name=\"sender\">Sender</param>\n        /// <param name=\"operation\">Operation type</param>\n        /// <param name=\"tag\">Operation Tag</param>\n        /// <param name=\"buffer\">RW Buffer</param>\n        /// <returns>0: No errors. Otherwise see errorcodes</returns>\n        public delegate int SrvRwAreaCallback(IntPtr usrPtr, int sender, int operation, ref S7Tag tag, ref RwBuffer buffer);\n\n        [DllImport(S7Consts.S7LibName)]\n        private static extern int Srv_SetEventsCallback(IntPtr server, SrvCallback callback, IntPtr usrPtr);\n        /// <summary>\n        /// Set a function callback\n        /// </summary>\n        /// <param name=\"callback\">Callback delegate</param>\n        /// <param name=\"usrPtr\">User pointer passed back</param>\n        /// <returns>0: No errors. Otherwise see errorcodes</returns>\n        public int SetEventsCallBack(SrvCallback callback, IntPtr usrPtr)\n        {\n            return Srv_SetEventsCallback(server, callback, usrPtr);\n        }\n\n        [DllImport(S7Consts.S7LibName)]\n        private static extern int Srv_SetReadEventsCallback(IntPtr server, SrvCallback callback, IntPtr usrPtr);\n        /// <summary>\n        /// Set a function callback for read events\n        /// </summary>\n        /// <param name=\"callback\">Callback delegate</param>\n        /// <param name=\"usrPtr\">User pointer passed back</param>\n        /// <returns>0: No errors. Otherwise see errorcodes</returns>\n        public int SetReadEventsCallBack(SrvCallback callback, IntPtr usrPtr)\n        {\n            return Srv_SetReadEventsCallback(server, callback, usrPtr);\n        }\n\n        [DllImport(S7Consts.S7LibName)]\n        private static extern int Srv_SetRWAreaCallback(IntPtr server, SrvRwAreaCallback callback, IntPtr usrPtr);\n        /// <summary>\n        /// Set a function callback for read-write events\n        /// </summary>\n        /// <param name=\"callback\">Callback delegate</param>\n        /// <param name=\"usrPtr\">User pointer passed back</param>\n        /// <returns>0: No errors. Otherwise see errorcodes</returns>\n        public int SetRwAreaCallBack(SrvRwAreaCallback callback, IntPtr usrPtr)\n        {\n            return Srv_SetRWAreaCallback(server, callback, usrPtr);\n        }\n\n        [DllImport(S7Consts.S7LibName)]\n        private static extern int Srv_PickEvent(IntPtr server, ref USrvEvent Event, ref Int32 evtReady);\n        /// <summary>\n        /// Extracts an event (if available) from the Events queue.\n        /// </summary>\n        /// <param name=\"Event\">Reference of User event</param>\n        /// <returns>0: No errors. Otherwise see errorcodes</returns>\n        public bool PickEvent(ref USrvEvent Event)\n        {\n            Int32 evtReady = new Int32();\n            if (Srv_PickEvent(server, ref Event, ref evtReady) == 0)\n                return evtReady != 0;\n            else\n                return false;\n        }\n\n        [DllImport(S7Consts.S7LibName)]\n        private static extern int Srv_ClearEvents(IntPtr server);\n        /// <summary>\n        /// clear the event queue\n        /// </summary>\n        /// <returns>0: No errors. Otherwise see errorcodes</returns>\n        public int ClearEvents()\n        {\n            return Srv_ClearEvents(server);\n        }\n\n        [DllImport(S7Consts.S7LibName, CharSet = CharSet.Ansi)]\n        private static extern int Srv_EventText(ref USrvEvent Event, StringBuilder evtMsg, int textSize);\n        /// <summary>\n        /// retrieve a message from an event\n        /// </summary>\n        /// <param name=\"Event\">Reference to Event</param>\n        /// <returns>The message for an event</returns>\n        public string EventText(ref USrvEvent Event)\n        {\n            StringBuilder message = new StringBuilder(MsgTextLen);\n            Srv_EventText(ref Event, message, MsgTextLen);\n            return message.ToString();\n        }\n        /// <summary>\n        /// Convet an the event time to datetime object\n        /// </summary>\n        /// <param name=\"timeStamp\">Event Time pointer</param>\n        /// <returns>the datetime for the timestamp</returns>\n        public DateTime EvtTimeToDateTime(IntPtr timeStamp)\n        {\n            DateTime unixStartEpoch = new DateTime(1970, 1, 1, 0, 0, 0, 0);\n            return unixStartEpoch.AddSeconds(Convert.ToDouble(timeStamp));\n        }\n\n        [DllImport(S7Consts.S7LibName)]\n        private static extern int Srv_GetMask(IntPtr server, Int32 maskKind, ref UInt32 mask);\n        [DllImport(S7Consts.S7LibName)]\n        private static extern int Srv_SetMask(IntPtr server, Int32 maskKind, UInt32 mask);\n\n        // Property LogMask R/W\n        /// <summary>\n        /// Activate o deactivate the LogMask\n        /// </summary>\n        public UInt32 LogMask\n        {\n            get\n            {\n                UInt32 mask = new UInt32();\n                if (Srv_GetMask(server, S7Server.MkLog, ref mask) == 0)\n                    return mask;\n                else\n                    return 0;\n            }\n            set => Srv_SetMask(server, S7Server.MkLog, value);\n        }\n\n        // Property EventMask R/W\n        /// <summary>\n        /// Activate o deactivate the EventMask\n        /// </summary>\n        public UInt32 EventMask\n        {\n            get\n            {\n                UInt32 mask = new UInt32();\n                if (Srv_GetMask(server, S7Server.MkEvent, ref mask) == 0)\n                    return mask;\n                else\n                    return 0;\n            }\n            set => Srv_SetMask(server, S7Server.MkEvent, value);\n        }\n\n\n        #endregion\n\n        #region [Info functions]\n\n        [DllImport(S7Consts.S7LibName)]\n        private static extern int Srv_GetStatus(IntPtr server, ref Int32 serverStatus, ref Int32 cpuStatus, ref Int32 clientsCount);\n        [DllImport(S7Consts.S7LibName)]\n        private static extern int Srv_SetCpuStatus(IntPtr server, Int32 cpuStatus);\n\n        // Property Virtual CPU status R/W\n        public int CpuStatus\n        {\n            get\n            {\n                Int32 cStatus = new Int32();\n                Int32 sStatus = new Int32();\n                Int32 cCount = new Int32();\n\n                if (Srv_GetStatus(server, ref sStatus, ref cStatus, ref cCount) == 0)\n                    return cStatus;\n                else\n                    return -1;\n            }\n            set => Srv_SetCpuStatus(server, value);\n        }\n\n        // Property Server Status Read Only\n        public int ServerStatus\n        {\n            get\n            {\n                Int32 cStatus = new Int32();\n                Int32 sStatus = new Int32();\n                Int32 cCount = new Int32();\n                if (Srv_GetStatus(server, ref sStatus, ref cStatus, ref cCount) == 0)\n                    return sStatus;\n                else\n                    return -1;\n            }\n        }\n\n        // Property Clients Count Read Only\n        public int ClientsCount\n        {\n            get\n            {\n                Int32 cStatus = new Int32();\n                Int32 sStatus = new Int32();\n                Int32 cCount = new Int32();\n                if (Srv_GetStatus(server, ref cStatus, ref sStatus, ref cCount) == 0)\n                    return cCount;\n                else\n                    return -1;\n            }\n        }\n\n        [DllImport(S7Consts.S7LibName, CharSet = CharSet.Ansi)]\n        private static extern int Srv_ErrorText(int error, StringBuilder errMsg, int textSize);\n        /// <summary>\n        /// Retrieve the error message for an error code\n        /// </summary>\n        /// <param name=\"error\">Error code</param>\n        /// <returns>Message for the error code</returns>\n        public string ErrorText(int error)\n        {\n            StringBuilder message = new StringBuilder(MsgTextLen);\n            Srv_ErrorText(error, message, MsgTextLen);\n            return message.ToString();\n        }\n\n        #endregion\n    }\n}"
  },
  {
    "path": "Sharp7.Tests/ServerClientTestBase.cs",
    "content": "using System;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Shouldly;\n\nnamespace Sharp7.Tests\n{\n    public class ServerClientTestBase : ServerTestBase, IDisposable\n    {\n        private S7Client client;\n        public S7Client Client => client;\n\n        public ServerClientTestBase() : base()\n        {\n            client = new S7Client(\"Test Plc\");\n            var rc = client.ConnectTo(Localhost, 0, 2);\n            rc.ShouldBe(Sharp7.S7Consts.ResultOK);\n        }\n\n\n        public new void Dispose()\n        {\n            client.Disconnect();\n            base.Dispose();\n        }\n    }\n}"
  },
  {
    "path": "Sharp7.Tests/ServerTestBase.cs",
    "content": "using System;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Shouldly;\n\nnamespace Sharp7.Tests\n{\n    public class ServerTestBase : IDisposable\n    {\n        private readonly S7Server server;\n        protected readonly string Localhost = \"127.0.0.1\";\n        public ServerTestBase()\n        {\n            server = new S7Server();\n            var rc = server.StartTo(Localhost);\n            rc.ShouldBe(0);\n        }\n\n        public S7Server Server => server;\n\n        public void Dispose()\n        {\n            server.Stop();\n        }\n    }\n}"
  },
  {
    "path": "Sharp7.Tests/Sharp7.Tests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net45</TargetFramework>\n    <Platforms>AnyCPU;x86</Platforms>\n    <IsPackable>false</IsPackable>\n  </PropertyGroup>\n\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|AnyCPU'\">\n    <PlatformTarget>x86</PlatformTarget>\n  </PropertyGroup>\n\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x86'\">\n    <PlatformTarget>x86</PlatformTarget>\n  </PropertyGroup>\n\n   <PropertyGroup>\n    <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>\n   </PropertyGroup>\n   \n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"16.4.0\" />\n    <PackageReference Include=\"Shouldly\" Version=\"3.0.2\" />\n    <PackageReference Include=\"xunit\" Version=\"2.4.1\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\" Version=\"2.4.1\">\n      <PrivateAssets>all</PrivateAssets>\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n    </PackageReference>\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Sharp7\\Sharp7.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Update=\"snap7.dll\">\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n    </None>\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "Sharp7.Tests/TestUtilities.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Linq.Expressions;\nusing Shouldly;\nusing Xunit;\n\nnamespace Sharp7.Tests\n{\n    public class TestUtilities\n    {\n        [Theory]\n        [InlineData(1,1)] \n        [InlineData(2,1)] \n        [InlineData(3,1)] \n        [InlineData(4,2)] \n        [InlineData(5,2)] \n        [InlineData(6,4)] \n        [InlineData(7,4)] \n        [InlineData(8,4)] \n        [InlineData(0x1D,2)] \n        [InlineData(0x1C,2)] \n        [InlineData(0,0)] \n        public void TestDataSizeByte(int wordLength, int expected) { S7.DataSizeByte(wordLength).ShouldBe(expected); }\n        [Fact] public void TestGetBitAt() { S7.GetBitAt(new byte[] {1,2,3,4}, 0, 0).ShouldBe(true); }\n        [Fact] public void TestSetBitAt() {\n            var buffer = new byte[] {1,2,3,4};\n            S7.SetBitAt(buffer, 0, 1, true);\n            buffer.ShouldBe(new byte[] {3, 2, 3, 4});\n        }\n        [Fact] public void TestSetBitAtAsExtensionMethod() {\n            var buffer = new byte[] {1,2,3,4};\n            buffer.SetBitAt(0, 1, true);\n            buffer.ShouldBe(new byte[] {3, 2, 3, 4});\n        }\n\n        //unsigned\n\n        [Theory]\n        [InlineData(new byte[] { 1, 2, 3, 4 }, 0, 1)]\n        [InlineData(new byte[] { 129, 2, 3, 4 }, 0, 129)]\n        public void TestGetUSIntAt(byte[] buffer, int pos, byte expected) { S7.GetUSIntAt(buffer, pos).ShouldBe(expected); }\n        [Theory]\n        [InlineData(new byte[] { 0, 2, 3, 4 }, 0, 1, new byte[] { 1, 2, 3, 4 })]\n        [InlineData(new byte[] { 0, 2, 3, 4 }, 0, 127, new byte[] { 127, 2, 3, 4 })] \n        public void TestSetUSIntAt(byte[] buffer, int pos, byte value, byte[] expected)\n        {\n            S7.SetUSIntAt(buffer, pos, value);\n            buffer.ShouldBe(expected);\n        }\n\n        [Theory]\n        [InlineData( new byte[] { 1, 1, 0, 0 }, 0, 257)]\n        public void TestGetUIntAt(byte[] buffer, int pos, ushort expected) { S7.GetUIntAt(buffer, pos).ShouldBe(expected); }\n\n        [Theory]\n        [InlineData(new byte[]{0,0,0,0}, 0, 1, new byte[] {0,1,0,0})]\n        public void TestSetUIntAt(byte[] buffer, int pos, ushort value, byte[] expected)\n        {\n            S7.SetUIntAt(buffer, pos, value);\n            buffer.ShouldBe(expected);\n        }\n        [Theory]\n        [InlineData(new byte[] { 0, 0, 0, 2 }, 0, 2)] \n        public void TestGetUDIntAt(byte[] buffer, int pos, uint expected) { S7.GetUDIntAt(buffer, pos).ShouldBe(expected); }\n\n        [Theory]\n        [InlineData(new byte[] {0, 0, 0, 0}, 0, 1, new byte[] {0, 0, 0, 1})]\n        public void TestSetUDIntAt(byte[] buffer, int pos, uint value, byte[] expected)\n        {\n            S7.SetUDIntAt(buffer, pos, value);\n            buffer.ShouldBe(expected);\n        }\n        [Theory]\n        [InlineData(new byte[] { 0, 0, 0, 0, 0, 0, 0, 2 }, 0, 2L)] \n        public void TestGetULIntAt(byte[] buffer, int pos, ulong expected) { S7.GetULIntAt(buffer, pos).ShouldBe(expected); }\n\n        [Theory]\n        [InlineData(new byte[] {0, 0, 0, 0, 0, 0, 0, 0}, 0, 1L, new byte[] { 0, 0, 0, 0, 0, 0, 0, 1})]\n        public void TestSetULIntAt(byte[] buffer, int pos, ulong value, byte[] expected)\n        {\n            S7.SetULintAt(buffer, pos, value);\n            buffer.ShouldBe(expected);\n        }\n\n        // signed\n\n        [Theory]\n        [InlineData(new byte[] { 1, 2, 3, 4 }, 0, 1)]\n        [InlineData(new byte[] { 129, 2, 3, 4 }, 0, -127)]\n        public void TestGetSIntAt(byte[] buffer, int pos, int expected) { S7.GetSIntAt(buffer, pos).ShouldBe(expected); }\n        [Theory]\n        [InlineData(new byte[] { 0, 2, 3, 4 }, 0, 1, new byte[] { 1, 2, 3, 4 })]\n        [InlineData(new byte[] { 0, 2, 3, 4 }, 0, -127, new byte[] { 129, 2, 3, 4 })]\n        public void TestSetSIntAt(byte[] buffer, int pos, int value, byte[] expected)\n        {\n            S7.SetSIntAt(buffer, pos, value);\n            buffer.ShouldBe(expected);\n        }\n\n        [Theory]\n        [InlineData(new byte[] { 1, 1, 0, 0 }, 0, 257)]\n        public void TestGetIntAt(byte[] buffer, int pos, short expected) { S7.GetIntAt(buffer, pos).ShouldBe(expected); }\n\n        [Theory]\n        [InlineData(new byte[] { 0, 0, 0, 0 }, 0, 1, new byte[] { 0, 1, 0, 0 })]\n        public void TestSetIntAt(byte[] buffer, int pos, Int16 value, byte[] expected)\n        {\n            S7.SetIntAt(buffer, pos, value);\n            buffer.ShouldBe(expected);\n        }\n        [Theory]\n        [InlineData(new byte[] { 0, 0, 0, 2 }, 0, 2)]\n        public void TestGetDIntAt(byte[] buffer, int pos, int expected) { S7.GetDIntAt(buffer, pos).ShouldBe(expected); }\n\n        [Theory]\n        [InlineData(new byte[] { 0, 0, 0, 0 }, 0, 1, new byte[] { 0, 0, 0, 1 })]\n        public void TestSetDIntAt(byte[] buffer, int pos, int value, byte[] expected)\n        {\n            S7.SetDIntAt(buffer, pos, value);\n            buffer.ShouldBe(expected);\n        }\n        [Theory]\n        [InlineData(new byte[] { 0, 0, 0, 0, 0, 0, 0, 2 }, 0, 2L)] \n        public void TestGetLIntAt(byte[] buffer, int pos, long expected) { S7.GetLIntAt(buffer, pos).ShouldBe(expected); }\n\n        [Theory]\n        [InlineData(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, 0, 1L, new byte[] { 0, 0, 0, 0, 0, 0, 0, 1 })]\n        public void TestSetLIntAt(byte[] buffer, int pos, long value, byte[] expected)\n        {\n            S7.SetLIntAt(buffer, pos, value);\n            buffer.ShouldBe(expected);\n        }\n\n\n        [Fact] public void TestGetByteAt() { S7.GetByteAt(new byte[] {1,2,3,4}, 1).ShouldBe((byte)2); }\n\n        [Fact]\n        public void TestSetByteAt()\n        {\n            var buffer = new byte[] { 1, 2, 3, 4 };\n            S7.SetByteAt(buffer, 0, (byte)5);\n            buffer.ShouldBe(new byte[] { 5, 2, 3, 4 });\n        }\n\n        [Theory]\n        [InlineData(new byte[] {0, 2, 0, 0, 0, 0, 0, 0}, 0, 2)]\n        public void TestGetWordAt(byte[] buffer, int pos, ushort expected)\n        {\n            S7.GetWordAt(buffer, pos).ShouldBe(expected);\n        }\n\n        [Theory]\n        [InlineData(new byte[] {0, 0, 0, 0, 0, 0, 0, 0}, 0, 1, new byte[] {0, 1, 0, 0, 0, 0, 0, 0})]\n        public void TestSetWordAt(byte[] buffer, int pos, ushort value, byte[] expected)\n        {\n            S7.SetWordAt(buffer, pos, value);\n            buffer.ShouldBe(expected);\n        }\n\n        [Theory]\n        [InlineData(new byte[] { 0, 0, 0, 3, 0, 0, 0, 0 }, 0, 3)]\n        public void TestGetDWordAt(byte[] buffer, int pos, uint expected)\n        {\n            S7.GetDWordAt(buffer, pos).ShouldBe(expected);\n        }\n\n        [Theory]\n        [InlineData(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, 0, 1, new byte[] { 0, 0, 0, 1, 0, 0, 0, 0 })]\n        public void TestSetDWordAt(byte[] buffer, int pos, uint value, byte[] expected)\n        {\n            S7.SetDWordAt(buffer, pos, value);\n            buffer.ShouldBe(expected);\n        }\n\n        [Theory]\n        [InlineData(new byte[] { 0, 0, 0, 0, 0, 0, 0, 4 }, 0, 4L)]\n        public void TestGetLWordAt(byte[] buffer, int pos, ulong expected)\n        {\n            S7.GetLWordAt(buffer, pos).ShouldBe(expected);\n        }\n\n        [Theory]\n        [InlineData(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, 0, 1L, new byte[] { 0, 0, 0, 0, 0, 0, 0, 1 })]\n        public void TestSetLWordAt(byte[] buffer, int pos, ulong value, byte[] expected)\n        {\n            S7.SetLWordAt(buffer, pos, value);\n            buffer.ShouldBe(expected);\n        }\n\n        [Theory]\n        [InlineData(new byte[] { 1, 2, 3, 0, 0, 11, 5, 4 }, 0, 2.387938E-38f)]\n        public void TestGetRealAt(byte[] buffer, int pos, float expected)\n        {\n            S7.GetRealAt(buffer, pos).ShouldBe(expected);\n        }\n\n        [Theory]\n        [InlineData(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, 0, 4f, new byte[] { 64, 128, 0, 0, 0, 0, 0, 0 })]\n        public void TestSetRealAt(byte[] buffer, int pos, float value, byte[] expected)\n        {\n            S7.SetRealAt(buffer, pos, value);\n            buffer.ShouldBe(expected);\n        }\n\n        [Theory]\n        [InlineData(new byte[] { 64, 128, 0, 0, 0, 0, 0, 0}, 0, 512d)]\n        public void TestGetLRealAt(byte[] buffer, int pos, double expected)\n        {\n            S7.GetLRealAt(buffer, pos).ShouldBe(expected);\n        }\n\n        [Theory]\n        [InlineData(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, 0, 4d, new byte[] { 64, 16, 0, 0, 0, 0, 0, 0 })]\n        public void TestSetLRealAt(byte[] buffer, int pos, double value, byte[] expected)\n        {\n            S7.SetLRealAt(buffer, pos, value);\n            buffer.ShouldBe(expected);\n        }\n\n\n        [Theory]\n        [InlineData(new byte[] {16,17,18,19,20,21,0,6})]\n        public void TestGetDateTimeAt(byte[] buffer)\n        {\n            var time = new DateTime(2010, 11, 12, 13, 14, 15);\n            S7.GetDateTimeAt(buffer, 0).ShouldBe(time);\n        }\n\n        [Theory]\n        [InlineData(new byte[] {16, 17, 18, 19, 20, 21, 0, 6})]\n        public void TestSetDateTimeAt(byte[] expected)\n        {\n            var time = new DateTime(2010, 11, 12, 13, 14, 15);\n            var buffer = new byte[8];\n            S7.SetDateTimeAt(buffer, 0, time);\n            buffer.ShouldBe(expected);\n        }\n\n        [Theory]\n        [InlineData(new byte[] {0,2})]\n        public void TestGetDateAt(byte[] buffer)\n        {\n            var date = new DateTime(1990, 1, 3);\n            S7.GetDateAt(buffer, 0).ShouldBe(date);\n        }\n        [Theory]\n        [InlineData(new byte[] { 0,3 })]\n        public void TestSetDateAt(byte[] expected)\n        {\n            var buffer = new byte[2];\n            var date = new DateTime(1990,1,4);\n            S7.SetDateAt(buffer, 0, date);\n            buffer.ShouldBe(expected);\n        }\n\n        [Theory]\n        [InlineData(new byte[] {0, 0,0,2}, 2)]\n        public void TestGetTODAt(byte[] buffer, int milliseconds)\n        {\n            S7.GetTODAt(buffer, 0).ShouldBe(new DateTime(0).AddMilliseconds(milliseconds));\n            S7.GetTODAsDateTimeAt(buffer, 0).ShouldBe(new DateTime(0).AddMilliseconds(milliseconds));\n            S7.GetTODAsTimeSpanAt(buffer, 0).ShouldBe(TimeSpan.FromMilliseconds(milliseconds));\n        }\n\n        [Theory]\n        [InlineData(new byte[] {0, 0,0,2}, 2)]\n        public void TestSetTODAt(byte[] expected, int milliseconds)\n        {\n            var buffer = new byte[4];\n            S7.SetTODAt(buffer, 0, new DateTime(0).AddMilliseconds(milliseconds));\n            buffer.ShouldBe(expected);\n            buffer = new byte[4];\n            S7.SetTODAt(buffer, 0, TimeSpan.FromMilliseconds(milliseconds));\n            buffer.ShouldBe(expected);\n        }\n        [Theory]\n        [InlineData(new byte[] { 0, 0, 0, 0,0,0,0,200 }, 2)]\n        public void TestGetLTODAt(byte[] buffer, int ticks)\n        {\n            S7.GetLTODAt(buffer, 0).ShouldBe(new DateTime(ticks));\n            S7.GetLTODAsDateTimeAt(buffer, 0).ShouldBe(new DateTime(ticks));\n            S7.GetLTODAsTimeSpanAt(buffer, 0).ShouldBe(TimeSpan.FromTicks(ticks));\n        }\n\n        [Theory]\n        [InlineData(new byte[] { 0, 0, 0, 0,0,0,0,200 }, 2)]\n        public void TestSetLTODAt(byte[] expected, int ticks)\n        {\n            var buffer = new byte[8];\n            S7.SetLTODAt(buffer, 0, new DateTime(ticks));\n            buffer.ShouldBe(expected);\n            buffer = new byte[8];\n            S7.SetLTODAt(buffer, 0, TimeSpan.FromTicks(ticks));\n            buffer.ShouldBe(expected);\n        }\n\n        [Theory]\n        [InlineData(new byte[] { 0, 0, 0, 0, 0, 0, 0, 200 }, 2)]\n        public void TestGetLDTAt(byte[] buffer, int ticks)\n        {\n            S7.GetLDTAt(buffer, 0).ShouldBe(new DateTime(1970, 1, 1).AddTicks(ticks));\n        }\n\n        [Theory]\n        [InlineData(new byte[] { 0, 0, 0, 0, 0, 0, 0, 200 }, 2)]\n        public void TestSetLDTAt(byte[] expected, int ticks)\n        {\n            var buffer = new byte[8];\n            S7.SetLDTAt(buffer, 0, new DateTime(1970,1,1).AddTicks(ticks));\n            buffer.ShouldBe(expected);\n        }\n\n        [Theory]\n        [InlineData(new byte[] { 10, 10, 10, 10, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0 })]\n        public void TestGetDTLAt(byte[] buffer)\n        {\n            S7.GetDTLAt(buffer, 0).ShouldBe(new DateTime(2570, 10, 10,10,10,0));\n        }\n\n        [Theory]\n        [InlineData(new byte[] { 10, 10, 10, 10, 4, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0 })]\n        public void TestSetDTLAt(byte[] expected)\n        {\n            var buffer = new byte[16];\n\n            S7.SetDTLAt(buffer, 0, new DateTime(2570, 10, 10, 10, 10, 0));\n            buffer.ShouldBe(expected);\n        }\n\n\n        [Theory]\n        [InlineData(new byte[] {0, 3, 55,55,55,0,0,0,0,0}, \"777\")]\n        public void TestGetStringAt(byte[] buffer, string expected)\n        {\n            S7.GetStringAt(buffer, 0).ShouldBe(expected);\n        }\n\n        [Theory]\n        [InlineData(\"888\", 200, new byte[] {200, 3, 56,56,56})]\n        [InlineData(\"888888\", 5, new byte[] {5, 5, 56,56,56,56,56})]\n        public void TestSetStringAt(string test, int maxLength, byte[] expected)\n        {\n            var buffer = new byte[maxLength+2];\n            S7.SetStringAt(buffer, 0, maxLength, test);\n            buffer.Take(expected.Length).ToArray().ShouldBe(expected);\n        }\n        \n        [Theory]\n        [InlineData(new byte[] { 55, 55, 55 }, \"777\")]\n        [InlineData(new byte[] { 56, 56, 56 }, \"888\")]\n        public void TestGetCharsAt(byte[] buffer, string expected) { S7.GetCharsAt(buffer, 0, buffer.Length).ShouldBe(expected); }\n\n        [Theory]\n        [InlineData(\"777\", new byte[] {55, 55, 55})]\n        [InlineData(\"888\", new byte[] {56, 56, 56})]\n        public void TestSetCharsAt(string chars, byte[] expected)\n        {\n            var buffer = new byte[chars.Length];\n            S7.SetCharsAt(buffer, 0, chars); \n            buffer.ShouldBe(expected);\n        }\n\n        [Theory]\n        [InlineData(12, 1200)] \n        [InlineData(13, 1300)] \n        public void TestGetCounter(ushort value, int expected) { S7.GetCounter(value).ShouldBe(expected); }\n\n        [Theory]\n        [InlineData(new ushort[]{12},0, 1200)]\n        [InlineData(new ushort[]{0,12},1, 1200)]\n        public void TestGetCounterAt(ushort[] buffer, int index, int expected) { S7.GetCounterAt(buffer, index).ShouldBe(expected); }\n\n        [Theory]\n        [InlineData(1200, 18)]\n        [InlineData(1300, 19)] \n        public void TestToCounter(int value, ushort expected) { S7.ToCounter(value).ShouldBe(expected); }\n\n        [Theory]\n        [InlineData(0, 1200, new ushort[] {18,0})]\n        [InlineData(1, 1200, new ushort[] {0, 18})]\n        public void TestSetCounterAt(int index, int counter, ushort[] expected)\n        {\n            var buffer = new ushort[2];\n            S7.SetCounterAt(buffer, index, counter); \n            buffer.ShouldBe(expected);\n        }\n\n        [Theory]\n        [InlineData(new byte[] { 18, 0,0,0,0,4,5,6,7,8,0,0,0,0,0,0,0,0,0 })] \n        public void TestGetS7TimerAt(byte[] buffer) { new S7TimerEqualityComparer().Equals(S7.GetS7TimerAt(buffer, 0), new S7Timer(buffer.Take(12).ToArray())).ShouldBe(true); }\n\n        [Theory]\n        [InlineData(10,new byte[] { 0, 0, 0, 10 })]\n        public void TestSetS7TimespanAt(int milliseconds, byte[] expected)\n        {\n            var buffer = new byte[8];\n            S7.SetS7TimespanAt(buffer, 0, TimeSpan.FromMilliseconds(milliseconds));\n            buffer.Take(expected.Length).ToArray().ShouldBe(expected);\n        }\n\n        [Theory]\n        [InlineData(new byte[] { 0, 0, 0, 10 }, 10)]\n        public void TestGetS7TimespanAt(byte[] buffer, int milliseconds)\n        {\n            S7.GetS7TimespanAt(buffer, 0).ShouldBe(TimeSpan.FromMilliseconds(milliseconds));\n        }\n    }\n\n    internal sealed class S7TimerEqualityComparer : IEqualityComparer<S7Timer>\n    {\n        public bool Equals(S7Timer x, S7Timer y)\n        {\n            if (ReferenceEquals(x, y)) return true;\n            if (ReferenceEquals(x, null)) return false;\n            if (ReferenceEquals(y, null)) return false;\n            if (x.GetType() != y.GetType()) return false;\n            return x.PT.Equals(y.PT) && x.ET.Equals(y.ET) && x.IN == y.IN && x.Q == y.Q;\n        }\n\n        public int GetHashCode(S7Timer obj)\n        {\n            unchecked\n            {\n                var hashCode = obj.PT.GetHashCode();\n                hashCode = (hashCode * 397) ^ obj.ET.GetHashCode();\n                hashCode = (hashCode * 397) ^ obj.IN.GetHashCode();\n                hashCode = (hashCode * 397) ^ obj.Q.GetHashCode();\n                return hashCode;\n            }\n        }\n    }\n}"
  },
  {
    "path": "Sharp7.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.29306.81\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Sharp7\", \"Sharp7\\Sharp7.csproj\", \"{4FE194AF-7FFE-48BA-9DFC-425E9D5B9F46}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Sharp7.Tests\", \"Sharp7.Tests\\Sharp7.Tests.csproj\", \"{A770A4B3-8BD7-49A8-BF7B-8CE1FA2E577A}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tDebug|x64 = Debug|x64\n\t\tDebug|x86 = Debug|x86\n\t\tRelease|Any CPU = Release|Any CPU\n\t\tRelease|x64 = Release|x64\n\t\tRelease|x86 = Release|x86\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{4FE194AF-7FFE-48BA-9DFC-425E9D5B9F46}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{4FE194AF-7FFE-48BA-9DFC-425E9D5B9F46}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{4FE194AF-7FFE-48BA-9DFC-425E9D5B9F46}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{4FE194AF-7FFE-48BA-9DFC-425E9D5B9F46}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{4FE194AF-7FFE-48BA-9DFC-425E9D5B9F46}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{4FE194AF-7FFE-48BA-9DFC-425E9D5B9F46}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{4FE194AF-7FFE-48BA-9DFC-425E9D5B9F46}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{4FE194AF-7FFE-48BA-9DFC-425E9D5B9F46}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{4FE194AF-7FFE-48BA-9DFC-425E9D5B9F46}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{4FE194AF-7FFE-48BA-9DFC-425E9D5B9F46}.Release|x64.Build.0 = Release|Any CPU\n\t\t{4FE194AF-7FFE-48BA-9DFC-425E9D5B9F46}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{4FE194AF-7FFE-48BA-9DFC-425E9D5B9F46}.Release|x86.Build.0 = Release|Any CPU\n\t\t{A770A4B3-8BD7-49A8-BF7B-8CE1FA2E577A}.Debug|Any CPU.ActiveCfg = Debug|x86\n\t\t{A770A4B3-8BD7-49A8-BF7B-8CE1FA2E577A}.Debug|Any CPU.Build.0 = Debug|x86\n\t\t{A770A4B3-8BD7-49A8-BF7B-8CE1FA2E577A}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{A770A4B3-8BD7-49A8-BF7B-8CE1FA2E577A}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{A770A4B3-8BD7-49A8-BF7B-8CE1FA2E577A}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{A770A4B3-8BD7-49A8-BF7B-8CE1FA2E577A}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{A770A4B3-8BD7-49A8-BF7B-8CE1FA2E577A}.Release|Any CPU.ActiveCfg = Release|x86\n\t\t{A770A4B3-8BD7-49A8-BF7B-8CE1FA2E577A}.Release|Any CPU.Build.0 = Release|x86\n\t\t{A770A4B3-8BD7-49A8-BF7B-8CE1FA2E577A}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{A770A4B3-8BD7-49A8-BF7B-8CE1FA2E577A}.Release|x64.Build.0 = Release|Any CPU\n\t\t{A770A4B3-8BD7-49A8-BF7B-8CE1FA2E577A}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{A770A4B3-8BD7-49A8-BF7B-8CE1FA2E577A}.Release|x86.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {5BDF8DCB-3749-4D92-AF54-2B6EA9C808E6}\n\tEndGlobalSection\nEndGlobal\n"
  }
]