Add new type of pump - Grundfoss

This commit is contained in:
Marek Frniak 2026-03-04 11:48:55 +01:00
parent b43657a4db
commit f0fb70e38b
13 changed files with 1159 additions and 3 deletions

View File

@ -67,11 +67,13 @@ namespace TBF.Rig.BuiltIn.PumpTandem
if (pump1 is BuiltIn.Pump.Pump) { mask1 = (pump1 as BuiltIn.Pump.Pump).Mask; }
else if (pump1 is Danfoss.VLT2800.Pump) { mask1 = (pump1 as Danfoss.VLT2800.Pump).Mask; }
else if (pump1 is Modbus.PumpFM.DanfossVLT.Pump) { mask1 = (pump1 as Modbus.PumpFM.DanfossVLT.Pump).Mask; }
else if (pump1 is Modbus.PumpFM.Grundfoss.Pump) { mask1 = (pump1 as Modbus.PumpFM.Grundfoss.Pump).Mask; }
else { mask1 = 0; }
if (pump2 is BuiltIn.Pump.Pump) { mask2 = (pump2 as BuiltIn.Pump.Pump).Mask; }
else if (pump2 is Danfoss.VLT2800.Pump) { mask2 = (pump2 as Danfoss.VLT2800.Pump).Mask; }
else if (pump2 is Modbus.PumpFM.DanfossVLT.Pump) { mask2 = (pump2 as Modbus.PumpFM.DanfossVLT.Pump).Mask; }
else if (pump2 is Modbus.PumpFM.Grundfoss.Pump) { mask2 = (pump2 as Modbus.PumpFM.Grundfoss.Pump).Mask; }
else { mask2 = 0; }
log.FatalFormat("{0} initialized: {1}", Name, this);

View File

@ -44,6 +44,7 @@ namespace TBF.Rig.BuiltIn.PumpTandem
if (TbfComponents.CmpntFactoryFromClassName(cmpnt.ClassName) is BuiltIn.Pump.PumpFactory ||
TbfComponents.CmpntFactoryFromClassName(cmpnt.ClassName) is Danfoss.VLT2800.PumpFactory ||
TbfComponents.CmpntFactoryFromClassName(cmpnt.ClassName) is Modbus.PumpFM.DanfossVLT.Factory ||
TbfComponents.CmpntFactoryFromClassName(cmpnt.ClassName) is Modbus.PumpFM.Grundfoss.Factory ||
TbfComponents.CmpntFactoryFromClassName(cmpnt.ClassName) is BuiltIn.PumpTandem.PumpFactory)
{
pump1ComboBox.Items.Add(cmpnt.Name);

View File

@ -120,7 +120,8 @@ namespace TBF.Rig.BuiltIn
if (valve is PumpTandem.Pump) point.MasksOpen |= (valve as PumpTandem.Pump).Mask;
if (valve is Danfoss.VLT2800.Pump) point.MasksOpen |= (valve as Danfoss.VLT2800.Pump).Mask;
if (valve is Modbus.PumpFM.DanfossVLT.Pump) point.MasksOpen |= (valve as Modbus.PumpFM.DanfossVLT.Pump).Mask;
}
if (valve is Modbus.PumpFM.Grundfoss.Pump) point.MasksOpen |= (valve as Modbus.PumpFM.Grundfoss.Pump).Mask;
}
point.MasksClose = 0;
foreach (var valve in point.VClose)
{
@ -129,7 +130,8 @@ namespace TBF.Rig.BuiltIn
if (valve is PumpTandem.Pump) point.MasksClose |= (valve as PumpTandem.Pump).Mask;
if (valve is Danfoss.VLT2800.Pump) point.MasksClose |= (valve as Danfoss.VLT2800.Pump).Mask;
if (valve is Modbus.PumpFM.DanfossVLT.Pump) point.MasksClose |= (valve as Modbus.PumpFM.DanfossVLT.Pump).Mask;
}
if (valve is Modbus.PumpFM.Grundfoss.Pump) point.MasksClose |= (valve as Modbus.PumpFM.Grundfoss.Pump).Mask;
}
point.TimeSec += timeShift;
}
}

View File

@ -35,6 +35,7 @@ namespace TBF.Rig.BuiltIn
if (vlv is Pump.Pump && ((vlv as Pump.Pump).Mask & changed) == 0) continue;
if (vlv is Danfoss.VLT2800.Pump && ((vlv as Danfoss.VLT2800.Pump).Mask & changed) == 0) continue;
if (vlv is Modbus.PumpFM.DanfossVLT.Pump && ((vlv as Modbus.PumpFM.DanfossVLT.Pump).Mask & changed) == 0) continue;
if (vlv is Modbus.PumpFM.Grundfoss.Pump && ((vlv as Modbus.PumpFM.Grundfoss.Pump).Mask & changed) == 0) continue;
if ((vlv != null) && (vlv.Delay > max)) max = vlv.Delay;
}
@ -45,6 +46,7 @@ namespace TBF.Rig.BuiltIn
if (vlv is Pump.Pump && ((vlv as Pump.Pump).Mask & changed) == 0) continue;
if (vlv is Danfoss.VLT2800.Pump && ((vlv as Danfoss.VLT2800.Pump).Mask & changed) == 0) continue;
if (vlv is Modbus.PumpFM.DanfossVLT.Pump && ((vlv as Modbus.PumpFM.DanfossVLT.Pump).Mask & changed) == 0) continue;
if (vlv is Modbus.PumpFM.Grundfoss.Pump && ((vlv as Modbus.PumpFM.Grundfoss.Pump).Mask & changed) == 0) continue;
if ((vlv != null) && (vlv.Delay > max)) max = vlv.Delay;
}

View File

@ -0,0 +1,25 @@
///
/// Copyright (c) 2020 Sensus Slovensko a.s.
///
using System.Collections.Generic;
using TBF.Rig.Generic;
namespace TBF.Rig.Modbus.PumpFM.Grundfoss
{
public class Factory : IComponentFactory
{
public string ClassName { get { return this.GetType().Namespace.Substring(8); } }
public override string ToString() { return ClassName; }
public IComponent DummyComponent() { return new Pump(); }
public IComponent GetComponent(IComponentCfg cfg, IList<IComponent> components) { return new Pump(cfg, components); }
public IComponentCfg DefaultConfig() { return new PumpCfg(this); }
public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component)
{
return ComponentCfgBase.CreateFromDbEntity(PumpCfg.Serializer, component, this);
}
}
}

View File

@ -0,0 +1,497 @@
using Common;
using Dirichlet.Numerics;
using log4net;
using SchematicDrawing;
using SharedComponents;
///
/// Copyright (c) 2020 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using System.Diagnostics;
using TBF.Rig.ControlBoard;
using TBF.Rig.Generic;
namespace TBF.Rig.Modbus.PumpFM.Grundfoss
{
/// <summary>
/// See page 20 of MG10S202 Operational Instructions Modbus RTU
/// </summary>
public enum CW : ushort
{
PresetRefLsb = (1 << 0),
PresetRefMsb = (1 << 1),
Not_DcBraking = (1 << 2),
Not_CoastingStop = (1 << 3),
Not_QuickStop = (1 << 4),
Not_FreezeFreq = (1 << 5),
Start_NotRampStop = (1 << 6),
Reset = (1 << 7),
Jog = (1 << 8),
Ramp2_NotRamp1 = (1 << 9),
DataValid = (1 << 10),
Relay01Activ = (1 << 11),
DOut46Activ = (1 << 12),
SelectSetupLsb = (1 << 13),
SelectSetupMsb = (1 << 14),
Reversing = (1 << 15),
}
/// <summary>
/// See page 22 of MG10S202 Operational Instructions Modbus RTU
/// </summary>
public enum SW : ushort
{
ControlReady = (1 << 0),
DriveReady = (1 << 1),
CoastingStop = (1 << 2),
Trip = (1 << 3),
TripLock = (1 << 6),
Warning = (1 << 7),
SpeedEqRef = (1 << 8),
RemoteCtrl = (1 << 9),
FreqLimitOK = (1 << 10),
MotorRunning = (1 << 11),
VoltageWarn = (1 << 13),
CurrentLimit = (1 << 14),
ThermalWarn = (1 << 15),
}
public enum Function : byte
{
ReadCoilStatus = 0x01,
ForceSingleCoil = 0x05,
ForceMultipleCoils = 0x0F,
ReadHoldingRegisters = 0x03,
PresetSingleRegister = 0x06,
PresetMultipleRegisters = 0x10,
}
public class Pump : ComponentBase, IDevice, IOperation, GenericDevices.IPumpFM, GenericDevices.IValve, IDrawingItCmpntWithSetpoint
{
private static readonly ILog log = LogManager.GetLogger(typeof(Pump));
public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); }
private readonly PumpCfg pumpCfg;
public IDrawingItem DrawingItem { get { return pumpCfg as IDrawingItem; } }
public int Delay { get { return pumpCfg.Delay; } }
public ValveCategory Category { get { return ValveCategory.Feeding; } } /// Pump category is Feeding
public GenericDevices.IValve CoupledTo { get { return null; } }
public bool InvertCouple { get { return false; } }
public int LagOpening { get { return 0; } }
public int LagClosing { get { return 0; } }
/// <summary>
/// Pump power in [%] in range 0 .. 100.0
/// </summary>
double power;
public double Power { get { return power; } }
///
public double SetpointVal
{
get { return power; }
set
{
power = (float)value;
if (power != 0) TurnOn(power);
}
}
///
public void IncreaseSetpoint()
{
power += 3.0;
if (power > 100.0) power = 100.0;
TurnOn(power);
}
///
public void DecreaseSetpoint()
{
power -= 3.0;
if (power <= 0)
{
power = 0;
TurnOff();
}
else
{
TurnOn(power);
}
}
Common.Modbus modbus;
IControlBoard controlBoard;
int bitNr; /// 0 .. 63
public UInt128 Mask; /// derived from bitPosition in the constructor
public bool State { get { return (controlBoard.Route & Mask) != 0; } }
public Pump() { }
/// <summary>
/// Ambient temperature / humidity / pressure meter 'Greco' connected via serial interface (RS232)
/// Connection settings: 19200 Bd 8-bits No-parity 1-stop-bit Flow control: none or hardware.
/// </summary>
public Pump(Generic.IComponentCfg cfg, IList<Generic.IComponent> components)
: base(cfg)
{
pumpCfg = cfg as PumpCfg;
}
public override void Initialize()
{
if (DebugLevel == DebugMode.Normal || DebugLevel == DebugMode.DetectedOn)
{
modbus = TbfComponents.FindComponent(pumpCfg.ParentName) as Common.Modbus;
if (modbus == null) throw new Exception("Cannot find " + Name + " parent");
controlBoard = null;
foreach (var name in new string[] { "CB", "UniCB" })
{
if ((controlBoard = TbfComponents.FindComponent(name) as IControlBoard) != null)
break;
}
if (controlBoard == null) throw new Exception("Cannot find a control board");
bitNr = pumpCfg.BitNr;
Mask = (((UInt128)1) << bitNr);
modbus.ComponentNames[pumpCfg.ModbusAddress] = Name;
TBF.UiBridge.Bridge.SetpointChangeHandler += delegate(object sndr, TBF.UiBridge.SetpointChangeArgs args)
{
if (args.Name == Name)
{
if (args.Increase) IncreaseSetpoint(); else DecreaseSetpoint();
}
};
log.FatalFormat("{0} initialized: {1}", Name, this);
}
else
{
log.FatalFormat("{0} simulated: {1}", Name, this);
}
}
///
/// IDevice interface
///
public void RunDeviceBefore()
{
/*if (DebugLevel == DebugMode.Normal || DebugLevel == DebugMode.DetectedOn)
{
if (modbus.ReceivedTelegrams[pumpCfg.ModbusAddress].Count > 0)
{
byte[] telegram = modbus.ReceivedTelegrams[pumpCfg.ModbusAddress].Dequeue();
string s = Telegram.LogTelegram(string.Format("Telegram received from {0}: ", Name), telegram);
log.Warn(s);
}
}*/
if (DebugLevel == DebugMode.Normal || DebugLevel == DebugMode.DetectedOn)
{
if (modbus.ReceivedTelegrams[pumpCfg.ModbusAddress].Count > 0)
{
try
{
byte[] telegram = modbus.ReceivedTelegrams[pumpCfg.ModbusAddress].Dequeue();
string hex = BitConverter.ToString(telegram).Replace("-", " ");
string msg = $"Telegram received from {Name}: {hex}";
log.Warn(msg);
LiveLogDiag.Log1(msg);
}
catch (Exception ex)
{
log.Error($"RunDeviceBefore() error processing telegram: {ex}");
LiveLogDiag.Log1($"RunDeviceBefore() error processing telegram: {ex.Message}");
}
}
}
}
public void RunDeviceAfter() { }
public void StopDevice() { }
public void StopDevice2() { }
/*/// <summary>
/// Turn the pmp on using Modbus commad, use the variable frequency
/// </summary>
/// <param name="powerArg">Frequency in percent (-200.0 .. 200.0)</param>
public void TurnOn(double powerArg)
{
log.DebugFormat("{0}.TurnOn({1})", Name, powerArg);
UInt16 controlWord = (UInt16)(CW.Not_DcBraking |
CW.Not_CoastingStop |
CW.Not_QuickStop |
CW.Not_FreezeFreq |
CW.Start_NotRampStop |
CW.DataValid);
this.power = powerArg;
UInt16 reference = (UInt16)Math.Round(0x4000 * powerArg / 100.0);
if (DebugLevel == DebugMode.Normal || DebugLevel == DebugMode.DetectedOn)
{
byte[] msg = new byte[13];
msg[0] = (byte)pumpCfg.ModbusAddress;
msg[1] = (byte)Function.ForceMultipleCoils;
msg[2] = 0; /// Data Hi
msg[3] = 0; /// Data Lo
msg[4] = 0; /// Nr. of coils Hi
msg[5] = 0x20; /// Nr. of coils Lo
msg[6] = 4; /// Byte count
msg[7] = (byte)(controlWord & 0xFF); /// Control Word Lo
msg[8] = (byte)(controlWord >> 8); /// Control Word Hi
msg[9] = (byte)(reference & 0xFF); /// Serial Com Reference Lo
msg[10] = (byte)(reference >> 8); /// Serial Com Reference Hi
///
modbus.SendMessage(msg, Name);
/// --- DIAGNOSTIKA ---
LiveLogDiag.Log1("--------------------------------------------");
LiveLogDiag.Log1($"TurnOff controlWord=0x{controlWord:X4}");
LiveLogDiag.Log1($"TurnOff reference={reference}");
LiveLogDiag.Log1("TurnOff msg = " + BitConverter.ToString(msg));
}
}*/
public void TurnOn(double powerArg)
{
log.DebugFormat("{0}.TurnOn({1})", Name, powerArg);
LiveLogDiag.Log1("--------------------------------------------");
LiveLogDiag.Log1("{0}.TurnOn({1})", Name, powerArg);
LiveLogDiag.Log1($"DebugLevel={DebugLevel}");
// clamp 0100 %
double pct = Math.Max(0, Math.Min(100.0, powerArg));
UInt16 setpoint = (UInt16)Math.Round(pct * 100); // fH,fL = %*100
this.power = pct;
if (DebugLevel == DebugMode.Normal || DebugLevel == DebugMode.DetectedOn)
{
byte[] msg = new byte[17];
msg[0] = (byte)pumpCfg.ModbusAddress; // adr
msg[1] = 0x10; // function = write multiple registers
msg[2] = 0x00; // start address hi
msg[3] = 0x64; // start address lo = 100
msg[4] = 0x00; // register count hi
msg[5] = 0x05; // register count lo = 5
msg[6] = 0x0A; // byte count = 10
// ----- registers -----
// reg100 = command = 0x0007 (RUN)
msg[7] = 0x00;
msg[8] = 0x07;
// reg101 = 0x0001
msg[9] = 0x00;
msg[10] = 0x01;
// reg102 = 0x0000
msg[11] = 0x00;
msg[12] = 0x00;
// reg103 = setpoint = fH,fL
msg[13] = (byte)(setpoint >> 8);
msg[14] = (byte)(setpoint & 0xFF);
// reg104 = 0x0001 (RUN)
msg[15] = 0x00;
msg[16] = 0x01;
//Telegram.UpdateTelegramCRC(msg);
modbus.SendMessage(msg, Name);
modbus.SendMessage(msg, Name);
// --- DIAGNOSTIKA ---
LiveLogDiag.Log1($"GF TurnOn Setpoint={pct}");
LiveLogDiag.Log1($"GF TurnOn raw reference={setpoint}");
LiveLogDiag.Log1("GF TurnOn msg = " + BitConverter.ToString(msg));
}
}
/*/// <summary>
/// Turn the pmp off using Modbus command
/// </summary>
public void TurnOff()
{
log.DebugFormat("{0}.TurnOff()", Name);
UInt16 controlWord = (UInt16)(CW.Not_DcBraking |
CW.Not_CoastingStop |
CW.Not_QuickStop |
CW.Not_FreezeFreq |
//CW.Start_NotRampStop |
CW.DataValid);
this.power = 0;
UInt16 reference = 0;
if (DebugLevel == DebugMode.Normal || DebugLevel == DebugMode.DetectedOn)
{
byte[] msg = new byte[13];
msg[0] = (byte)pumpCfg.ModbusAddress;
msg[1] = (byte)Function.ForceMultipleCoils;
msg[2] = 0; /// Data Hi
msg[3] = 0; /// Data Lo
msg[4] = 0; /// Nr. of coils Hi
msg[5] = 0x20; /// Nr. of coils Lo
msg[6] = 4; /// Byte count
msg[7] = (byte)(controlWord & 0xFF); /// Control Word Lo
msg[8] = (byte)(controlWord >> 8); /// Control Word Hi
msg[9] = (byte)(reference & 0xFF); /// Serial Com Reference Lo
msg[10] = (byte)(reference >> 8); /// Serial Com Reference Hi
Telegram.UpdateTelegramCRC(msg);
modbus.SendMessage(msg, Name);
/// --- DIAGNOSTIKA ---
LiveLogDiag.Log1("--------------------------------------------");
LiveLogDiag.Log1($"TurnOff controlWord=0x{controlWord:X4}");
LiveLogDiag.Log1($"TurnOff reference={reference}");
LiveLogDiag.Log1("TurnOff msg = " + BitConverter.ToString(msg));
}
}*/
/// <summary>
/// Turn the pump off using Modbus command (Grundfos version)
/// </summary>
public void TurnOff()
{
log.DebugFormat("{0}.TurnOff()", Name);
LiveLogDiag.Log1("--------------------------------------------");
LiveLogDiag.Log1("{0}.TurnOff()", Name);
LiveLogDiag.Log1($"DebugLevel={DebugLevel}");
this.power = 0;
UInt16 setpoint = 0; // desired = 0%
if (DebugLevel == DebugMode.Normal || DebugLevel == DebugMode.DetectedOn)
{
byte[] msg = new byte[17];
msg[0] = (byte)pumpCfg.ModbusAddress; // adr
msg[1] = 0x10; // function
msg[2] = 0x00;
msg[3] = 0x64; // reg100
msg[4] = 0x00;
msg[5] = 0x05; // 5 registers
msg[6] = 0x0A; // 10 bytes
// reg100 = 0x0005 (STOP)
msg[7] = 0x00;
msg[8] = 0x05;
// reg101 = 0x0001
msg[9] = 0x00;
msg[10] = 0x01;
// reg102 = 0x0000
msg[11] = 0x00;
msg[12] = 0x00;
// reg103 = setpoint = 0
msg[13] = 0x00;
msg[14] = 0x00;
// reg104 = 0x0000 (STOP)
msg[15] = 0x00;
msg[16] = 0x00;
//Telegram.UpdateTelegramCRC(msg);
modbus.SendMessage(msg, Name);
modbus.SendMessage(msg, Name);
// --- DIAGNOSTIKA ---
LiveLogDiag.Log1("GF TurnOff msg = " + BitConverter.ToString(msg));
}
}
/// <summary>
/// The currently running operation.
/// </summary>
public enum CurrentOp
{
None,
TurnOn,
TurnOff,
}
///
CurrentOp currentOp;
double powerForOp;
/// <summary>
/// Turn the pump frequency inverter on.
/// </summary>
public IOperation TurnOnOp(double powerArg)
{
if (currentOp != CurrentOp.None) throw new Exception("Sequence error");
currentOp = CurrentOp.TurnOn;
powerForOp = powerArg;
return this;
}
/// <summary>
/// Turn the pump frequency inverter on.
/// </summary>
public IOperation TurnOffOp()
{
if (currentOp != CurrentOp.None) throw new Exception("Sequence error");
currentOp = CurrentOp.TurnOff;
return this;
}
/// <summary>Start the operation</summary>
public void Start()
{
switch (currentOp)
{
case CurrentOp.TurnOn:
TurnOn(powerForOp);
return;
case CurrentOp.TurnOff:
default:
TurnOff();
return;
}
}
/// <summary>Run the operation</summary>
public Event Run()
{
return Event.TurnPumpOnOffDone;
}
/// <summary>Stop the operation</summary>
public void Stop()
{
currentOp = CurrentOp.None;
}
}
/// <summary>
/// Diagnostic logging
/// Activated by compilation condition: DIAG_ENDURANCE_LOG
/// </summary>
static class LiveLogDiag
{
[Conditional("DIAG_LOG_PUMP")]
public static void Log1(string format, params object[] args)
{
LiveLogCache.Instance.AddLog(string.Format(format, args));
}
}
}

View File

@ -0,0 +1,84 @@
///
/// Copyright (c) 2020 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using System.Xml.Serialization;
using Common;
using Config.Entities;
using SchematicDrawing;
using TBF.Rig.Generic;
namespace TBF.Rig.Modbus.PumpFM.Grundfoss
{
public class PumpCfg : ComponentCfgBase, IChildComponentCfg, IRouteBasedDrawingItem, IDrawingItemWithSetpoint
{
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(PumpCfg) })[0];
public override XmlSerializer GetSerializer() { return Serializer; }
public IComponentCfgCtrl GetControl(IList<Config.Entities.Component> cmpntEntities) { return new PumpCfgCtrl(); }
///
/// Serialized parameters
///
public int BitNr { get; set; }
public bool Inverted { get; set; } /// When true the pump function is inverted: 0 = on, 1 = off
public int Delay; /// Delay of the pump function in [s] (affects the duration of transition sequence steps)
public byte ModbusAddress; /// 1..254
public Shape Shape { get; set; }
public int X { get; set; }
public int Y { get; set; }
public Sz Sz { get; set; }
public Orient Orient { get; set; }
public bool Flip { get; set; }
public int LblX { get; set; }
public int LblY { get; set; }
public Orient LblOrient { get; set; }
public int SetpX { get; set; }
public int SetpY { get; set; }
public Orient SetpOrient { get; set; }
public string SetpFormat { get; set; }
public Unit SetpUnit { get; set; }
[XmlIgnore]
public IList<GNode> GNodes { get; set; }
[XmlIgnore]
public IList<GEdge> EdgesToSet { get; set; }
/// Private parameterless constructor invoked by all other (public) constructors
PumpCfg()
{
GNodes = new List<GNode>();
EdgesToSet = new List<GEdge>();
}
public PumpCfg(IComponentFactory factory)
: this()
{
Shape = Shape.PumpFM;
Sz = Sz.M;
SetpFormat = "{0:F0} %";
SetpUnit = Unit.Pct;
Name = "P";
Factory = factory;
ParentName = "Modbus";
BitNr = 0;
Delay = 1;
ModbusAddress = 49;
}
public string ToString(int i)
{
return string.Format("name={0} bit={1} delay={2} addr={3} parent={4}",
Name,
BitNr,
Delay,
ModbusAddress,
(string.IsNullOrEmpty(ParentName) ? "-" : ParentName));
}
}
}

View File

@ -0,0 +1,150 @@
///
/// Copyright (c) 2020 Sensus Slovensko a.s.
///
using System;
using System.Windows.Forms;
using Common;
using Config.Entities;
using TBF.Rig.Generic;
using TBF.UI.Bench.Components;
namespace TBF.Rig.Modbus.PumpFM.Grundfoss
{
public partial class PumpCfgCtrl : UserControl, IComponentCfgCtrl
{
ComponentParametersDlg parent;
public bool ShowMore { get { return false; } }
PumpCfg config;
public IComponentCfg Config
{
get { return config as IComponentCfg; }
set
{
config = value as PumpCfg;
Redraw();
}
}
public PumpCfgCtrl()
{
InitializeComponent();
}
private void PressureMeterCfgCtrl_Load(object sender, EventArgs e)
{
parent = ParentForm as ComponentParametersDlg;
if (parent == null) return;
if (parent.CmpntEntities != null)
{
foreach (var cmpnt in parent.CmpntEntities)
{
if (TbfComponents.CmpntFactoryFromClassName(cmpnt.ClassName) is Modbus.Common.Factory)
{
parentNameComboBox.Items.Add(cmpnt.Name);
}
}
}
for (Unit units = 0; units < Unit.Count; units++)
{
if (global::Common.Units.IsQuantity(units, Quantity.Error))
{
unitsComboBox.Items.Add(units.ToString());
}
}
Redraw();
}
public void Closing()
{
}
void Redraw()
{
if (config == null) return; /// Control was not loaded, settings were not changed
componentNameLabel.Text = config.Factory.ClassName;
nameTextBox.Text = config.Name;
parentNameComboBox.Text = string.IsNullOrEmpty(config.ParentName) ? "---" : config.ParentName;
bitPositionTextBox.Text = config.BitNr.ToString();
delayTextBox.Text = config.Delay.ToString();
modbusAddressTextBox.Text = config.ModbusAddress.ToString();
formatTextBox.Text = config.SetpFormat;
unitsComboBox.Text = config.SetpUnit.ToString();
}
public void Unlock()
{
nameTextBox.Enabled = true;
parentNameComboBox.Enabled = true;
bitPositionTextBox.Enabled = true;
delayTextBox.Enabled = true;
modbusAddressTextBox.Enabled = true;
formatTextBox.Enabled = true;
unitsComboBox.Enabled = true;
}
public CfgUpdateFlags VerifyCfg(ref string message)
{
CfgUpdateFlags flags = CfgUpdateFlags.None;
int dummy;
if (!parentNameComboBox.Items.Contains(parentNameComboBox.Text))
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "Invalid 'Parent Name'";
}
if (!int.TryParse(bitPositionTextBox.Text, out dummy) || dummy < 0 || dummy >= 128)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "'Bit Position' should be between 0 and 127";
}
if (!int.TryParse(delayTextBox.Text, out dummy) || dummy < 0 || dummy > 300)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "'Delay' is not valid";
}
if (!int.TryParse(modbusAddressTextBox.Text, out dummy) || dummy < 0 || dummy > 254)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "'Modbus Address' should be between 0 and 254";
}
if (!unitsComboBox.Items.Contains(unitsComboBox.Text))
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "Invalid 'Units'";
}
return flags;
}
public CfgUpdateFlags UpdateCfg()
{
CfgUpdateFlags flags = CfgUpdateFlags.RestartRqrd;
if (config == null) return CfgUpdateFlags.Error; /// Control was not loaded, settings were not changed
config.Name = nameTextBox.Text;
config.ParentName = parentNameComboBox.Text.Equals("---") ? string.Empty : parentNameComboBox.Text;
config.BitNr = int.Parse(bitPositionTextBox.Text);
config.Delay = int.Parse(delayTextBox.Text);
config.ModbusAddress = (byte)int.Parse(modbusAddressTextBox.Text);
config.SetpFormat = formatTextBox.Text;
config.SetpUnit = global::Common.Unit.None;
for (Unit units = 0; units < Unit.Count; units++)
{
if (unitsComboBox.Text == units.ToString())
{
config.SetpUnit = units;
break;
}
}
return flags;
}
}
}

View File

@ -0,0 +1,226 @@
///
/// Copyright (c) 2020 Sensus Slovensko a.s.
///
namespace TBF.Rig.Modbus.PumpFM.Grundfoss
{
partial class PumpCfgCtrl
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.parentNameLabel = new System.Windows.Forms.Label();
this.nameTextBox = new System.Windows.Forms.TextBox();
this.nameLabel = new System.Windows.Forms.Label();
this.componentNameLabel = new System.Windows.Forms.Label();
this.modbusAddressLabel = new System.Windows.Forms.Label();
this.modbusAddressTextBox = new System.Windows.Forms.TextBox();
this.parentNameComboBox = new System.Windows.Forms.ComboBox();
this.bitPositionTextBox = new System.Windows.Forms.TextBox();
this.bitPositionLabel = new System.Windows.Forms.Label();
this.delayTextBox = new System.Windows.Forms.TextBox();
this.delayLabel = new System.Windows.Forms.Label();
this.unitsComboBox = new System.Windows.Forms.ComboBox();
this.unitsLabel = new System.Windows.Forms.Label();
this.formatTextBox = new System.Windows.Forms.TextBox();
this.formatLabel = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// parentNameLabel
//
this.parentNameLabel.AutoSize = true;
this.parentNameLabel.Location = new System.Drawing.Point(36, 81);
this.parentNameLabel.Name = "parentNameLabel";
this.parentNameLabel.Size = new System.Drawing.Size(69, 13);
this.parentNameLabel.TabIndex = 3;
this.parentNameLabel.Text = "Parent Name";
//
// nameTextBox
//
this.nameTextBox.Enabled = false;
this.nameTextBox.Location = new System.Drawing.Point(146, 52);
this.nameTextBox.Name = "nameTextBox";
this.nameTextBox.Size = new System.Drawing.Size(130, 20);
this.nameTextBox.TabIndex = 2;
//
// nameLabel
//
this.nameLabel.AutoSize = true;
this.nameLabel.Location = new System.Drawing.Point(36, 55);
this.nameLabel.Name = "nameLabel";
this.nameLabel.Size = new System.Drawing.Size(35, 13);
this.nameLabel.TabIndex = 1;
this.nameLabel.Text = "Name";
//
// componentNameLabel
//
this.componentNameLabel.AutoSize = true;
this.componentNameLabel.Location = new System.Drawing.Point(143, 28);
this.componentNameLabel.Name = "componentNameLabel";
this.componentNameLabel.Size = new System.Drawing.Size(83, 13);
this.componentNameLabel.TabIndex = 0;
this.componentNameLabel.Text = "ComonentName";
//
// modbusAddressLabel
//
this.modbusAddressLabel.AutoSize = true;
this.modbusAddressLabel.Location = new System.Drawing.Point(36, 157);
this.modbusAddressLabel.Name = "modbusAddressLabel";
this.modbusAddressLabel.Size = new System.Drawing.Size(86, 13);
this.modbusAddressLabel.TabIndex = 7;
this.modbusAddressLabel.Text = "Modbus Address";
//
// modbusAddressTextBox
//
this.modbusAddressTextBox.Enabled = false;
this.modbusAddressTextBox.Location = new System.Drawing.Point(146, 154);
this.modbusAddressTextBox.Name = "modbusAddressTextBox";
this.modbusAddressTextBox.Size = new System.Drawing.Size(46, 20);
this.modbusAddressTextBox.TabIndex = 8;
//
// parentNameComboBox
//
this.parentNameComboBox.Enabled = false;
this.parentNameComboBox.FormattingEnabled = true;
this.parentNameComboBox.Location = new System.Drawing.Point(146, 78);
this.parentNameComboBox.Name = "parentNameComboBox";
this.parentNameComboBox.Size = new System.Drawing.Size(130, 21);
this.parentNameComboBox.TabIndex = 4;
//
// bitPositionTextBox
//
this.bitPositionTextBox.Enabled = false;
this.bitPositionTextBox.Location = new System.Drawing.Point(146, 104);
this.bitPositionTextBox.Name = "bitPositionTextBox";
this.bitPositionTextBox.Size = new System.Drawing.Size(46, 20);
this.bitPositionTextBox.TabIndex = 22;
//
// bitPositionLabel
//
this.bitPositionLabel.AutoSize = true;
this.bitPositionLabel.Location = new System.Drawing.Point(36, 107);
this.bitPositionLabel.Name = "bitPositionLabel";
this.bitPositionLabel.Size = new System.Drawing.Size(89, 13);
this.bitPositionLabel.TabIndex = 21;
this.bitPositionLabel.Text = "Valve Bit Position";
//
// delayTextBox
//
this.delayTextBox.Enabled = false;
this.delayTextBox.Location = new System.Drawing.Point(146, 129);
this.delayTextBox.Name = "delayTextBox";
this.delayTextBox.Size = new System.Drawing.Size(46, 20);
this.delayTextBox.TabIndex = 24;
//
// delayLabel
//
this.delayLabel.AutoSize = true;
this.delayLabel.Location = new System.Drawing.Point(35, 131);
this.delayLabel.Name = "delayLabel";
this.delayLabel.Size = new System.Drawing.Size(45, 13);
this.delayLabel.TabIndex = 23;
this.delayLabel.Text = "Delay[s]";
//
// unitsComboBox
//
this.unitsComboBox.Enabled = false;
this.unitsComboBox.FormattingEnabled = true;
this.unitsComboBox.Location = new System.Drawing.Point(146, 206);
this.unitsComboBox.Name = "unitsComboBox";
this.unitsComboBox.Size = new System.Drawing.Size(80, 21);
this.unitsComboBox.TabIndex = 28;
//
// unitsLabel
//
this.unitsLabel.AutoSize = true;
this.unitsLabel.Location = new System.Drawing.Point(36, 209);
this.unitsLabel.Name = "unitsLabel";
this.unitsLabel.Size = new System.Drawing.Size(71, 13);
this.unitsLabel.TabIndex = 27;
this.unitsLabel.Text = "Setpoint units";
//
// formatTextBox
//
this.formatTextBox.Enabled = false;
this.formatTextBox.Location = new System.Drawing.Point(146, 180);
this.formatTextBox.Name = "formatTextBox";
this.formatTextBox.Size = new System.Drawing.Size(130, 20);
this.formatTextBox.TabIndex = 26;
//
// formatLabel
//
this.formatLabel.AutoSize = true;
this.formatLabel.Location = new System.Drawing.Point(36, 183);
this.formatLabel.Name = "formatLabel";
this.formatLabel.Size = new System.Drawing.Size(78, 13);
this.formatLabel.TabIndex = 25;
this.formatLabel.Text = "Setpoint format";
//
// PumpCfgCtrl
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.unitsComboBox);
this.Controls.Add(this.unitsLabel);
this.Controls.Add(this.formatTextBox);
this.Controls.Add(this.formatLabel);
this.Controls.Add(this.delayTextBox);
this.Controls.Add(this.delayLabel);
this.Controls.Add(this.bitPositionTextBox);
this.Controls.Add(this.bitPositionLabel);
this.Controls.Add(this.parentNameComboBox);
this.Controls.Add(this.modbusAddressTextBox);
this.Controls.Add(this.modbusAddressLabel);
this.Controls.Add(this.parentNameLabel);
this.Controls.Add(this.nameTextBox);
this.Controls.Add(this.nameLabel);
this.Controls.Add(this.componentNameLabel);
this.Name = "PumpCfgCtrl";
this.Size = new System.Drawing.Size(400, 250);
this.Load += new System.EventHandler(this.PressureMeterCfgCtrl_Load);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Label parentNameLabel;
private System.Windows.Forms.TextBox nameTextBox;
private System.Windows.Forms.Label nameLabel;
private System.Windows.Forms.Label componentNameLabel;
private System.Windows.Forms.Label modbusAddressLabel;
private System.Windows.Forms.TextBox modbusAddressTextBox;
private System.Windows.Forms.ComboBox parentNameComboBox;
private System.Windows.Forms.TextBox bitPositionTextBox;
private System.Windows.Forms.Label bitPositionLabel;
private System.Windows.Forms.TextBox delayTextBox;
private System.Windows.Forms.Label delayLabel;
private System.Windows.Forms.ComboBox unitsComboBox;
private System.Windows.Forms.Label unitsLabel;
private System.Windows.Forms.TextBox formatTextBox;
private System.Windows.Forms.Label formatLabel;
}
}

View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -70,6 +70,7 @@ namespace TBF.Rig
new Modbus.PressureMeter.Meret.Factory(), /// Meret pressure meter connected via a modbus on a PC
new Modbus.Meret.AdjustableScale.Factory(), /// Adjustable meter connected via a modbus on a PC
new Modbus.PumpFM.DanfossVLT.Factory(), /// Pump controlled by Danfoss VLT connected via Modbus
new Modbus.PumpFM.Grundfoss.Factory(), /// Pump controlled by Grundfoss VLT connected via Modbus
new Modbus.QuidoRS.Factory(), /// Modbus.QuidoRS
new Modbus.TankSelector.Factory(), /// Modbus.TankSelector
new Modbus.TempControl.Easytherm.Factory(),

View File

@ -762,6 +762,15 @@
<Compile Include="Rig\Modbus\PumpFM\DanfossVLT\PumpCfgCtrl.designer.cs">
<DependentUpon>PumpCfgCtrl.cs</DependentUpon>
</Compile>
<Compile Include="Rig\Modbus\PumpFM\Grundfoss\Factory.cs" />
<Compile Include="Rig\Modbus\PumpFM\Grundfoss\Pump.cs" />
<Compile Include="Rig\Modbus\PumpFM\Grundfoss\PumpCfg.cs" />
<Compile Include="Rig\Modbus\PumpFM\Grundfoss\PumpCfgCtrl.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="Rig\Modbus\PumpFM\Grundfoss\PumpCfgCtrl.designer.cs">
<DependentUpon>PumpCfgCtrl.cs</DependentUpon>
</Compile>
<Compile Include="Rig\Modbus\QuidoRS\ConfirmationForm.cs">
<SubType>Form</SubType>
</Compile>
@ -1456,7 +1465,9 @@
<Compile Include="Rig\Scales\MettlerToledo\Factory.cs" />
<Compile Include="Rig\Scales\MettlerToledo\GetSerNumOp.cs" />
<Compile Include="Rig\Scales\MettlerToledo\ReadStableMassOp.cs" />
<Compile Include="Rig\Scales\MettlerToledo\SerialPortDevice.cs" />
<Compile Include="Rig\Scales\MettlerToledo\SerialPortDevice.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="Rig\Scales\MettlerToledo\SerialPortDeviceFake.cs" />
<Compile Include="Rig\Scales\MettlerToledo\SetUnitsOp.cs" />
<Compile Include="Rig\Scales\MettlerToledo\TaringOp.cs" />
@ -3207,6 +3218,9 @@
<EmbeddedResource Include="Rig\Modbus\PumpFM\DanfossVLT\PumpCfgCtrl.resx">
<DependentUpon>PumpCfgCtrl.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Rig\Modbus\PumpFM\Grundfoss\PumpCfgCtrl.resx">
<DependentUpon>PumpCfgCtrl.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Rig\Modbus\QuidoRS\ConfirmationForm.resx">
<DependentUpon>ConfirmationForm.cs</DependentUpon>
</EmbeddedResource>

View File

@ -370,6 +370,7 @@ namespace TBF.UI.Process
/// water
Rig.Various.Drawing.Tank.Configuration tankCfg; /// |
Rig.Modbus.PumpFM.DanfossVLT.PumpCfg pumpCfg; /// | setpoint, route based (initially bit nr. = 124)
//Rig.Modbus.PumpFM.Grundfoss.PumpCfg pump2Cfg; /// | setpoint, route based (initially bit nr. = 124)//
Rig.Modbus.TempMeter.Groch.TempMeterCfg tempInCfg; /// | measured value
Rig.Modbus.PressureMeter.Meret.PressureMeterCfg pressUpCfg; /// | measured value
Rig.Modbus.Meret.AdjustableScale.AdjustableMeterCfg electricUpCfg; /// | measured value
@ -438,6 +439,31 @@ namespace TBF.UI.Process
Inverted = false,
});
/*/// Pump
pumpSetpIx = setpIx++;
processDrawingCtrl.AddItem(
pump2Cfg = new Rig.Modbus.PumpFM.Grundfoss.PumpCfg(new Rig.Modbus.PumpFM.Grundfoss.Factory())
{
Id = pumpId = id++,
Name = "P Grundfoss",
X = 450,
Y = 480,
Shape = Shape.PumpFM,
Sz = Sz.L,
Orient = Orient.L,
Flip = false,
LblX = 0,
LblY = -46,
LblOrient = Orient.R,
SetpX = 0,
SetpY = -24,
SetpOrient = Orient.R,
SetpFormat = "{0:F0} %",
SetpUnit = Unit.Pct,
BitNr = DfltPumpBitNr,
Inverted = false,
});*/
/// Junctions
processDrawingCtrl.AddItem(new Configuration("J1", new Factory()) { Id=j1=id++, Shape=Shape.Junction, X=50, Y=490, Sz=Sz.L, });
processDrawingCtrl.AddItem(new Configuration("J2", new Factory()) { Id=j2=id++, Shape=Shape.Junction, X=50, Y=370, Sz=Sz.L, });
@ -856,6 +882,12 @@ namespace TBF.UI.Process
pumpCfg.BitNr = (args.FeedingPath.Pump.Cfg as Rig.Modbus.PumpFM.DanfossVLT.PumpCfg).BitNr;
pumpCfg.Inverted = (args.FeedingPath.Pump.Cfg as Rig.Modbus.PumpFM.DanfossVLT.PumpCfg).Inverted;
}
else if (args.FeedingPath != null && args.FeedingPath.Pump != null &&
args.FeedingPath.Pump.Cfg is Rig.Modbus.PumpFM.Grundfoss.PumpCfg)
{
pumpCfg.BitNr = (args.FeedingPath.Pump.Cfg as Rig.Modbus.PumpFM.Grundfoss.PumpCfg).BitNr;
pumpCfg.Inverted = (args.FeedingPath.Pump.Cfg as Rig.Modbus.PumpFM.Grundfoss.PumpCfg).Inverted;
}
else
{
pumpCfg.BitNr = DfltPumpBitNr;