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.
633 lines
21 KiB
C#
633 lines
21 KiB
C#
using System;
|
|
using System.Text;
|
|
using log4net;
|
|
using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed;
|
|
using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol;
|
|
using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.protocolCommons;
|
|
using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.wiredProtocol;
|
|
using TBF.Rig.TestMethods.iPerlCommunication.communication.Utils;
|
|
using TBF.Rig.TestMethods.iPerlCommunication.iPerlHead;
|
|
|
|
namespace TBF.Rig.TestMethods.iPerlCommunication.communication
|
|
{
|
|
public class RadioService
|
|
{
|
|
private static readonly ILog log = LogManager.GetLogger(typeof(RadioService));
|
|
|
|
static string okResponse = "Command complete, no errors";
|
|
static string errorResponse = "Unable to execute";
|
|
|
|
private ISerialDriver serialDriver;
|
|
public RadioService(SerialDriver serialDriver)
|
|
{
|
|
this.serialDriver = serialDriver;
|
|
log.Debug("RadioService created with serialDriver= " + serialDriver + "");
|
|
}
|
|
|
|
public RadioService(ISerialDriver serialDriver)
|
|
{
|
|
this.serialDriver = serialDriver;
|
|
log.Debug("RadioService created with serialDriver= " + serialDriver + "");
|
|
}
|
|
|
|
public string ReadRequest_PCB(ref IperlHead iHead)
|
|
{
|
|
if (!serialDriver.IsOpen())
|
|
{
|
|
serialDriver.Open();
|
|
}
|
|
|
|
var request = new IperlHatFrameBuilder()
|
|
.RequestResponse(true)
|
|
.AddCommand(ProtocolCommand.ViewFactoryId)
|
|
.BuildBytes();
|
|
|
|
|
|
byte[] rawData = serialDriver.SendAndWait(request, 10000);
|
|
if (rawData == null)
|
|
return null;
|
|
|
|
// parse rawData
|
|
var parser = new IperlHatFrameParser();
|
|
IperlHatResponse decoded = parser.Parse(rawData);
|
|
if (decoded.IsOk)
|
|
{
|
|
string asciiPayload = decoded.GetAsciiPayload();
|
|
if (iHead.ConfigStruct != null) // store mechanism
|
|
{
|
|
iHead.ConfigStruct.PCBNumberString = asciiPayload;
|
|
}
|
|
return asciiPayload;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public ProtocolStatuses GetActivityStatusMode(IperlHead iHead)
|
|
{
|
|
if (!serialDriver.IsOpen())
|
|
serialDriver.Open();
|
|
|
|
var request = new IperlHatFrameBuilder()
|
|
.RequestResponse(true)
|
|
.AddCommand(ProtocolCommand.ViewState)
|
|
.BuildBytes();
|
|
|
|
byte[] rawData = serialDriver.SendAndWait(request, 10000);
|
|
if (rawData == null)
|
|
return ProtocolStatuses.Unknown;
|
|
|
|
var parser = new IperlHatFrameParser();
|
|
IperlHatResponse decoded = parser.Parse(rawData);
|
|
|
|
if (!decoded.IsOk)
|
|
return ProtocolStatuses.Unknown;
|
|
|
|
ProtocolStatuses statusMode = decoded.GetResponse<ProtocolStatuses>(out bool isOK);
|
|
|
|
if (!isOK)
|
|
return ProtocolStatuses.Unknown; // wrong payload
|
|
|
|
return statusMode;
|
|
}
|
|
|
|
public DiagnosticLedState SetOptoStatusMode(IperlHead iHead, DiagnosticLedState opthoStatusMode)
|
|
{
|
|
if (!serialDriver.IsOpen())
|
|
serialDriver.Open();
|
|
|
|
var request = new IperlHatFrameBuilder()
|
|
.RequestResponse(true)
|
|
.AddDeviceCommand(ProtocolDeviceSubCommand.SetDiagnosticLEDState)
|
|
.AddPayload(opthoStatusMode)
|
|
.BuildBytes();
|
|
|
|
byte[] rawData = serialDriver.SendAndWait(request, 10000);
|
|
if (rawData == null)
|
|
return DiagnosticLedState.StatusUnknown;
|
|
|
|
var parser = new IperlHatFrameParser();
|
|
IperlHatResponse decoded = parser.Parse(rawData);
|
|
|
|
log.Debug("SetOptoStatusMode isOK: " + decoded.IsOk);
|
|
// if is response ok - it set it correctly
|
|
if (!decoded.IsOk)
|
|
return DiagnosticLedState.StatusUnknown;
|
|
|
|
return opthoStatusMode;
|
|
}
|
|
|
|
|
|
private static ushort SafeIntToUShort(int value)
|
|
{
|
|
if (value < ushort.MinValue || value > ushort.MaxValue)
|
|
return 0xFD; // your error code
|
|
|
|
return (ushort)value;
|
|
}
|
|
|
|
|
|
public string GetVersion(IperlHead iHead)
|
|
{
|
|
if (!serialDriver.IsOpen())
|
|
{
|
|
serialDriver.Open();
|
|
}
|
|
|
|
byte[] request = new IperlHatFrameBuilder()
|
|
.RequestResponse(true)
|
|
.AddCommand(ProtocolCommand.Question)
|
|
.AddPayload(IperlHatProtocolConstants.Version)
|
|
.BuildBytes();
|
|
|
|
|
|
byte[] rawData = serialDriver.SendAndWait(request, 10000);
|
|
if (rawData == null)
|
|
return "";
|
|
|
|
// parse rawData
|
|
var parser = new IperlHatFrameParser();
|
|
IperlHatResponse decoded = parser.Parse(rawData);
|
|
log.Debug("GetVersion isOK: " + decoded.IsOk);
|
|
if (decoded.IsOk)
|
|
{
|
|
return decoded.GetAsciiPayload();
|
|
}
|
|
|
|
return "";
|
|
}
|
|
|
|
|
|
public VersionTypeResult SetViewVersionAndType(IperlHead iHead)
|
|
{
|
|
if (!serialDriver.IsOpen())
|
|
{
|
|
serialDriver.Open();
|
|
}
|
|
|
|
byte[] request = new IperlHatFrameBuilder()
|
|
.RequestResponse(true)
|
|
.AddCommand(ProtocolCommand.ViewVersionAndType)
|
|
.BuildBytes();
|
|
|
|
byte[] rawData = serialDriver.SendAndWait(request, 5000);
|
|
|
|
if (rawData == null || rawData.Length == 0)
|
|
{
|
|
log.Warn("SetViewVersionAndType: No response received.");
|
|
return null;
|
|
}
|
|
|
|
try
|
|
{
|
|
var parser = new IperlHatFrameParser();
|
|
IperlHatResponse decoded = parser.Parse(rawData);
|
|
|
|
log.Debug("SetViewVersionAndType isOK: " + decoded.IsOk);
|
|
|
|
if (!decoded.IsOk)
|
|
{
|
|
log.Warn("SetViewVersionAndType: Device returned NOK response.");
|
|
return null;
|
|
}
|
|
|
|
if (decoded.Payload == null || decoded.Payload.Length == 0)
|
|
{
|
|
log.Warn("SetViewVersionAndType: Response payload is empty.");
|
|
return null;
|
|
}
|
|
|
|
string payloadText = Encoding.ASCII
|
|
.GetString(decoded.Payload)
|
|
.Trim('\0', '\r', '\n', ' ');
|
|
|
|
log.Debug("SetViewVersionAndType payload: " + payloadText);
|
|
|
|
VersionTypeResult result = VersionTypeResult.ParseVersionTypePayload(payloadText);
|
|
|
|
if (result == null)
|
|
{
|
|
log.Warn(
|
|
"SetViewVersionAndType: Unable to parse response payload: " +
|
|
payloadText);
|
|
|
|
return null;
|
|
}
|
|
|
|
log.Debug("SetViewVersionAndType result: " + result);
|
|
|
|
return result;
|
|
}
|
|
catch (FormatException ex)
|
|
{
|
|
log.Error("SetViewVersionAndType: Invalid response frame.", ex);
|
|
return null;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
log.Error("SetViewVersionAndType failed.", ex);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public ReadingUnits? ViewReadingUnits(IperlHead iHead)
|
|
{
|
|
if (!serialDriver.IsOpen())
|
|
{
|
|
serialDriver.Open();
|
|
}
|
|
|
|
byte[] request = new IperlHatFrameBuilder()
|
|
.RequestResponse(true)
|
|
.AddCommand(ProtocolCommand.ViewReadingUnits)
|
|
.BuildBytes();
|
|
|
|
byte[] rawData = serialDriver.SendAndWait(request, 5000);
|
|
|
|
if (rawData == null || rawData.Length == 0)
|
|
{
|
|
log.Warn("ViewReadingUnits: No response received.");
|
|
return null;
|
|
}
|
|
|
|
try
|
|
{
|
|
var parser = new IperlHatFrameParser();
|
|
IperlHatResponse decoded = parser.Parse(rawData);
|
|
|
|
log.Debug("ViewReadingUnits isOK: " + decoded.IsOk);
|
|
|
|
if (!decoded.IsOk)
|
|
{
|
|
log.Warn("ViewReadingUnits: Device returned NOK response.");
|
|
return null;
|
|
}
|
|
|
|
ReadingUnits readingUnits =
|
|
decoded.GetResponse<ReadingUnits>(out bool responseOk);
|
|
|
|
if (!responseOk)
|
|
{
|
|
string payload = BitConverter.ToString(decoded.Payload);
|
|
|
|
log.Warn(
|
|
"ViewReadingUnits: Invalid response payload. Payload=" +
|
|
payload);
|
|
|
|
return null;
|
|
}
|
|
|
|
log.Debug(
|
|
$"ViewReadingUnits: {readingUnits} " +
|
|
$"(0x{Convert.ToByte(readingUnits):X2})");
|
|
|
|
return readingUnits;
|
|
}
|
|
catch (FormatException ex)
|
|
{
|
|
log.Error("ViewReadingUnits: Invalid response frame.", ex);
|
|
return null;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
log.Error("ViewReadingUnits failed.", ex);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public FlipMode? ViewFlipMode(IperlHead iHead)
|
|
{
|
|
if (!serialDriver.IsOpen())
|
|
{
|
|
serialDriver.Open();
|
|
}
|
|
|
|
byte[] request = new IperlHatFrameBuilder()
|
|
.RequestResponse(true)
|
|
.AddDeviceCommand(ProtocolDeviceSubCommand.ViewFlipMode)
|
|
.BuildBytes();
|
|
|
|
byte[] rawData = serialDriver.SendAndWait(request, 5000);
|
|
|
|
if (rawData == null || rawData.Length == 0)
|
|
{
|
|
log.Warn( "ViewFlipMode: No response received.");
|
|
return null;
|
|
}
|
|
|
|
try
|
|
{
|
|
var parser = new IperlHatFrameParser();
|
|
|
|
IperlHatResponse decoded = parser.Parse(rawData);
|
|
|
|
log.Debug( "ViewFlipMode isOK: " + decoded.IsOk);
|
|
|
|
if (!decoded.IsOk)
|
|
{
|
|
log.Warn( "ViewFlipMode: Device returned NOK response.");
|
|
return null;
|
|
}
|
|
|
|
if (decoded.Payload == null || decoded.Payload.Length != 1)
|
|
{
|
|
log.Warn( "ViewFlipMode: Invalid payload. Expected exactly one byte. Payload="
|
|
+ BitConverter.ToString( decoded.Payload ?? new byte[0]));
|
|
return null;
|
|
}
|
|
|
|
byte rawValue = decoded.Payload[0];
|
|
|
|
if (!Enum.IsDefined( typeof(FlipMode), rawValue))
|
|
{
|
|
log.Warn( $"ViewFlipMode: Unknown value. Value=0x{rawValue:X2}");
|
|
return null;
|
|
}
|
|
|
|
FlipMode flipMode = (FlipMode)rawValue;
|
|
|
|
log.Debug( $"ViewFlipMode: {flipMode} " + $"(0x{rawValue:X2})");
|
|
return flipMode;
|
|
}
|
|
catch (FormatException ex)
|
|
{
|
|
log.Error( "ViewFlipMode: Invalid response frame.", ex);
|
|
return null;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
log.Error( "ViewFlipMode failed.", ex);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public bool SetFlipMode(IperlHead iHead, FlipMode flipMode)
|
|
{
|
|
if (!Enum.IsDefined(typeof(FlipMode), flipMode))
|
|
throw new ArgumentOutOfRangeException(nameof(flipMode));
|
|
|
|
if (!serialDriver.IsOpen())
|
|
serialDriver.Open();
|
|
|
|
byte[] request = new IperlHatFrameBuilder()
|
|
.RequestResponse(true)
|
|
.AddDeviceCommand(ProtocolDeviceSubCommand.SetFlipMode)
|
|
.AddPayload((byte)flipMode)
|
|
.BuildBytes();
|
|
|
|
byte[] rawData = serialDriver.SendAndWait(request, 5000);
|
|
if (rawData == null || rawData.Length == 0)
|
|
{
|
|
log.Warn("SetFlipMode: No response received.");
|
|
return false;
|
|
}
|
|
|
|
var parser = new IperlHatFrameParser();
|
|
IperlHatResponse decoded = parser.Parse(rawData);
|
|
|
|
log.Debug(
|
|
string.Format(
|
|
"SetFlipMode({0}, 0x{1:X2}) isOK: {2}",
|
|
flipMode,
|
|
(byte)flipMode,
|
|
decoded.IsOk));
|
|
|
|
if (!decoded.IsOk)
|
|
return false;
|
|
|
|
if (iHead != null && iHead.ConfigStruct != null)
|
|
iHead.ConfigStruct.FlipMode = flipMode;
|
|
|
|
return true;
|
|
}
|
|
|
|
public CalibrationFactorResult ViewCalibration( IperlHead iHead)
|
|
{
|
|
if (!serialDriver.IsOpen())
|
|
{
|
|
serialDriver.Open();
|
|
}
|
|
|
|
byte[] request = new IperlHatFrameBuilder()
|
|
.RequestResponse(true)
|
|
.AddDeviceCommand( ProtocolDeviceSubCommand.ViewCalibration)
|
|
.BuildBytes();
|
|
|
|
byte[] rawData = serialDriver.SendAndWait(request, 5000);
|
|
|
|
if (rawData == null || rawData.Length == 0)
|
|
{
|
|
log.Warn( "ViewCalibration: No response received.");
|
|
return null;
|
|
}
|
|
|
|
try
|
|
{
|
|
var parser = new IperlHatFrameParser();
|
|
IperlHatResponse decoded = parser.Parse(rawData);
|
|
|
|
log.Debug( "ViewCalibration isOK: " + decoded.IsOk);
|
|
|
|
if (!decoded.IsOk)
|
|
{
|
|
log.Warn( "ViewCalibration: Device returned NOK response.");
|
|
return null;
|
|
}
|
|
|
|
if (decoded.Payload == null || decoded.Payload.Length != 2)
|
|
{
|
|
log.Warn( "ViewCalibration: Invalid payload. Expected two-byte little-endian value. Payload=" +
|
|
BitConverter.ToString( decoded.Payload ?? new byte[0]));
|
|
return null;
|
|
}
|
|
|
|
ushort calibrationFactor = (ushort)( decoded.Payload[0] | (decoded.Payload[1] << 8));
|
|
|
|
double percentage = calibrationFactor * 100.0 / 4096.0;
|
|
|
|
var result = new CalibrationFactorResult
|
|
{
|
|
RawValue = calibrationFactor,
|
|
Percentage = percentage,
|
|
CorrectionPercentage = percentage - 100.0
|
|
};
|
|
|
|
log.Debug( "ViewCalibration result: " + result);
|
|
return result;
|
|
}
|
|
catch (FormatException ex)
|
|
{
|
|
log.Error( "ViewCalibration: Invalid response frame.", ex);
|
|
return null;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
log.Error("ViewCalibration failed.", ex);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
// ----------------------
|
|
|
|
|
|
public bool SetActivityMode_Active(IperlHead iHead)
|
|
{
|
|
if (!serialDriver.IsOpen())
|
|
{
|
|
serialDriver.Open();
|
|
}
|
|
|
|
//Set State to Active 02
|
|
byte[] request = new IperlHatFrameBuilder()
|
|
.RequestResponse(true)
|
|
.AddCommand(ProtocolCommand.SetState)
|
|
.AddSubCommand(ProtocolStatuses.Active) // Active
|
|
.BuildBytes();
|
|
|
|
byte[] rawData = serialDriver.SendAndWait(request, 5000);
|
|
if (rawData == null)
|
|
return false;
|
|
|
|
|
|
// parse rawData
|
|
var parser = new IperlHatFrameParser();
|
|
IperlHatResponse decoded = parser.Parse(rawData);
|
|
log.Debug("SetActivityMode_Active isOK: " + decoded.IsOk);
|
|
if (decoded.IsOk && iHead.ConfigStruct != null)
|
|
{
|
|
iHead.ConfigStruct.StatusMode = ProtocolStatuses.Active;
|
|
}
|
|
return decoded.IsOk;
|
|
}
|
|
|
|
public bool SetActivityMode_Idle(IperlHead iHead)
|
|
{
|
|
if (!serialDriver.IsOpen())
|
|
{
|
|
serialDriver.Open();
|
|
}
|
|
|
|
//Set Activity State Idle 01
|
|
byte[] request = new IperlHatFrameBuilder()
|
|
.RequestResponse(true)
|
|
.AddCommand(ProtocolCommand.SetState)
|
|
.AddSubCommand(ProtocolStatuses.Idle)
|
|
.BuildBytes();
|
|
|
|
byte[] rawData = serialDriver.SendAndWait(request, 5000);
|
|
if (rawData == null)
|
|
return false;
|
|
|
|
|
|
// parse rawData
|
|
var parser = new IperlHatFrameParser();
|
|
IperlHatResponse decoded = parser.Parse(rawData);
|
|
log.Debug("SetActivityMode_Idle isOK: " + decoded.IsOk);
|
|
if (decoded.IsOk && iHead.ConfigStruct != null)
|
|
{
|
|
iHead.ConfigStruct.StatusMode = ProtocolStatuses.Idle;
|
|
}
|
|
return decoded.IsOk;
|
|
}
|
|
|
|
public bool SetOptTestMode(IperlHead iHead)
|
|
{
|
|
if (!serialDriver.IsOpen())
|
|
{
|
|
serialDriver.Open();
|
|
}
|
|
|
|
//Set LED to state 7
|
|
var request = new IperlHatFrameBuilder()
|
|
.RequestResponse(true)
|
|
.AddDeviceCommand(ProtocolDeviceSubCommand.SetDiagnosticLEDState)
|
|
.AddPayload(DiagnosticLedState.State7)
|
|
.BuildBytes();
|
|
|
|
byte[] rawData = serialDriver.SendAndWait(request, 5000);
|
|
if (rawData == null)
|
|
return false;
|
|
|
|
|
|
// parse rawData
|
|
var parser = new IperlHatFrameParser();
|
|
IperlHatResponse decoded = parser.Parse(rawData);
|
|
bool isOk = decoded.IsOk;
|
|
log.Debug("SetOptTestMode isOK: " + isOk);
|
|
if (decoded.IsOk && iHead.ConfigStruct != null)
|
|
{
|
|
iHead.ConfigStruct.OpthoStatusMode = DiagnosticLedState.State7;
|
|
}
|
|
return isOk;
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// stop data streaming by LED
|
|
/// </summary>
|
|
/// <param name="iHead"></param>
|
|
/// <returns></returns>
|
|
public bool SetOptActiveMode(IperlHead iHead)
|
|
{
|
|
if (!serialDriver.IsOpen())
|
|
{
|
|
serialDriver.Open();
|
|
}
|
|
|
|
//Set LED to state 1
|
|
var request = new IperlHatFrameBuilder()
|
|
.RequestResponse(true)
|
|
.AddDeviceCommand(ProtocolDeviceSubCommand.SetDiagnosticLEDState)
|
|
.AddPayload(DiagnosticLedState.StateOFF)
|
|
.BuildBytes();
|
|
|
|
byte[] rawData = serialDriver.SendAndWait(request, 5000);
|
|
if (rawData == null)
|
|
return false;
|
|
|
|
|
|
// parse rawData
|
|
var parser = new IperlHatFrameParser();
|
|
IperlHatResponse decoded = parser.Parse(rawData);
|
|
log.Debug("SetOptActiveMode isOK: " + decoded.IsOk);
|
|
if (decoded.IsOk && iHead.ConfigStruct != null)
|
|
{
|
|
iHead.ConfigStruct.OpthoStatusMode = DiagnosticLedState.StateOFF;
|
|
}
|
|
return decoded.IsOk;
|
|
}
|
|
|
|
public string GetUnit(IperlHead iperlHead)
|
|
{
|
|
if (!serialDriver.IsOpen())
|
|
{
|
|
serialDriver.Open();
|
|
}
|
|
|
|
var request = new IperlHatFrameBuilder()
|
|
.RequestResponse(true)
|
|
.AddCommand(ProtocolCommand.ViewFactoryId)
|
|
.BuildBytes();
|
|
|
|
|
|
byte[] rawData = serialDriver.SendAndWait(request, 10000);
|
|
if (rawData == null)
|
|
return null;
|
|
|
|
// parse rawData
|
|
var parser = new IperlHatFrameParser();
|
|
IperlHatResponse decoded = parser.Parse(rawData);
|
|
if (decoded.IsOk)
|
|
{
|
|
string asciiPayload = decoded.GetAsciiPayload();
|
|
if (iperlHead.ConfigStruct != null) // store mechanism
|
|
{
|
|
iperlHead.ConfigStruct.Unit = asciiPayload;
|
|
}
|
|
return asciiPayload;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|
|
} |