From cef8d3ff95454391b71d5a11432881410e692271 Mon Sep 17 00:00:00 2001 From: Milan Hanajik Date: Fri, 14 Sep 2018 12:13:15 +0200 Subject: [PATCH] Stubs of Hart.Common and Hart.Nivotrack components added. --- TBF/BenchControl/GenericDevices/IHart.cs | 31 +++ TBF/BenchControl/Hart/Common/Factory.cs | 26 ++ TBF/BenchControl/Hart/Common/Hart.cs | 211 +++++++++++++++ TBF/BenchControl/Hart/Common/HartCfg.cs | 248 ++++++++++++++++++ TBF/BenchControl/Hart/Nivotrack/Factory.cs | 26 ++ TBF/BenchControl/Hart/Nivotrack/Nivotrack.cs | 211 +++++++++++++++ .../Hart/Nivotrack/NivotrackCfg.cs | 248 ++++++++++++++++++ TBF/BenchControl/Modbus/Common/HartCfg.cs | 54 ++++ TBF/BenchControl/TbfComponents.cs | 4 +- TBF/TBF.csproj | 7 + 10 files changed, 1065 insertions(+), 1 deletion(-) create mode 100644 TBF/BenchControl/GenericDevices/IHart.cs create mode 100644 TBF/BenchControl/Hart/Common/Factory.cs create mode 100644 TBF/BenchControl/Hart/Common/Hart.cs create mode 100644 TBF/BenchControl/Hart/Common/HartCfg.cs create mode 100644 TBF/BenchControl/Hart/Nivotrack/Factory.cs create mode 100644 TBF/BenchControl/Hart/Nivotrack/Nivotrack.cs create mode 100644 TBF/BenchControl/Hart/Nivotrack/NivotrackCfg.cs create mode 100644 TBF/BenchControl/Modbus/Common/HartCfg.cs diff --git a/TBF/BenchControl/GenericDevices/IHart.cs b/TBF/BenchControl/GenericDevices/IHart.cs new file mode 100644 index 000000000..e6aecd7c7 --- /dev/null +++ b/TBF/BenchControl/GenericDevices/IHart.cs @@ -0,0 +1,31 @@ +/// +/// Copyright (c) 2018 Sensus Slovensko a.s. +/// +using System.Collections.Generic; +using TBF.BenchControl.Generic; + +namespace TBF.BenchControl.GenericDevices +{ + public interface IHart : IComponent + { + /// + /// Send an arbitrary modbus message. + /// When the message length is N, however only bytes 1..N-2 have to be set. + /// The last two message bytes (CRC) may be uninitialized or zero. + /// They are calculated inside this function as required by Modbus specification. + /// + /// Message incl CRC fields, CRC bytes dont have to be set + void SendMessage(byte[] message); + + /// + /// Send a structured modbus message. + /// + /// Device address (1..255) or 0 = broadcast + /// Function (0..127) + /// Address of data to be transferred (0..65535) + /// Count of data bytes to be transferred (0..65535) + void SendMessage(byte modbusAddress, byte function, ushort dataAddress, ushort dataCount); + + Queue[] ReceivedTelegrams { get; } + } +} diff --git a/TBF/BenchControl/Hart/Common/Factory.cs b/TBF/BenchControl/Hart/Common/Factory.cs new file mode 100644 index 000000000..662873e26 --- /dev/null +++ b/TBF/BenchControl/Hart/Common/Factory.cs @@ -0,0 +1,26 @@ +/// +/// Copyright (c) 2018 Sensus Slovensko a.s. +/// +using System.Collections.Generic; +using TBF.BenchControl.Generic; + +namespace TBF.BenchControl.Hart.Common +{ + public class Factory : IComponentFactory + { + public string ClassName { get { return this.GetType().Namespace.Substring(17); } } + + public void ResetStaticProperties() { Hart.ResetStaticProperties(); } + + public IComponent DummyComponent() { return new Hart(); } + + public IComponent GetComponent(IComponentCfg cfg, IList components) { return new Hart(cfg); } + + public IComponentCfg DefaultConfig() { return new HartCfg(this.GetType().Namespace.Substring(17), this); } + + public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component) + { + return ComponentCfgBase.CreateFromDbEntity(HartCfg.Serializer, component, this); + } + } +} diff --git a/TBF/BenchControl/Hart/Common/Hart.cs b/TBF/BenchControl/Hart/Common/Hart.cs new file mode 100644 index 000000000..fb98022dd --- /dev/null +++ b/TBF/BenchControl/Hart/Common/Hart.cs @@ -0,0 +1,211 @@ +/// +/// Copyright (c) 2018 Sensus Slovensko a.s. +/// +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.IO.Ports; +using System.Text; +using System.Threading; +using Config.Entities; +using log4net; +using TBF.BenchControl.Generic; +using TBF.Boxes; + +namespace TBF.BenchControl.Hart.Common +{ + /// + /// Root component for Modbus communication via serial port (RS485) + /// + public class Hart : ComponentBase, IDevice, GenericDevices.IModbus + { + private static readonly ILog log = LogManager.GetLogger(typeof(Hart)); + public override string ToString() { return string.Format("Modbus({0})", Cfg.ToString(1)); } + + private readonly HartCfg modbusCommonCfg; + + /// Private fields + SerialPort serialPort; + DateTime lastSerialPortWrite; + + public Queue[] ReceivedTelegrams + { + get { return receivedTelegrams; } + } + Queue[] receivedTelegrams; + + Queue telegramsToSend; + + public Hart() + { + } + + /// + /// 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. + /// + public Hart(Generic.IComponentCfg cfg) + : base(cfg) + { + receivedTelegrams = new Queue[256]; + for (int i = 0; i < receivedTelegrams.Length; i++) + { + receivedTelegrams[i] = new Queue(); + } + telegramsToSend = new Queue(); + + serialPort = null; + modbusCommonCfg = cfg as HartCfg; + log.Debug(this.ToString()); + } + + ~Hart() + { + } + + public void Initialize() + { + if (modbusCommonCfg.DebugLevel == DebugMode.Simulate) + { + serialPort = null; + log.FatalFormat("{0} - Device simulated", Name); + return; + } + + string comPortName = "COM" + modbusCommonCfg.ComPortNr.ToString(); + serialPort = new SerialPort(comPortName, modbusCommonCfg.BaudRate, modbusCommonCfg.Parity, modbusCommonCfg.DataBits, modbusCommonCfg.StopBits); + serialPort.Handshake = modbusCommonCfg.Handshake; + serialPort.Open(); + + //stopWorkerThread = false; + //workerThread = new Thread(Worker); + //workerThread.Start(); + + log.FatalFormat("{0} - Device successfully initialized", Name); + } + + + /// + /// Send an arbitrary modbus message. + /// When the message length is N, however only bytes 1..N-2 have to be set. + /// The last two message bytes (CRC) may be uninitialized or zero. + /// They are calculated inside this function as required by Modbus specification. + /// + /// Message incl CRC fields, CRC bytes dont have to be set + public void SendMessage(byte[] message) + { + if (serialPort == null) return; + + Telegram.UpdateTelegramCRC(message); + + if ((DateTime.Now - lastSerialPortWrite) > new TimeSpan(0, 0, 0, 0, 100)) + { + /// More then 100 ms since last 'send' --> do not enqueue the message + SendMessageNow(message); + } + else + { + telegramsToSend.Enqueue(message); + + string s = Telegram.LogTelegram(string.Format("{0} - Enqueueing message ", Name), message); + Debug.WriteLine(s); + log.Debug(s); + } + } + + + /// + /// Send a structured modbus message. + /// + /// Device address (1..255) or 0 = broadcast + /// Function (0..127) + /// Address of data to be transferred (0..65535) + /// Count of data bytes to be transferred (0..65535) + public void SendMessage(byte modbusAddress, byte function, ushort dataAddress, ushort dataCount) + { + if (serialPort == null) return; + + byte[] message = new byte[8] + { + modbusAddress, + function, + (byte)(dataAddress / 256), + (byte)(dataAddress % 256), + (byte)(dataCount / 256), + (byte)(dataCount % 256), + 0, + 0, + }; + + SendMessage(message); + } + + public void SendMessageNow(byte[] message) + { + serialPort.Write(message, 0, message.Length); + lastSerialPortWrite = DateTime.Now; + + string s = Telegram.LogTelegram(string.Format("{0} - Sending message ", Name), message); + Debug.WriteLine(s); + log.Debug(s); + } + + + /// Run this device + public void RunDeviceBefore() + { + if (serialPort == null) return; + + int nrBytes = serialPort.BytesToRead; + if (nrBytes > 0) + { + byte[] buffer = new byte[nrBytes]; + serialPort.Read(buffer, 0, nrBytes); + + int deviceAddress = (nrBytes >= 1) ? buffer[0] : 0; + int function = (nrBytes >= 2) ? buffer[1] : 0; + + if ((nrBytes >= 4) && Telegram.VerifyTelegramCRC(buffer)) + { + receivedTelegrams[deviceAddress].Enqueue(buffer); + + string s = string.Format("{0} - {1} address={2} count={3}", Name, Telegram.LogTelegram("Telegram received: ", buffer), deviceAddress, receivedTelegrams[deviceAddress].Count); + Debug.WriteLine(s); + log.Debug(s); + } + else + { + string s = Telegram.LogTelegram(string.Format("{0} - Invalid data received ", Name), buffer); + Debug.WriteLine(s); + log.Debug(s); + } + } + } + + /// Run this device + public void RunDeviceAfter() + { + if (serialPort == null) return; + + if (telegramsToSend.Count > 0 && (DateTime.Now - lastSerialPortWrite) > new TimeSpan(0, 0, 0, 0, 500)) + { + SendMessageNow(telegramsToSend.Dequeue()); + } + } + + /// Stop this device + public void StopDevice() + { + if (serialPort != null) + { + //stopWorkerThread = true; + //workerThread.Join(2000); + serialPort.Close(); + serialPort = null; + } + } + + public void StopDevice2() { } + } +} diff --git a/TBF/BenchControl/Hart/Common/HartCfg.cs b/TBF/BenchControl/Hart/Common/HartCfg.cs new file mode 100644 index 000000000..1a9b311d0 --- /dev/null +++ b/TBF/BenchControl/Hart/Common/HartCfg.cs @@ -0,0 +1,248 @@ +/// +/// Copyright (c) 2018 Sensus Slovensko a.s. +/// +using System.IO; +using System.Collections.Generic; +using System.IO.Ports; +using System.Xml.Serialization; +using Config.Entities; +using TBF.BenchControl.Generic; + +namespace TBF.BenchControl.Hart.Common +{ + public class HartCfg : ComponentCfgBase, Generic.IComponentCfg, Config.Entities.IParamsProvider + { + public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(HartCfg) })[0]; + public override XmlSerializer GetSerializer() { return Serializer; } + + static readonly int[] AllBaudRates = new int[] { 300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200 }; + static readonly Parity[] AllParities = new Parity[] { Parity.None, Parity.Even, Parity.Odd }; + static readonly int[] AllDataBits = new int[] { 7, 8 }; + static readonly StopBits[] AllStopBits = new StopBits[] { StopBits.None, StopBits.One, StopBits.OnePointFive, StopBits.Two }; + static readonly Handshake[] AllHandshakes = new Handshake[] { Handshake.None, Handshake.XOnXOff, Handshake.RequestToSend, Handshake.RequestToSendXOnXOff }; + + + public IComponentCfgCtrl GetControl() + { + return new Configs.ParamsProvider.ComponentCfgCtrl(this, null); + } + + /// + /// Serialized parameters + /// + public int ComPortNr; + public int BaudRate; + public int DataBits; + public Parity Parity; + public StopBits StopBits; + public Handshake Handshake; + + /// Private parameterless constructor invoked by all other (public) constructors + HartCfg() + { + } + + public HartCfg(string name, IComponentFactory factory) + : this() + { + Name = name; + Factory = factory; + ParentName = string.Empty; + InitializeAll(); + } + + public string ComponentName { get { return Name; } } + + public void InitializeAll() + { + ComPortNr = 3; + BaudRate = 9600; + DataBits = 8; + Parity = System.IO.Ports.Parity.None; + StopBits = System.IO.Ports.StopBits.One; + Handshake = System.IO.Ports.Handshake.None; + } + string[] paramNames = new string[] + { + "Com port number", + "Baud rate", + "Data bits", + "Parity", + "Stop bits", + "Handshake" + }; + public string ParamName(int i) { return paramNames[i]; } + public int ParamsCount() { return paramNames.Length; } + + public IList ParamValues(int i) + { + IList list = new List(); + switch (i) + { + case 1: foreach (var v in AllBaudRates) list.Add(v.ToString()); break; + case 2: foreach (var v in AllDataBits) list.Add(v.ToString()); break; + case 3: foreach (var v in AllParities) list.Add(v.ToString()); break; + case 4: foreach (var v in AllStopBits) list.Add(v.ToString()); break; + case 5: foreach (var v in AllHandshakes) list.Add(v.ToString()); break; + default: return null; + } + return list; + } + + public string ToString(int i) + { + if (i == -1) + { + return string.Format("Com{0}, {1}Bd, {2}-bits, parity={3}, stopBits={4}, {5}", + ComPortNr, BaudRate, DataBits, Parity, StopBits, Handshake); + } + + switch (i) + { + case 0: return ComPortNr.ToString(); + case 1: return BaudRate.ToString(); + case 2: return DataBits.ToString(); + case 3: return Parity.ToString(); + case 4: return StopBits.ToString(); + case 5: return Handshake.ToString(); + default: return string.Empty; + } + } + + + public CfgUpdateFlags UpdateParam(int i, string strValue) + { + switch (i) + { + case 0: + if (ComPortNr != int.Parse(strValue)) + { + ComPortNr = int.Parse(strValue); + return CfgUpdateFlags.RestartRqrd; + } + else + { + return CfgUpdateFlags.None; + } + + case 1: + foreach (var v in AllBaudRates) + { + if ((strValue == v.ToString()) && (BaudRate != v)) + { + BaudRate = v; + return CfgUpdateFlags.RestartRqrd; + } + } + return CfgUpdateFlags.None; + + case 2: + foreach (var v in AllDataBits) + { + if ((strValue == v.ToString()) && (DataBits != v)) + { + DataBits = v; + return CfgUpdateFlags.RestartRqrd; + } + } + return CfgUpdateFlags.None; + + case 3: + foreach (var v in AllParities) + { + if ((strValue == v.ToString()) && (Parity != v)) + { + Parity = v; + return CfgUpdateFlags.RestartRqrd; + } + } + return CfgUpdateFlags.None; + + case 4: + foreach (var v in AllStopBits) + { + if ((strValue == v.ToString()) && (StopBits != v)) + { + StopBits = v; + return CfgUpdateFlags.RestartRqrd; + } + } + return CfgUpdateFlags.None; + + case 5: + foreach (var v in AllHandshakes) + { + if ((strValue == v.ToString()) && (Handshake != v)) + { + Handshake = v; + return CfgUpdateFlags.RestartRqrd; + } + } + return CfgUpdateFlags.None; + + default: + return CfgUpdateFlags.None; + } + } + + + public bool ValidateParam(int i, string strValue, out string message) + { + message = string.Empty; + + switch (i) + { + case 0: + int comPortNr; + if (int.TryParse(strValue, out comPortNr) && comPortNr > 0 && comPortNr <= 999) return true; + break; + case 1: + foreach (var v in AllBaudRates) if (strValue == v.ToString()) return true; + break; + case 2: + foreach (var v in AllDataBits) if (strValue == v.ToString()) return true; + break; + case 3: + foreach (var v in AllParities) if (strValue == v.ToString()) return true; + break; + case 4: + foreach (var v in AllStopBits) if (strValue == v.ToString()) return true; + break; + case 5: + foreach (var v in AllHandshakes) if (strValue == v.ToString()) return true; + break; + + default: + message = "Invalid index"; + return false; + } + + message = ParamName(i) + " is invalid"; + return false; + } + + void CopyContentTo(HartCfg prms) + { + prms.ParentName = this.ParentName; + prms.ComPortNr = this.ComPortNr; + prms.BaudRate = this.BaudRate; + prms.DataBits = this.DataBits; + prms.Parity = this.Parity; + prms.StopBits = this.StopBits; + prms.Handshake = this.Handshake; + } + + + public Config.Entities.IParamsProvider Clone() + { + HartCfg pars = new HartCfg(); + CopyContentTo(pars); + return pars; + } + + public void UpdateEmbeddedDbEntity() + { + /// Do nothing + } + } +} diff --git a/TBF/BenchControl/Hart/Nivotrack/Factory.cs b/TBF/BenchControl/Hart/Nivotrack/Factory.cs new file mode 100644 index 000000000..8f7d4e1c4 --- /dev/null +++ b/TBF/BenchControl/Hart/Nivotrack/Factory.cs @@ -0,0 +1,26 @@ +/// +/// Copyright (c) 2018 Sensus Slovensko a.s. +/// +using System.Collections.Generic; +using TBF.BenchControl.Generic; + +namespace TBF.BenchControl.Hart.Nivotrack +{ + public class Factory : IComponentFactory + { + public string ClassName { get { return this.GetType().Namespace.Substring(17); } } + + public void ResetStaticProperties() { Nivotrack.ResetStaticProperties(); } + + public IComponent DummyComponent() { return new Nivotrack(); } + + public IComponent GetComponent(IComponentCfg cfg, IList components) { return new Nivotrack(cfg); } + + public IComponentCfg DefaultConfig() { return new NivotrackCfg(this.GetType().Namespace.Substring(17), this); } + + public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component) + { + return ComponentCfgBase.CreateFromDbEntity(NivotrackCfg.Serializer, component, this); + } + } +} diff --git a/TBF/BenchControl/Hart/Nivotrack/Nivotrack.cs b/TBF/BenchControl/Hart/Nivotrack/Nivotrack.cs new file mode 100644 index 000000000..776228068 --- /dev/null +++ b/TBF/BenchControl/Hart/Nivotrack/Nivotrack.cs @@ -0,0 +1,211 @@ +/// +/// Copyright (c) 2018 Sensus Slovensko a.s. +/// +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.IO.Ports; +using System.Text; +using System.Threading; +using Config.Entities; +using log4net; +using TBF.BenchControl.Generic; +using TBF.Boxes; + +namespace TBF.BenchControl.Hart.Nivotrack +{ + /// + /// Root component for Modbus communication via serial port (RS485) + /// + public class Nivotrack : ComponentBase, IDevice, GenericDevices.IHart + { + private static readonly ILog log = LogManager.GetLogger(typeof(Nivotrack)); + public override string ToString() { return string.Format("Modbus({0})", Cfg.ToString(1)); } + + private readonly NivotrackCfg modbusCommonCfg; + + /// Private fields + SerialPort serialPort; + DateTime lastSerialPortWrite; + + public Queue[] ReceivedTelegrams + { + get { return receivedTelegrams; } + } + Queue[] receivedTelegrams; + + Queue telegramsToSend; + + public Nivotrack() + { + } + + /// + /// 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. + /// + public Nivotrack(Generic.IComponentCfg cfg) + : base(cfg) + { + receivedTelegrams = new Queue[256]; + for (int i = 0; i < receivedTelegrams.Length; i++) + { + receivedTelegrams[i] = new Queue(); + } + telegramsToSend = new Queue(); + + serialPort = null; + modbusCommonCfg = cfg as NivotrackCfg; + log.Debug(this.ToString()); + } + + ~Nivotrack() + { + } + + public void Initialize() + { + if (modbusCommonCfg.DebugLevel == DebugMode.Simulate) + { + serialPort = null; + log.FatalFormat("{0} - Device simulated", Name); + return; + } + + string comPortName = "COM" + modbusCommonCfg.ComPortNr.ToString(); + serialPort = new SerialPort(comPortName, modbusCommonCfg.BaudRate, modbusCommonCfg.Parity, modbusCommonCfg.DataBits, modbusCommonCfg.StopBits); + serialPort.Handshake = modbusCommonCfg.Handshake; + serialPort.Open(); + + //stopWorkerThread = false; + //workerThread = new Thread(Worker); + //workerThread.Start(); + + log.FatalFormat("{0} - Device successfully initialized", Name); + } + + + /// + /// Send an arbitrary modbus message. + /// When the message length is N, however only bytes 1..N-2 have to be set. + /// The last two message bytes (CRC) may be uninitialized or zero. + /// They are calculated inside this function as required by Modbus specification. + /// + /// Message incl CRC fields, CRC bytes dont have to be set + public void SendMessage(byte[] message) + { + if (serialPort == null) return; + + Telegram.UpdateTelegramCRC(message); + + if ((DateTime.Now - lastSerialPortWrite) > new TimeSpan(0, 0, 0, 0, 100)) + { + /// More then 100 ms since last 'send' --> do not enqueue the message + SendMessageNow(message); + } + else + { + telegramsToSend.Enqueue(message); + + string s = Telegram.LogTelegram(string.Format("{0} - Enqueueing message ", Name), message); + Debug.WriteLine(s); + log.Debug(s); + } + } + + + /// + /// Send a structured modbus message. + /// + /// Device address (1..255) or 0 = broadcast + /// Function (0..127) + /// Address of data to be transferred (0..65535) + /// Count of data bytes to be transferred (0..65535) + public void SendMessage(byte modbusAddress, byte function, ushort dataAddress, ushort dataCount) + { + if (serialPort == null) return; + + byte[] message = new byte[8] + { + modbusAddress, + function, + (byte)(dataAddress / 256), + (byte)(dataAddress % 256), + (byte)(dataCount / 256), + (byte)(dataCount % 256), + 0, + 0, + }; + + SendMessage(message); + } + + public void SendMessageNow(byte[] message) + { + serialPort.Write(message, 0, message.Length); + lastSerialPortWrite = DateTime.Now; + + string s = Telegram.LogTelegram(string.Format("{0} - Sending message ", Name), message); + Debug.WriteLine(s); + log.Debug(s); + } + + + /// Run this device + public void RunDeviceBefore() + { + if (serialPort == null) return; + + int nrBytes = serialPort.BytesToRead; + if (nrBytes > 0) + { + byte[] buffer = new byte[nrBytes]; + serialPort.Read(buffer, 0, nrBytes); + + int deviceAddress = (nrBytes >= 1) ? buffer[0] : 0; + int function = (nrBytes >= 2) ? buffer[1] : 0; + + if ((nrBytes >= 4) && Telegram.VerifyTelegramCRC(buffer)) + { + receivedTelegrams[deviceAddress].Enqueue(buffer); + + string s = string.Format("{0} - {1} address={2} count={3}", Name, Telegram.LogTelegram("Telegram received: ", buffer), deviceAddress, receivedTelegrams[deviceAddress].Count); + Debug.WriteLine(s); + log.Debug(s); + } + else + { + string s = Telegram.LogTelegram(string.Format("{0} - Invalid data received ", Name), buffer); + Debug.WriteLine(s); + log.Debug(s); + } + } + } + + /// Run this device + public void RunDeviceAfter() + { + if (serialPort == null) return; + + if (telegramsToSend.Count > 0 && (DateTime.Now - lastSerialPortWrite) > new TimeSpan(0, 0, 0, 0, 500)) + { + SendMessageNow(telegramsToSend.Dequeue()); + } + } + + /// Stop this device + public void StopDevice() + { + if (serialPort != null) + { + //stopWorkerThread = true; + //workerThread.Join(2000); + serialPort.Close(); + serialPort = null; + } + } + + public void StopDevice2() { } + } +} diff --git a/TBF/BenchControl/Hart/Nivotrack/NivotrackCfg.cs b/TBF/BenchControl/Hart/Nivotrack/NivotrackCfg.cs new file mode 100644 index 000000000..ac7c81209 --- /dev/null +++ b/TBF/BenchControl/Hart/Nivotrack/NivotrackCfg.cs @@ -0,0 +1,248 @@ +/// +/// Copyright (c) 2018 Sensus Slovensko a.s. +/// +using System.IO; +using System.Collections.Generic; +using System.IO.Ports; +using System.Xml.Serialization; +using Config.Entities; +using TBF.BenchControl.Generic; + +namespace TBF.BenchControl.Hart.Nivotrack +{ + public class NivotrackCfg : ComponentCfgBase, Generic.IComponentCfg, Config.Entities.IParamsProvider + { + public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(NivotrackCfg) })[0]; + public override XmlSerializer GetSerializer() { return Serializer; } + + static readonly int[] AllBaudRates = new int[] { 300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200 }; + static readonly Parity[] AllParities = new Parity[] { Parity.None, Parity.Even, Parity.Odd }; + static readonly int[] AllDataBits = new int[] { 7, 8 }; + static readonly StopBits[] AllStopBits = new StopBits[] { StopBits.None, StopBits.One, StopBits.OnePointFive, StopBits.Two }; + static readonly Handshake[] AllHandshakes = new Handshake[] { Handshake.None, Handshake.XOnXOff, Handshake.RequestToSend, Handshake.RequestToSendXOnXOff }; + + + public IComponentCfgCtrl GetControl() + { + return new Configs.ParamsProvider.ComponentCfgCtrl(this, null); + } + + /// + /// Serialized parameters + /// + public int ComPortNr; + public int BaudRate; + public int DataBits; + public Parity Parity; + public StopBits StopBits; + public Handshake Handshake; + + /// Private parameterless constructor invoked by all other (public) constructors + NivotrackCfg() + { + } + + public NivotrackCfg(string name, IComponentFactory factory) + : this() + { + Name = name; + Factory = factory; + ParentName = string.Empty; + InitializeAll(); + } + + public string ComponentName { get { return Name; } } + + public void InitializeAll() + { + ComPortNr = 3; + BaudRate = 9600; + DataBits = 8; + Parity = System.IO.Ports.Parity.None; + StopBits = System.IO.Ports.StopBits.One; + Handshake = System.IO.Ports.Handshake.None; + } + string[] paramNames = new string[] + { + "Com port number", + "Baud rate", + "Data bits", + "Parity", + "Stop bits", + "Handshake" + }; + public string ParamName(int i) { return paramNames[i]; } + public int ParamsCount() { return paramNames.Length; } + + public IList ParamValues(int i) + { + IList list = new List(); + switch (i) + { + case 1: foreach (var v in AllBaudRates) list.Add(v.ToString()); break; + case 2: foreach (var v in AllDataBits) list.Add(v.ToString()); break; + case 3: foreach (var v in AllParities) list.Add(v.ToString()); break; + case 4: foreach (var v in AllStopBits) list.Add(v.ToString()); break; + case 5: foreach (var v in AllHandshakes) list.Add(v.ToString()); break; + default: return null; + } + return list; + } + + public string ToString(int i) + { + if (i == -1) + { + return string.Format("Com{0}, {1}Bd, {2}-bits, parity={3}, stopBits={4}, {5}", + ComPortNr, BaudRate, DataBits, Parity, StopBits, Handshake); + } + + switch (i) + { + case 0: return ComPortNr.ToString(); + case 1: return BaudRate.ToString(); + case 2: return DataBits.ToString(); + case 3: return Parity.ToString(); + case 4: return StopBits.ToString(); + case 5: return Handshake.ToString(); + default: return string.Empty; + } + } + + + public CfgUpdateFlags UpdateParam(int i, string strValue) + { + switch (i) + { + case 0: + if (ComPortNr != int.Parse(strValue)) + { + ComPortNr = int.Parse(strValue); + return CfgUpdateFlags.RestartRqrd; + } + else + { + return CfgUpdateFlags.None; + } + + case 1: + foreach (var v in AllBaudRates) + { + if ((strValue == v.ToString()) && (BaudRate != v)) + { + BaudRate = v; + return CfgUpdateFlags.RestartRqrd; + } + } + return CfgUpdateFlags.None; + + case 2: + foreach (var v in AllDataBits) + { + if ((strValue == v.ToString()) && (DataBits != v)) + { + DataBits = v; + return CfgUpdateFlags.RestartRqrd; + } + } + return CfgUpdateFlags.None; + + case 3: + foreach (var v in AllParities) + { + if ((strValue == v.ToString()) && (Parity != v)) + { + Parity = v; + return CfgUpdateFlags.RestartRqrd; + } + } + return CfgUpdateFlags.None; + + case 4: + foreach (var v in AllStopBits) + { + if ((strValue == v.ToString()) && (StopBits != v)) + { + StopBits = v; + return CfgUpdateFlags.RestartRqrd; + } + } + return CfgUpdateFlags.None; + + case 5: + foreach (var v in AllHandshakes) + { + if ((strValue == v.ToString()) && (Handshake != v)) + { + Handshake = v; + return CfgUpdateFlags.RestartRqrd; + } + } + return CfgUpdateFlags.None; + + default: + return CfgUpdateFlags.None; + } + } + + + public bool ValidateParam(int i, string strValue, out string message) + { + message = string.Empty; + + switch (i) + { + case 0: + int comPortNr; + if (int.TryParse(strValue, out comPortNr) && comPortNr > 0 && comPortNr <= 999) return true; + break; + case 1: + foreach (var v in AllBaudRates) if (strValue == v.ToString()) return true; + break; + case 2: + foreach (var v in AllDataBits) if (strValue == v.ToString()) return true; + break; + case 3: + foreach (var v in AllParities) if (strValue == v.ToString()) return true; + break; + case 4: + foreach (var v in AllStopBits) if (strValue == v.ToString()) return true; + break; + case 5: + foreach (var v in AllHandshakes) if (strValue == v.ToString()) return true; + break; + + default: + message = "Invalid index"; + return false; + } + + message = ParamName(i) + " is invalid"; + return false; + } + + void CopyContentTo(NivotrackCfg prms) + { + prms.ParentName = this.ParentName; + prms.ComPortNr = this.ComPortNr; + prms.BaudRate = this.BaudRate; + prms.DataBits = this.DataBits; + prms.Parity = this.Parity; + prms.StopBits = this.StopBits; + prms.Handshake = this.Handshake; + } + + + public Config.Entities.IParamsProvider Clone() + { + NivotrackCfg pars = new NivotrackCfg(); + CopyContentTo(pars); + return pars; + } + + public void UpdateEmbeddedDbEntity() + { + /// Do nothing + } + } +} diff --git a/TBF/BenchControl/Modbus/Common/HartCfg.cs b/TBF/BenchControl/Modbus/Common/HartCfg.cs new file mode 100644 index 000000000..6491377c0 --- /dev/null +++ b/TBF/BenchControl/Modbus/Common/HartCfg.cs @@ -0,0 +1,54 @@ +/// +/// Copyright (c) 2015-2016 Sensus Metering Systems +/// +using System.IO; +using System.Collections.Generic; +using System.IO.Ports; +using System.Xml.Serialization; +using TBF.BenchControl.Generic; + +namespace TBF.BenchControl.Modbus.Common +{ + public class HartCfg : ComponentCfgBase, Generic.IComponentCfg + { + public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(HartCfg) })[0]; + public override XmlSerializer GetSerializer() { return Serializer; } + + public IComponentCfgCtrl GetControl() { return new ModbusCfgCtrl(); } + + /// + /// Serialized parameters + /// + public int ComPortNr; + public int BaudRate; + public Parity Parity; + public int DataBits; + public StopBits StopBits; + public Handshake Handshake; + + /// Private parameterless constructor invoked by all other (public) constructors + HartCfg() + { + Name = "Modbus"; + ParentName = string.Empty; + ComPortNr = 3; + BaudRate = 9600; + Parity = System.IO.Ports.Parity.None; + DataBits = 8; + StopBits = System.IO.Ports.StopBits.One; + Handshake = System.IO.Ports.Handshake.None; + } + + public HartCfg(IComponentFactory factory) + : this() + { + this.Factory = factory; + } + + public string ToString(int i) + { + return string.Format("Name={0}, Com{1}, {2}Bd, {3}-bits, parity={4}, stopBits={5}, {6}", + Name, ComPortNr, BaudRate, DataBits, Parity, StopBits, Handshake); + } + } +} diff --git a/TBF/BenchControl/TbfComponents.cs b/TBF/BenchControl/TbfComponents.cs index 8f56ecf64..0318732cc 100644 --- a/TBF/BenchControl/TbfComponents.cs +++ b/TBF/BenchControl/TbfComponents.cs @@ -83,7 +83,9 @@ namespace TBF.BenchControl Factories.Add(new DataEntry.WMStates.EntryFormFactory()); Factories.Add(new Ambient.Comet.Factory()); Factories.Add(new Ambient.Greco.Factory()); - Factories.Add(new Keithley.Multimeter_2010_RS232.Factory()); /// Keithley.Multimeter_2010_RS232 + Factories.Add(new Hart.Common.Factory()); + Factories.Add(new Hart.Nivotrack.Factory()); + Factories.Add(new Keithley.Multimeter_2010_RS232.Factory()); /// Keithley.Multimeter_2010_RS232 Factories.Add(new Keithley.TempMeter.Factory()); /// Keithley.TempMeter Factories.Add(new MettlerToledo.Standard.BalanceFactory()); /// MettlerToledo Balance Factories.Add(new MettlerToledo.Standard.BalanceOldFactory()); /// MettlerToledoBalanceOld diff --git a/TBF/TBF.csproj b/TBF/TBF.csproj index b6006e692..3fa098334 100644 --- a/TBF/TBF.csproj +++ b/TBF/TBF.csproj @@ -511,6 +511,7 @@ ValveCfgCtrl.cs + @@ -529,6 +530,12 @@ + + + + + +