tbf/TestBenchFramework/BenchControl/Keithley/Multimeter_2010_RS232/Multimeter.cs
2016-08-23 15:21:17 +02:00

260 lines
6.6 KiB
C#

///
/// Copyright (c) 2016 Sensus Metering Systems
///
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO.Ports;
using System.Text;
using System.Threading;
using log4net;
using Config.Entities;
using TBF.BenchControl.Generic;
using TBF.Boxes;
namespace TBF.BenchControl.Keithley.Multimeter_2010_RS232
{
/// <summary>
/// Root component for Modbus communication via serial port (RS485)
/// </summary>
public class Multimeter : ComponentBase, IDevice
{
private static readonly ILog log = LogManager.GetLogger(typeof(Multimeter));
public override string ToString() { return string.Format("{0}({1})", GetType().Namespace.Substring(17), Cfg.ToString(1)); }
private readonly MultimeterCfg multimeterCfg;
///
/// Main result
///
public const int ChannelFrom = 1;
public const int ChannelTo = 5;
///
public double[] Resistance; /// ChannelNr in range <ChannelFrom, ChannelTo> is used as an index to this array
/// Private fields
SerialPort serialPort;
IList<int> listOfReadOperations;
IList<int> listOfChannels;
int nextChannelIx; /// index to listOfChannels
int currentChannel; /// current channel (ChannelFrom .. ChannelTo), 0 = invalid, updated when sending :rout:clos command
enum ScanState
{
Off,
Start_Reset,
Reset_SwitchCh,
SwitchCh_Read,
Read_SwitchCh,
}
ScanState scanState;
public Multimeter()
{
Resistance = new double[ChannelTo + 1];
}
/// <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 Multimeter(Generic.IComponentCfg cfg)
: base(cfg)
{
multimeterCfg = cfg as MultimeterCfg;
serialPort = null;
Resistance = new double[ChannelTo + 1];
for (int i = 0; i < Resistance.Length; i++) Resistance[i] = 0;
listOfReadOperations = new List<int>();
listOfChannels = new List<int>();
nextChannelIx = 0;
currentChannel = 0; /// invalid, no :rout:clos command yet
scanState = ScanState.Off;
log.Debug(this.ToString());
}
~Multimeter()
{
}
/// <summary>
/// Start reading temperature from specified channel
/// </summary>
/// <param name="channel">channel in range ChannelFrom .. ChannelTo</param>
/// <returns>true when successful</returns>
public bool StartReadingMultimeter(int channel)
{
log.DebugFormat("StartReadingMultimeter({0})", channel);
if (channel < ChannelFrom || channel > ChannelTo) return false; /// Invalid channel
listOfReadOperations.Add(channel);
if (!listOfChannels.Contains(channel))
{
listOfChannels.Add(channel);
if (listOfChannels.Count == 1) StartScanning(); /// Count changed from 0 to 1
}
return true;
}
/// <summary>
/// Stop reading temperature from specified channel
/// </summary>
/// <param name="channel">channel in range ChannelFrom .. ChannelTo</param>
/// <returns>true when successful</returns>
public bool StopReadingMultimeter(int channel)
{
log.DebugFormat("StopReadingMultimeter({0})", channel);
if (channel < ChannelFrom || channel > ChannelTo) return false; /// Invalid channel
if (!listOfReadOperations.Remove(channel)) return false; /// Channel not found on the list (no matching StartReading...)
for (int i = 0; i < listOfChannels.Count; i++)
{
if (listOfChannels[i] == channel)
{
listOfChannels.RemoveAt(i);
if (listOfChannels.Count == 0)
{
StopScanning();
}
else if (nextChannelIx > i)
{
nextChannelIx--;
}
}
}
return true;
}
public double ReadResistance(int channelNr)
{
if (channelNr < ChannelFrom || channelNr > ChannelTo) return 0;
return Resistance[channelNr];
}
private void StartScanning()
{
for (int i = 0; i < Resistance.Length; i++) Resistance[i] = 0; /// Reset resistances (0 == invalid)
///
nextChannelIx = 0;
currentChannel = 0; /// invalid, no :rout:clos command yet
scanState = ScanState.Start_Reset;
}
private void StopScanning()
{
scanState = ScanState.Off;
}
public void Initialize()
{
if (multimeterCfg.DebugLevel == DebugMode.Simulate)
{
log.FatalFormat("Simulated device {0}", ToString());
return;
}
string comPortName = "COM" + multimeterCfg.ComPortNr.ToString();
serialPort = new SerialPort(comPortName, multimeterCfg.BaudRate, multimeterCfg.Parity, multimeterCfg.DataBits, multimeterCfg.StopBits);
serialPort.Handshake = multimeterCfg.Handshake;
serialPort.Open();
log.FatalFormat("Successfully initialized device {0}", ToString());
}
public void SendMessage(string message)
{
if (multimeterCfg.DebugLevel == DebugMode.Simulate) return;
serialPort.Write(message + "\r\n");
log.DebugFormat("Sending message {0}", message);
}
/// <summary>Run this device</summary>
public void RunDeviceBefore()
{
if ((scanState == ScanState.Read_SwitchCh) && (currentChannel >= ChannelFrom) && (currentChannel <= ChannelTo))
{
string completeStr = serialPort.ReadExisting();
int len = completeStr.Length - 2;
if (len > 0)
{
string resStr = completeStr.Substring(0, len);
log.DebugFormat("Received message {0}", resStr);
double res;
if (completeStr.IndexOf("\r\n") == len &&
double.TryParse(resStr, NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingSign, CultureInfo.InvariantCulture, out res))
{
Resistance[currentChannel] = res;
}
}
}
}
/// <summary>Run this device</summary>
public void RunDeviceAfter()
{
switch (scanState)
{
case ScanState.Start_Reset:
SendMessage("*RST");
SendMessage("*CLS");
SendMessage(":conf:fres");
scanState = ScanState.Reset_SwitchCh;
return;
case ScanState.Reset_SwitchCh:
case ScanState.Read_SwitchCh:
if (nextChannelIx >= 0 && nextChannelIx < listOfChannels.Count)
{
/// Update 'curentChannel'
currentChannel = listOfChannels[nextChannelIx];
/// Switch to the 'curentChannel'
SendMessage(string.Format(":rout:clos (@{0})", currentChannel));
/// Increase 'nextChannelIx'
nextChannelIx++;
if (nextChannelIx >= listOfChannels.Count) nextChannelIx = 0;
}
scanState = ScanState.SwitchCh_Read;
return;
case ScanState.SwitchCh_Read:
SendMessage(":read?");
scanState = ScanState.Read_SwitchCh;
return;
default: /// Scanning is off
return;
}
}
/// <summary>Stop this device</summary>
public void StopDevice()
{
serialPort.Close();
}
}
}