Files
tbf/TBF/Rig/TestMethods/iPerlCommunication/communication/OptoHeadTest.cs
T
michal 8738edd0c5 Added FLIP MODE Constant, Randomised
Add support for Flip Mode configuration in iPerl: Implement `SetFlipMode` functionality in `OptoHeadTest` and `RadioService`, integrate constants, enhance UI, and add unit and integration tests for constant/randomized flip mode settings.
2026-08-18 13:59:59 +02:00

890 lines
28 KiB
C#

using System;
using System.IO.Ports;
using Common;
using log4net;
using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed;
using TBF.Rig.TestMethods.iPerlCommunication.communication.Utils;
using TBF.Rig.TestMethods.iPerlCommunication.iPerlHead;
using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.protocolCommons;
namespace TBF.Rig.TestMethods.iPerlCommunication.communication
{
public class OptoHeadTest : IDisposable
{
//protected static readonly ILog rfidDataLogger = LogManager.GetLogger("RfidData");
private static readonly ILog log = LogManager.GetLogger(typeof(OptoHeadTest));
private IperlHead iperlHead;
private SerialDriver serialDriver;
public static SerialDriver BuildConnection(IperlHead iHead)
{
return new SerialDriverBuilder()
.WithPort($"COM{iHead.RfidComPortNr}")
.WithBaudRate(2400)
.WithDataBits(8)
.WithParity(Parity.None)
.WithStopBits(StopBits.One)
.WithTimeouts(4000, 2000)
.BuildAndConnect();
}
public OptoHeadTest(IperlHead iperlHead)
{
this.iperlHead = iperlHead;
}
public void CloseConnection()
{
if (serialDriver != null)
serialDriver.CloseConnection();
serialDriver = null;
}
public bool ReadSerialNr()
{
try
{
if (iperlHead != null)
{
if (serialDriver == null)
serialDriver = BuildConnection(iperlHead);
log.Debug("ReadSerialNr called for iHead: " + iperlHead.ToString() + " serialDriver: " + serialDriver);
RadioService headService = new RadioService(serialDriver);
string serialNo = headService.ReadRequest_PCB(ref iperlHead);
if (!string.IsNullOrEmpty(serialNo))
{
log.Info($"Success Serial No: {serialNo} on COM{iperlHead.RfidComPortNr} serialDriver: {serialDriver}");
return true;
}
}
}
catch (Exception ex)
{
log.Error($"ReadSerialNr(COM{iperlHead.RfidComPortNr}) - Exception:" + ex.Message);
}
return false;
}
public string ReadRequest_PCB()
{
if (iperlHead.DebugLevel == DebugMode.Simulate)
{
return "-OK Simulated response-";
}
try
{
if (iperlHead != null)
{
if (serialDriver == null)
serialDriver = BuildConnection(iperlHead);
RadioService headService = new RadioService(serialDriver);
string serialNo = headService.ReadRequest_PCB(ref iperlHead);
log.Info($"PCB Number: {serialNo} on COM{iperlHead.RfidComPortNr} serialDriver: {serialDriver}");
return serialNo;
}
}
catch (Exception ex)
{
log.Error("ReadRequest_PCB() - Exception:" + ex.StackTrace);
return (ex.Message.ToString());
}
return "";
}
/// <summary>
/// Set Test mode
/// </summary>
/// <param name="iHead"></param>
/// <returns></returns>
public bool SetTestMode()
{
log.Debug("SetTestMode called for iHead: " + iperlHead.ToString());
bool activityModeActive = SetActivityMode_Active();
bool optActiveMode = SetOptTestMode();
log.Debug("SetTestMode result: optoMod-> " + optActiveMode + " meterModeActive ->" + activityModeActive);
return (optActiveMode && activityModeActive);
}
/// <summary>
/// Set Active mode
/// </summary>
/// <param name="iHead"></param>
/// <returns></returns>
public bool SetActiveMode()
{
log.Debug("SetActiveMode called for iHead: " + iperlHead.ToString());
bool optActiveMode = SetOptActiveMode(iperlHead);
//bool activityModeIdle = SetActivityMode_Idle();
return optActiveMode;
}
/// <summary>
/// Set Idle mode - only
/// </summary>
/// <param name="iHead"></param>
/// <returns></returns>
public bool SetIdleMode()
{
log.Debug("SetIdleMode called for iHead: " + iperlHead.ToString());
bool activityModeIdle = SetActivityMode_Idle();
return activityModeIdle;
}
/// <summary>
/// Set Test mode - string response
/// </summary>
/// <param name="iHead"></param>
/// <param name="isTestModeSuccessful"></param>
/// <returns></returns>
public string SetTestMode(ref bool isTestModeSuccessful)
{
if (iperlHead.DebugLevel == DebugMode.Simulate)
{
isTestModeSuccessful = true;
return "-OK Simulated response-";
}
try
{
bool testMode = SetTestMode();
isTestModeSuccessful = testMode;
return testMode ? "Set Test Mode - OK" : "Set Test Mode - FAILED";
}catch (Exception ex)
{
log.Error("SetTestMode() - Exception:" + ex.StackTrace);
return "Set Test Mode - Exception";
}
}
/// <summary>
/// Set Optical -> Test mode
/// </summary>
/// <param name="iHead"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
private bool SetOptTestMode()
{
try
{
if (iperlHead != null)
{
if (serialDriver == null)
serialDriver = BuildConnection(iperlHead);
RadioService headService = new RadioService(serialDriver);
bool optTestMode = headService.SetOptTestMode(iperlHead);
if (iperlHead.ConfigStruct != null)
iperlHead.ConfigStruct.OpthoStatusMode = optTestMode ? DiagnosticLedState.State7 : DiagnosticLedState.StatusUnknown;
return optTestMode;
}
}
catch (Exception ex)
{
log.Error("SetOptTestMode() - Exception:" + ex.StackTrace);
}
return false;
}
/// <summary>
/// Set Active mode - string response
/// </summary>
/// <param name="iHead"></param>
/// <param name="isTestModeSuccessful"></param>
/// <returns></returns>
public string SetActiveMode(ref bool isTestModeSuccessful)
{
if (iperlHead.DebugLevel == DebugMode.Simulate)
{
isTestModeSuccessful = true;
return "-OK Simulated response-";
}
try
{
bool activeMode = SetActiveMode();
isTestModeSuccessful = activeMode;
return activeMode ? "Set Active Mode - OK" : "Set Active Mode - FAILED";
}
catch (Exception ex)
{
log.Error("SetActiveMode() - Exception:" + ex.StackTrace);
return "Set Active Mode - Exception";
}
}
/// <summary>
/// Set Optical -> Active mode
/// </summary>
/// <param name="iHead"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
private bool SetOptActiveMode(IperlHead iHead)
{
try
{
if (iHead != null)
{
if (serialDriver == null)
serialDriver = BuildConnection(iHead);
RadioService headService = new RadioService(serialDriver);
return headService.SetOptActiveMode(iHead);
}
}
catch (Exception ex)
{
log.Error("SetOptActiveMode() - Exception:" + ex.StackTrace);
}
return false;
}
/// <summary>
/// Set activity mode to active
/// </summary>
/// <param name="iHead"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
private bool SetActivityMode_Active()
{
try
{
if (iperlHead != null)
{
if (serialDriver == null)
serialDriver = BuildConnection(iperlHead);
log.Debug("SetActivityMode_Active called for iHead: " + iperlHead.ToString() + " serialDriver: " + serialDriver);
RadioService headService = new RadioService(serialDriver);
return headService.SetActivityMode_Active(iperlHead);
}
}
catch (Exception ex)
{
log.Error("SetActivityMode_Active() - Exception:" + ex.StackTrace);
}
return false;
}
/// <summary>
/// Set activity mode to idle
/// </summary>
/// <param name="iHead"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
private bool SetActivityMode_Idle()
{
try
{
if (iperlHead != null)
{
if (serialDriver == null)
serialDriver = BuildConnection(iperlHead);
log.Debug("SetActivityMode_Idle called for iHead: " + iperlHead.ToString() + " serialDriver: " + serialDriver);
RadioService headService = new RadioService(serialDriver);
return headService.SetActivityMode_Idle(iperlHead);
}
}
catch (Exception ex)
{
log.Error("SetActivityMode_Idle() - Exception:" + ex.StackTrace);
}
return false;
}
public void Dispose()
{
CloseConnection();
}
/// <summary>
/// Read configuration from iHead
/// DiagnosticLedState is not readable, mus only be set!
/// </summary>
/// <param name="iHead"></param>
/// <param name="ledState"></param>
/// <returns></returns>
public bool ReadConfiguration(DiagnosticLedState ledState )
{
if (iperlHead.DebugLevel == DebugMode.Simulate)
{
return true;
}
try
{
if (iperlHead != null)
{
if (iperlHead.ConfigStruct == null)
{
iperlHead.ConfigStruct = new ConfigStruct();
}
if (serialDriver == null)
serialDriver = BuildConnection(iperlHead);
RadioService headService = new RadioService(serialDriver);
iperlHead.ConfigStruct.PCBNumberString = headService.ReadRequest_PCB(ref iperlHead);
iperlHead.ConfigStruct.StatusMode = headService.GetActivityStatusMode(iperlHead);
iperlHead.ConfigStruct.Unit = headService.GetUnit(iperlHead);
if (ledState != DiagnosticLedState.StatusUnknown) // do set
{
iperlHead.ConfigStruct.OpthoStatusMode = headService.SetOptoStatusMode(iperlHead, ledState);
}
else
{
iperlHead.ConfigStruct.OpthoStatusMode = DiagnosticLedState.StatusUnknown;
}
iperlHead.ConfigStruct.Version = headService.GetVersion(iperlHead);
return true;
}
else
{
return false;
}
}
catch (Exception ex)
{
return false;
}
}
/// <summary>
/// Reads TouchRead version, meter device type
/// and meter firmware version.
/// </summary>
/// <returns>
/// Parsed version information or null when the operation fails.
/// </returns>
public VersionTypeResult SetViewVersionAndType()
{
if (iperlHead == null)
{
log.Warn(
"SetViewVersionAndType: IperlHead is null.");
return null;
}
if (iperlHead.DebugLevel == DebugMode.Simulate)
{
return new VersionTypeResult
{
TouchReadVersion = "SIMULATED",
MeterDeviceType = "SIMULATED",
MeterFirmwareVersion = "SIMULATED"
};
}
try
{
if (serialDriver == null)
{
serialDriver = BuildConnection(iperlHead);
}
log.Debug(
"SetViewVersionAndType called for iHead: " +
iperlHead +
" serialDriver: " +
serialDriver);
var headService =
new RadioService(serialDriver);
VersionTypeResult result =
headService.SetViewVersionAndType(iperlHead);
if (result == null)
{
log.Warn(
"SetViewVersionAndType: No valid response received.");
}
else
{
log.Info(
"SetViewVersionAndType result: " +
result);
}
return result;
}
catch (Exception ex)
{
log.Error(
"SetViewVersionAndType failed.",
ex);
return null;
}
}
/// <summary>
/// Reads the configured meter reading units.
/// </summary>
/// <returns>
/// Reading units or null when the operation fails.
/// </returns>
public ReadingUnits? ViewReadingUnits()
{
if (iperlHead == null)
{
log.Warn(
"ViewReadingUnits: IperlHead is null.");
return null;
}
if (iperlHead.DebugLevel == DebugMode.Simulate)
{
return ReadingUnits.CubicMeters;
}
try
{
if (serialDriver == null)
{
serialDriver = BuildConnection(iperlHead);
}
log.Debug(
"ViewReadingUnits called for iHead: " +
iperlHead +
" serialDriver: " +
serialDriver);
var headService =
new RadioService(serialDriver);
ReadingUnits? result =
headService.ViewReadingUnits(iperlHead);
if (!result.HasValue)
{
log.Warn(
"ViewReadingUnits: No valid response received.");
}
else
{
log.Info(
$"ViewReadingUnits result: {result.Value} " +
$"(0x{Convert.ToByte(result.Value):X2})");
}
return result;
}
catch (Exception ex)
{
log.Error(
"ViewReadingUnits failed.",
ex);
return null;
}
}
/// <summary>
/// Reads the configured display flip mode.
/// </summary>
/// <returns>
/// Flip mode or null when the operation fails.
/// </returns>
public FlipMode? ViewFlipMode()
{
if (iperlHead == null)
{
log.Warn(
"ViewFlipMode: IperlHead is null.");
return null;
}
if (iperlHead.DebugLevel == DebugMode.Simulate)
{
return (FlipMode)0x00;
}
try
{
if (serialDriver == null)
{
serialDriver = BuildConnection(iperlHead);
}
log.Debug(
"ViewFlipMode called for iHead: " +
iperlHead +
" serialDriver: " +
serialDriver);
var headService =
new RadioService(serialDriver);
FlipMode? result =
headService.ViewFlipMode(iperlHead);
if (!result.HasValue)
{
log.Warn(
"ViewFlipMode: No valid response received.");
}
else
{
log.Info(
$"ViewFlipMode result: {result.Value} " +
$"(0x{Convert.ToByte(result.Value):X2})");
}
return result;
}
catch (Exception ex)
{
log.Error(
"ViewFlipMode failed.",
ex);
return null;
}
}
/// <summary>
/// Sets constant (0x00) or randomized (0x01) field flip-rate mode.
/// </summary>
public bool SetFlipMode(FlipMode flipMode)
{
if (iperlHead == null)
{
log.Warn("SetFlipMode: IperlHead is null.");
return false;
}
if (!Enum.IsDefined(typeof(FlipMode), flipMode))
{
log.WarnFormat("SetFlipMode: Unsupported value 0x{0:X2}.", (byte)flipMode);
return false;
}
if (iperlHead.DebugLevel == DebugMode.Simulate)
{
if (iperlHead.ConfigStruct == null)
iperlHead.ConfigStruct = new ConfigStruct();
iperlHead.ConfigStruct.FlipMode = flipMode;
return true;
}
try
{
if (serialDriver == null)
serialDriver = BuildConnection(iperlHead);
log.DebugFormat(
"SetFlipMode started: Head={0}, Mode={1} (0x{2:X2})",
iperlHead,
flipMode,
(byte)flipMode);
var headService = new RadioService(serialDriver);
bool successful = headService.SetFlipMode(iperlHead, flipMode);
log.InfoFormat(
"SetFlipMode finished: Head={0}, Mode={1}, successful={2}",
iperlHead,
flipMode,
successful);
return successful;
}
catch (Exception ex)
{
log.Error("SetFlipMode failed.", ex);
return false;
}
}
/// <summary>
/// Reads the calibration factor.
/// </summary>
/// <returns>
/// Calibration factor information or null when the operation fails.
/// </returns>
public CalibrationFactorResult ViewCalibration()
{
if (iperlHead == null)
{
log.Warn(
"ViewCalibration: IperlHead is null.");
return null;
}
if (iperlHead.DebugLevel == DebugMode.Simulate)
{
return new CalibrationFactorResult
{
RawValue = 4096,
Percentage = 100.0,
CorrectionPercentage = 0.0
};
}
try
{
if (serialDriver == null)
{
serialDriver = BuildConnection(iperlHead);
}
log.Debug(
"ViewCalibration called for iHead: " +
iperlHead +
" serialDriver: " +
serialDriver);
var headService =
new RadioService(serialDriver);
CalibrationFactorResult result =
headService.ViewCalibration(iperlHead);
if (result == null)
{
log.Warn(
"ViewCalibration: No valid response received.");
}
else
{
log.Info(
"ViewCalibration result: " +
result);
}
return result;
}
catch (Exception ex)
{
log.Error(
"ViewCalibration failed.",
ex);
return null;
}
}
/// <summary>
/// Reads and logs all additional configuration values.
/// </summary>
/// <returns>
/// True when all values were read successfully.
/// </returns>
public bool ReadExtendedConfiguration()
{
if (iperlHead == null)
{
log.Warn(
"ReadExtendedConfiguration: IperlHead is null.");
return false;
}
try
{
VersionTypeResult versionType =
SetViewVersionAndType();
ReadingUnits? readingUnits =
ViewReadingUnits();
FlipMode? flipMode =
ViewFlipMode();
CalibrationFactorResult calibration =
ViewCalibration();
bool successful =
versionType != null &&
readingUnits.HasValue &&
flipMode.HasValue &&
calibration != null;
log.Info(
"ReadExtendedConfiguration result: " +
$"Success={successful}, " +
$"VersionType={versionType}, " +
$"ReadingUnits={readingUnits}, " +
$"FlipMode={flipMode}, " +
$"Calibration={calibration}");
return successful;
}
catch (Exception ex)
{
log.Error(
"ReadExtendedConfiguration failed.",
ex);
return false;
}
}
/// <summary>
/// Reads additional common parameters and stores them
/// in the current iPerl ConfigStruct.
/// </summary>
public bool ReadAdditionalCommonParameters( out string resultStr, bool prettyText)
{
resultStr = string.Empty;
if (iperlHead == null)
{
resultStr = "Read additional common parameters: iPerl head is null.";
log.Warn(resultStr);
return false;
}
if (iperlHead.ConfigStruct == null)
{
iperlHead.ConfigStruct = new ConfigStruct();
}
if (iperlHead.DebugLevel == DebugMode.Simulate)
{
iperlHead.ConfigStruct.VersionType = new VersionTypeResult
{
TouchReadVersion = "SIMULATED",
MeterDeviceType = "SIMULATED",
MeterFirmwareVersion = "SIMULATED"
};
iperlHead.ConfigStruct.ReadingUnits = ReadingUnits.CubicMeters;
iperlHead.ConfigStruct.FlipMode = (FlipMode)0x00;
iperlHead.ConfigStruct.Calibration = new CalibrationFactorResult {
RawValue = 4096,
Percentage = 100.0,
CorrectionPercentage = 0.0
};
resultStr = BuildAdditionalCommonParametersString( iperlHead.ConfigStruct, false);
return true;
}
try
{
if (serialDriver == null)
{
serialDriver =
BuildConnection(iperlHead);
}
var headService = new RadioService(serialDriver);
VersionTypeResult versionType = headService.SetViewVersionAndType( iperlHead);
ReadingUnits? readingUnits = headService.ViewReadingUnits( iperlHead);
FlipMode? flipMode = headService.ViewFlipMode( iperlHead);
CalibrationFactorResult calibration = headService.ViewCalibration( iperlHead);
/*
* Save received values into ConfigStruct.
* Null values replace old values after an unsuccessful read.
*/
iperlHead.ConfigStruct.VersionType = versionType;
iperlHead.ConfigStruct.ReadingUnits = readingUnits;
iperlHead.ConfigStruct.FlipMode = flipMode;
iperlHead.ConfigStruct.Calibration = calibration;
bool successful = versionType != null && readingUnits.HasValue && flipMode.HasValue && calibration != null;
resultStr = BuildAdditionalCommonParametersString( iperlHead.ConfigStruct, prettyText);
if (successful)
{
log.Info( "ReadAdditionalCommonParameters: " + resultStr);
}
else
{
log.Warn( "ReadAdditionalCommonParameters failed: " + resultStr);
}
return successful;
}
catch (Exception ex)
{
resultStr = "Read additional common parameters failed: " + ex.Message;
log.Error( "ReadAdditionalCommonParameters failed.", ex);
return false;
}
}
private static string BuildAdditionalCommonParametersString(
ConfigStruct config, bool prettyText)
{
if (config == null)
{
return "Additional common parameters are not available.";
}
string versionTypeText = config.VersionType == null ? "Not available" : config.VersionType.ToString();
string readingUnitsText = config.ReadingUnits.HasValue ?
string.Format( "{0} (0x{1:X2})", config.ReadingUnits.Value, Convert.ToByte( config.ReadingUnits.Value))
: "Not available";
string flipModeText = config.FlipMode.HasValue ?
string.Format( "{0} (0x{1:X2})", config.FlipMode.Value, Convert.ToByte( config.FlipMode.Value))
: "Not available";
string calibrationText;
if (config.Calibration == null)
{
calibrationText = "Not available";
}
else
{
calibrationText =
string.Format( "{0} ({1:F4} %, correction " + "{2:+0.0000;-0.0000;0.0000} %)",
config.Calibration.RawValue,
config.Calibration.Percentage,
config.Calibration.CorrectionPercentage);
}
if (prettyText)
{
return string.Format(
"Version/type: {0}{4}" +
"Reading units: {1}{4}" +
"Flip mode: {2}{4}" +
"Calibration: {3}",
versionTypeText,
readingUnitsText,
flipModeText,
calibrationText,
Environment.NewLine);
}
return
"Version/type: " + versionTypeText +
"; Reading units: " + readingUnitsText +
"; Flip mode: " + flipModeText +
"; Calibration: " + calibrationText;
}
}
}