using System;
using NLog;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using Newtonsoft.Json;
using Xylem.Common.CommonCore.Consts;
using Xylem.Common.Hardware.Interfaces.Ports.PortCore;
using Xylem.Common.Hardware.Interfaces.Ports.PortCore.EventArguments;
using Xylem.Common.Hardware.Interfaces.Ports.SerialPorts;
using Xylem.Common.Hardware.Interfaces.Protocols.ProtocolCore;
using Xylem.Common.Hardware.Interfaces.Protocols.ProtocolCore.EventArguments;
using Xylem.Common.Hardware.Interfaces.Protocols.TransmitProtocol;
using Xylem.Common.Hardware.WaterMeter.MagFlux.DataPackages.DataTypes;
using Xylem.Common.Hardware.WaterMeter.MagFlux.Protocols.StreamingProtocol;
using Xylem.Common.Hardware.WaterMeter.MagFlux.DataPackages.EventArguments;
using Xylem.Common.Hardware.WaterMeter.MagFlux.DataPackages.MeasurementRecords;
using Xylem.Common.Hardware.WaterMeter.MagFlux.MagFluxConfig;
using Xylem.Common.Hardware.WaterMeter.MagFlux.Protocols.RequestProtocol;
using Xylem.Common.Hardware.WaterMeter.WaterMeterCore;
using Xylem.Common.Hardware.WaterMeter.WaterMeterCore.Consts;
using Xylem.Common.Metrology.Measurements;
using Xylem.Common.Metrology.Measurements.Consts;
using Xylem.Common.Utils.Logging;
using XYLEM.Device;
namespace Xylem.Common.Hardware.WaterMeter.MagFlux.MagFluxCore
{
///
///
/// MagFlux meter is the core class for the MJK MagFlux water meter.
/// One meter always is always linked to two port, one for communication and one for LED streaming.
///
public class MagFluxMeter : IMeter, IMeterEvents
{
#region Variables and Properties
///
/// Mark the streaming catcher as active
///
private Boolean _streamingCatcherIsActive;
///
/// Enable raw record logging, if set every incoming package will be logged
///
private Boolean _enableRawDataLogging;
///
/// to reduce the IrdA communication in test bench, preparation will be done once (when SkipPreparationForTestBench is true)
///
public Boolean SkipPreparationForTestBench
{
get; set;
}
///
/// List of ongoing measurements, base- and calibration-measurements
///
private List _listOfIMeasurement = new List();
///
/// Quality watch mode can be used to decode intermediate records and check
/// for actual quality of the measurements.
///
public Boolean QualityWatchMode;
///
/// Represent FW version
///
public String FwVersion
{
get;
private set;
} = "?";
///
/// Represent meter size in mm
///
public Int32 MeterSizeMm
{
get;
private set;
}
///
/// Represent FW version
///
public String FwBuildDate
{
get;
private set;
} = "?";
///
/// Represent FW GIT hash
///
public String FwGitHash
{
get;
private set;
} = "?";
///
/// Represent pcb serial number
///
public String PcbId
{
get; private set;
}
///
/// Represent unique id
///
public String UniqueId
{
get; private set;
}
private String _currentActionText = "";
///
/// Hold the current process name e.g. FlowTest, Preadjustment for logging
///
public String CurrentActionText
{
get => _currentActionText;
set
{
_currentActionText = value;
SetLogger();
}
}
/////
///// Add on ctor a password and it will be used for login in if no other password is set
/////
//private String _password;
///
/// request port assignment/info
///
private IPort RequestPort
{
get;
set;
}
///
/// request protocol assignment/info
///
private RequestProtocol RequestProtocol;
///
/// streaming port assignment/info
///
private IPort StreamingPort
{
get;
set;
}
///
/// streaming protocol assignment/info
///
private StreamingProtocol StreamingProtocol;
///
public String SerialNumber
{
get; set;
}
///
/// do not use it to set ProcessStatus
/// if you want to change ProcessStatus of this genesis use
/// is just store for some routines
///
private ProcessState _myProcessStatus;
///
/// if state is change
///
/// will be invoked.
/// on some states other events will be invoke as well
public ProcessState ProcessStatus
{
get => _myProcessStatus;
private set
{
if (_myProcessStatus == value)
{
return;
}
_myProcessStatus = value;
Invoker(OnProcessStatusChanged);
switch (value)
{
case ProcessState.InitIsActive:
Invoker(OnInitCompleted);
break;
case ProcessState.MeasurementIsActive:
Invoker(OnMeasurementInitCompleted);
break;
case ProcessState.MeasurementIsDone:
Invoker(OnMeasurementCompleted);
break;
case ProcessState.CalibrationIsActive:
Invoker(OnCalibInitCompleted);
break;
case ProcessState.CalibrationIsDone:
Invoker(OnCalibCompleted);
break;
case ProcessState.QRefDone:
case ProcessState.WaitForQRef:
case ProcessState.WaitForCalibration:
case ProcessState.WaitForMeasurement:
case ProcessState.IsNotInit:
//no extra event needed
break;
default:
throw new OverflowException("MagFlux measurement unknown process status");
}
}
}
public Boolean IsLoggedOn
{
private set;
get;
}
///
public ErrorState ErrorStatus
{
private set;
get;
} = ErrorState.None;
///
public Int32 Slot
{
get; set;
}
///
public Int32 IntermediateUpdateTimeS
{
get;
set;
} = CommunicationConfig.MeasurementUpdateTimeS;
///
/// Process configuration
///
public ProcessConfig Configuration = new ProcessConfig();
///
/// Transmit protocol access for underlie objects to change response timeout
///
private ITransmitProtocol TransmitProtocol;
//initially do not signal event
private readonly AutoResetEvent _onSyncKeepSessionThread = new AutoResetEvent(false);
private Thread _keepSessionThread;
private readonly CancellationTokenSource _keepSessionToken = new CancellationTokenSource();
private ILogger _logger;
#endregion
#region Events
event EventHandler IMeter.OnDisposeCompleted
{
add
{
// throw new NotImplementedException();
}
remove
{
// throw new NotImplementedException();
}
}
//public event EventHandler HasInformationForCaller;
///
public event EventHandler OnCalibCompleted;
///
public event EventHandler OnErrorStatusChanged;
///
public event EventHandler OnProcessStatusChanged;
///
public event EventHandler OnCalibInitCompleted;
///
public event EventHandler OnInitCompleted;
///
public event EventHandler OnMeasurementInitCompleted;
///
public event EventHandler OnMeasurementCompleted;
///
/// Response received after request for record
///
public event EventHandler OnRequestRecordReceived;
///
/// Streaming record is decoded
///
public event EventHandler OnStreamingRecordDecoded;
/////
///// call this if session is expired and you need an re-authorization
/////
//public EventHandler AuthorizationRequired;
///
/// A helper to invoke events only if someone is listening, otherwise nothing will happen
///
/// Event handler to call
/// Sender (can be null)
/// Event arguments (can be null)
private void Invoker(EventHandler handler, Object sender = null, EventArgs e = null)
{
if (handler != null)
{
if (sender == null)
{
sender = this;
}
if (e == null)
{
e = new EventArgs();
}
handler.Invoke(sender, e);
}
// ReSharper disable once RedundantIfElseBlock
else
{
//nobody is listening
}
}
///
/// Track all incoming led record packages (Calibration and Flow)
///
///
///
/// I should be
/// otherwise this method does nothing
///
private void StreamingProtocol_ApplyDecodedRecord(Object sender, BaseDataEventArgs e)
{
var result = e.GetEventData();
if (result is IMeasurementRecord)
{
if (result is MagFluxRecord)
{
if (!((MagFluxRecord)result).IsValid)
{
return;
}
}
AddData(((IMeasurementRecord)result));
}
}
///
/// tracking request record processing
///
///
///
private void RequestProtocol_ApplyDecodedRecord(Object sender, BaseDataEventArgs e)
{
if (e is RequestResponseDataEventArgs)
{
OnRequestRecordReceived?.Invoke(sender, (RequestResponseDataEventArgs)e);
}
}
///
/// Kick off the streaming catcher.
///
public void StartStreamingCatcher()
{
if (_streamingCatcherIsActive)
{
return;
}
if (!(StreamingPort is LedSerialPort))
{
throw new ApplicationException("No valid streaming port");
}
SyncStreamingBuffer(SyncMarkRecord.DecodeEveryPackage);
StreamingProtocol.OnRecordIsDecoded += StreamingCatcher_OnRawRecordReceived;
LogRawData(true);
_streamingCatcherIsActive = true;
}
///
/// Cyclic execution of catcher on incoming events.
///
///
///
private void StreamingCatcher_OnRawRecordReceived(Object sender, BaseDataEventArgs e)
{
OnStreamingRecordDecoded?.Invoke(this, (MagFluxFlowDataEventArgs)e);
}
///
/// Stop the streaming catcher.
///
///
public void StopStreamingCatcher()
{
if (StreamingPort == null || !(StreamingPort is LedSerialPort))
{
throw new ApplicationException("No valid streaming port");
}
LogRawData(false);
StreamingProtocol.OnRecordIsDecoded -= StreamingCatcher_OnRawRecordReceived;
SyncStreamingBuffer(SyncMarkRecord.SkipDecoding);
_streamingCatcherIsActive = false;
}
#endregion
#region class handling
///
/// Ctor - default
///
///
/// - Initial
///
public MagFluxMeter()
{
}
///
public void Dispose()
{
_logger.Trace($"Slot:{Slot} - Start to dispose");
StreamingProtocol.OnRecordIsDecoded -= StreamingProtocol_ApplyDecodedRecord;
RequestProtocol.OnRecordIsDecoded -= RequestProtocol_ApplyDecodedRecord;
LogRawData(false);
LogManager.Flush();
//isPart of Logout
//StopKeepSession();
//Cancel receive tokens
_keepSessionToken?.Cancel();
try
{
Logout();
}
catch (Exception)
{
// ignored
}
//Run thread again to notice CancellationToken has changed
_onSyncKeepSessionThread?.Set();
//this timeout counter is being used for dispose only
var timeoutCounter = 100;
if (_keepSessionThread != null)
{
while (_keepSessionThread.ThreadState != ThreadState.Stopped && timeoutCounter > 0)
{
Thread.Sleep(1);
timeoutCounter -= 1;
}
if (_keepSessionThread.ThreadState != ThreadState.Stopped)
{
//if thread is still running try to abort
// try to avoid abort (takes age to run and is not safe)
_keepSessionThread.Abort();
}
}
_keepSessionThread = null;
RequestPort?.Dispose();
StreamingPort?.Dispose();
RequestProtocol?.Dispose();
StreamingProtocol?.Dispose();
_logger.Trace($"Slot:{Slot} - Dispose is finished");
}
///
/// Ctor
///
/// Slot number for test-bench
/// for request Port
/// for streaming Port
/// don´t send CRC error or telegrams with error flag to caller
///
/// If you have a password for highest access level you need, if you don't want to access the meter
/// (just read led record) than you can leave it null
///
///
/// - Initial
///
public MagFluxMeter(Int32 slot, PortConfig? requestPort, PortConfig? streamingPort,
Boolean ignoreCorruptedData = true, String password = null)
{
_logger = NLogHelper.CreateOrGetMultiLogger($"Slot:{slot}", "Slot", "Meter", "MeterBase", "MeterBase");
SetupMagFluxMeter(slot, requestPort, streamingPort, ignoreCorruptedData, password);
}
#endregion
#region MagFlux handling
///
/// just internal setup. called on ctor or from vb6 setup function
///
/// Slot Number for test-bench
/// for RFID/UART/IrDA Port
/// for LED Port
/// don´t send CRC error or telegrams with error flag to caller
///
/// If you have a password for highest access level you need, if you don't want to access the meter
/// (just read led record) than you can leave it nullS
///
private void SetupMagFluxMeter(Int32 slot, PortConfig? requestPort, PortConfig? streamingPort,
Boolean ignoreCorruptedData = true, String password = "")
{
Slot = slot;
//_password = password;
if (requestPort != null)
{
if (requestPort.Value.Type == "Xylem.Common.Hardware.Interfaces.Ports.SerialPorts.UartSerialPort")
{
var requestIdent = $"Slot:{Slot}, Port:{requestPort.Value.PortName}, Protocol:Request, Type:UART -";
RequestProtocol = new RequestProtocol(requestIdent);
TransmitProtocol = new UartTransmitProtocol(requestPort.Value.PortName);
//RequestProtocol.SetTransmitProtocol(TransmitProtocol);
// request port is needed to assign the port name from file, else it is not used
// as the IMagFluxRequestProtocol implements the port handling and communication
RequestPort = new UartSerialPort(requestIdent, requestPort.Value.GetSerialPort(),
TransmitProtocol.GetTransmitPortSettings());
}
}
if (streamingPort != null)
{
var ledTransmit = new LedTransmitProtocol(streamingPort.Value.PortName);
var streamingIdent = $"Slot:{Slot}, Port:{streamingPort.Value.PortName}, Protocol:LED";
StreamingPort = new LedSerialPort(streamingIdent, streamingPort.Value.GetSerialPort(),
ledTransmit.GetTransmitPortSettings());
StreamingProtocol = new StreamingProtocol(streamingIdent, ignoreCorruptedData);
}
Configuration = new ProcessConfig(ProgramConfig.ConfigFileName);
SetLogger();
_logger.Debug($"Slot:{Slot} - Setup done");
}
///
///
/// Start Event listening, has to be called after
///
public void ConnectMeter()
{
if (RequestPort != null && RequestPort.GetPortName() != BaseSerialPort.PortNotAssigned)
{
if (RequestProtocol.Connect(RequestPort.GetPortName()))
{
_logger.Trace($"Slot:{Slot} - RequestPort and RequestProtocol linked");
RequestProtocol.OnRecordIsDecoded += RequestProtocol_ApplyDecodedRecord;
RequestProtocol.CloseConnection();
}
else
{
_logger.Trace($"Slot:{Slot} - RequestPort Connection failed");
}
}
if (StreamingPort != null && StreamingPort.GetPortName() != BaseSerialPort.PortNotAssigned)
{
LinkPortToProtocol(StreamingPort, StreamingProtocol);
_logger.Trace($"Slot:{Slot} - StreamingPort and StreamingProtocol linked");
StreamingProtocol.OnRecordIsDecoded += StreamingProtocol_ApplyDecodedRecord;
}
_logger.Debug($"Slot:{Slot} - Connected and communication started");
}
///
/// Add a port to working queue
///
/// On should one once added in runtime
///
private static void LinkPortToProtocol(IPort port, IProtocol protocol)
{
//for streaming mode only
if (port == null)
{
return;
}
port.OnRawRecordReceived += delegate (Object o, BasePortDataEventArgs rawMsg)
{
protocol.FillDecodingBuffer(rawMsg);
};
try
{
if (!port.IsOpen())
{
port.Open();
}
}
catch (Exception ex)
{
throw new ApplicationException($"Cannot Open Comport. Check TaskManager for other Genesis relevant programs and close them. Also check if the comport is valid! { Environment.NewLine }{ ex.Message}");
}
protocol.OnRecordReadyToSend += delegate (Object o, BasePortDataEventArgs dataToSend)
{
var data = (List)dataToSend.GetData();
port.PortWrite(data.ToArray());
};
}
///
/// Synchronization of the record for the streaming interface
///
///
///
private void SyncStreamingBuffer(SyncMarkRecord markRecord)
{
if (StreamingPort == null)
{
throw new ApplicationException("Synchronization not possible due to undefined streaming port");
}
StreamingPort.SynchronizeReceiveBuffer(markRecord);
}
private void RequestProtocol_AuthorizationGrant(Object sender, EventArgs e)
{
_logger.Debug($"Slot:{Slot} - Authorization succeeded");
}
public void SetupFromConfigFile(Int32 slot, Boolean ignoreCorruptedData = true)
{
SetupFromConfigFile(slot, ignoreCorruptedData, true, true);
}
///
/// Copy list of flow results to and kick off the
/// writing of calibrations to MagFlux.
///
/// List of flow results
public void WriteCalibrationTestBench(List results)
{
if (RequestProtocol == null) return;
var calibrationsCmPerH = new List();
var calibrationCmPerH = new Calibration();
foreach (var result in results)
{
calibrationCmPerH.refFlowRate = (Single)result.MeasuredRefFlowQmPerH;
calibrationCmPerH.dutFlowRate = (Single)result.MeasuredDutFlowQmPerH;
calibrationsCmPerH.Add(calibrationCmPerH);
}
RequestProtocol.SetCalibrationPoints(calibrationsCmPerH);
}
///
void IMeter.SetupFromConfigFile(Int32 slot, Boolean ignoreCorruptedData, Boolean useRequest, Boolean useStreaming)
{
SetupFromConfigFile(slot, ignoreCorruptedData);
}
///
/// Setup water meter from configuration file:
/// -slot,
/// -streaming protocol,
/// -streaming port
/// -request port
///
///
///
///
///
///
private void SetupFromConfigFile(Int32 slot, Boolean ignoreCorruptedData, Boolean useRequest, Boolean useStreaming)
{
Slot = slot;
var configFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), nameof(MagFlux), ProgramConfig.SerialConfigFileName);
if (!File.Exists(configFile))
{
configFile = Path.Combine(ProgramConfig.SerialConfigFileName);
if (!File.Exists(configFile))
{
throw new ApplicationException($"Configuration file {configFile} not found ");
}
}
var tr = new StreamReader(configFile);
var slotConfigList = JsonConvert.DeserializeObject(tr.ReadToEnd());
var slotConfig = slotConfigList.FirstOrDefault(t => t.Slot == slot);
if (slotConfig == null)
{
throw new ApplicationException($"Slot:{slot} - File " +
$"{ProgramConfig.SerialConfigFileName} does not contain valid configuration");
}
if (!useRequest)
{
SetupMagFluxMeter(slot, null, slotConfig.Streaming, ignoreCorruptedData);
}
else if (!useStreaming)
{
SetupMagFluxMeter(slot, slotConfig.Request, null, ignoreCorruptedData);
}
else
{
SetupMagFluxMeter(slot, slotConfig.Request, slotConfig.Streaming, ignoreCorruptedData);
}
SetLogger();
_logger.Debug($"Slot:{slot} - Configuration loaded");
}
///
public Boolean Logout()
{
RequestProtocol.CloseConnection();
IsLoggedOn = false;
return true;
}
///
///
/// - Unique Id introduced,
/// - Sensor Serial number mapped as PcbId.
///
public Boolean Login()
{
if (!RequestProtocol.Connect(RequestPort.GetPortName()))
return IsLoggedOn;
IsLoggedOn = true;
if (RequestProtocol.GetFirmwareVersion(out var fwVersion))
{
FwVersion = fwVersion;
}
if (RequestProtocol.GetFwBuildDate(out var fwBuildDate))
{
FwBuildDate = fwBuildDate;
}
if (RequestProtocol.GetMeterSizeMm(out var meterSizeMm))
{
MeterSizeMm = meterSizeMm;
}
if (RequestProtocol.GetFwGitHash(out var gitHash))
{
FwGitHash = gitHash;
}
if (RequestProtocol.GetUniqueId(out var uniqueId))
{
UniqueId = uniqueId;
}
// The PcbId will be named as SensorSerialNo by MJK
if (RequestProtocol.GetPcbId(out var pcbId))
{
PcbId = pcbId;
}
StreamingProtocol?.SetDecodingMask(pcbId, uniqueId);
return IsLoggedOn;
}
///
public Boolean Login(String password, Boolean runImmediately = true, Boolean skipReadMeterFwAndAssignRegisters = false)
{
return true;
}
///
public void InitMeasurement()
{
_logger.Info($"Slot:{Slot} - Init measurement");
PreMeasurement();
}
private void PreMeasurement()
{
if (!SkipPreparationForTestBench)
{
SkipPreparationForTestBench = true;
}
else
{
WriteLog("Wait on measurement start");
}
ProcessStatus = ProcessState.WaitForMeasurement;
}
///
public void StartMeasurement()
{
_listOfIMeasurement = new List
{
new BaseMeasurement(Slot, typeof(MagFluxRecord), IntermediateUpdateTimeS)
};
foreach (var measurement in _listOfIMeasurement)
{
measurement.OnActionStateHasChanged += Measurement_ActionStateHasChanged;
}
_logger.Info($"Slot:{Slot} - Start measurement");
ProcessStatus = ProcessState.MeasurementIsActive;
_listOfIMeasurement.ForEach(m => m.MeasurementState = MeasurementStates.IsWaitingForStartData);
SyncStreamingBuffer(SyncMarkRecord.SyncStart);
}
///
public void StopMeasurement()
{
_logger.Info($"Slot:{Slot} - Stop measurement");
ProcessStatus = ProcessState.MeasurementIsDone;
_listOfIMeasurement.ForEach(m => m.MeasurementState = MeasurementStates.IsWaitingForEndData);
SyncStreamingBuffer(SyncMarkRecord.SyncEnd);
}
private void Measurement_ActionStateHasChanged(Object sender, EventArgs e)
{
SyncStreamingBuffer(SyncMarkRecord.DecodeIntermediate);
}
///
public MeasurementResults GetMainMeasurementResult(Double? refVolume, Double? refTimeS,
Boolean intermediateMeasurement = false)
{
if (!intermediateMeasurement && GetMeasurementState(0) != MeasurementStates.IsCompleted)
{
throw new ApplicationException("Measurement is not completed");
}
return GetAllMeasurementResults(refVolume, refTimeS, intermediateMeasurement, 0).First();
}
///
public List GetAllMeasurementResults(Double? refVolume, Double? refTimeS, Boolean intermediateMeasurement = false,
Int32? channel = null)
{
if (!intermediateMeasurement && GetMeasurementState(channel) != MeasurementStates.IsCompleted)
{
throw new ApplicationException("Measurement is not completed");
}
var mainMeasurement = _listOfIMeasurement.FirstOrDefault(m => m.GetType() == typeof(MagFluxRecord));
if (mainMeasurement == null)
{
throw new ApplicationException("Can not find an ongoing measurement");
}
var results = new List();
var mainResult = intermediateMeasurement
? mainMeasurement.GetIntermediateMeasurementResult(refVolume, refTimeS)
: mainMeasurement.GetFinalMeasurementResult(refVolume, refTimeS);
results.Add(mainResult);
_logger.Info($"Slot:{Slot}, Channel:{mainMeasurement.GetChannel()} - MeasuredTime({mainResult.DutTimeS}s), " +
$"MeasuredVolume({mainResult.DutVolumeCm}Qm)");
foreach (var otherMeasurement in _listOfIMeasurement.Where(m => m.GetType() != typeof(MagFluxRecord)))
{
try
{
var otherResults = intermediateMeasurement
? otherMeasurement.GetIntermediateMeasurementResult(refVolume, refTimeS)
: otherMeasurement.GetFinalMeasurementResult(refVolume, refTimeS);
_logger.Info($"Slot:{Slot}, Channel:{otherMeasurement.GetChannel()} - ChannelTime({otherResults.DutTimeS}s), " +
$"ChannelVolume({otherResults.DutVolumeCm}Qm)");
results.Add(otherResults);
}
catch (Exception ex)
{
_logger.Warn($"Slot:{Slot}, No Results for channel:{otherMeasurement.GetChannel()} Ex: {ex.Message}");
if (channel == null)
{
throw new ApplicationException($"Can not read result from channel:{otherMeasurement.GetChannel() } Ex: {ex.Message}");
}
}
}
return results;
}
///
public MeasurementStates GetMeasurementState(Int32? onlyChannelNr = null)
{
_logger.Trace($"Slot:{Slot} - Get measurement state");
if (!_listOfIMeasurement.Any())
{
return MeasurementStates.NotStarted;
}
if (onlyChannelNr.HasValue)
{
var measurement = _listOfIMeasurement.First(f => f.GetChannel() == onlyChannelNr.Value);
return measurement.GetMeasurementState();
}
return _listOfIMeasurement.Min(m => m.MeasurementState);
}
///
public Boolean RequestIntermediateMeasurementState(Int32? onlyChannelNr = null)
{
_logger.Trace($"Slot:{Slot} - Get measurement state");
if (!_listOfIMeasurement.Any())
{
return false;
}
Boolean? ret = null;
foreach (var item in _listOfIMeasurement)
{
if (!onlyChannelNr.HasValue || item.GetChannel() == onlyChannelNr.Value)
{
var measurement = _listOfIMeasurement.First(f => onlyChannelNr != null && f.GetChannel() == onlyChannelNr.Value);
if ((measurement.MeasurementState == MeasurementStates.IsRunning
|| measurement.MeasurementState == MeasurementStates.IsWaitingForIntermediateData))
{
measurement.RequestIntermediateRecord();
if (!ret.HasValue)
{
ret = true;
}
}
else
{
ret = false;
}
}
}
return ret.HasValue ? ret.Value : false;
}
/// >
public String GetPcbId(Int32 expectedLength = 12)
{
if (!string.IsNullOrEmpty(PcbId) && !string.Equals("?", PcbId))
{
return PcbId;
}
var pcbId = PcbId;
RequestProtocol?.GetPcbId(out pcbId);
PcbId = pcbId;
return pcbId;
}
///
/// Write calibration values to MagFlux
///
public void WriteCalibration(List calibrationsCmPerH)
{
_logger.Info($"Slot:{Slot} - Write calibration values to MagFlux");
RequestProtocol?.SetCalibrationPoints(calibrationsCmPerH);
}
///
/// Read calibration values to MagFlux
///
public void ReadCalibration(out List calibrationsCmPerH)
{
calibrationsCmPerH = null;
_logger.Info($"Slot:{Slot} - Read calibration values from MagFlux");
RequestProtocol?.GetCalibrationPoints(out calibrationsCmPerH);
}
///
public void InitCalibration()
{
_logger.Info($"Slot:{Slot} - Init calibration and set calibration values of all channels to default");
if (RequestProtocol == null)
return;
if (RequestProtocol.PrepareDeviceForCalibration())
PreMeasurement();
}
///
public void StartCalibration()
{
StartMeasurement();
}
///
public void StopCalibration()
{
StopMeasurement();
RequestProtocol?.AbortDeviceForCalibration();
}
///
public MeasurementStates GetCalibrationState()
{
return GetMeasurementState();
}
///
public void BuildAndCheckCalibFactorsAllChannels(Double refVolumeCm, Double? refTimeS = null,
Double reqDeviationPercent = 0, Double maxCalibFactorTolerancePercent = 0)
{
throw new NotImplementedException();
}
///
public void SetCalibFactorsAllChannels(Boolean justLog = false)
{
throw new NotImplementedException();
}
///
public void SetLcdText(Boolean release, Byte[] textInHex)
{
throw new NotImplementedException();
}
///
public void SetProcessState(DisplayCodes newState, Boolean webRequest = true)
{
throw new NotImplementedException();
}
///
public DisplayCodes GetLastProcessState()
{
throw new NotImplementedException();
}
///
public void WriteLog(String text)
{
_logger.Info($"Slot:{Slot} - {text}");
//if (_enableRawDataLogging)
//{
// if (_loggerRawData == null)
// {
// _loggerRawData = NLogHelper.CreateOrGetMultiLogger(
// StreamingPort.GetPortName(), "", "LedRawData", "TargetLedRawDataBase", "LedRawDataBase");
// }
// _loggerRawData.Info($"{text}");
//}
}
///
public void LogRawData(Boolean on)
{
_enableRawDataLogging = on;
if (StreamingPort is LedSerialPort port)
{
port.RecordStreamingRawData = _enableRawDataLogging;
}
}
///
public Boolean CheckStateAfterMeasurement()
{
throw new NotImplementedException();
}
///
public void DisposeMeter()
{
Dispose();
}
private void AddData(IMeasurementRecord newRecord)
{
foreach (var measurement in _listOfIMeasurement)
{
if (measurement.GetType() != newRecord.GetType())
{
continue;
}
if (measurement.GetChannel() == newRecord.GetChannel())
{
measurement.AddData(newRecord);
}
}
// when every measurement has state IsRunning or every measurement has state IsCompleted, the streaming buffer set to skip decoding
if (_listOfIMeasurement.All(m => m.MeasurementState == MeasurementStates.IsRunning)
|| _listOfIMeasurement.All(m => m.MeasurementState == MeasurementStates.IsCompleted))
{
SyncStreamingBuffer(QualityWatchMode
? SyncMarkRecord.DecodeIntermediateQuality
: SyncMarkRecord.SkipDecoding);
}
}
#endregion
#region logging
private void SetLogger()
{
if (_logger != null)
{
LogManager.Flush();
}
// the id is a combination of UniqueId stored in PcbId and SensorSN (SensorId)
var id = !string.IsNullOrEmpty(PcbId) ? $"PCBID{PcbId}" : "?";
id += !string.IsNullOrEmpty(SerialNumber) ? $"_SN{SerialNumber}" : "?";
var fileName = $"MagFluxRawData_Slot_{Slot}";
if (string.IsNullOrEmpty(CurrentActionText))
{
_logger = NLogHelper.CreateOrGetMultiLogger($"Slot:{Slot}", $"", "Meter", "MeterBase", "MeterBase");
if (RequestProtocol != null)
{
var pathName = NLogHelper.GetPath(_logger);
var path = Path.GetDirectoryName(pathName);
RequestProtocol.SetLogLocation(path, fileName);
}
}
else
{
_logger = NLogHelper.CreateOrGetMultiLogger($"Slot:{Slot}_{id}_{CurrentActionText}", "Slot", "Meter", "MeterBase", "MeterBase");
if (RequestProtocol != null)
{
var pathName = NLogHelper.GetPath(_logger);
var path = Path.GetDirectoryName(pathName);
RequestProtocol.SetLogLocation(path, fileName);
}
//TODO check with roland
if (StreamingPort is LedSerialPort)
{
var streamingIdent = $"LedRawData_Slot_{Slot}_{id}_{CurrentActionText}";
((LedSerialPort)StreamingPort).Ident = streamingIdent;
((LedSerialPort)StreamingPort).RefreshLogger();
if (!string.IsNullOrEmpty(SerialNumber) && CurrentActionText.Contains("PG"))
{
//var pathMain = NLogHelper.GetPath(_logger);
//var pathRaw = NLogHelper.GetPath(((LedSerialPort)StreamingPort).GetRawLogger());
//var basePath = Path.GetDirectoryName(pathMain);
//var testRunString = CurrentActionText.Replace("PG", "");
//var lastChat = pathMain.LastIndexOf('\\');
//pathMain = pathMain.Substring(lastChat + 1);
//pathRaw = Path.GetFileName(pathRaw);
//var tmpUrl = $"http://10.49.40.25/MeterProcessState/api/TestBench/SetMeterLogPathInfo?SerialNumber={SerialNumber}&TestRunId={testRunString}&BasePath={basePath}&MainLogName={pathMain}&LEDName={pathRaw}";
//_logger.Debug($"Request Url: { tmpUrl}");
////ToDO: Update to service URl
//LocalWebRequest.GetRequest(tmpUrl);
}
}
}
}
#endregion
}
}