diff --git a/TBF/Properties/AssemblyInfo.cs b/TBF/Properties/AssemblyInfo.cs index ef5605a28..e05f7a9c7 100644 --- a/TBF/Properties/AssemblyInfo.cs +++ b/TBF/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("2.28.1921.0")] -[assembly: AssemblyFileVersion("2.28.1921.0")] +[assembly: AssemblyVersion("2.28.1924.0")] +[assembly: AssemblyFileVersion("2.28.1924.0")] diff --git a/TBF/Rig/Modbus/TempControl/Novus/SetTemperatureSetpointOp.cs b/TBF/Rig/Modbus/TempControl/Novus/SetTemperatureSetpointOp.cs index 5d5bb4fc1..ef30098a4 100644 --- a/TBF/Rig/Modbus/TempControl/Novus/SetTemperatureSetpointOp.cs +++ b/TBF/Rig/Modbus/TempControl/Novus/SetTemperatureSetpointOp.cs @@ -7,6 +7,16 @@ using TBF.Boxes; namespace TBF.Rig.Modbus.TempControl.Novus { + public enum SetpSource + { + TempArgument, + ProcParamA, + ProcParamB, + ProcParamC, + ProcParamD, + ProcParamE + } + public class SetTemperatureSetpointOp : IOperation { private static readonly ILog log = LogManager.GetLogger(typeof(SetTemperatureSetpointOp)); @@ -14,6 +24,7 @@ namespace TBF.Rig.Modbus.TempControl.Novus /// Set by the constructor readonly TControl tempControl; + readonly SetpSource spSrc; readonly double temperature; readonly Event eventDone; @@ -22,24 +33,33 @@ namespace TBF.Rig.Modbus.TempControl.Novus /// /// Temp. controller reference /// Event to be returned by Run() when completed OK - public SetTemperatureSetpointOp(TControl tempControl, double temperature, Event eventDone) + public SetTemperatureSetpointOp(TControl tempControl, SetpSource spSrc, double temperature, Event eventDone = Event.ConditionNotMet) { if (tempControl == null) throw new ArgumentNullException("tempControl"); this.tempControl = tempControl; + this.spSrc = spSrc; this.temperature = temperature; this.eventDone = eventDone; log.Debug(this.ToString()); } - public SetTemperatureSetpointOp(TControl tempControl, double temperature) - : this(tempControl, temperature, Event.ConditionNotMet) - { - } /// Start this operation public void Start() { - tempControl.SetTemperatureSetpoint(temperature); + double selectedTemp; + switch (spSrc) + { + default: + case SetpSource.TempArgument: selectedTemp = temperature; break; + case SetpSource.ProcParamA: selectedTemp = tempControl.ProcParamA; break; + case SetpSource.ProcParamB: selectedTemp = tempControl.ProcParamB; break; + case SetpSource.ProcParamC: selectedTemp = tempControl.ProcParamC; break; + case SetpSource.ProcParamD: selectedTemp = tempControl.ProcParamD; break; + case SetpSource.ProcParamE: selectedTemp = tempControl.ProcParamE; break; + } + + tempControl.SetTemperatureSetpoint(selectedTemp); } /// Run this operation diff --git a/TBF/Rig/Modbus/TempControl/Novus/TControl.cs b/TBF/Rig/Modbus/TempControl/Novus/TControl.cs index b31f461c1..af3d577be 100644 --- a/TBF/Rig/Modbus/TempControl/Novus/TControl.cs +++ b/TBF/Rig/Modbus/TempControl/Novus/TControl.cs @@ -19,14 +19,27 @@ namespace TBF.Rig.Modbus.TempControl.Novus const UInt16 SetpointAddress = 0; /// Temperature setpoint address const UInt16 ProcessValueAddress = 1; /// Actual temperature address - const UInt16 Status1Address = 6; /// Status word 1 address - const UInt16 FWVersionAddress = 7; /// Firmware version address - const UInt16 ControllerIdAddress = 8; /// Controller ID address - const UInt16 Status2Address = 9; /// Status word 2 address - const UInt16 Status3Address = 10; /// Status word 3 address + + const UInt16 N1200_FWVerAddr = 7; /// Firmware ver. address (N1200/N1200HC) + const UInt16 N1200_CtrlIdAddr = 8; /// Controller ID address (N1200/N1200HC) + const UInt16 N1200_Status1Addr = 6; /// Status word 1 address (N1200/N1200HC) + const UInt16 N1200_Status2Addr = 9; /// Status word 2 address (N1200/N1200HC) + const int N1200_WordsCount = 10; + + const UInt16 N1040_FWVerAddr = 8; /// Firmware ver. address (N1040) + const UInt16 N1040_CtrlIdAddr = 9; /// Controller ID address (N1040) + const UInt16 N1040_Status1Addr = 12; /// Status word 1 address (N1040) + const UInt16 N1040_Status2Addr = 13; /// Status word 2 address (N1040) + const int N1040_WordsCount = 14; readonly TControlCfg novusCfg; + public double ProcParamA { get { return novusCfg.ProcParams != null ? novusCfg.ProcParams.Temp_A : 0; } } + public double ProcParamB { get { return novusCfg.ProcParams != null ? novusCfg.ProcParams.Temp_B : 0; } } + public double ProcParamC { get { return novusCfg.ProcParams != null ? novusCfg.ProcParams.Temp_C : 0; } } + public double ProcParamD { get { return novusCfg.ProcParams != null ? novusCfg.ProcParams.Temp_D : 0; } } + public double ProcParamE { get { return novusCfg.ProcParams != null ? novusCfg.ProcParams.Temp_E : 0; } } + Common.Modbus modbus; int ticketNumber; /// 0 .. number of devices registered for regular polling - 1 @@ -86,14 +99,43 @@ namespace TBF.Rig.Modbus.TempControl.Novus Int16 status1; Int16 status2; - Int16 status3; Int16 fwVersion; Int16 controllerId; double temperatureSetpoint; double actualTemperature; - bool isHeating { get { return (status2 & (1 << 11)) != 0; } } /// Output 1: Heating - bool isCooling { get { return (status2 & (1 << 12)) != 0; } } /// Output 2: Cooling + bool isHeating + { + get + { + switch (novusCfg.Type) + { + case Type.N1200HC: + case Type.N1200: + return (status2 & (1 << 11)) != 0; /// Output 1 set + case Type.N1040: + default: + return false; /// isHeating info unknown + } + } + } + + bool isCooling + { + get + { + switch (novusCfg.Type) + { + case Type.N1200HC: + case Type.N1200: + return (status2 & (1 << 12)) != 0; /// Output 2 set + case Type.N1040: + default: + return false; /// isCooling info unknown + } + } + } + bool isFahrenheit { get { return (status2 & (1 << 9)) != 0; } } @@ -144,20 +186,22 @@ namespace TBF.Rig.Modbus.TempControl.Novus { log.InfoFormat("[{0}] received 5 bytes", Name); } - else if (telegram.Length == 27 && telegram[1] == (byte)Function.ReadHoldingRegisters && telegram[2] == 22) + else if ((novusCfg.Type == Type.N1200HC || novusCfg.Type == Type.N1200) && + telegram.Length == 2 * N1200_WordsCount + 5 && + telegram[1] == (byte)Function.ReadHoldingRegisters && + telegram[2] == 2 * N1200_WordsCount) { - Int16[] values = new Int16[11]; + Int16[] values = new Int16[N1200_WordsCount]; for (int i = 0; i < values.Length; i++) { values[i] = (Int16)(256 * telegram[2 * i + 3] + telegram[2 * i + 4] - ((telegram[2 * i + 3] & 0x80) != 0 ? 65536 : 0)); } - status1 = values[Status1Address]; - status2 = values[Status2Address]; - status3 = values[Status3Address]; - fwVersion = values[FWVersionAddress]; - controllerId = values[ControllerIdAddress]; + status1 = values[N1200_Status1Addr]; + status2 = values[N1200_Status2Addr]; + fwVersion = values[N1200_FWVerAddr]; + controllerId = values[N1200_CtrlIdAddr]; double setpointCorF = (double)values[SetpointAddress] * 0.1; temperatureSetpoint = isFahrenheit ? Units.ConvertFrom(Unit.F, setpointCorF) : setpointCorF; @@ -173,9 +217,44 @@ namespace TBF.Rig.Modbus.TempControl.Novus StateMachine.ControlBoard.SetReservoirTemp(2 * (novusCfg.ReservoirNr - 1) + 1, setpointStr, Convert.ToSingle(temperatureSetpoint)); log.InfoFormat("[{0}] setpoint = {1} temperature = {2}", Name, temperatureSetpoint, actualTemperature); - log.InfoFormat("[{0}] s1=0x{1} s2=0x{2} s3=0x{3} fw={4} id={5}", - Name, status1.ToString("X4"), status2.ToString("X4"), status3.ToString("X4"), - fwVersion, controllerId == 18 ? "N1200HC" : controllerId == 48 ? "N1200" : "unknonw"); + log.InfoFormat("[{0}] s1=0x{1} s2=0x{2} fw={3} id={4}", + Name, status1.ToString("X4"), status2.ToString("X4"), fwVersion, + controllerId == 18 ? "N1200HC" : controllerId == 48 ? "N1200" : "unknown"); + } + else if (novusCfg.Type == Type.N1040 && + telegram.Length == 2 * N1040_WordsCount + 5 && + telegram[1] == (byte)Function.ReadHoldingRegisters && + telegram[2] == 2 * N1040_WordsCount) + { + Int16[] values = new Int16[N1040_WordsCount]; + for (int i = 0; i < values.Length; i++) + { + values[i] = (Int16)(256 * telegram[2 * i + 3] + telegram[2 * i + 4] + - ((telegram[2 * i + 3] & 0x80) != 0 ? 65536 : 0)); + } + + status1 = values[N1040_Status1Addr]; + status2 = values[N1040_Status2Addr]; + fwVersion = values[N1040_FWVerAddr]; + controllerId = values[N1040_CtrlIdAddr]; + + double setpointCorF = (double)values[SetpointAddress] * 0.1; + temperatureSetpoint = isFahrenheit ? Units.ConvertFrom(Unit.F, setpointCorF) : setpointCorF; + string setpointStr = string.Format(novusCfg.SetpFormat, Units.ConvertTo(novusCfg.SetpUnit, temperatureSetpoint)); + + double temperatureCorF = (double)values[ProcessValueAddress] * 0.1; + actualTemperature = isFahrenheit ? Units.ConvertFrom(Unit.F, temperatureCorF) : temperatureCorF; + string temperatureStr = string.Format(novusCfg.MsrdFormat, Units.ConvertTo(novusCfg.MsrdUnit, actualTemperature)); + + novusDataValid = true; + + StateMachine.ControlBoard.SetReservoirTemp(2 * (novusCfg.ReservoirNr - 1), temperatureStr, Convert.ToSingle(actualTemperature)); + StateMachine.ControlBoard.SetReservoirTemp(2 * (novusCfg.ReservoirNr - 1) + 1, setpointStr, Convert.ToSingle(temperatureSetpoint)); + + log.InfoFormat("[{0}] setpoint = {1} temperature = {2}", Name, temperatureSetpoint, actualTemperature); + log.InfoFormat("[{0}] s1=0x{1} s2=0x{2} fw={3} id={4}", + Name, status1.ToString("X4"), status2.ToString("X4"), fwVersion, + controllerId == 66 ? "N1040" : "unknown"); } else { @@ -200,8 +279,16 @@ namespace TBF.Rig.Modbus.TempControl.Novus if (DebugLevel != DebugMode.Simulate && DebugLevel != DebugMode.FailureDuringOperation && (StateMachine.Time % 3 == novusCfg.ReservoirNr - 1)) { - /// Read setpoint, PV (actual temperature), status1, status2, status3, FW version etc. - SendValueToNovus(Function.ReadHoldingRegisters, 0, 11); + if (novusCfg.Type == Type.N1200HC || novusCfg.Type == Type.N1200) + { + /// Read SP (setpoint), PV (actual temperature), status1, status2, status3, FW version etc. + SendValueToNovus(Function.ReadHoldingRegisters, 0, N1200_WordsCount); + } + else if (novusCfg.Type == Type.N1040) + { + /// Read SP (setpoint) and PV (actual temperature) + SendValueToNovus(Function.ReadHoldingRegisters, 0, N1040_WordsCount); + } } } @@ -263,14 +350,14 @@ namespace TBF.Rig.Modbus.TempControl.Novus return actualTemperature; } - /// - /// Events: SetOpututsDone, Error - /// - /// SetOutputsOp instance reference casted to IOperaton - public IOperation SetTemperatureSetpointOp(double temperature) - { - return new SetTemperatureSetpointOp(this, temperature); - } + /// + /// Events: SetOpututsDone, Error + /// + /// SetOutputsOp instance reference casted to IOperaton + public IOperation SetTemperatureSetpointOp(double temperature) + { + return new SetTemperatureSetpointOp(this, SetpSource.TempArgument, temperature); + } public IOperation ReadTempOp(ref DoubleBox temp) { @@ -329,11 +416,11 @@ namespace TBF.Rig.Modbus.TempControl.Novus void CreateConditions(bool createOps) { ClearConditions(); - AddCondition("Set temperature setpoint A", createOps, SetTemperatureSetpointOp(novusCfg.ProcParams.Temp_A)); - AddCondition("Set temperature setpoint B", createOps, SetTemperatureSetpointOp(novusCfg.ProcParams.Temp_B)); - AddCondition("Set temperature setpoint C", createOps, SetTemperatureSetpointOp(novusCfg.ProcParams.Temp_C)); - AddCondition("Set temperature setpoint D", createOps, SetTemperatureSetpointOp(novusCfg.ProcParams.Temp_D)); - AddCondition("Set temperature setpoint E", createOps, SetTemperatureSetpointOp(novusCfg.ProcParams.Temp_E)); + AddCondition(string.Format("Set {0} setpoint A", Name), createOps, new SetTemperatureSetpointOp(this, SetpSource.ProcParamA, 0)); + AddCondition(string.Format("Set {0} setpoint B", Name), createOps, new SetTemperatureSetpointOp(this, SetpSource.ProcParamB, 0)); + AddCondition(string.Format("Set {0} setpoint C", Name), createOps, new SetTemperatureSetpointOp(this, SetpSource.ProcParamC, 0)); + AddCondition(string.Format("Set {0} setpoint D", Name), createOps, new SetTemperatureSetpointOp(this, SetpSource.ProcParamD, 0)); + AddCondition(string.Format("Set {0} setpoint E", Name), createOps, new SetTemperatureSetpointOp(this, SetpSource.ProcParamE, 0)); } } } diff --git a/TBF/Rig/Modbus/TempControl/Novus/TControlCfg.cs b/TBF/Rig/Modbus/TempControl/Novus/TControlCfg.cs index 8cc1745eb..1a732a503 100644 --- a/TBF/Rig/Modbus/TempControl/Novus/TControlCfg.cs +++ b/TBF/Rig/Modbus/TempControl/Novus/TControlCfg.cs @@ -12,6 +12,14 @@ using TBF.Rig.Generic; namespace TBF.Rig.Modbus.TempControl.Novus { + public enum Type + { + N1200HC, + N1200, + N1040, + Count + } + public class TControlCfg : ComponentCfgBase, IChildComponentCfg, IParamsProvider { public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(TControlCfg) })[0]; @@ -28,15 +36,16 @@ namespace TBF.Rig.Modbus.TempControl.Novus /// Serialized parameters /// public int ModbusAddress; /// 0: 1..254 - public string MsrdFormat { get; set; } /// 1 - public Unit MsrdUnit { get; set; } /// 2 + public Type Type; /// 1: N1200HC, N1200 or N1040 + public string MsrdFormat { get; set; } /// 2 + public Unit MsrdUnit { get; set; } /// 3 public double MsrdValLimLo { get; set; } public double MsrdValLimHi { get; set; } - public string SetpFormat { get; set; } /// 3 - public Unit SetpUnit { get; set; } /// 4 - public double SetpStep { get; set; } /// 5 - public bool RoundToSetpStep { get; set; } /// 6 - public int ReservoirNr { get; set; } /// 7 + public string SetpFormat { get; set; } /// 4 + public Unit SetpUnit { get; set; } /// 5 + public double SetpStep { get; set; } /// 6 + public bool RoundToSetpStep { get; set; } /// 7 + public int ReservoirNr { get; set; } /// 8 /// Procedure parameters @@ -66,6 +75,7 @@ namespace TBF.Rig.Modbus.TempControl.Novus Name = "Novus"; ParentName = "Modbus"; ModbusAddress = 49; + Type = Novus.Type.N1200HC; MsrdFormat = "{0:F1} °C"; MsrdUnit = Unit.C; MsrdValLimLo = 5; @@ -80,13 +90,14 @@ namespace TBF.Rig.Modbus.TempControl.Novus string[] paramNames = new string[] { "Modbus address", /// 0 - "Measured temperature format", /// 1 - "Unit of measured temperature", /// 2 - "Setpoint format", /// 3 - "Unit of temperature setpoint", /// 4 - "Setpoint step", /// 5 - "Round to setpoint step", /// 6 - "Reservoir nr. (1-based)", /// 7 + "Type", /// 1 + "Measured temperature format", /// 2 + "Unit of measured temperature", /// 3 + "Setpoint format", /// 4 + "Unit of temperature setpoint", /// 5 + "Setpoint step", /// 6 + "Round to setpoint step", /// 7 + "Reservoir nr. (1-based)", /// 8 }; public string ParamName(int i) { return paramNames[i]; } public int ParamsCount() { return paramNames.Length; } @@ -95,10 +106,14 @@ namespace TBF.Rig.Modbus.TempControl.Novus { switch (i) { - case 2: - case 4: + case 1: + var list = new List(); + for (Novus.Type t = 0; t < Novus.Type.Count; t++) list.Add(t.ToString()); + return list; + case 3: + case 5: return new string[] { "°C", "°F", "K" }; - case 6: + case 7: return new string[] { Strings.yes, Strings.no }; default: return null; @@ -111,15 +126,17 @@ namespace TBF.Rig.Modbus.TempControl.Novus switch (i) { case 0: return ModbusAddress.ToString(); - case 1: return MsrdFormat; - case 2: return (MsrdUnit == Unit.K) ? "K" : (MsrdUnit == Unit.F) ? "°F" : "°C"; - case 3: return SetpFormat; - case 4: return (SetpUnit == Unit.K) ? "K" : (SetpUnit == Unit.F) ? "°F" : "°C"; - case 5: return SetpStep.ToString(); - case 6: return RoundToSetpStep ? Strings.yes : Strings.no; - case 7: return ReservoirNr.ToString(); + case 1: return Type.ToString(); + case 2: return MsrdFormat; + case 3: return (MsrdUnit == Unit.K) ? "K" : (MsrdUnit == Unit.F) ? "°F" : "°C"; + case 4: return SetpFormat; + case 5: return (SetpUnit == Unit.K) ? "K" : (SetpUnit == Unit.F) ? "°F" : "°C"; + case 6: return SetpStep.ToString(); + case 7: return RoundToSetpStep ? Strings.yes : Strings.no; + case 8: return ReservoirNr.ToString(); default: - return string.Format("{0}({1}) address={2}", Name, string.IsNullOrEmpty(ParentName) ? "-" : ParentName, ModbusAddress); + return string.Format("{0}({1}) address = {2}, type = {3}, reservoir = {4}", + Name, string.IsNullOrEmpty(ParentName) ? "-" : ParentName, ModbusAddress, Type, ReservoirNr); } } @@ -128,19 +145,29 @@ namespace TBF.Rig.Modbus.TempControl.Novus switch (i) { case 0: ModbusAddress = int.Parse(str); return CfgUpdateFlags.RestartRqrd; - case 1: MsrdFormat = str; return CfgUpdateFlags.RestartRqrd; - case 2: MsrdUnit = (str == "°K" || str == "K") ? Unit.K + case 1: + for (Novus.Type t = 0; t < Novus.Type.Count; t++) + { + if (t.ToString() == str) + { + Type = t; + return CfgUpdateFlags.RestartRqrd; + } + } + return CfgUpdateFlags.None; + case 2: MsrdFormat = str; return CfgUpdateFlags.RestartRqrd; + case 3: MsrdUnit = (str == "°K" || str == "K") ? Unit.K : (str == "°F" || str == "F") ? Unit.F : Unit.C; return CfgUpdateFlags.RestartRqrd; - case 3: SetpFormat = str; return CfgUpdateFlags.RestartRqrd; - case 4: SetpUnit = (str == "°K" || str == "K") ? Unit.K + case 4: SetpFormat = str; return CfgUpdateFlags.RestartRqrd; + case 5: SetpUnit = (str == "°K" || str == "K") ? Unit.K : (str == "°F" || str == "F") ? Unit.F : Unit.C; return CfgUpdateFlags.RestartRqrd; - case 5: SetpStep = Utils.ParseUDouble(str); return CfgUpdateFlags.RestartRqrd; - case 6: RoundToSetpStep = (str == Strings.yes); return CfgUpdateFlags.RestartRqrd; - case 7: ReservoirNr = int.Parse(str); return CfgUpdateFlags.RestartRqrd; + case 6: SetpStep = Utils.ParseUDouble(str); return CfgUpdateFlags.RestartRqrd; + case 7: RoundToSetpStep = (str == Strings.yes); return CfgUpdateFlags.RestartRqrd; + case 8: ReservoirNr = int.Parse(str); return CfgUpdateFlags.RestartRqrd; default: return CfgUpdateFlags.None; } } @@ -154,22 +181,29 @@ namespace TBF.Rig.Modbus.TempControl.Novus switch (i) { case 0: + /// ModbusAddress if (int.TryParse(str, out idummy) && idummy >= 1 && idummy <= 254) return true; break; case 1: - case 3: - return true; + case 7: + /// Type, RoundToSetpStep (yes/no) + if (ParamValues(i).Contains(str)) return true; + break; case 2: case 4: - if (str == "°K" || str == "K" || str == "°F" || str == "F" || str == "°C" || str == "C") return true; - break; + /// MsrdFormat, SetpFormat + return true; + case 3: case 5: - if (Utils.TryParseUDouble(str, out ddummy)) return true; + /// MsrdUnit, SetpUnit + if (ParamValues(i).Contains(str) || str == "C" || str == "F" || str == "°K") return true; break; case 6: - if (str == Strings.yes || str == Strings.no) return true; + /// SetpStep + if (Utils.TryParseUDouble(str, out ddummy)) return true; break; - case 7: + case 8: + /// ReservoirNr if (int.TryParse(str, out idummy) && idummy >= 1 && idummy <= 10) return true; break; default: @@ -185,6 +219,7 @@ namespace TBF.Rig.Modbus.TempControl.Novus { prms.ParentName = ParentName; prms.ModbusAddress = ModbusAddress; + prms.Type = Type; prms.MsrdFormat = MsrdFormat; prms.MsrdUnit = MsrdUnit; prms.MsrdValLimLo = MsrdValLimLo;