tbf/TBF/Rig/TestMethods/iPerlCommunication/communication/RadioService.cs
Michal Buzik 865528e344 iPerlASIC - additional parameters.
Add protocolCommons classes and enhance RadioService with support for CalibrationFactor, VersionType, ReadingUnits, and FlipMode operations. Add corresponding unit tests for validation. Update project files.
2026-08-03 15:42:16 +02:00

592 lines
19 KiB
C#

using System;
using System.Text;
using System.Text.RegularExpressions;
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 TouchReadFrameBuilder()
.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;
}
FlipMode flipMode =
decoded.GetResponse<FlipMode>(out bool responseOk);
if (!responseOk)
{
log.Warn(
"ViewFlipMode: Invalid payload. Expected one byte " +
"with value 0x00 or 0x01. Payload=" +
BitConverter.ToString(decoded.Payload));
return null;
}
log.Debug(
$"ViewFlipMode: {flipMode} " +
$"(0x{(byte)flipMode: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 CalibrationFactorResult ViewCalibration(IperlHead iHead)
{
if (!serialDriver.IsOpen())
{
serialDriver.Open();
}
byte[] request = new TouchReadFrameBuilder()
.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;
}
ushort calibrationFactor = decoded.GetUInt16LittleEndian(out bool responseOk);
if (!responseOk)
{
log.Warn( "ViewCalibration: Invalid payload. Expected uint16 little-endian value. Payload=" + BitConverter.ToString(decoded.Payload));
return null;
}
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;
}
}
}