Fix things after testing with virtual serial port

This commit is contained in:
2026-07-07 15:28:50 +02:00
parent 08d12d5307
commit fdb7976dda
4 changed files with 45 additions and 14 deletions
+12 -4
View File
@@ -1,9 +1,10 @@
using System.Windows;
using System.IO;
using System.Windows;
namespace PamhagenSysCtrl.Helpers {
public class PamhagenPlant : IDisposable {
protected PamhagenPlc Plc;
protected PamhagenPlc? Plc;
protected bool IsRunning = true;
protected Thread? BackgroundThread;
@@ -61,6 +62,7 @@ namespace PamhagenSysCtrl.Helpers {
}
public async Task StartThread() {
if (Plc == null) throw new Exception();
await Plc.TestConnection();
Actuators = await Plc.ReadOutputs();
BackgroundThread = new Thread(new ParameterizedThreadStart(BackgroundLoop));
@@ -71,12 +73,12 @@ namespace PamhagenSysCtrl.Helpers {
IsRunning = false;
BackgroundThread?.Interrupt();
BackgroundThread?.Join();
Plc.Dispose();
Plc?.Dispose();
GC.SuppressFinalize(this);
}
protected async void BackgroundLoop(object? parameters) {
while (IsRunning) {
while (IsRunning && Plc != null) {
try {
if (ActuatorsChanged) {
await Plc.WriteOutputs(Actuators);
@@ -90,9 +92,15 @@ namespace PamhagenSysCtrl.Helpers {
var str = "Bei der SPS ist ein Fehler aufgetreten:\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "SPS-Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
if (exc is TimeoutException or IOException) {
Plc?.Dispose();
Plc = null;
IsRunning = false;
}
}
}
try {
if (Plc != null)
await Plc.WriteOutputs(new());
} catch (Exception exc) {
var str = "Beim Schließen der Verbindung zur SPS ist ein Fehler aufgetreten:\n\n" + exc.Message;
+8 -8
View File
@@ -31,15 +31,15 @@ namespace PamhagenSysCtrl.Helpers {
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:02}{cmd}", d);
int n = Encoding.ASCII.GetBytes($"(A{1:00}{cmd}", d);
if (data != null) {
if (data.Length > 244) throw new ArgumentException("T1 playload too long");
n += Encoding.ASCII.GetBytes(data, 0, data.Length, d, n);
}
if (checksum) {
d[n++] = (byte)'&';
byte chk = d.Take(n).Aggregate((s, c) => s = (byte)((s + c) & 0xFF));
n += Encoding.ASCII.GetBytes($"{chk:02X}", 0, 2, d, n);
byte chk = d.Take(n).Aggregate((s, c) => (byte)((s + c) & 0xFF));
n += Encoding.ASCII.GetBytes($"{chk:X2}", 0, 2, d, n);
}
d[n++] = (byte)')';
d[n++] = (byte)'\r';
@@ -55,13 +55,13 @@ namespace PamhagenSysCtrl.Helpers {
}
var chk1 = (byte)Convert.ToInt32(line[^4..^2], 16);
var chk2 = Encoding.ASCII.GetBytes(line).SkipLast(5).Aggregate((s, c) => (byte)((s + c) & 0xFF));
var chk2 = Encoding.ASCII.GetBytes(line).SkipLast(4).Aggregate((s, c) => (byte)((s + c) & 0xFF));
if (chk1 != chk2) {
throw new IOException("Ungültige Prüfsumme von SPS (T1)");
throw new IOException($"Ungültige Prüfsumme von SPS (T1)");
}
var (cmd, data) = (line[3..5], line[5..^5]);
if (cmd == "ST" && data[4] == '6') {
var (cmd, data) = (line[4..6], line[6..^5]);
if (cmd == "ST" && data[3] == '6') {
// TODO check for other error bits?
await SendCommand("ER");
var (_, res) = await ReceiveResponse("ER");
@@ -124,7 +124,7 @@ namespace PamhagenSysCtrl.Helpers {
}
public async Task<Status> DataWrite(params (string Register, ushort[] Values)[] registers) {
await SendCommand("DW", string.Join(',', registers.Select(r => $"{r.Register},{r.Values.Length}," + string.Join(',', r.Values.Select(v => $"{v:04X}")))));
await SendCommand("DW", string.Join(',', registers.Select(r => $"{r.Register},{r.Values.Length}," + string.Join(',', r.Values.Select(v => $"{v:X4}")))));
var (_, res) = await ReceiveResponse("ST");
return new Status((Mode)(res[3] - '0'), ((res[0] - '0') << 4) | (res[1] - '0'));
}
+3
View File
@@ -15,5 +15,8 @@
<Grid x:Name="ButtonPanel" Margin="5,50,5,5">
</Grid>
<TextBlock x:Name="Status"
Margin="500,50,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"/>
</Grid>
</Window>
+21 -1
View File
@@ -24,7 +24,8 @@ namespace PamhagenSysCtrl {
borderStyle.Setters.Add(new Setter(Border.CornerRadiusProperty, new CornerRadius(5)));
b.Resources.Add(typeof(Border), borderStyle);
b.Click += (sender, evt) => {
if (App.Plant == null) return;
if (App.Plant == null || sender is not Button b) return;
var i = int.Parse($"{b.Content}"[1..]);
if (App.Plant.WantValveOpen(i)) {
App.Plant.CloseV(i);
} else {
@@ -62,6 +63,25 @@ namespace PamhagenSysCtrl {
b.Foreground = target ? Brushes.DarkRed : Brushes.Black;
b.Background = actual ? Brushes.MistyRose : Brushes.WhiteSmoke;
}
Status.Text = $"""
Gradation °Oe: {plant.GradationOe:N2}
Presse Querschnecke: {plant.PresseQuerSchnecke}
Füllstände:
Wanne A1: {plant.FillLevelA1} (ausgewählt: {plant.WantA1Selected}, Status: {plant.IsA1Selected})
Wanne A2: {plant.FillLevelA2} (ausgewählt: {plant.WantA2Selected}, Status: {plant.IsA2Selected})
Presse 1: {plant.FillLevelPress1}
Presse 2: {plant.FillLevelPress2}
Tank 1: {plant.FillLevelT1}
Tank 2: {plant.FillLevelT2}
Tank 3: {plant.FillLevelT3}
Tank 4: {plant.FillLevelT4}
Tank 5: {plant.FillLevelT5}
Tank 6: {plant.FillLevelT6}
Tank 7: {plant.FillLevelT7}
Tank 8: {plant.FillLevelT8}
Tank 9: {plant.FillLevelT9}
""";
}
}
}