Stubs of Hart.Common and Hart.Nivotrack components added.
This commit is contained in:
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <param name="message">Message incl CRC fields, CRC bytes dont have to be set</param>
|
||||
void SendMessage(byte[] message);
|
||||
|
||||
/// <summary>
|
||||
/// Send a structured modbus message.
|
||||
/// </summary>
|
||||
/// <param name="modbusAddress">Device address (1..255) or 0 = broadcast</param>
|
||||
/// <param name="function">Function (0..127)</param>
|
||||
/// <param name="dataAddress">Address of data to be transferred (0..65535)</param>
|
||||
/// <param name="dataCount">Count of data bytes to be transferred (0..65535)</param>
|
||||
void SendMessage(byte modbusAddress, byte function, ushort dataAddress, ushort dataCount);
|
||||
|
||||
Queue<byte[]>[] ReceivedTelegrams { get; }
|
||||
}
|
||||
}
|
||||
@@ -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<IComponent> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Root component for Modbus communication via serial port (RS485)
|
||||
/// </summary>
|
||||
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<byte[]>[] ReceivedTelegrams
|
||||
{
|
||||
get { return receivedTelegrams; }
|
||||
}
|
||||
Queue<byte[]>[] receivedTelegrams;
|
||||
|
||||
Queue<byte[]> telegramsToSend;
|
||||
|
||||
public Hart()
|
||||
{
|
||||
}
|
||||
|
||||
/// <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 Hart(Generic.IComponentCfg cfg)
|
||||
: base(cfg)
|
||||
{
|
||||
receivedTelegrams = new Queue<byte[]>[256];
|
||||
for (int i = 0; i < receivedTelegrams.Length; i++)
|
||||
{
|
||||
receivedTelegrams[i] = new Queue<byte[]>();
|
||||
}
|
||||
telegramsToSend = new Queue<byte[]>();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <param name="message">Message incl CRC fields, CRC bytes dont have to be set</param>
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Send a structured modbus message.
|
||||
/// </summary>
|
||||
/// <param name="modbusAddress">Device address (1..255) or 0 = broadcast</param>
|
||||
/// <param name="function">Function (0..127)</param>
|
||||
/// <param name="dataAddress">Address of data to be transferred (0..65535)</param>
|
||||
/// <param name="dataCount">Count of data bytes to be transferred (0..65535)</param>
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>Run this device</summary>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Run this device</summary>
|
||||
public void RunDeviceAfter()
|
||||
{
|
||||
if (serialPort == null) return;
|
||||
|
||||
if (telegramsToSend.Count > 0 && (DateTime.Now - lastSerialPortWrite) > new TimeSpan(0, 0, 0, 0, 500))
|
||||
{
|
||||
SendMessageNow(telegramsToSend.Dequeue());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Stop this device</summary>
|
||||
public void StopDevice()
|
||||
{
|
||||
if (serialPort != null)
|
||||
{
|
||||
//stopWorkerThread = true;
|
||||
//workerThread.Join(2000);
|
||||
serialPort.Close();
|
||||
serialPort = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void StopDevice2() { }
|
||||
}
|
||||
}
|
||||
@@ -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<string> ParamValues(int i)
|
||||
{
|
||||
IList<string> list = new List<string>();
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<IComponent> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Root component for Modbus communication via serial port (RS485)
|
||||
/// </summary>
|
||||
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<byte[]>[] ReceivedTelegrams
|
||||
{
|
||||
get { return receivedTelegrams; }
|
||||
}
|
||||
Queue<byte[]>[] receivedTelegrams;
|
||||
|
||||
Queue<byte[]> telegramsToSend;
|
||||
|
||||
public Nivotrack()
|
||||
{
|
||||
}
|
||||
|
||||
/// <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 Nivotrack(Generic.IComponentCfg cfg)
|
||||
: base(cfg)
|
||||
{
|
||||
receivedTelegrams = new Queue<byte[]>[256];
|
||||
for (int i = 0; i < receivedTelegrams.Length; i++)
|
||||
{
|
||||
receivedTelegrams[i] = new Queue<byte[]>();
|
||||
}
|
||||
telegramsToSend = new Queue<byte[]>();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <param name="message">Message incl CRC fields, CRC bytes dont have to be set</param>
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Send a structured modbus message.
|
||||
/// </summary>
|
||||
/// <param name="modbusAddress">Device address (1..255) or 0 = broadcast</param>
|
||||
/// <param name="function">Function (0..127)</param>
|
||||
/// <param name="dataAddress">Address of data to be transferred (0..65535)</param>
|
||||
/// <param name="dataCount">Count of data bytes to be transferred (0..65535)</param>
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>Run this device</summary>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Run this device</summary>
|
||||
public void RunDeviceAfter()
|
||||
{
|
||||
if (serialPort == null) return;
|
||||
|
||||
if (telegramsToSend.Count > 0 && (DateTime.Now - lastSerialPortWrite) > new TimeSpan(0, 0, 0, 0, 500))
|
||||
{
|
||||
SendMessageNow(telegramsToSend.Dequeue());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Stop this device</summary>
|
||||
public void StopDevice()
|
||||
{
|
||||
if (serialPort != null)
|
||||
{
|
||||
//stopWorkerThread = true;
|
||||
//workerThread.Join(2000);
|
||||
serialPort.Close();
|
||||
serialPort = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void StopDevice2() { }
|
||||
}
|
||||
}
|
||||
@@ -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<string> ParamValues(int i)
|
||||
{
|
||||
IList<string> list = new List<string>();
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -511,6 +511,7 @@
|
||||
<DependentUpon>ValveCfgCtrl.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="BenchControl\Elde\ValveEx\ValveFactory.cs" />
|
||||
<Compile Include="BenchControl\GenericDevices\IHart.cs" />
|
||||
<Compile Include="BenchControl\GenericDevices\IHasTestName.cs" />
|
||||
<Compile Include="BenchControl\GenericDevices\ICameraDisplay.cs" />
|
||||
<Compile Include="BenchControl\GenericDevices\IDataEntryForCamera.cs" />
|
||||
@@ -529,6 +530,12 @@
|
||||
<Compile Include="BenchControl\GenericDevices\ITankDraining.cs" />
|
||||
<Compile Include="BenchControl\GenericDevices\ITankDrainingCfg.cs" />
|
||||
<Compile Include="BenchControl\GenericDevices\ITestMethodWith2ndPass.cs" />
|
||||
<Compile Include="BenchControl\Hart\Common\Factory.cs" />
|
||||
<Compile Include="BenchControl\Hart\Common\Hart.cs" />
|
||||
<Compile Include="BenchControl\Hart\Common\HartCfg.cs" />
|
||||
<Compile Include="BenchControl\Hart\Nivotrack\Factory.cs" />
|
||||
<Compile Include="BenchControl\Hart\Nivotrack\Nivotrack.cs" />
|
||||
<Compile Include="BenchControl\Hart\Nivotrack\NivotrackCfg.cs" />
|
||||
<Compile Include="BenchControl\HeatMetersPath.cs" />
|
||||
<Compile Include="BenchControl\Keithley\Multimeter_2010_RS232\Factory.cs" />
|
||||
<Compile Include="BenchControl\Keithley\Multimeter_2010_RS232\Multimeter.cs" />
|
||||
|
||||
Reference in New Issue
Block a user