HART communication : IHart,Hart, Nivotrack changes, sending/receiving works OK. Todo: Interface the level, ver. 2.18.1044
This commit is contained in:
parent
3725e238fc
commit
845c66b511
@ -15,16 +15,7 @@ namespace TBF.BenchControl.GenericDevices
|
||||
/// 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);
|
||||
void SendMessage(int preambLen, byte[] message);
|
||||
|
||||
Queue<byte[]>[] ReceivedTelegrams { get; }
|
||||
}
|
||||
|
||||
34
TBF/BenchControl/Hart/Common/Enums.cs
Normal file
34
TBF/BenchControl/Hart/Common/Enums.cs
Normal file
@ -0,0 +1,34 @@
|
||||
///
|
||||
/// Copyright (c) 2018 Sensus Slovensko a.s.
|
||||
///
|
||||
namespace TBF.BenchControl.Hart.Common
|
||||
{
|
||||
/// <summary>
|
||||
/// HART start bytes
|
||||
/// </summary>
|
||||
public enum Mark : byte
|
||||
{
|
||||
ShortFrameMaster2Slave = 0x02,
|
||||
ShortFrameSlave2Master = 0x06,
|
||||
LongFrameMaster2Slave = 0x82,
|
||||
LongFrameSlave2Master = 0x86,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// HART master addresses
|
||||
/// </summary>
|
||||
public enum Master : byte
|
||||
{
|
||||
Secondary = 0,
|
||||
Primary = 0x80,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// HART commands
|
||||
/// </summary>
|
||||
public enum Cmd : byte
|
||||
{
|
||||
ReadUniqueID = 0,
|
||||
ReadPrimaryVar = 1,
|
||||
}
|
||||
}
|
||||
@ -16,39 +16,49 @@ using TBF.Boxes;
|
||||
namespace TBF.BenchControl.Hart.Common
|
||||
{
|
||||
/// <summary>
|
||||
/// Root component for Modbus communication via serial port (RS485)
|
||||
/// Root component for HART communication via a modem connected to a serial port (RS232)
|
||||
/// </summary>
|
||||
public class Hart : ComponentBase, IDevice, GenericDevices.IModbus
|
||||
public class Hart : ComponentBase, IDevice, GenericDevices.IHart
|
||||
{
|
||||
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 readonly HartCfg hartCfg;
|
||||
|
||||
/// Private fields
|
||||
SerialPort serialPort;
|
||||
DateTime lastSerialPortWrite;
|
||||
|
||||
/// <summary>
|
||||
/// An array of Queue-s of received telegrams fetched by HART components (as Nivotrack).
|
||||
/// There is one queue for each device (each slave address).
|
||||
/// </summary>
|
||||
public Queue<byte[]>[] ReceivedTelegrams
|
||||
{
|
||||
get { return receivedTelegrams; }
|
||||
}
|
||||
Queue<byte[]>[] receivedTelegrams;
|
||||
|
||||
/// <summary>
|
||||
/// A Queue of telegrams to send. System prevents sending more then one telegram per 500ms.
|
||||
/// Function SendMessage( ) either send the telegram immediately using SendMessageNow( ) or
|
||||
/// inserts the telegram into telegramsToSend queue. The queue is emptied in RunDeviceAfter( ).
|
||||
/// </summary>
|
||||
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.
|
||||
/// HART modem connected via serial interface (RS232).
|
||||
/// Connection settings: 1200 Bd 8-bits odd-parity 1-stop-bit Flow control: none or hardware.
|
||||
/// </summary>
|
||||
public Hart(Generic.IComponentCfg cfg)
|
||||
: base(cfg)
|
||||
{
|
||||
receivedTelegrams = new Queue<byte[]>[256];
|
||||
receivedTelegrams = new Queue<byte[]>[16]; /// Max. 16 slaves with adresses 0..15
|
||||
for (int i = 0; i < receivedTelegrams.Length; i++)
|
||||
{
|
||||
receivedTelegrams[i] = new Queue<byte[]>();
|
||||
@ -56,7 +66,7 @@ namespace TBF.BenchControl.Hart.Common
|
||||
telegramsToSend = new Queue<byte[]>();
|
||||
|
||||
serialPort = null;
|
||||
modbusCommonCfg = cfg as HartCfg;
|
||||
hartCfg = cfg as HartCfg;
|
||||
log.Debug(this.ToString());
|
||||
}
|
||||
|
||||
@ -64,27 +74,62 @@ namespace TBF.BenchControl.Hart.Common
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
if (modbusCommonCfg.DebugLevel == DebugMode.Simulate)
|
||||
if (hartCfg.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;
|
||||
string comPortName = "COM" + hartCfg.ComPortNr.ToString();
|
||||
serialPort = new SerialPort(comPortName, hartCfg.BaudRate, hartCfg.Parity, hartCfg.DataBits, hartCfg.StopBits);
|
||||
serialPort.Handshake = hartCfg.Handshake;
|
||||
serialPort.Open();
|
||||
|
||||
//stopWorkerThread = false;
|
||||
//workerThread = new Thread(Worker);
|
||||
//workerThread.Start();
|
||||
|
||||
log.FatalFormat("{0} - Device successfully initialized", Name);
|
||||
}
|
||||
|
||||
public void RunDeviceBefore()
|
||||
{
|
||||
if (serialPort != null)
|
||||
{
|
||||
ParseReceivedData();
|
||||
}
|
||||
}
|
||||
|
||||
public void RunDeviceAfter()
|
||||
{
|
||||
if ((serialPort != null) && (telegramsToSend.Count > 0) && (DateTime.Now - lastSerialPortWrite) > new TimeSpan(0, 0, 0, 0, 500))
|
||||
{
|
||||
SendMessageNow(telegramsToSend.Dequeue());
|
||||
}
|
||||
}
|
||||
|
||||
public void StopDevice()
|
||||
{
|
||||
if (serialPort != null)
|
||||
{
|
||||
serialPort.Close();
|
||||
serialPort = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void StopDevice2() { }
|
||||
|
||||
|
||||
|
||||
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>
|
||||
/// Send an arbitrary modbus message.
|
||||
@ -92,21 +137,25 @@ namespace TBF.BenchControl.Hart.Common
|
||||
/// 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)
|
||||
/// <param name="message">Message incl. a reserved checksum byte, checksum does not have to be set</param>
|
||||
public void SendMessage(int preambLen, byte[] message)
|
||||
{
|
||||
if (serialPort == null) return;
|
||||
|
||||
Telegram.UpdateTelegramCRC(message);
|
||||
Telegram.UpdateTelegramChecksum(message);
|
||||
byte[] preambAndMessage = new byte[message.Length + preambLen];
|
||||
|
||||
if ((DateTime.Now - lastSerialPortWrite) > new TimeSpan(0, 0, 0, 0, 100))
|
||||
for (int i = 0; i < preambLen; i++) preambAndMessage[i] = (byte)0xFF;
|
||||
for (int i = preambLen; i < preambLen + message.Length; i++) preambAndMessage[i] = message[i - preambLen];
|
||||
|
||||
if ((DateTime.Now - lastSerialPortWrite) > new TimeSpan(0, 0, 0, 0, 500))
|
||||
{
|
||||
/// More then 100 ms since last 'send' --> do not enqueue the message
|
||||
SendMessageNow(message);
|
||||
SendMessageNow(preambAndMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
telegramsToSend.Enqueue(message);
|
||||
telegramsToSend.Enqueue(preambAndMessage);
|
||||
|
||||
string s = Telegram.LogTelegram(string.Format("{0} - Enqueueing message ", Name), message);
|
||||
Debug.WriteLine(s);
|
||||
@ -114,98 +163,61 @@ namespace TBF.BenchControl.Hart.Common
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <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)
|
||||
void ParseReceivedData()
|
||||
{
|
||||
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);
|
||||
/// Read available data
|
||||
byte[] buf = new byte[nrBytes];
|
||||
serialPort.Read(buf, 0, nrBytes);
|
||||
|
||||
int deviceAddress = (nrBytes >= 1) ? buffer[0] : 0;
|
||||
int function = (nrBytes >= 2) ? buffer[1] : 0;
|
||||
|
||||
if ((nrBytes >= 4) && Telegram.VerifyTelegramCRC(buffer))
|
||||
/// Determine count of leading FF-s
|
||||
int preambLen = 0;
|
||||
for (int i = 0; i < nrBytes; i++)
|
||||
{
|
||||
receivedTelegrams[deviceAddress].Enqueue(buffer);
|
||||
if (buf[i] != (byte)0xFF) break;
|
||||
preambLen++;
|
||||
}
|
||||
|
||||
string s = string.Format("{0} - {1} address={2} count={3}", Name, Telegram.LogTelegram("Telegram received: ", buffer), deviceAddress, receivedTelegrams[deviceAddress].Count);
|
||||
int telegramLen = nrBytes - preambLen;
|
||||
|
||||
/// Check a telegram length, a checksum, a start byte (S -> M) and a master address (primary)
|
||||
if (preambLen < 3 ||
|
||||
telegramLen < 4 ||
|
||||
!Telegram.VerifyTelegramChecksum(preambLen, buf) ||
|
||||
((buf[preambLen] != (byte)Mark.ShortFrameSlave2Master) && (buf[preambLen] != (byte)Mark.LongFrameSlave2Master)) ||
|
||||
((buf[preambLen + 1] & 0x80) != (byte)Master.Primary))
|
||||
{
|
||||
string s = Telegram.LogTelegram(string.Format("{0} - Invalid data received ", Name), buf);
|
||||
Debug.WriteLine(s);
|
||||
log.Debug(s);
|
||||
return;
|
||||
}
|
||||
|
||||
/// Strip the preamble
|
||||
byte[] data = new byte[telegramLen];
|
||||
for (int i = preambLen; i < nrBytes; i++) data[i - preambLen] = buf[i];
|
||||
|
||||
bool isShortFrame = (data[0] == 0x06);
|
||||
|
||||
if (isShortFrame)
|
||||
{
|
||||
int address = data[1] & 0x0F;
|
||||
receivedTelegrams[address].Enqueue(data);
|
||||
|
||||
string s = string.Format("{0} - {1} address={2} preambLen={3} count={4}", Name, Telegram.LogTelegram("Valid telegram received: ", data), address, preambLen, receivedTelegrams[address].Count);
|
||||
Debug.WriteLine(s);
|
||||
log.Debug(s);
|
||||
}
|
||||
else
|
||||
{
|
||||
string s = Telegram.LogTelegram(string.Format("{0} - Invalid data received ", Name), buffer);
|
||||
/// TODO
|
||||
string s = Telegram.LogTelegram(string.Format("{0} - Telegram with long address received ", Name), buf);
|
||||
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() { }
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,9 +56,9 @@ namespace TBF.BenchControl.Hart.Common
|
||||
public void InitializeAll()
|
||||
{
|
||||
ComPortNr = 3;
|
||||
BaudRate = 9600;
|
||||
BaudRate = 1200;
|
||||
DataBits = 8;
|
||||
Parity = System.IO.Ports.Parity.None;
|
||||
Parity = System.IO.Ports.Parity.Odd;
|
||||
StopBits = System.IO.Ports.StopBits.One;
|
||||
Handshake = System.IO.Ports.Handshake.None;
|
||||
}
|
||||
|
||||
@ -14,7 +14,7 @@ namespace TBF.BenchControl.Hart.Nivotrack
|
||||
|
||||
public IComponent DummyComponent() { return new Nivotrack(); }
|
||||
|
||||
public IComponent GetComponent(IComponentCfg cfg, IList<IComponent> components) { return new Nivotrack(cfg); }
|
||||
public IComponent GetComponent(IComponentCfg cfg, IList<IComponent> components) { return new Nivotrack(cfg, components); }
|
||||
|
||||
public IComponentCfg DefaultConfig() { return new NivotrackCfg(this.GetType().Namespace.Substring(17), this); }
|
||||
|
||||
|
||||
@ -11,31 +11,35 @@ using System.Threading;
|
||||
using Config.Entities;
|
||||
using log4net;
|
||||
using TBF.BenchControl.Generic;
|
||||
using TBF.BenchControl.GenericDevices;
|
||||
using TBF.Boxes;
|
||||
using TBF.BenchControl.Hart.Common;
|
||||
|
||||
namespace TBF.BenchControl.Hart.Nivotrack
|
||||
{
|
||||
/// <summary>
|
||||
/// Root component for Modbus communication via serial port (RS485)
|
||||
/// </summary>
|
||||
public class Nivotrack : ComponentBase, IDevice, GenericDevices.IHart
|
||||
public class Nivotrack : ComponentBase, IDevice, IOperation
|
||||
{
|
||||
private static readonly ILog log = LogManager.GetLogger(typeof(Nivotrack));
|
||||
public override string ToString() { return string.Format("Modbus({0})", Cfg.ToString(1)); }
|
||||
public override string ToString() { return string.Format("Nivotrack({0})", Cfg.ToString(1)); }
|
||||
|
||||
private readonly NivotrackCfg modbusCommonCfg;
|
||||
private readonly NivotrackCfg nivotrackCfg;
|
||||
private readonly IHart hart;
|
||||
|
||||
/// Private fields
|
||||
SerialPort serialPort;
|
||||
DateTime lastSerialPortWrite;
|
||||
bool readingValid;
|
||||
double waterLevel;
|
||||
|
||||
public Queue<byte[]>[] ReceivedTelegrams
|
||||
DoubleBox levelBox;
|
||||
|
||||
enum CurrentOp
|
||||
{
|
||||
get { return receivedTelegrams; }
|
||||
None,
|
||||
ReadLevel,
|
||||
}
|
||||
Queue<byte[]>[] receivedTelegrams;
|
||||
CurrentOp currentOp;
|
||||
|
||||
Queue<byte[]> telegramsToSend;
|
||||
|
||||
public Nivotrack()
|
||||
{
|
||||
@ -45,167 +49,156 @@ namespace TBF.BenchControl.Hart.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.
|
||||
/// </summary>
|
||||
public Nivotrack(Generic.IComponentCfg cfg)
|
||||
public Nivotrack(Generic.IComponentCfg cfg, IList<Generic.IComponent> components)
|
||||
: base(cfg)
|
||||
{
|
||||
receivedTelegrams = new Queue<byte[]>[256];
|
||||
for (int i = 0; i < receivedTelegrams.Length; i++)
|
||||
{
|
||||
receivedTelegrams[i] = new Queue<byte[]>();
|
||||
}
|
||||
telegramsToSend = new Queue<byte[]>();
|
||||
nivotrackCfg = cfg as NivotrackCfg;
|
||||
|
||||
hart = (IHart)TbfComponents.FindComponent(cfg.ParentName, components);
|
||||
if (hart == null) throw new Exception("Cannot find " + Name + " parent");
|
||||
|
||||
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;
|
||||
}
|
||||
if (nivotrackCfg.DebugLevel == DebugMode.Simulate) return;
|
||||
|
||||
//string comPortName = "COM" + modbusCommonCfg.Address.ToString();
|
||||
//serialPort = new SerialPort(comPortName, modbusCommonCfg.Par1, modbusCommonCfg.Parity, modbusCommonCfg.Par2, modbusCommonCfg.StopBits);
|
||||
//serialPort.Handshake = modbusCommonCfg.Handshake;
|
||||
//serialPort.Open();
|
||||
|
||||
//stopWorkerThread = false;
|
||||
//workerThread = new Thread(Worker);
|
||||
//workerThread.Start();
|
||||
|
||||
log.FatalFormat("{0} - Device successfully initialized", Name);
|
||||
waterLevel = 0;
|
||||
readingValid = false;
|
||||
}
|
||||
|
||||
|
||||
/// <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)
|
||||
void Detect()
|
||||
{
|
||||
if (serialPort == null) return;
|
||||
byte bcnt = (byte)0; /// block count
|
||||
|
||||
Telegram.UpdateTelegramCRC(message);
|
||||
byte[] data = new byte[5];
|
||||
data[0] = (byte)Mark.ShortFrameMaster2Slave;
|
||||
data[1] = (byte)((int)Master.Primary + (byte)nivotrackCfg.Address);
|
||||
data[2] = (byte)Cmd.ReadUniqueID;
|
||||
data[3] = bcnt;
|
||||
data[4] = 0; /// reserved for chehcksum
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
hart.SendMessage(5, data);
|
||||
}
|
||||
|
||||
|
||||
/// <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)
|
||||
void RequestProcessValue()
|
||||
{
|
||||
if (serialPort == null) return;
|
||||
byte bcnt = (byte)0; /// block count
|
||||
|
||||
byte[] message = new byte[8]
|
||||
byte[] data = new byte[5];
|
||||
data[0] = (byte)Mark.ShortFrameMaster2Slave;
|
||||
data[1] = (byte)((int)Master.Primary + (byte)nivotrackCfg.Address);
|
||||
data[2] = (byte)Cmd.ReadPrimaryVar;
|
||||
data[3] = bcnt;
|
||||
data[4] = 0; /// reserved for chehcksum
|
||||
|
||||
hart.SendMessage(5, data);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>Run this device</summary>
|
||||
public void RunDeviceBefore()
|
||||
{
|
||||
if (nivotrackCfg.DebugLevel == DebugMode.Simulate) return;
|
||||
|
||||
if (hart.ReceivedTelegrams[nivotrackCfg.Address].Count > 0)
|
||||
{
|
||||
modbusAddress,
|
||||
function,
|
||||
(byte)(dataAddress / 256),
|
||||
(byte)(dataAddress % 256),
|
||||
(byte)(dataCount / 256),
|
||||
(byte)(dataCount % 256),
|
||||
0,
|
||||
0,
|
||||
};
|
||||
byte[] data = hart.ReceivedTelegrams[nivotrackCfg.Address].Dequeue();
|
||||
|
||||
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))
|
||||
if ((data.Length == 12) && (data[0] == (byte)Mark.ShortFrameSlave2Master)
|
||||
&& (data[2] == (byte)Cmd.ReadPrimaryVar)
|
||||
&& (data[3] == 7))
|
||||
{
|
||||
receivedTelegrams[deviceAddress].Enqueue(buffer);
|
||||
///
|
||||
/// A frame with a status and a primary variable
|
||||
///
|
||||
ushort state = (ushort)(256 * data[4] + data[5]);
|
||||
|
||||
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);
|
||||
byte unitsID = data[6];
|
||||
|
||||
float val = System.BitConverter.ToSingle(data, 7);
|
||||
|
||||
byte[] floatData2 = new byte[] { data[10], data[9], data[8], data[7] };
|
||||
float val2 = System.BitConverter.ToSingle(floatData2, 0);
|
||||
|
||||
waterLevel = val;
|
||||
readingValid = true;
|
||||
|
||||
string msg = string.Format("{0} : Received water level = {1} mm / {2} mm, State = {3}", Name, val, val2, state.ToString("X4"));
|
||||
Debug.WriteLine(msg);
|
||||
log.Info(msg);
|
||||
}
|
||||
else
|
||||
else if ((data.Length == 7) && (data[0] == (byte)Mark.ShortFrameSlave2Master)
|
||||
&& (data[2] == (byte)Cmd.ReadPrimaryVar)
|
||||
&& (data[3] == 2))
|
||||
{
|
||||
string s = Telegram.LogTelegram(string.Format("{0} - Invalid data received ", Name), buffer);
|
||||
Debug.WriteLine(s);
|
||||
log.Debug(s);
|
||||
///
|
||||
/// A frame with a status only
|
||||
///
|
||||
ushort state = (ushort)(256 * data[4] + data[5]);
|
||||
string msg = string.Format("{0} : State = {1}", Name, state.ToString("X4"));
|
||||
Debug.WriteLine(msg);
|
||||
log.Info(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Run this device</summary>
|
||||
public void RunDeviceAfter()
|
||||
{
|
||||
if (serialPort == null) return;
|
||||
public void RunDeviceAfter()
|
||||
{
|
||||
if (nivotrackCfg.DebugLevel == DebugMode.Simulate) 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)
|
||||
if ((StateMachine.Time % 2) == (nivotrackCfg.Address % 2))
|
||||
{
|
||||
//stopWorkerThread = true;
|
||||
//workerThread.Join(2000);
|
||||
serialPort.Close();
|
||||
serialPort = null;
|
||||
RequestProcessValue();
|
||||
}
|
||||
}
|
||||
|
||||
public void StopDevice() { }
|
||||
public void StopDevice2() { }
|
||||
|
||||
|
||||
public double ReadLevel()
|
||||
{
|
||||
return waterLevel;
|
||||
}
|
||||
|
||||
/// <returns>Reference to the operation</returns>
|
||||
public IOperation ReadLevelOp(ref DoubleBox levelBox)
|
||||
{
|
||||
if (currentOp != CurrentOp.None) throw new Exception("Sequence error");
|
||||
this.levelBox = levelBox;
|
||||
currentOp = CurrentOp.ReadLevel;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>Start this operation</summary>
|
||||
public void Start()
|
||||
{
|
||||
if (readingValid && (levelBox != null)) levelBox.Val = waterLevel;
|
||||
}
|
||||
|
||||
/// <summary>Run this operation</summary>
|
||||
/// <returns>Event.ResultsPrinted</returns>
|
||||
public Event Run()
|
||||
{
|
||||
if (readingValid && (levelBox != null))
|
||||
{
|
||||
levelBox.Val = ReadLevel();
|
||||
return Event.LevelDone;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Event.Busy;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Stop this operation</summary>
|
||||
public void Stop()
|
||||
{
|
||||
currentOp = CurrentOp.None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,7 +10,7 @@ using TBF.BenchControl.Generic;
|
||||
|
||||
namespace TBF.BenchControl.Hart.Nivotrack
|
||||
{
|
||||
public class NivotrackCfg : ComponentCfgBase, Generic.IComponentCfg, Config.Entities.IParamsProvider
|
||||
public class NivotrackCfg : ComponentCfgBase, Generic.IChildComponentCfg, Config.Entities.IParamsProvider
|
||||
{
|
||||
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(NivotrackCfg) })[0];
|
||||
public override XmlSerializer GetSerializer() { return Serializer; }
|
||||
@ -21,7 +21,10 @@ namespace TBF.BenchControl.Hart.Nivotrack
|
||||
|
||||
public IComponentCfgCtrl GetControl()
|
||||
{
|
||||
return new Configs.ParamsProvider.ComponentCfgCtrl(this, null);
|
||||
IList<string> parents = new List<string>();
|
||||
parents.Add("Hart");
|
||||
|
||||
return new Configs.ParamsProvider.ComponentCfgCtrl(this, parents);
|
||||
}
|
||||
|
||||
///
|
||||
@ -32,16 +35,14 @@ namespace TBF.BenchControl.Hart.Nivotrack
|
||||
public int Par2;
|
||||
|
||||
/// Private parameterless constructor invoked by all other (public) constructors
|
||||
NivotrackCfg()
|
||||
{
|
||||
}
|
||||
NivotrackCfg() { }
|
||||
|
||||
public NivotrackCfg(string name, IComponentFactory factory)
|
||||
: this()
|
||||
{
|
||||
Name = name;
|
||||
Factory = factory;
|
||||
ParentName = string.Empty;
|
||||
ParentName = "Hart";
|
||||
InitializeAll();
|
||||
}
|
||||
|
||||
@ -141,8 +142,8 @@ namespace TBF.BenchControl.Hart.Nivotrack
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
int comPortNr;
|
||||
if (int.TryParse(strValue, out comPortNr) && comPortNr > 0 && comPortNr <= 999) return true;
|
||||
int address;
|
||||
if (int.TryParse(strValue, out address) && address >= 0 && address <= 15) return true;
|
||||
break;
|
||||
case 1:
|
||||
foreach (var v in Par1Values) if (strValue == v.ToString()) return true;
|
||||
|
||||
@ -98,18 +98,8 @@ namespace TBF.BenchControl.Modbus.Easytherm
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Run this device</summary>
|
||||
public void RunDeviceAfter()
|
||||
{
|
||||
if (easythermCfg.DebugLevel == DebugMode.Simulate) return;
|
||||
}
|
||||
|
||||
/// <summary>Stop this device</summary>
|
||||
public void StopDevice()
|
||||
{
|
||||
if (easythermCfg.DebugLevel == DebugMode.Simulate) return;
|
||||
}
|
||||
|
||||
public void RunDeviceAfter() { }
|
||||
public void StopDevice() { }
|
||||
public void StopDevice2() { }
|
||||
|
||||
|
||||
|
||||
@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
[assembly: AssemblyVersion("2.18.1042.0")]
|
||||
[assembly: AssemblyFileVersion("2.18.1042.0")]
|
||||
[assembly: AssemblyVersion("2.18.1044.0")]
|
||||
[assembly: AssemblyFileVersion("2.18.1044.0")]
|
||||
|
||||
@ -538,6 +538,7 @@
|
||||
<Compile Include="BenchControl\GenericDevices\ITankWithVolumeMsrmnt.cs" />
|
||||
<Compile Include="BenchControl\GenericDevices\ITestMethodWith2ndPass.cs" />
|
||||
<Compile Include="BenchControl\GenericDevices\IVolumeMeter.cs" />
|
||||
<Compile Include="BenchControl\Hart\Common\Enums.cs" />
|
||||
<Compile Include="BenchControl\Hart\Common\Factory.cs" />
|
||||
<Compile Include="BenchControl\Hart\Common\Hart.cs" />
|
||||
<Compile Include="BenchControl\Hart\Common\HartCfg.cs" />
|
||||
|
||||
@ -91,7 +91,7 @@ namespace TBF
|
||||
/// must be supplied as an argument.
|
||||
/// </summary>
|
||||
/// <param name="data">Data telegram</param>
|
||||
/// <returns>Calculated CRC</returns>
|
||||
/// <returns>Calculated checksum</returns>
|
||||
public static byte ClaculateTelegramChecksum(byte[] data)
|
||||
{
|
||||
byte checksum = 0;
|
||||
@ -99,6 +99,21 @@ namespace TBF
|
||||
return checksum;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the checksum from a data telegram (an array of bytes).
|
||||
/// A complete telegram including one bytes reserved for the checksum
|
||||
/// must be supplied as an argument.
|
||||
/// </summary>
|
||||
/// <param name="hartPreambLen">Length of HART telegram preamble (FF bytes)</param>
|
||||
/// <param name="data">Data telegram</param>
|
||||
/// <returns>Calculated checksum</returns>
|
||||
public static byte ClaculateTelegramChecksum(int hartPreambLen, byte[] data)
|
||||
{
|
||||
byte checksum = 0;
|
||||
for (int i = hartPreambLen; i < data.Length - 1; i++) checksum = (byte)(checksum ^ data[i]);
|
||||
return checksum;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This function modifies the last byte in the message buffer
|
||||
/// by the checksum calculated from the remaining first (Lenght - 1) bytes.
|
||||
@ -113,6 +128,21 @@ namespace TBF
|
||||
data[len - 1] = ClaculateTelegramChecksum(data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This function modifies the last byte in the message buffer
|
||||
/// by the checksum calculated from the preceeding (Lenght - hartPreambLen - 1) bytes.
|
||||
/// First hartPreambLen bytes in the telegram are skipped.
|
||||
/// A complete telegram including preamble and one bytes reserved for the checksum
|
||||
/// after data bytes must be supplied as an argument.
|
||||
/// </summary>
|
||||
/// <param name="hartPreambLen">Length of HART telegram preamble (FF bytes)</param>
|
||||
/// <param name="data">Data telegram</param>
|
||||
public static void UpdateTelegramChecksum(int hartPreambLen, byte[] data)
|
||||
{
|
||||
if (data.Length - hartPreambLen < 1) return;
|
||||
data[data.Length - 1] = ClaculateTelegramChecksum(hartPreambLen, data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This function compares the last byte in the message buffer
|
||||
/// with the checksum calculated from the remaining first (Lenght - 1) bytes.
|
||||
@ -120,7 +150,7 @@ namespace TBF
|
||||
/// must be supplied as an argument.
|
||||
/// </summary>
|
||||
/// <param name="data">Data telegram</param>
|
||||
/// <returns>true if the CRC in the telegram is correct</returns>
|
||||
/// <returns>true if the checksum in the telegram is correct</returns>
|
||||
public static bool VerifyTelegramChecksum(byte[] data)
|
||||
{
|
||||
int len = data.Length;
|
||||
@ -128,6 +158,21 @@ namespace TBF
|
||||
return (data[len - 1] == ClaculateTelegramChecksum(data));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This function compares the last byte in the message buffer
|
||||
/// with the checksum calculated from the remaining first (Lenght - 1) bytes.
|
||||
/// A complete telegram including two bytes reserved for the checksum
|
||||
/// must be supplied as an argument.
|
||||
/// </summary>
|
||||
/// <param name="hartPreambLen">Length of HART telegram preamble (FF bytes)</param>
|
||||
/// <param name="data">Data telegram</param>
|
||||
/// <returns>true if the checksum in the telegram is correct</returns>
|
||||
public static bool VerifyTelegramChecksum(int hartPreambLen, byte[] data)
|
||||
{
|
||||
if (data.Length - hartPreambLen < 1) return false;
|
||||
return (data[data.Length - 1] == ClaculateTelegramChecksum(hartPreambLen, data));
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static string LogTelegram(string intro, byte[] data)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user