From fb35ddb3896ded69f396ac8846af31ec2ed67cff Mon Sep 17 00:00:00 2001 From: Lorenz Stechauner Date: Fri, 10 Jul 2026 11:05:02 +0200 Subject: [PATCH] Fixes after testing live --- PamhagenSysCtrl/Helpers/Extensions.cs | 64 ---------------------- PamhagenSysCtrl/Helpers/PamhagenPlant.cs | 15 ++--- PamhagenSysCtrl/Helpers/PamhagenPlc.cs | 2 - PamhagenSysCtrl/Helpers/T1.cs | 47 ++++++++-------- PamhagenSysCtrl/Windows/MainWindow.xaml.cs | 4 +- 5 files changed, 32 insertions(+), 100 deletions(-) delete mode 100644 PamhagenSysCtrl/Helpers/Extensions.cs diff --git a/PamhagenSysCtrl/Helpers/Extensions.cs b/PamhagenSysCtrl/Helpers/Extensions.cs deleted file mode 100644 index 3b52fc3..0000000 --- a/PamhagenSysCtrl/Helpers/Extensions.cs +++ /dev/null @@ -1,64 +0,0 @@ -using System.IO; -using System.Runtime.InteropServices; - -namespace PamhagenSysCtrl.Helpers { - public static partial class Extensions { - - [LibraryImport("msvcrt.dll")] - [UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] - private static unsafe partial int memcmp(void* b1, void* b2, long count); - - public static unsafe int CompareBuffers(char[] buffer1, int offset1, char[] buffer2, int offset2, int count) { - fixed (char* b1 = buffer1, b2 = buffer2) { - return memcmp(b1 + offset1, b2 + offset2, count); - } - } - - - public static string? ReadUntil(this StreamReader reader, string delimiter) { - return ReadUntil(reader, delimiter.ToCharArray()); - } - - public static string? ReadUntil(this StreamReader reader, char delimiter) { - return ReadUntil(reader, [delimiter]); - } - - public static string? ReadUntil(this StreamReader reader, char[] delimiter) { - var buf = new char[512]; - int bufSize = 0, ret; - while (!reader.EndOfStream && bufSize < buf.Length - 1) { - if ((ret = reader.Read()) == -1) - return null; - buf[bufSize++] = (char)ret; - - if (bufSize >= delimiter.Length && CompareBuffers(buf, bufSize - delimiter.Length, delimiter, 0, delimiter.Length) == 0) - return new string(buf, 0, bufSize); - } - return null; - } - - public static Task ReadUntilAsync(this StreamReader reader, string delimiter) { - return ReadUntilAsync(reader, delimiter.ToCharArray()); - } - - public static Task ReadUntilAsync(this StreamReader reader, char delimiter) { - return ReadUntilAsync(reader, [delimiter]); - } - - public static async Task ReadUntilAsync(this StreamReader reader, char[] delimiter) { - var buf = new char[512]; - int bufSize = 0; - var tmpBuf = new char[1]; - while (!reader.EndOfStream && bufSize < buf.Length - 1) { - if ((await reader.ReadAsync(tmpBuf, 0, 1)) != 1) - return null; - buf[bufSize++] = tmpBuf[0]; - - if (bufSize >= delimiter.Length && CompareBuffers(buf, bufSize - delimiter.Length, delimiter, 0, delimiter.Length) == 0) - return new string(buf, 0, bufSize); - } - return null; - } - - } -} diff --git a/PamhagenSysCtrl/Helpers/PamhagenPlant.cs b/PamhagenSysCtrl/Helpers/PamhagenPlant.cs index 805d5e7..f07964e 100644 --- a/PamhagenSysCtrl/Helpers/PamhagenPlant.cs +++ b/PamhagenSysCtrl/Helpers/PamhagenPlant.cs @@ -15,13 +15,10 @@ namespace PamhagenSysCtrl.Helpers { protected PamhagenPlc.ActuatorStates Actuators; protected PamhagenPlc.SensorStates Sensors; - protected bool GetDS(int n) => Sensors.GetDS(n >= 1 && n <= 60 ? n : throw new ArgumentException("Invalid value for n: 1 <= #DS <= 60")); - protected bool GetV(int n) => Actuators.GetV(n >= 1 && n <= 60 ? n : throw new ArgumentException("Invalid value for n: 1 <= #V <= 60")); - - public bool IsValveClosed(int n) => GetDS(n); public bool IsValveOpen(int n) => !IsValveClosed(n); - public bool WantValveClosed(int n) => GetV(n); - public bool WantValveOpen(int n) => !WantValveClosed(n); + public bool IsValveClosed(int n) => Sensors.GetDS(n); + public bool WantValveClosed(int n) => !WantValveOpen(n); + public bool WantValveOpen(int n) => Actuators.GetV(n); public bool IsA1Selected => Sensors.TroughSelector == 1; public bool IsA2Selected => Sensors.TroughSelector == 2; @@ -149,10 +146,10 @@ namespace PamhagenSysCtrl.Helpers { } - public void OpenV(int n) => SetV(n, false); - public void CloseV(int n) => SetV(n, true); + public void OpenV(int n) => SetV(n, true); + public void CloseV(int n) => SetV(n, false); - public void SetV(int n, bool val) { + protected void SetV(int n, bool val) { if (n < 1 || n > 60) throw new ArgumentException("Invalid value for n: 1 <= #V <= 60"); Actuators.SetV(n, val); diff --git a/PamhagenSysCtrl/Helpers/PamhagenPlc.cs b/PamhagenSysCtrl/Helpers/PamhagenPlc.cs index 299bed4..e039ab0 100644 --- a/PamhagenSysCtrl/Helpers/PamhagenPlc.cs +++ b/PamhagenSysCtrl/Helpers/PamhagenPlc.cs @@ -27,8 +27,6 @@ namespace PamhagenSysCtrl.Helpers { Valves &= ~(1L << (n - 1)); } } - public void CloseV(int n) => SetV(n, true); - public void OpenV(int n) => SetV(n, false); } protected readonly T1 Plc; diff --git a/PamhagenSysCtrl/Helpers/T1.cs b/PamhagenSysCtrl/Helpers/T1.cs index cfaa230..473d06c 100644 --- a/PamhagenSysCtrl/Helpers/T1.cs +++ b/PamhagenSysCtrl/Helpers/T1.cs @@ -9,58 +9,59 @@ namespace PamhagenSysCtrl.Helpers { public readonly record struct Status(Mode Mode, int Flags); protected SerialPort Serial; - protected Stream Stream; - protected StreamReader Reader; public T1(string portName, Parity parity = Parity.Odd) { - Serial = new SerialPort(portName, 9600, parity, 8, StopBits.One); + Serial = new SerialPort(portName, 9600, parity, 8, StopBits.One) { + Handshake = Handshake.None, + NewLine = "\r", + ReadTimeout = 1000, + WriteTimeout = 1000, + DtrEnable = true, + RtsEnable = true, + Encoding = Encoding.ASCII, + }; Serial.Open(); - Stream = Serial.BaseStream ?? Stream.Null; - Stream.ReadTimeout = 250; - Stream.WriteTimeout = 250; - Reader = new(Stream, Encoding.ASCII, false, 256); + Serial.DiscardInBuffer(); + Serial.DiscardOutBuffer(); } public void Dispose() { - Reader.Dispose(); - Stream.Dispose(); Serial.Dispose(); GC.SuppressFinalize(this); } protected async Task SendCommand(string cmd, string? data = null, bool checksum = true) { // max 255 bytes - byte[] d = new byte[255]; - int n = Encoding.ASCII.GetBytes($"(A{1:00}{cmd}", d); + var line = new StringBuilder("(A", 256); + line.AppendFormat("{0:00}{1}", 1, cmd); if (data != null) { if (data.Length > 244) throw new ArgumentException("T1 playload too long"); - n += Encoding.ASCII.GetBytes(data, 0, data.Length, d, n); + line.Append(data); } if (checksum) { - d[n++] = (byte)'&'; - byte chk = d.Take(n).Aggregate((s, c) => (byte)((s + c) & 0xFF)); - n += Encoding.ASCII.GetBytes($"{chk:X2}", 0, 2, d, n); + line.Append('&'); + var chk = Enumerable.Range(0, line.Length).Aggregate(0, (c, i) => c + line[i]) & 0xFF; + line.AppendFormat("{0:X2}", chk); } - d[n++] = (byte)')'; - d[n++] = (byte)'\r'; - await Stream.WriteAsync(d.AsMemory(0, n)); + line.Append(')'); + Serial.WriteLine(line.ToString()); } protected async Task<(string, string)> ReceiveResponse(string? expectedCmd = null) { - var line = await Reader.ReadUntilAsync('\r'); + var line = Serial.ReadLine(); if (line == null) { throw new IOException("Verbindung zu SPS (T1) verloren"); - } else if (line.Length < 9 || !line.StartsWith("(A") || !line.EndsWith(")\r") || line[^5] != '&') { + } else if (line.Length < 8 || !line.StartsWith("(A") || !line.EndsWith(')') || line[^4] != '&') { throw new FormatException("Invalid response from PLC (T1)"); } - var chk1 = (byte)Convert.ToInt32(line[^4..^2], 16); - var chk2 = Encoding.ASCII.GetBytes(line).SkipLast(4).Aggregate((s, c) => (byte)((s + c) & 0xFF)); + var chk1 = Convert.ToInt32(line[^3..^1], 16); + var chk2 = Enumerable.Range(0, line.Length - 3).Aggregate(0, (c, i) => c + line[i]) & 0xFF; if (chk1 != chk2) { throw new IOException($"Ungültige Prüfsumme von SPS (T1)"); } - var (cmd, data) = (line[4..6], line[6..^5]); + var (cmd, data) = (line[4..6], line[6..^4]); if (cmd == "ST" && data[3] == '6') { // TODO check for other error bits? await SendCommand("ER"); diff --git a/PamhagenSysCtrl/Windows/MainWindow.xaml.cs b/PamhagenSysCtrl/Windows/MainWindow.xaml.cs index bcad344..769950c 100644 --- a/PamhagenSysCtrl/Windows/MainWindow.xaml.cs +++ b/PamhagenSysCtrl/Windows/MainWindow.xaml.cs @@ -46,8 +46,8 @@ namespace PamhagenSysCtrl { } catch (Exception exc) { App.Plant?.Dispose(); App.Plant = null; - var str = "Beim Aufbauen einer Verbindung zur SPS ist ein Fehler aufgetreten:\n\n" + exc.Message; - if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message; + var str = $"Beim Aufbauen einer Verbindung zur SPS ist ein Fehler aufgetreten:\n\n{exc.GetType().Name}: {exc.Message}"; + if (exc.InnerException != null) str += $"\n\n{exc.InnerException.GetType().Name}: {exc.InnerException.Message}"; MessageBox.Show(str, "SPS-Fehler", MessageBoxButton.OK, MessageBoxImage.Error); } }