Add ReconnectThread to reconnect to PLC and Keyboard on the fly
Test / Run tests (push) Successful in 26s
Test / Run tests (push) Successful in 26s
This commit is contained in:
@@ -32,40 +32,79 @@ namespace PamhagenSysCtrl.Helpers {
|
||||
protected Xbe24Keyboard? Keyboard;
|
||||
public PamhagenGraph Graph;
|
||||
|
||||
public bool IsPlcConnected => Plc != null;
|
||||
public bool IsKeyboardConnected => Keyboard != null;
|
||||
|
||||
protected bool IsRunning = true;
|
||||
protected Thread? BackgroundThread;
|
||||
protected Thread? ReconnectThread;
|
||||
protected Thread? PlcThread;
|
||||
|
||||
public event EventHandler<PlantEventArgs>? Update;
|
||||
|
||||
public string? PlcPortName => Plc?.PortName;
|
||||
public readonly string PlcComPort;
|
||||
public string? PlcConnectionError { get; private set; }
|
||||
public T1.Status? LastPlcStatus => Plc?.LastStatus;
|
||||
public T1Error? LastPlcError => Plc?.LastError;
|
||||
public long? LastRttNs { get; private set; }
|
||||
|
||||
public PamhagenState State => Plc?.State ?? default; // FIXME
|
||||
public PamhagenState State => Plc?.State ?? default;
|
||||
public bool ManualControlMode { get => Plc?.ManualControlMode ?? false; set => Plc?.ManualControlMode = value; }
|
||||
public bool OverridePathClearances { get => Plc?.OverridePathClearances ?? false; set => Plc?.OverridePathClearances = value; }
|
||||
public bool OverrideDryRunClearances { get => Plc?.OverrideDryRunClearances ?? false; set => Plc?.OverrideDryRunClearances = value; }
|
||||
|
||||
public PamhagenPlant(string portName) {
|
||||
try {
|
||||
Plc = new(portName);
|
||||
} catch (Exception exc) {
|
||||
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);
|
||||
}
|
||||
public PamhagenPlant(string comPort) {
|
||||
PlcComPort = comPort;
|
||||
Graph = new();
|
||||
|
||||
try {
|
||||
Keyboard = new();
|
||||
Keyboard.KeyDown += Keyboard_KeyDown;
|
||||
Keyboard.KeysChanged += Keyboard_KeysChanged;
|
||||
Keyboard.SetFashFrequency(250);
|
||||
Keyboard.SetBacklight(Color.FromRgb(4, 4, 4));
|
||||
} catch { }
|
||||
|
||||
Update += UpdateKeyboardBacklights;
|
||||
ReconnectThread = new Thread(new ParameterizedThreadStart(ReconnectLoop));
|
||||
ReconnectThread.Start();
|
||||
}
|
||||
|
||||
protected async void ReconnectLoop(object? parameters) {
|
||||
while (IsRunning) {
|
||||
if (Plc == null) {
|
||||
PlcThread?.Join();
|
||||
PlcThread = null;
|
||||
PamhagenPlc? tmp = null;
|
||||
try {
|
||||
tmp = new PamhagenPlc(PlcComPort);
|
||||
await tmp.Initialize();
|
||||
Plc = tmp;
|
||||
PlcConnectionError = null;
|
||||
PlcThread = new Thread(new ParameterizedThreadStart(PlcLoop));
|
||||
PlcThread.Start();
|
||||
} catch (Exception exc) {
|
||||
tmp?.Dispose();
|
||||
PlcConnectionError = $"{exc.GetType().Name}: {exc.Message}";
|
||||
if (exc is FileNotFoundException) {
|
||||
// COM port does not exist - ignore
|
||||
PlcConnectionError = "Port existiert nicht";
|
||||
} else if (exc is UnauthorizedAccessException) {
|
||||
// COM port exists, but is used by other process - ignore
|
||||
PlcConnectionError = "Port wird bereits verwendet";
|
||||
} else if (exc is TimeoutException) {
|
||||
// COM port exists, but PLC not responding - ignore
|
||||
PlcConnectionError = "Keine Rückmeldung von SPS";
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
}
|
||||
RaiseUpdateEvent(new());
|
||||
}
|
||||
|
||||
if (Keyboard == null) {
|
||||
try {
|
||||
Keyboard = new();
|
||||
Keyboard.KeyDown += Keyboard_KeyDown;
|
||||
Keyboard.KeysChanged += Keyboard_KeysChanged;
|
||||
Keyboard.SetFashFrequency(250);
|
||||
} catch { }
|
||||
}
|
||||
|
||||
await Task.Delay(100);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void RaiseUpdateEvent(PlantEventArgs evt) {
|
||||
@@ -132,22 +171,17 @@ namespace PamhagenSysCtrl.Helpers {
|
||||
k.SetBacklight((int)Xbe24Key.STOP_MP1, highlightOffMP1 ? Color.FromRgb(255, 32, 0) : !State.MP1_IsActive ? Color.FromRgb(255, 0, 0) : Color.FromRgb(32, 4, 4));
|
||||
}
|
||||
|
||||
public async Task StartThread() {
|
||||
if (Plc == null) throw new Exception();
|
||||
await Plc.Initialize();
|
||||
BackgroundThread = new Thread(new ParameterizedThreadStart(BackgroundLoop));
|
||||
BackgroundThread.Start();
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
IsRunning = false;
|
||||
BackgroundThread?.Join();
|
||||
ReconnectThread?.Join();
|
||||
PlcThread?.Join();
|
||||
Plc?.Dispose();
|
||||
Keyboard?.Dispose();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected async void BackgroundLoop(object? parameters) {
|
||||
protected async void PlcLoop(object? parameters) {
|
||||
App.MainDispatcher?.Invoke(InitializePaths);
|
||||
while (IsRunning && Plc != null) {
|
||||
var start = DateTime.Now;
|
||||
try {
|
||||
@@ -160,22 +194,24 @@ namespace PamhagenSysCtrl.Helpers {
|
||||
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) {
|
||||
PlcConnectionError = $"{exc.GetType().Name}: {exc.Message}";
|
||||
Plc?.Dispose();
|
||||
Plc = null;
|
||||
IsRunning = false;
|
||||
} else {
|
||||
await Task.Delay(1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
if (Plc != null)
|
||||
if (Plc != null) {
|
||||
try {
|
||||
await Plc.Shutdown();
|
||||
} catch (Exception exc) {
|
||||
var str = "Beim Schließen der Verbindung zur 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);
|
||||
} catch (Exception exc) {
|
||||
var str = "Beim Schließen der Verbindung zur 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);
|
||||
}
|
||||
}
|
||||
RaiseUpdateEvent(new());
|
||||
}
|
||||
|
||||
public void InitializePaths() {
|
||||
@@ -219,69 +255,67 @@ namespace PamhagenSysCtrl.Helpers {
|
||||
}
|
||||
|
||||
private void Keyboard_KeyDown(object? sender, int keyIndex) {
|
||||
if (Plc == null) return;
|
||||
var key = (Xbe24Key)keyIndex;
|
||||
App.MainDispatcher?.BeginInvoke(() => {
|
||||
if (Plc == null) return;
|
||||
try {
|
||||
if (key == Xbe24Key.START_REBLER) {
|
||||
Plc.StartRebler();
|
||||
} else if (key == Xbe24Key.STOP_REBLER) {
|
||||
if (State.Rebler_IsActive) {
|
||||
Plc.StopRebler();
|
||||
} else {
|
||||
Plc.StopAuger1();
|
||||
if (!State.PressCrossAuger_IsActive) {
|
||||
Plc.StopAuger2();
|
||||
Plc.StopAuger3();
|
||||
}
|
||||
try {
|
||||
if (key == Xbe24Key.START_REBLER) {
|
||||
Plc.StartRebler();
|
||||
} else if (key == Xbe24Key.STOP_REBLER) {
|
||||
if (State.Rebler_IsActive) {
|
||||
Plc.StopRebler();
|
||||
} else {
|
||||
Plc.StopAuger1();
|
||||
if (!State.PressCrossAuger_IsActive) {
|
||||
Plc.StopAuger2();
|
||||
Plc.StopAuger3();
|
||||
}
|
||||
} else if (key == Xbe24Key.START_TROUGH_AUGER) {
|
||||
Plc.StartTroughAuger();
|
||||
} else if (key == Xbe24Key.STOP_TROUGH_AUGER) {
|
||||
Plc.StopTroughAuger();
|
||||
} else if (key == Xbe24Key.SELECT_MW2) {
|
||||
Plc.SelectMW2();
|
||||
} else if (key == Xbe24Key.SELECT_MW1) {
|
||||
Plc.SelectMW1();
|
||||
} else if (key == Xbe24Key.START_MP2) {
|
||||
Plc.StartMP2Forward();
|
||||
} else if (key == Xbe24Key.STOP_MP2) {
|
||||
Plc.StopMP2();
|
||||
} else if (key == Xbe24Key.START_MP1) {
|
||||
Plc.StartMP1Forward();
|
||||
} else if (key == Xbe24Key.STOP_MP1) {
|
||||
Plc.StopMP1();
|
||||
} else if (key == Xbe24Key.FAST_SELECT_MW1_1) {
|
||||
FastSelect(Graph.MW1, Graph.Press1);
|
||||
} else if (key == Xbe24Key.FAST_SELECT_MW1_2) {
|
||||
FastSelect(Graph.MW1, Graph.Press2);
|
||||
} else if (key == Xbe24Key.FAST_SELECT_MW1_3) {
|
||||
FastSelect(Graph.MW1, Graph.Tank1);
|
||||
} else if (key == Xbe24Key.FAST_SELECT_MW1_4) {
|
||||
FastSelect(Graph.MW1, Graph.Tank2);
|
||||
} else if (key == Xbe24Key.FAST_SELECT_MW1_5) {
|
||||
FastSelect(Graph.MW1, Graph.Tank3);
|
||||
} else if (key == Xbe24Key.FAST_SELECT_MW1_6) {
|
||||
FastSelect(Graph.MW1, Graph.Tank4);
|
||||
} else if (key == Xbe24Key.FAST_SELECT_MW2_1) {
|
||||
FastSelect(Graph.MW2, Graph.Press1);
|
||||
} else if (key == Xbe24Key.FAST_SELECT_MW2_2) {
|
||||
FastSelect(Graph.MW2, Graph.Press2);
|
||||
} else if (key == Xbe24Key.FAST_SELECT_MW2_3) {
|
||||
FastSelect(Graph.MW2, Graph.Tank1);
|
||||
} else if (key == Xbe24Key.FAST_SELECT_MW2_4) {
|
||||
FastSelect(Graph.MW2, Graph.Tank2);
|
||||
} else if (key == Xbe24Key.FAST_SELECT_MW2_5) {
|
||||
FastSelect(Graph.MW2, Graph.Tank3);
|
||||
} else if (key == Xbe24Key.FAST_SELECT_MW2_6) {
|
||||
FastSelect(Graph.MW2, Graph.Tank4);
|
||||
}
|
||||
} catch (NoClearanceException) {
|
||||
// Keyboard?.SetBacklight(keyIndex, Color.FromRgb(255, 0, 0));
|
||||
} catch (Exception) {
|
||||
// ignore
|
||||
} else if (key == Xbe24Key.START_TROUGH_AUGER) {
|
||||
Plc.StartTroughAuger();
|
||||
} else if (key == Xbe24Key.STOP_TROUGH_AUGER) {
|
||||
Plc.StopTroughAuger();
|
||||
} else if (key == Xbe24Key.SELECT_MW2) {
|
||||
Plc.SelectMW2();
|
||||
} else if (key == Xbe24Key.SELECT_MW1) {
|
||||
Plc.SelectMW1();
|
||||
} else if (key == Xbe24Key.START_MP2) {
|
||||
Plc.StartMP2Forward();
|
||||
} else if (key == Xbe24Key.STOP_MP2) {
|
||||
Plc.StopMP2();
|
||||
} else if (key == Xbe24Key.START_MP1) {
|
||||
Plc.StartMP1Forward();
|
||||
} else if (key == Xbe24Key.STOP_MP1) {
|
||||
Plc.StopMP1();
|
||||
} else if (key == Xbe24Key.FAST_SELECT_MW1_1) {
|
||||
FastSelect(Graph.MW1, Graph.Press1);
|
||||
} else if (key == Xbe24Key.FAST_SELECT_MW1_2) {
|
||||
FastSelect(Graph.MW1, Graph.Press2);
|
||||
} else if (key == Xbe24Key.FAST_SELECT_MW1_3) {
|
||||
FastSelect(Graph.MW1, Graph.Tank1);
|
||||
} else if (key == Xbe24Key.FAST_SELECT_MW1_4) {
|
||||
FastSelect(Graph.MW1, Graph.Tank2);
|
||||
} else if (key == Xbe24Key.FAST_SELECT_MW1_5) {
|
||||
FastSelect(Graph.MW1, Graph.Tank3);
|
||||
} else if (key == Xbe24Key.FAST_SELECT_MW1_6) {
|
||||
FastSelect(Graph.MW1, Graph.Tank4);
|
||||
} else if (key == Xbe24Key.FAST_SELECT_MW2_1) {
|
||||
FastSelect(Graph.MW2, Graph.Press1);
|
||||
} else if (key == Xbe24Key.FAST_SELECT_MW2_2) {
|
||||
FastSelect(Graph.MW2, Graph.Press2);
|
||||
} else if (key == Xbe24Key.FAST_SELECT_MW2_3) {
|
||||
FastSelect(Graph.MW2, Graph.Tank1);
|
||||
} else if (key == Xbe24Key.FAST_SELECT_MW2_4) {
|
||||
FastSelect(Graph.MW2, Graph.Tank2);
|
||||
} else if (key == Xbe24Key.FAST_SELECT_MW2_5) {
|
||||
FastSelect(Graph.MW2, Graph.Tank3);
|
||||
} else if (key == Xbe24Key.FAST_SELECT_MW2_6) {
|
||||
FastSelect(Graph.MW2, Graph.Tank4);
|
||||
}
|
||||
});
|
||||
} catch (NoClearanceException) {
|
||||
// Keyboard?.SetBacklight(keyIndex, Color.FromRgb(255, 0, 0));
|
||||
} catch (Exception) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
private void Keyboard_KeysChanged(object? sender, Xbe24Keyboard.KeyState state) {
|
||||
|
||||
Reference in New Issue
Block a user