Files
pamhagen-sysctrl/PamhagenSysCtrl/Helpers/PamhagenPlc.cs
T

232 lines
9.8 KiB
C#

using System.IO.Ports;
namespace PamhagenSysCtrl.Helpers {
public class PamhagenPlc : IDisposable {
public record struct SensorStates(
long PressureSensors,
(FillState A1, FillState A2, FillState Press1, FillState Press2) FillingLevels,
int TroughSelector,
double GradationOe,
FillState[] FillingLevelTanks,
MotorState PresseQuerSchnecke
) {
public readonly bool GetDS(int n) => (PressureSensors & (1L << (n - 1))) != 0;
}
public record struct ActuatorStates(
long Valves,
MotorState MP1, MotorState MP2, MotorState P12, MotorState P3, MotorState P4, MotorState P5, MotorState P6,
bool TroughAuger, bool Rebler, bool StirrerA1, bool StirrerA2, bool Belt, bool Auger1, bool Auger2, bool GradationPump
) {
public readonly bool GetV(int n) => (Valves & (1L << (n - 1))) != 0;
public void SetV(int n, bool val) {
if (val) {
Valves |= 1L << (n - 1);
} else {
Valves &= ~(1L << (n - 1));
}
}
}
protected readonly T1 Plc;
public PamhagenPlc(string portName, Parity parity = Parity.Odd) {
Plc = new T1(portName, parity);
}
public void Dispose() {
Plc.Dispose();
GC.SuppressFinalize(this);
}
protected static FillState Int3ToFillState(int n) {
return n switch {
7 => FillState.Full,
6 => FillState.Half,
4 => FillState.Filled,
0 => FillState.Empty,
_ => FillState.Invalid,
};
}
protected static FillState Int2ToFillState(int n) {
return n switch {
2 => FillState.Full,
0 => FillState.Filled,
1 => FillState.Empty,
_ => FillState.Invalid,
};
}
protected static FillState Int1ToFillState(int n) {
return n switch {
1 => FillState.Full,
0 => FillState.Unknown,
_ => FillState.Invalid,
};
}
protected static MotorState Int2ToPumpState(int n, bool inverse) {
return n switch {
0 => MotorState.Halt,
1 => inverse ? MotorState.Backward : MotorState.Forward,
2 => inverse ? MotorState.Forward : MotorState.Backward,
_ => MotorState.Invalid,
};
}
protected static MotorState Int1ToPumpState(int n) {
return n switch {
1 => MotorState.Forward,
_ => MotorState.Halt,
};
}
public async Task EnsureRunning() {
var s = await Plc.StatusRead();
if (s.Mode == T1.Mode.RUN || s.Mode == T1.Mode.RUN_F)
return;
var error = await Plc.ErrorStatusRead();
throw new T1Exception($"Interner Fehler: {error} ({(int)error:0000})");
}
protected async Task<(ushort RW010, ushort RW011, ushort RW012, ushort RW013, ushort RW014, ushort RW015, ushort RW016)> ReadInputRegisters() {
var d = await Plc.DataRead("RW010", 7);
// RW010, RW011, RW012, RW013 Drucksensoren
// RW014 Füllstände A1, A2, Presse1, Presse2, Wannenselekt
// RW015 Messwert von Marselli Gerät
// RW016 Füllstände der Tanks
return (d[0], d[1], d[2], d[3], d[4], d[5], d[6]);
}
public async Task<SensorStates> ReadInputs() {
await EnsureRunning();
var (r1, r2, r3, r4, f1, v, f2) = await ReadInputRegisters();
long pressure = (long)r1 | ((long)r2 << 16) | ((long)r3 << 32) | ((long)r4 << 48);
pressure = (pressure & 0x01FFFFFFFFFFFFFF) | ((pressure & 0x0600000000000000) << 1);
var a1 = Int3ToFillState((f1 ) & 0x7); // 111 011 001 000
var a2 = Int3ToFillState((f1 >> 3) & 0x7); // 111 011 001 000
var p1 = Int1ToFillState((f1 >> 6) & 0x1); // 1 0
var p2 = Int1ToFillState((f1 >> 7) & 0x1); // 1 0
var wp = ((f1 >> 8) & 0x3); // 10 01
// Masseligerät : 4mA => 50 Oe
// 20mA => 150 Oe
// ---> 0mA => 25 Oe
// Oe mA T1Wert
// 25 0 0
// 50 4 800
// 75 8 1600
// 100 12 2400
// 125 16 3200
// 150 20 4000
// -> factor: 0,03125 + (offset) 25 Oe
double oe = v * 0.03125 + 25;
var t1 = Int2ToFillState((f2 ) & 0x3); // 10 01 00
var t2 = Int2ToFillState((f2 >> 2) & 0x3); // 10 01 00
var t3 = Int2ToFillState((f2 >> 4) & 0x3); // 10 01 00
var t4 = Int2ToFillState((f2 >> 6) & 0x3); // 10 01 00
var t5 = Int2ToFillState((f2 >> 8) & 0x3); // 10 01 00
var t6 = Int1ToFillState((f2 >> 10) & 0x1); // 1 0
var t7 = Int1ToFillState((f2 >> 11) & 0x1); // 1 0
var t8 = Int1ToFillState((f2 >> 12) & 0x1); // 1 0
var t9 = Int1ToFillState((f2 >> 13) & 0x1); // 1 0
var q1 = Int1ToPumpState((f2 >> 15) & 0x1); // 1 0
return new SensorStates(pressure, (a1, a2, p1, p2), wp == 3 ? -1 : wp == 1 ? 2 : wp == 2 ? 1 : 0, oe, [t1, t2, t3, t4, t5, t6, t7, t8, t9], q1);
}
protected async Task<(ushort RW000, ushort RW001, ushort RW002, ushort RW003, ushort RW004, ushort RW005, ushort RW006)> ReadOutputRegisters() {
var d = await Plc.DataRead("RW000", 7);
// RW000, RW001, RW002, RW003 Ventile
// RW004 Pumpensteuerung MP1, MP2, P1/2, P3, P4, P5, P6
// RW005 Steuerung Wannenschnecke, Rebler, Förderung, Rührer
// RW006 MessungsSteuerung
return (d[0], d[1], d[2], d[3], d[4], d[5], d[6]);
}
protected async Task WriteOutputRegisters(ushort rw000, ushort rw001, ushort rw002, ushort rw003, ushort rw004, ushort rw005, ushort rw006) {
// RW000, RW001, RW002, RW003 Ventile
// RW004 Pumpensteuerung MP1, MP2, P1/2, P3, P4, P5, P6
// RW005 Steuerung Wannenschnecke, Rebler, Förderung, Rührer
// RW006 MessungsSteuerung
await Plc.DataWrite("RW000", rw000, rw001, rw002, rw003, rw004, rw005, rw006);
}
public async Task<ActuatorStates> ReadOutputs() {
await EnsureRunning();
var (v1, v2, v3, v4, p1, s1, s2) = await ReadOutputRegisters();
long valves = (long)v1 | ((long)v2 << 16) | ((long)v3 << 32) | ((long)v4 << 48);
var mp1 = Int2ToPumpState((p1 ) & 0x3, true);
var mp2 = Int2ToPumpState((p1 >> 2) & 0x3, false);
var p12 = Int1ToPumpState((p1 >> 4) & 0x1);
var p3 = Int1ToPumpState((p1 >> 5) & 0x1);
var p4 = Int1ToPumpState((p1 >> 6) & 0x1);
var p5 = Int1ToPumpState((p1 >> 7) & 0x1);
var p6 = Int1ToPumpState((p1 >> 8) & 0x1);
var m1 = (s1 & 0x01) != 0;
var m2 = (s1 & 0x02) != 0;
var m3 = (s1 & 0x08) != 0;
var m4 = (s1 & 0x10) != 0;
var m5 = (s1 & 0x20) != 0;
var m6 = (s1 & 0x40) != 0;
var m7 = (s1 & 0x80) != 0;
var m8 = (s2 & 0x04) != 0;
var state = new ActuatorStates(valves, mp1, mp2, p12, p3, p4, p5, p6, m1, m2, m3, m4, m5, m6, m7, m8);
state.SetV(58, (s1 & 0x04) != 0);
state.SetV(59, (s2 & 0x01) != 0);
state.SetV(60, (s2 & 0x02) != 0);
return state;
}
public async Task WriteOutputs(ActuatorStates state) {
await EnsureRunning();
var v1 = (ushort)((state.Valves ) & 0xFFFF);
var v2 = (ushort)((state.Valves >> 16) & 0xFFFF);
var v3 = (ushort)((state.Valves >> 32) & 0xFFFF);
var v4 = (ushort)((state.Valves >> 48) & 0x01FF);
int pumps =
(state.MP1 == MotorState.Backward ? 0x001 : 0x000) |
(state.MP1 == MotorState.Forward ? 0x002 : 0x000) |
(state.MP2 == MotorState.Forward ? 0x004 : 0x000) |
(state.MP2 == MotorState.Backward ? 0x008 : 0x000) |
(state.P12 == MotorState.Forward ? 0x010 : 0x000) |
(state.P3 == MotorState.Forward ? 0x020 : 0x000) |
(state.P4 == MotorState.Forward ? 0x040 : 0x000) |
(state.P5 == MotorState.Forward ? 0x080 : 0x000) |
(state.P6 == MotorState.Forward ? 0x100 : 0x000);
int devices =
(state.TroughAuger ? 0x01 : 0x00) |
(state.Rebler ? 0x02 : 0x00) |
(state.GetV(58) ? 0x04 : 0x00) |
(state.StirrerA1 ? 0x08 : 0x00) |
(state.StirrerA2 ? 0x10 : 0x00) |
(state.Belt ? 0x20 : 0x00) |
(state.Auger1 ? 0x40 : 0x00) |
(state.Auger2 ? 0x80 : 0x00);
int measuring =
(state.GetV(59) ? 0x01 : 0x00) |
(state.GetV(60) ? 0x02 : 0x00) |
(state.GradationPump ? 0x04 : 0x00);
await WriteOutputRegisters(v1, v2, v3, v4, (ushort)pumps, (ushort)devices, (ushort)measuring);
}
public async Task TestConnection() {
await Plc.Test();
}
}
}