tbf/TBF/BenchControl/Hart/Nivotrack/Nivotrack.cs

219 lines
5.7 KiB
C#
Raw Normal View History

///
/// 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.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, ILevelMeter, IOperation
{
private static readonly ILog log = LogManager.GetLogger(typeof(Nivotrack));
public override string ToString() { return string.Format("{0}({1})", Cfg.Name, Cfg.ToString(-1)); }
private readonly NivotrackCfg nivotrackCfg;
private readonly IHart hart;
bool readingValid;
double rawLevel_mm;
public double Level { get { return ReadLevel(); } }
DoubleBox levelBox;
double sdev;
enum CurrentOp
{
None,
ReadLevel,
ReadStableLevel,
}
CurrentOp currentOp;
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, IList<Generic.IComponent> components)
: base(cfg)
{
nivotrackCfg = cfg as NivotrackCfg;
hart = (IHart)TbfComponents.FindComponent(cfg.ParentName, components);
if (hart == null) throw new Exception("Cannot find " + Name + " parent");
log.Debug(this.ToString());
}
public void Initialize()
{
if (nivotrackCfg.DebugLevel == DebugMode.Simulate) return;
rawLevel_mm = 0;
readingValid = false;
}
void Detect()
{
byte bcnt = (byte)0; /// block count
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
hart.SendMessage(5, data);
}
void RequestProcessValue()
{
byte bcnt = (byte)0; /// block count
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)
{
byte[] data = hart.ReceivedTelegrams[nivotrackCfg.Address].Dequeue();
if ((data.Length == 12) && (data[0] == (byte)Mark.ShortFrameSlave2Master)
&& (data[2] == (byte)Cmd.ReadPrimaryVar)
&& (data[3] == 7))
{
///
/// A frame with a status and a primary variable
///
ushort state = (ushort)(256 * data[4] + data[5]);
byte unitsID = data[6];
byte[] floatData = new byte[] { data[10], data[9], data[8], data[7] };
rawLevel_mm = System.BitConverter.ToSingle(floatData, 0);
readingValid = true;
string msg = string.Format("{0} : Received water level = {1} mm, State = {2}", Name, rawLevel_mm, state.ToString("X4"));
Debug.WriteLine(msg);
log.Info(msg);
}
else if ((data.Length == 7) && (data[0] == (byte)Mark.ShortFrameSlave2Master)
&& (data[2] == (byte)Cmd.ReadPrimaryVar)
&& (data[3] == 2))
{
///
/// 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);
}
}
}
public void RunDeviceAfter()
{
if (nivotrackCfg.DebugLevel == DebugMode.Simulate) return;
if ((StateMachine.Time % 2) == (nivotrackCfg.Address % 2))
{
RequestProcessValue();
}
}
public void StopDevice() { }
public void StopDevice2() { }
/// <summary>
/// Gets the most recent raw level measurement and applies correction table
/// </summary>
/// <returns></returns>
public double ReadLevel()
{
return Config.Formulas.CorrectedValue(rawLevel_mm, Corrections);
}
/// <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;
}
/// <returns>Reference to the operation</returns>
public IOperation ReadStableLevelOp(ref DoubleBox levelBox, double sdev)
{
if (currentOp != CurrentOp.None) throw new Exception("Sequence error");
this.levelBox = levelBox;
this.sdev = sdev;
currentOp = CurrentOp.ReadStableLevel;
return this;
}
/// <summary>Start this operation</summary>
public void Start()
{
if (readingValid && (levelBox != null))
{
levelBox.Val = ReadLevel();
}
}
/// <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;
}
}
}