Files
S7CommPlusV3Driver/DriverTest/Program.cs
CoderShen ada79f2073 1. Resolved the hourly connection termination problem in non-TLS firmware communication.
2. Enhanced socket-level data packet reception throughput.
2025-11-24 17:23:12 +08:00

282 lines
11 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//#define _TEST_BASIC_VAR
#define _TEST_PLCTAG
using System;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using S7CommPlusDriver;
using S7CommPlusDriver.ClientApi;
namespace DriverTest
{
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();
conn.OnlySecurePGOrPCAndHMI = false;
System.Diagnostics.Stopwatch stopwatch1 = new System.Diagnostics.Stopwatch();
stopwatch1.Start();
res = conn.Connect(HostIp, Password);
stopwatch1.Stop();
byte[] var1_crc_bytes = { 0x88, 0xdd, 0xa4, 0x83, 0x34 };
Console.WriteLine($"PLCType: {conn.PLCInformation.PLCType} | MLFB: {conn.PLCInformation.MLFB} | Firmware: {conn.PLCInformation.Firmware}");
Console.WriteLine($"连接耗时{stopwatch1.ElapsedMilliseconds}ms.");
if (res == 0)
{
Console.WriteLine("按任意键浏览变量");
Console.ReadKey();
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);
#if _TEST_PLCTAG
#region Werte aller Variablen einlesen
Console.WriteLine("Main - Lese Werte aller Variablen aus");
List<PlcTag> taglist = new List<PlcTag>();
foreach (var v in vars_)
{
ItemAddress itemAddress = new ItemAddress(v.AccessSequence);
//S7p.DecodeUInt32Vlq(new MemoryStream(var1_crc_bytes), out itemAddress.SymbolCrc);
taglist.Add(PlcTags.TagFactory(v.Name, itemAddress, v.Softdatatype));
}
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();
res = conn.SubscriptionCreate(taglist, 100);
if (res == 0)
{
Task.Run(() =>
{
conn.TestWaitForVariableChangeNotifications(50000000000);
});
}
while (res == 0)
{
System.Diagnostics.Stopwatch stopwatch2 = new System.Diagnostics.Stopwatch();
stopwatch2.Start();
res = PlcTags.ReadTags(conn, taglist);
stopwatch2.Stop();
long ms = stopwatch2.ElapsedMilliseconds;
if (res == 0)
{
string header = $"读取{vars_.Count}个变量耗时{ms}毫秒";
Console.WriteLine(header);
}
//System.Threading.Thread.Sleep(50);
}
#endif
#if _TEST_BASIC_VAR
#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
#endif
/*
#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();
}
}
public static class S7SymbolCrc32
{
private const uint Polynomial = 0xFA567993; // 多项式(x³² + x³¹ + x³⁰ + x²⁹ + x²⁸ + x²⁶ + x²³ + x²¹ + x¹⁹ + x¹⁸ + x¹⁵ + x¹⁴ + x¹³ + x¹² + x⁹ + x⁸ + x⁴ + x + 1)
private const uint InitialValue = 0xFFFFFFFF;
private static readonly uint[] Table;
static S7SymbolCrc32()
{
// 预计算CRC表
Table = new uint[256];
for (uint i = 0; i < 256; i++)
{
uint crc = i << 24;
for (int j = 0; j < 8; j++)
{
if ((crc & 0x80000000) != 0)
{
crc = (crc << 1) ^ Polynomial;
}
else
{
crc <<= 1;
}
}
Table[i] = crc;
}
}
/// <summary>
/// 计算S7CommPlus符号名的CRC32校验和
/// </summary>
/// <param name="symbolName">符号名(如"DB1.TempBottom"</param>
/// <param name="dataType">数据类型字节</param>
/// <returns>CRC32校验和</returns>
public static uint CalculateSymbolCrc(string symbolName)
{
// 1. 替换分隔符 '.' → 0x09
string processedName = symbolName.Replace('.', '\t');
// 2. 转换为字节数组
byte[] nameBytes = Encoding.ASCII.GetBytes(processedName);
// 3. 添加数据类型字节
byte[] data = new byte[nameBytes.Length];
Array.Copy(nameBytes, 0, data, 0, nameBytes.Length);
// 4. 计算CRC32
uint crc = InitialValue;
foreach (byte b in data)
{
crc = (crc << 8) ^ Table[((crc >> 24) & 0xFF) ^ b];
}
// 5. 根据作者提示,可能需要再次计算(需要验证)
//crc = CalculateSecondPass(crc);
return crc;
}
// 如果需要二次计算的方法
public static uint CalculateSecondPass(uint firstResult)
{
byte[] crcBytes = BitConverter.GetBytes(firstResult);
if (BitConverter.IsLittleEndian)
{
Array.Reverse(crcBytes); // 确保大端序
}
uint crc = InitialValue;
foreach (byte b in crcBytes)
{
crc = (crc << 8) ^ Table[((crc >> 24) & 0xFF) ^ b];
}
return crc;
}
}
}