Ultrasound level meter modbus communication completed.

This commit is contained in:
Milan Hanajik 2018-10-01 11:19:57 +02:00
parent 2d484ea993
commit e5b61825ff
12 changed files with 374 additions and 73 deletions

View File

@ -56,6 +56,9 @@ namespace DeviceTest
static TBF.Boxes.FloatBox floatBox;
static TBF.Boxes.DoubleBox dblBox1;
static TBF.Boxes.DoubleBox dblBox2;
static TBF.Boxes.DoubleBox dblBox3;
static Event evnt;
@ -657,6 +660,12 @@ namespace DeviceTest
operation1 = (tbfComponent1forOp as TBF.BenchControl.Modbus.Easytherm.Easytherm).SetTemperatureOp(10);
operation2 = (tbfComponent1forOp as TBF.BenchControl.Modbus.Easytherm.Easytherm).SetTemperatureOp(20);
}
else if (tbfComponent1forOp is TBF.BenchControl.Modbus.UltrasoundLevelMeter.LevelMeter)
{
operation1 = (tbfComponent1forOp as TBF.BenchControl.Modbus.UltrasoundLevelMeter.LevelMeter).ReadLevelOp(ref dblBox1);
operation2 = (tbfComponent1forOp as TBF.BenchControl.Modbus.UltrasoundLevelMeter.LevelMeter).ReadVolumeOp(ref dblBox2);
operation3 = (tbfComponent1forOp as TBF.BenchControl.Modbus.UltrasoundLevelMeter.LevelMeter).ReadTempOp(ref dblBox3);
}
else if (tbfComponent1forOp is TBF.BenchControl.Modbus.TankSelector.TankSelector)
{
//operation1 = (tbfComponent1forOp as TBF.BenchControl.Modbus.TankSelector.TankSelector).SelectTankOp(1);
@ -681,8 +690,14 @@ namespace DeviceTest
}
else if (tbfComponent2forOp is TBF.BenchControl.Modbus.Easytherm.Easytherm)
{
operation21 = (tbfComponent1forOp as TBF.BenchControl.Modbus.Easytherm.Easytherm).SetTemperatureOp(10);
operation22 = (tbfComponent1forOp as TBF.BenchControl.Modbus.Easytherm.Easytherm).SetTemperatureOp(20);
operation21 = (tbfComponent2forOp as TBF.BenchControl.Modbus.Easytherm.Easytherm).SetTemperatureOp(10);
operation22 = (tbfComponent2forOp as TBF.BenchControl.Modbus.Easytherm.Easytherm).SetTemperatureOp(20);
}
else if (tbfComponent2forOp is TBF.BenchControl.Modbus.UltrasoundLevelMeter.LevelMeter)
{
operation21 = (tbfComponent2forOp as TBF.BenchControl.Modbus.UltrasoundLevelMeter.LevelMeter).ReadLevelOp(ref dblBox1);
operation22 = (tbfComponent2forOp as TBF.BenchControl.Modbus.UltrasoundLevelMeter.LevelMeter).ReadVolumeOp(ref dblBox2);
operation23 = (tbfComponent2forOp as TBF.BenchControl.Modbus.UltrasoundLevelMeter.LevelMeter).ReadTempOp(ref dblBox3);
}
else if (tbfComponent2forOp is TBF.BenchControl.Modbus.TankSelector.TankSelector)
{
@ -708,8 +723,14 @@ namespace DeviceTest
}
else if (tbfComponent3forOp is TBF.BenchControl.Modbus.Easytherm.Easytherm)
{
operation31 = (tbfComponent1forOp as TBF.BenchControl.Modbus.Easytherm.Easytherm).SetTemperatureOp(10);
operation32 = (tbfComponent1forOp as TBF.BenchControl.Modbus.Easytherm.Easytherm).SetTemperatureOp(20);
operation31 = (tbfComponent3forOp as TBF.BenchControl.Modbus.Easytherm.Easytherm).SetTemperatureOp(10);
operation32 = (tbfComponent3forOp as TBF.BenchControl.Modbus.Easytherm.Easytherm).SetTemperatureOp(20);
}
else if (tbfComponent3forOp is TBF.BenchControl.Modbus.UltrasoundLevelMeter.LevelMeter)
{
operation31 = (tbfComponent3forOp as TBF.BenchControl.Modbus.UltrasoundLevelMeter.LevelMeter).ReadLevelOp(ref dblBox1);
operation32 = (tbfComponent3forOp as TBF.BenchControl.Modbus.UltrasoundLevelMeter.LevelMeter).ReadVolumeOp(ref dblBox2);
operation33 = (tbfComponent3forOp as TBF.BenchControl.Modbus.UltrasoundLevelMeter.LevelMeter).ReadTempOp(ref dblBox3);
}
else if (tbfComponent3forOp is TBF.BenchControl.Modbus.TankSelector.TankSelector)
{
@ -720,10 +741,13 @@ namespace DeviceTest
}
int time = 0;
while (workerThreadRunning)
{
Thread.Sleep(1000);
StateMachine.Time = ++time;
if (workerThreadRunning)
{
foreach (var d in tbfDevices) d.RunDeviceBefore();

View File

@ -72,10 +72,10 @@ namespace DeviceTest
}
/// Configure and start logging
log4net.Config.XmlConfigurator.Configure(new System.IO.FileInfo(LocAppDataDir + log4netConfigFName));
log4net.Config.XmlConfigurator.Configure(new System.IO.FileInfo(Path.Combine(LocAppDataDir, log4netConfigFName)));
log = LogManager.GetLogger(typeof(Program));
log.Fatal("--------------------------------------------------------------------------------");
log.Fatal(string.Format("TBF ver.{0}", Version));
log.FatalFormat("DeviceTest ver.{0}", Version);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);

View File

@ -1,5 +1,5 @@
///
/// Copyright (c) 2013-2017 Sensus Metering Systems
/// Copyright (c) 2013-2018 Sensus Slovensko a.s.
///
namespace TBF.BenchControl
{
@ -93,6 +93,8 @@ namespace TBF.BenchControl
TempInDone,
TempOutDone,
TempDivDone,
LevelDone,
VolumeDone,
FlowMeasurementDone,
FlowReached,
PositionReached,

View File

@ -0,0 +1,37 @@
///
/// Copyright (c) 2018 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using Config.Entities;
using TBF.BenchControl.Generic;
using TBF.Boxes;
namespace TBF.BenchControl.GenericDevices
{
/// <summary>
/// Basic level meter functions
/// </summary>
public interface ILevelMeter
{
/// <summary>
/// Measurement correction table
/// </summary>
IList<MeasurementCorrection> Corrections { get; }
/// <summary>
/// Events: LevelDone, Error
/// </summary>
/// <param name="level">Reference to a variable for the measured level in mm</param>
/// <returns>ReadLevelOp instance reference casted to IOperaton</returns>
IOperation ReadLevelOp(ref DoubleBox level);
/// <summary>
/// Events: levelDone, Error
/// </summary>
/// <param name="level">Reference to a variable for the measured level in mm</param>
/// <param name="levelDone">Event returned when measurement done</param>
/// <returns>ReadLevelOp instance reference casted to IOperaton</returns>
IOperation ReadLevelOp(ref DoubleBox level, Event levelDone);
}
}

View File

@ -0,0 +1,34 @@
///
/// Copyright (c) 2018 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using Config.Entities;
using TBF.BenchControl.Generic;
using TBF.Boxes;
namespace TBF.BenchControl.GenericDevices
{
public interface IVolumeMeter
{
/// <summary>
/// Measurement correction table
/// </summary>
IList<MeasurementCorrection> Corrections { get; }
/// <summary>
/// Events: VolumeDone, Error
/// </summary>
/// <param name="volume">Reference to a variable for the measured volume in l</param>
/// <returns>ReadPressureOp instance reference casted to IOperaton</returns>
IOperation ReadVolumeOp(ref DoubleBox volume);
/// <summary>
/// Events: volumeDone, Error
/// </summary>
/// <param name="volume">Reference to a variable for the measured volume in l</param>
/// <param name="volumeDone">Event returned when measurement done</param>
/// <returns>ReadPressureOp instance reference casted to IOperaton</returns>
IOperation ReadVolumeOp(ref DoubleBox volume, Event volumeDone);
}
}

View File

@ -6,10 +6,12 @@ using System.Collections.Generic;
using log4net;
using TBF.BenchControl.Generic;
using TBF.Boxes;
using Config.Entities;
using System.Diagnostics;
namespace TBF.BenchControl.Modbus.UltrasoundLevelMeter
{
public class LevelMeter : ComponentBase, GenericDevices.IPressureMeter, IDevice
public class LevelMeter : ComponentBase, GenericDevices.ILevelMeter, GenericDevices.IVolumeMeter, GenericDevices.ITempMeter, IDevice
{
private static readonly ILog log = LogManager.GetLogger(typeof(LevelMeter));
public override string ToString() { return string.Format("LevelMeter({0})", Cfg.ToString(1)); }
@ -17,9 +19,22 @@ namespace TBF.BenchControl.Modbus.UltrasoundLevelMeter
readonly LevelMeterCfg myCfg;
readonly GenericDevices.IModbus modbus;
private float receivedLevel;
/// <summary>The state of the measurement</summary>
MsrmntState msrmntState;
///
/// Measured values when MsrmntState == MsrmntState.Valid
///
double distance; /// [mm]
double level; /// [mm]
double percentage; /// [%]
double volume; /// [l]
double temperature; /// [°C]
ushort state;
/// <summary>Measurement time stamp when MsrmntState == MsrmntState.Valid</summary>
int msrmntTimeStamp;
const ushort WatchdogBitMask = 0x0010;
public LevelMeter()
{
@ -42,38 +57,37 @@ namespace TBF.BenchControl.Modbus.UltrasoundLevelMeter
/// <summary>Initialize this device</summary>
public void Initialize()
{
}
/// <summary>
/// Returns the water pressure
/// </summary>
/// <returns>Pressure in mBar</returns>
public float ReadLevel()
if (myCfg.DebugLevel == DebugMode.Simulate)
{
return (float)Config.Units.ConvertFrom(Config.Unit.mm, receivedLevel);
distance = 200.0;
level = 0;
percentage = 0;
volume = 0;
temperature = 20.0;
state = 0;
msrmntTimeStamp = StateMachine.Time;
msrmntState = MsrmntState.Valid;
return;
}
/// <summary>
/// Events: PressureDone, Error
/// </summary>
/// <param name="pressure">Reference to a variable for the pressure in Bar</param>
/// <returns>ReadPressureOp instance reference casted to IOperaton</returns>
public IOperation ReadPressureOp(ref FloatBox pressure)
{
return new ReadLevelOp(this, ref pressure);
msrmntState = MsrmntState.Busy;
log.FatalFormat("Successfully initialized device {0}", ToString());
}
/// <summary>
/// Events: pressureDone, Error
/// </summary>
/// <param name="pressure">Reference to a variable for the pressure in Bar</param>
/// <param name="pressureDone">Event returned when measurement done</param>
/// <returns>ReadPressureOp instance reference casted to IOperaton</returns>
public IOperation ReadPressureOp(ref FloatBox pressure, Event pressureDone)
{
return new ReadLevelOp(this, ref pressure, pressureDone);
}
public double ReadLevel() { return level; } /// Returns water level in mm
public double ReadVolume() { return volume; } /// Returns volume in l
public double ReadTemperature() { return temperature; } /// Returns temperature in °C
public IOperation ReadLevelOp(ref DoubleBox level) { return new ReadLevelOp(this, ref level); }
public IOperation ReadVolumeOp(ref DoubleBox volume) { return new ReadVolumeOp(this, ref volume); }
public IOperation ReadTempOp(ref DoubleBox temperature) { return new ReadTempOp(this, ref temperature); }
public IOperation ReadLevelOp(ref DoubleBox level, Event eventDone) { return new ReadLevelOp(this, ref level, eventDone); }
public IOperation ReadVolumeOp(ref DoubleBox volume, Event eventDone) { return new ReadVolumeOp(this, ref volume, eventDone); }
public IOperation ReadTempOp(ref DoubleBox temperature, Event eventDone) { return new ReadTempOp(this, ref temperature, eventDone); }
/// <summary>Run this device</summary>
@ -82,33 +96,86 @@ namespace TBF.BenchControl.Modbus.UltrasoundLevelMeter
if (myCfg.DebugLevel == Config.Entities.DebugMode.Simulate ||
myCfg.DebugLevel == Config.Entities.DebugMode.FailureDuringOperation)
{
msrmntTimeStamp = StateMachine.Time;
return;
}
if (modbus.ReceivedTelegrams[myCfg.ModbusAddress].Count > 0)
{
byte[] telegram = modbus.ReceivedTelegrams[myCfg.ModbusAddress].Dequeue();
if (telegram.Length == 9 && telegram[1] == 4 && telegram[2] == 4)
{
/// Swap byte order
byte t1 = telegram[3];
byte t2 = telegram[4];
byte t3 = telegram[5];
byte t4 = telegram[6];
telegram[3] = t4;
telegram[4] = t3;
telegram[5] = t2;
telegram[6] = t1;
receivedLevel = System.BitConverter.ToSingle(telegram, 3);
if (telegram.Length == 15 && telegram[1] == 3 && telegram[2] == 10)
{
distance = (double)(256 * telegram[3] + telegram[4]);
level = (double)(256 * telegram[5] + telegram[6]);
percentage = (double)(256 * telegram[7] + telegram[8]);
temperature = (double)256 * telegram[9] + telegram[10];
state = (ushort)(256 * telegram[11] + telegram[12]);
volume = 0; /// TODO
string line = string.Format("dist={0} mm level={1} mm, %={2} %, temp={3} °C, volume={4} l, state={5}",
distance, level, percentage, temperature, volume, state);
log.Debug(line);
Debug.WriteLine(line);
}
}
if ((StateMachine.Time % 3) == (myCfg.ModbusAddress % 3)) /// Each 3 seconds
byte[] msg = new byte[8]; /// Buffer for data to send
if ((StateMachine.Time % 3) == 0) /// Each 3 seconds
{
const byte Function = 4; /// Read input registers
const ushort Address = 0; /// Pressure
modbus.SendMessage(myCfg.ModbusAddress, Function, Address, 2);
///
/// Read distance, level, quantity, percentage and temperature in IEEE754 (DWORD-s)
///
UInt16 regAddr = 100;
UInt16 count = 5;
/// Prepare data to be sent
msg[0] = myCfg.ModbusAddress;
msg[1] = 3; /// CMD =
msg[2] = (byte)(regAddr >> 8); /// Control Word Hi
msg[3] = (byte)(regAddr & 0xFF); /// Control Word Lo
msg[4] = (byte)(count >> 8); /// Serial Com Reference Hi
msg[5] = (byte)(count & 0xFF); /// Serial Com Reference Lo
modbus.SendMessage(msg);
}
else if ((StateMachine.Time % 3) == 1) /// Each 3 seconds
{
/////
///// Read STATUS1
/////
//UInt16 regAddr = 104;
//UInt16 count = 1;
///// Prepare data to be sent
//msg[0] = myCfg.ModbusAddress;
//msg[1] = 3; /// CMD =
//msg[2] = (byte)(regAddr >> 8); /// Control Word Hi
//msg[3] = (byte)(regAddr & 0xFF); /// Control Word Lo
//msg[4] = (byte)(count >> 8); /// Serial Com Reference Hi
//msg[5] = (byte)(count & 0xFF); /// Serial Com Reference Lo
//modbus.SendMessage(msg);
}
else if ((StateMachine.Time % 3) == 2) /// Each 3 seconds
{
/////
///// Read distance, level, quantity, percentage and temperature in IEEE754 (DWORD-s)
/////
//UInt16 regAddr = 300;
//UInt16 count = 10;
///// Prepare data to be sent
//msg[0] = myCfg.ModbusAddress;
//msg[1] = 3; /// CMD =
//msg[2] = (byte)(regAddr >> 8); /// Control Word Hi
//msg[3] = (byte)(regAddr & 0xFF); /// Control Word Lo
//msg[4] = (byte)(count >> 8); /// Serial Com Reference Hi
//msg[5] = (byte)(count & 0xFF); /// Serial Com Reference Lo
//modbus.SendMessage(msg);
}
}

View File

@ -37,7 +37,7 @@ namespace TBF.BenchControl.Modbus.UltrasoundLevelMeter
///
/// Serialized parameters
///
public byte ModbusAddress; /// 1..255
public byte ModbusAddress; /// 1..247
/// Private parameterless constructor invoked by all other (public) constructors
LevelMeterCfg() {}
@ -55,7 +55,7 @@ namespace TBF.BenchControl.Modbus.UltrasoundLevelMeter
public void InitializeAll()
{
ModbusAddress = 49;
ModbusAddress = 1;
}
@ -111,8 +111,9 @@ namespace TBF.BenchControl.Modbus.UltrasoundLevelMeter
switch (i)
{
case 0:
if (int.TryParse(strValue, out dummy) && dummy >= 0 && dummy <= 255) return true;
break;
if (int.TryParse(strValue, out dummy) && dummy >= 1 && dummy <= 247) return true;
message = ParamName(i) + " is invalid. Address range is 1 .. 247";
return false;
default:
message = "Invalid index";
return false;

View File

@ -17,25 +17,25 @@ namespace TBF.BenchControl.Modbus.UltrasoundLevelMeter
readonly Event eventDone;
/// Measured value
FloatBox level;
DoubleBox level;
/// <summary>
/// Events: PressureInDone, PressureOutDone or Error
/// Events: LevelDone or Error
/// </summary>
/// <param name="levelMeter">Pressure meter reference</param>
/// <param name="pressure">Reference to the measured pressure variable, value is in bar</param>
/// <param name="levelMeter">Water level meter reference</param>
/// <param name="level">Reference to the measured level variable, value is in mm</param>
/// <param name="eventDone">Event to be returned by Run() when completed OK</param>
public ReadLevelOp(LevelMeter levelMeter, ref FloatBox pressure, Event eventDone)
public ReadLevelOp(LevelMeter levelMeter, ref DoubleBox level, Event eventDone)
{
if (levelMeter == null) throw new ArgumentNullException("levelMeter");
this.levelMeter = levelMeter;
this.level = pressure;
this.level = level;
this.eventDone = eventDone;
log.Debug(this.ToString());
}
public ReadLevelOp(LevelMeter pressureMeter, ref FloatBox pressure)
: this(pressureMeter, ref pressure, Event.PressureDone)
public ReadLevelOp(LevelMeter levelMeter, ref DoubleBox level)
: this(levelMeter, ref level, Event.LevelDone)
{
}
@ -48,7 +48,7 @@ namespace TBF.BenchControl.Modbus.UltrasoundLevelMeter
/// <summary>Run this operation</summary>
/// <returns>
/// Event.PressureInDone or Event.PressureOutDone
/// Event.LevelDone
/// </returns>
public Event Run()
{

View File

@ -0,0 +1,64 @@
///
/// Copyright (c) 2018 Sensus Slovensko a.s.
///
using System;
using log4net;
using TBF.Boxes;
namespace TBF.BenchControl.Modbus.UltrasoundLevelMeter
{
public class ReadTempOp : IOperation
{
private static readonly ILog log = LogManager.GetLogger(typeof(ReadTempOp));
public override string ToString() { return string.Format("ReadTempOp(.,{0},.)", eventDone); }
/// Set by the constructor
readonly LevelMeter levelMeter;
readonly Event eventDone;
/// Measured value
DoubleBox temperature;
/// <summary>
/// Events: eventDone or Error
/// </summary>
/// <param name="levelMeter">Water temperature meter reference</param>
/// <param name="temperature">Reference to the measured temperature variable, value is in l</param>
/// <param name="eventDone">Event to be returned by Run() when completed OK</param>
public ReadTempOp(LevelMeter levelMeter, ref DoubleBox temperature, Event eventDone)
{
if (levelMeter == null) throw new ArgumentNullException("levelMeter");
this.levelMeter = levelMeter;
this.temperature = temperature;
this.eventDone = eventDone;
log.Debug(this.ToString());
}
public ReadTempOp(LevelMeter levelMeter, ref DoubleBox temperature)
: this(levelMeter, ref temperature, Event.TempDone)
{
}
/// <summary>Start this operation</summary>
public void Start()
{
temperature.Val = levelMeter.ReadTemperature();
}
/// <summary>Run this operation</summary>
/// <returns>
/// Event.temperatureDone
/// </returns>
public Event Run()
{
temperature.Val = levelMeter.ReadTemperature();
return eventDone;
}
/// <summary>Stop this operation</summary>
public void Stop()
{
}
}
}

View File

@ -0,0 +1,64 @@
///
/// Copyright (c) 2018 Sensus Slovensko a.s.
///
using System;
using log4net;
using TBF.Boxes;
namespace TBF.BenchControl.Modbus.UltrasoundLevelMeter
{
public class ReadVolumeOp : IOperation
{
private static readonly ILog log = LogManager.GetLogger(typeof(ReadVolumeOp));
public override string ToString() { return string.Format("ReadVolumeOp(.,{0},.)", eventDone); }
/// Set by the constructor
readonly LevelMeter levelMeter;
readonly Event eventDone;
/// Measured value
DoubleBox volume;
/// <summary>
/// Events: VolumeDone or Error
/// </summary>
/// <param name="levelMeter">Water volume meter reference</param>
/// <param name="volume">Reference to the measured volume variable, value is in l</param>
/// <param name="eventDone">Event to be returned by Run() when completed OK</param>
public ReadVolumeOp(LevelMeter levelMeter, ref DoubleBox volume, Event eventDone)
{
if (levelMeter == null) throw new ArgumentNullException("levelMeter");
this.levelMeter = levelMeter;
this.volume = volume;
this.eventDone = eventDone;
log.Debug(this.ToString());
}
public ReadVolumeOp(LevelMeter levelMeter, ref DoubleBox volume)
: this(levelMeter, ref volume, Event.VolumeDone)
{
}
/// <summary>Start this operation</summary>
public void Start()
{
volume.Val = levelMeter.ReadVolume();
}
/// <summary>Run this operation</summary>
/// <returns>
/// Event.VolumeDone
/// </returns>
public Event Run()
{
volume.Val = levelMeter.ReadVolume();
return eventDone;
}
/// <summary>Stop this operation</summary>
public void Stop()
{
}
}
}

View File

@ -121,7 +121,11 @@ namespace TBF.BenchControl
/// <summary>
/// Current state name
/// </summary>
public static int Time { get { return currentTimeSec; } }
public static int Time
{
get { return currentTimeSec; }
set { currentTimeSec = value; }
}
/// <summary>
/// Constructor

View File

@ -516,6 +516,7 @@
<Compile Include="BenchControl\GenericDevices\ICameraDisplay.cs" />
<Compile Include="BenchControl\GenericDevices\IDataEntryForCamera.cs" />
<Compile Include="BenchControl\GenericDevices\IErrorFlags.cs" />
<Compile Include="BenchControl\GenericDevices\ILevelMeter.cs" />
<Compile Include="BenchControl\GenericDevices\IPlotter.cs" />
<Compile Include="BenchControl\GenericDevices\IRoiForFixedStart.cs" />
<Compile Include="BenchControl\GenericDevices\IScaleCfg.cs" />
@ -530,6 +531,7 @@
<Compile Include="BenchControl\GenericDevices\ITankDraining.cs" />
<Compile Include="BenchControl\GenericDevices\ITankDrainingCfg.cs" />
<Compile Include="BenchControl\GenericDevices\ITestMethodWith2ndPass.cs" />
<Compile Include="BenchControl\GenericDevices\IVolumeMeter.cs" />
<Compile Include="BenchControl\Hart\Common\Factory.cs" />
<Compile Include="BenchControl\Hart\Common\Hart.cs" />
<Compile Include="BenchControl\Hart\Common\HartCfg.cs" />
@ -658,6 +660,8 @@
<Compile Include="BenchControl\Modbus\UltrasoundLevelMeter\LevelMeter.cs" />
<Compile Include="BenchControl\Modbus\UltrasoundLevelMeter\LevelMeterCfg.cs" />
<Compile Include="BenchControl\Modbus\UltrasoundLevelMeter\ReadLevelOp.cs" />
<Compile Include="BenchControl\Modbus\UltrasoundLevelMeter\ReadTempOp.cs" />
<Compile Include="BenchControl\Modbus\UltrasoundLevelMeter\ReadVolumeOp.cs" />
<Compile Include="BenchControl\Network\Adapter\AdapterInfo.cs" />
<Compile Include="BenchControl\Network\Adapter\Netadapter.cs" />
<Compile Include="BenchControl\Network\Adapter\Factory.cs" />