Files
S7CommPlusV3Driver/README.md
2025-08-05 15:44:42 +08:00

8.8 KiB

Siemens S7CommPlus Communication Driver (Testing Phase)

A .NET-based communication driver for Siemens S7-1200/1500 PLCs without TLS dependency

Overview

This communication driver enables secure interaction with Siemens S7-1200 and S7-1500 PLCs without requiring TLS configuration. It provides symbolic variable access and batch operations using modern .NET Framework infrastructure.

Technical Specifications

Component Specification
Target Framework .NET Framework 4.7.2
Core Protocol S7CommPlus
Security Model Non-TLS communication support

Key Features

  • 🔍 Online browsing of global symbolic variable tree
  • 📥 Batch read operations via symbolic variable names
  • 📤 Value writing through symbolic variables
  • Direct communication with S7-1200/1500 PLCs

Implementation Foundation

This project integrates and extends the following critical open-source components:

  1. Communication Core
    S7CommPlusDriver
    Handles all low-level protocol operations

  2. Authentication System
    HarpoS7
    Implements PLC security handshake algorithms

Getting Started

Prerequisites

  • Visual Studio 2019+
  • .NET Framework 4.7.2 Developer Pack
  • Siemens PLC with enabled PUT/GET communication

Basic Usage

class Program
    {
        static void Main(string[] args)
        {
            string HostIp = "192.168.0.250";
            string Password = "";
            int res;
            List<ItemAddress> readlist = new List<ItemAddress>();
            Console.WriteLine("Main - START");
            // Als Parameter lässt sich die IP-Adresse übergeben, sonst Default-Wert von oben
            if (args.Length >= 1) {
                HostIp = args[0];
            }
            // Als Parameter lässt sich das Passwort übergeben, sonst Default-Wert von oben (kein Passwort)
            if (args.Length >= 2) {
                Password = args[1];
            }
            Console.WriteLine("Main - Versuche Verbindungsaufbau zu: " + HostIp);

            S7CommPlusConnection conn = new S7CommPlusConnection();
            res = conn.Connect(HostIp, Password);
            if (res == 0)
            {
                Console.WriteLine("Main - Connect fertig");

                #region Variablenhaushalt browsen
                Console.WriteLine("Main - Starte Browse...");
                // Variablenhaushalt auslesen
                List<VarInfo> vars = new List<VarInfo>();
                res = conn.Browse(out vars);
                Console.WriteLine("Main - Browse res=" + res);
                #endregion
                List<VarInfo> vars_ = vars.GetRange(0,1000);
                #region Werte aller Variablen einlesen
                Console.WriteLine("Main - Lese Werte aller Variablen aus");

                List<PlcTag> taglist = new List<PlcTag>();
                PlcTags tags = new PlcTags();

                foreach (var v in vars_)
                {
                    taglist.Add(PlcTags.TagFactory(v.Name, new ItemAddress(v.AccessSequence), v.Softdatatype));
                }
                foreach (var t in taglist)
                {
                    tags.AddTag(t);
                }
                if (res == 0)
                {
                    Console.WriteLine("====================== VARIABLENHAUSHALT ======================");

                    string formatstring = "{0,-80}{1,-30}{2,-20}{3,-20}";
                    Console.WriteLine(String.Format(formatstring, "SYMBOLIC-NAME", "ACCESS-SEQUENCE", "TYP", "QC: VALUE"));
                    for (int i = 0; i < vars_.Count; i++)
                    {
                        string s;
      
                        s = String.Format(formatstring, taglist[i].Name, taglist[i].Address.GetAccessString(), Softdatatype.Types[taglist[i].Datatype], taglist[i].ToString());
                        Console.WriteLine(s);
                    }
                }
                #endregion
                Console.WriteLine("按任意键开始读");
                Console.ReadKey();
                while (res == 0)
                {
                    System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
                    stopwatch.Start();
                    res = tags.ReadTags(conn);
                    stopwatch.Stop();
                    long ms = stopwatch.ElapsedMilliseconds;
                    if (res == 0)
                    {
                        string header = $"读取{vars_.Count}个变量耗时{ms}毫秒";
                        Console.WriteLine(header);
                    }
                }
                
                #region Werte aller Variablen einlesen
                Console.WriteLine("Main - Lese Werte aller Variablen aus");

                foreach (var v in vars)
                {
                    readlist.Add(new ItemAddress(v.AccessSequence));
                }
                List<object> values = new List<object>();
                List<UInt64> errors = new List<UInt64>();

                
                // Fehlerhafte Variable setzen
                //readlist[2].LID[0] = 123;
                res = conn.ReadValues(readlist, out values, out errors);
                #endregion


                #region Variablenhaushalt mit Werten ausgeben

                if (res == 0)
                {
                    Console.WriteLine("====================== VARIABLENHAUSHALT ======================");

                    // Liste ausgeben
                    string formatstring = "{0,-80}{1,-30}{2,-20}{3,-20}";
                    Console.WriteLine(String.Format(formatstring, "SYMBOLIC-NAME", "ACCESS-SEQUENCE", "TYP", "VALUE"));
                    for (int i = 0; i < vars.Count; i++)
                    { 
                        string s = String.Format(formatstring, vars[i].Name, vars[i].AccessSequence, Softdatatype.Types[vars[i].Softdatatype], values[i]);
                        Console.WriteLine(s);
                    }
                    Console.WriteLine("===============================================================");
                }
                #endregion

                /*
                #region Test: Wert schreiben
                List<PValue> writevalues = new List<PValue>();
                PValue writeValue = new ValueInt(8888);
                writevalues.Add(writeValue);
                List<ItemAddress> writelist = new List<ItemAddress>();
                writelist.Add(new ItemAddress("8A0E0001.F"));
                errors.Clear();
                res = conn.WriteValues(writelist, writevalues, out errors);
                Console.WriteLine("res=" + res);
                #endregion
                */

                /*
                #region Test: Absolutadressen lesen
                // Daten aus nicht "optimierten" Datenbausteinen lesen
                readlist.Clear();
                ItemAddress absAdr = new ItemAddress();
                absAdr.SetAccessAreaToDatablock(100); // DB 100
                absAdr.SymbolCrc = 0;

                absAdr.AccessSubArea = Ids.DB_ValueActual;
                absAdr.LID.Add(3);  // LID_OMS_STB_ClassicBlob
                absAdr.LID.Add(0);  // Blob Start Offset, Anfangsadresse
                absAdr.LID.Add(20); // 20 Bytes

                readlist.Add(absAdr);

                values.Clear();
                errors.Clear();

                res = conn.ReadValues(readlist, out values, out errors);
                Console.WriteLine(values.ToString());
                #endregion
                */


                #region Test: SPS in Stopp setzen
                Console.WriteLine("Setze SPS in STOP...");
                conn.SetPlcOperatingState(1);
                Console.WriteLine("Taste drücken um wieder in RUN zu setzen...");
                Console.ReadKey();
                Console.WriteLine("Setze SPS in RUN...");
                conn.SetPlcOperatingState(3);
                #endregion

                conn.Disconnect();
            }
            else
            {
                Console.WriteLine("Main - Connect fehlgeschlagen!");
            }
            Console.WriteLine("Main - ENDE. Bitte Taste drücken.");
            Console.ReadKey();
        }
    }

Current Status

+ Functional communication established
+ Symbolic variable operations working
- Stability testing ongoing
- Edge case validation pending
- Production hardening required

Contribution & Feedback

We welcome issue reports and testing feedback during this development phase.
Please create detailed tickets including:

  • PLC firmware version
  • Reproduction steps
  • Error logs

License

MIT (Compatible with upstream dependencies)