Refactor iPerl communication services: replace legacy calibration and configuration methods with OptoHeadTest functionality, streamline diagnostic LED state handling, and clean up unused code.

This commit is contained in:
Michal Buzik 2026-02-15 22:45:13 +01:00
parent 010bc7131a
commit 2b3eb5f10a
19 changed files with 1154 additions and 948 deletions

View File

@ -31,7 +31,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication
ThreadId,
WMNr0,
(Ihead != null) ? Ihead.Name : "null",
Wm.WMPosition,
(Wm != null) ? Wm.WMPosition : -1,
(CommMessage != null) ? CommMessage : "null",
CommErr);
}

View File

@ -14,7 +14,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.IperlHatProtoc
public IperlHatFrameBuilder RequestResponse(bool enabled)
{
_direction = enabled ? TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.Constants.Write : TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.Constants.Read;
_direction = enabled ? TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.Write : TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.Read;
return this;
}
@ -57,7 +57,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.IperlHatProtoc
public IperlHatFrameBuilder SetVersionCommand()
{
_commandBytes.Add((byte)ProtocolCommand.Question);
_payload.AddRange(TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.Constants.Version);
_payload.AddRange(TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.Version);
return this;
}
@ -110,19 +110,19 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.IperlHatProtoc
return new IperlHatFrame(
TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.Constants.Start,
TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.Start,
_direction,
length,
_commandBytes.ToArray(),
_payload.ToArray(),
TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.Constants.End);
TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.End);
}
public byte[] BuildBytes()
{
IperlHatFrame frame = BuildFrame();
if (frame.CommandInformation.Length > 0 && frame.CommandInformation[0] == TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.Constants.Question)
if (frame.CommandInformation.Length > 0 && frame.CommandInformation[0] == TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.Question)
{
var bytes = new List<byte>
{

View File

@ -16,28 +16,28 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.IperlHatProtoc
if (data[0] != TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.Constants.Start)
if (data[0] != TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.Start)
{
//if version parse version
if (data[0] == TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.Constants.Question)
if (data[0] == TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.Question)
{
//Define Question answer
var prefix = new List<byte>{ TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.Constants.Question };
var end = new List<byte>{ TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.Constants.End };
var prefix = new List<byte>{ TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.Question };
var end = new List<byte>{ TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.End };
if (IsPrefixValid(data, prefix, end))
{
//whole payload may be like "vers: Harry T:B800, V:06.06.01, FW:190215, 7ECE, B1.6.01, HW:4, Serial:0"
prefix = new List<byte>{ TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.Constants.Question };
prefix = new List<byte>{ TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.Question };
byte[] payloadVersion = ExtractPayloadUsePrefix(data, prefix, end);
return new IperlHatResponse(TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.Constants.Question, payloadVersion.Length > 0 ? TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.Constants.StatusOk : TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.Constants.StatusNok, payloadVersion);
return new IperlHatResponse(TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.Question, payloadVersion.Length > 0 ? TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.StatusOk : TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.StatusNok, payloadVersion);
}
}
throw new FormatException("Invalid START byte.");
}
if (data[1] != TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.Constants.Read)
if (data[1] != TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.Read)
throw new FormatException("Frame is no Response.");
byte length = data[2];
@ -47,8 +47,8 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.IperlHatProtoc
byte direction = data[1];
byte status = data[3];
var prefixCommand = new List<byte>{ TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.Constants.Start,direction,length,status };
var endCommand = new List<byte>{ TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.Constants.End };
var prefixCommand = new List<byte>{ TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.Start,direction,length,status };
var endCommand = new List<byte>{ TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.End };
byte[] payload = ExtractPayloadUsePrefix(data,prefixCommand,endCommand);

View File

@ -1,6 +1,6 @@
namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol
{
public static class Constants
public static class IperlHatProtocolConstants
{
public const byte Start = 0x53; //'S'
public const byte Write = 0x57; // 'W'

View File

@ -8,7 +8,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.IperlHatProtoc
private byte Status { get; }
public byte[] Payload { get; }
public bool IsOk => Status == TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.Constants.StatusOk;
public bool IsOk => Status == TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.StatusOk;
public IperlHatResponse(byte control, byte status, byte[] payload)
{
@ -16,7 +16,66 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.IperlHatProtoc
Status = status;
Payload = payload ?? Array.Empty<byte>();
}
public int GetResponse(ref bool isInt)
{
if (Payload.Length > 0 && Payload.Length <= 1)
{
isInt = true;
return Payload[0];
}
isInt = false;
return 0xFD;
}
public T GetResponse<T>(out bool ok) where T : struct
{
ok = false;
// we expect exactly 1 byte payload
if (Payload == null || Payload.Length != 1)
return default;
byte raw = Payload[0];
Type t = typeof(T);
// ----- BYTE -----
if (t == typeof(byte))
{
ok = true;
return (T)(object)raw;
}
// ----- INT -----
if (t == typeof(int))
{
ok = true;
return (T)(object)(int)raw;
}
// ----- USHORT -----
if (t == typeof(ushort))
{
ok = true;
return (T)(object)(ushort)raw;
}
// ----- ENUM -----
if (t.IsEnum)
{
// check if value exists in enum
if (!Enum.IsDefined(t, raw))
return default;
ok = true;
return (T)Enum.ToObject(t, raw);
}
// unsupported type
return default;
}
public string GetAsciiPayload()
{

View File

@ -90,6 +90,11 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed
/// electrode voltage noise, and ADC offset learning status.
/// </para>
/// </summary>
State7 = 0x07
State7 = 0x07,
/// <summary>
/// Unknown state.
/// </summary>
StatusUnknown = 0xFF,
}
}

View File

@ -9,10 +9,10 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.hexLogger
public static string DescribeDirection(byte direction)
{
if (direction == IperlHatProtocol.Constants.Write)
if (direction == IperlHatProtocol.IperlHatProtocolConstants.Write)
return "(WRITE - OUTGOING)";
if (direction == IperlHatProtocol.Constants.Read)
if (direction == IperlHatProtocol.IperlHatProtocolConstants.Read)
return "(READ - INCOMING)";
return "INVALID CONTROL BITS (unsupported pattern)";

View File

@ -10,7 +10,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.hexLogger
if (frame == null || frame.Length < 5)
return "Invalid frame";
if (frame[2] == IperlHatProtocol.Constants.Question)
if (frame[2] == IperlHatProtocol.IperlHatProtocolConstants.Question)
{
return
"TX Frame\n" +

View File

@ -4,7 +4,10 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.protocolCommon
{
Idle = 0x01,
Active = 0x02,
Inactive = 0x03,
EndOfLife = 0x03,
MeterTest = 0x04,
MeterTestEMF = 0x05,
Unknown = 0x00
}
}

View File

@ -2,6 +2,7 @@ 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;
@ -26,14 +27,14 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication
}
public void CloseConnection()
private void CloseConnection()
{
if (serialDriver != null)
serialDriver.CloseConnection();
}
public static string ReadRequest_PCB(IperlHead iHead)
public static string ReadRequest_PCB(ref IperlHead iHead)
{
if (iHead.DebugLevel == DebugMode.Simulate)
{
@ -48,7 +49,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication
serialDriver = BuildConnection(iHead);
RadioService headService = new RadioService(serialDriver);
string serialNo = headService.ReadRequest_PCB(iHead);
string serialNo = headService.ReadRequest_PCB(ref iHead);
return serialNo;
}
}
@ -60,14 +61,67 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication
return "";
}
public static string SetTestMode(IperlHead iHead)
/// <summary>
/// Set Test mode
/// </summary>
/// <param name="iHead"></param>
/// <returns></returns>
public static bool SetTestMode(ref IperlHead iHead)
{
bool activityModeActive = SetActivityMode_Active(iHead);
bool optActiveMode = SetOptTestMode(ref iHead);
return (optActiveMode && activityModeActive);
}
/// <summary>
/// Set Active mode
/// </summary>
/// <param name="iHead"></param>
/// <returns></returns>
public static bool SetActiveMode(ref IperlHead iHead)
{
bool optActiveMode = SetOptActiveMode(iHead);
bool activityModeIdle = SetActivityMode_Idle(iHead);
return (optActiveMode && activityModeIdle);
}
/// <summary>
/// Set Test mode - string response
/// </summary>
/// <param name="iHead"></param>
/// <param name="isTestModeSuccessful"></param>
/// <returns></returns>
public static string SetTestMode(ref IperlHead iHead, ref bool isTestModeSuccessful)
{
if (iHead.DebugLevel == DebugMode.Simulate)
{
isTestModeSuccessful = true;
return "-OK Simulated response-";
}
try
{
isTestModeSuccessful = SetTestMode(ref iHead);
return isTestModeSuccessful ? "Set Test Mode - OK" : "Set Test Mode - FAILED";
}catch (Exception ex)
{
return "Set Test Mode - Exception";
}
}
/// <summary>
/// Set Optical -> Test mode
/// </summary>
/// <param name="iHead"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
private static bool SetOptTestMode(ref IperlHead iHead)
{
try
{
if (iHead != null)
@ -76,25 +130,50 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication
serialDriver = BuildConnection(iHead);
RadioService headService = new RadioService(serialDriver);
string answer = headService.SetTestMode(iHead);
return answer;
var optTestMode = headService.SetOptTestMode(iHead);
iHead.ConfigStruct.OpthoStatusMode = optTestMode ? DiagnosticLedState.State4 : DiagnosticLedState.StatusUnknown;
return optTestMode;
}
}
catch (Exception ex)
{
return (ex.Message.ToString());
throw ex;
}
return "";
return false;
}
public static string SetActiveMode(IperlHead iHead)
/// <summary>
/// Set Active mode - string response
/// </summary>
/// <param name="iHead"></param>
/// <param name="isTestModeSuccessful"></param>
/// <returns></returns>
public static string SetActiveMode(ref IperlHead iHead, ref bool isTestModeSuccessful)
{
if (iHead.DebugLevel == DebugMode.Simulate)
{
isTestModeSuccessful = true;
return "-OK Simulated response-";
}
try
{
isTestModeSuccessful = SetActiveMode(ref iHead);
return isTestModeSuccessful ? "Set Active Mode - OK" : "Set Active Mode - FAILED";
}
catch (Exception ex)
{
return "Set Active Mode - Exception";
}
}
/// <summary>
/// Set Optical -> Active mode
/// </summary>
/// <param name="iHead"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
private static bool SetOptActiveMode(IperlHead iHead)
{
try
{
if (iHead != null)
@ -103,21 +182,127 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication
serialDriver = BuildConnection(iHead);
RadioService headService = new RadioService(serialDriver);
string answer = headService.SetActiveMode(iHead);
return answer;
return headService.SetOptActiveMode(iHead);
}
}
catch (Exception ex)
{
return (ex.Message.ToString());
throw ex;
}
return "";
return false;
}
/// <summary>
/// Set activity mode to active
/// </summary>
/// <param name="iHead"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
private static bool SetActivityMode_Active(IperlHead iHead)
{
try
{
if (iHead != null)
{
if (serialDriver == null)
serialDriver = BuildConnection(iHead);
RadioService headService = new RadioService(serialDriver);
return headService.SetActivityMode_Active(iHead);
}
}
catch (Exception ex)
{
throw ex;
}
return false;
}
/// <summary>
/// Set activity mode to idle
/// </summary>
/// <param name="iHead"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
private static bool SetActivityMode_Idle(IperlHead iHead)
{
try
{
if (iHead != null)
{
if (serialDriver == null)
serialDriver = BuildConnection(iHead);
RadioService headService = new RadioService(serialDriver);
return headService.SetActivityMode_Idle(iHead);
}
}
catch (Exception ex)
{
throw ex;
}
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 static bool ReadConfiguration(ref IperlHead iHead, DiagnosticLedState ledState )
{
if (iHead.DebugLevel == DebugMode.Simulate)
{
return true;
}
try
{
if (iHead != null)
{
iHead.ConfigStruct = new ConfigStruct();
if (serialDriver == null)
serialDriver = BuildConnection(iHead);
RadioService headService = new RadioService(serialDriver);
iHead.ConfigStruct.PCBNumberString = headService.ReadRequest_PCB(ref iHead);
iHead.ConfigStruct.StatusMode = headService.GetActivityStatusMode(iHead);
if (ledState != DiagnosticLedState.StatusUnknown) // do set
{
iHead.ConfigStruct.OpthoStatusMode = headService.SetOptoStatusMode(iHead, ledState);
}
else
{
iHead.ConfigStruct.OpthoStatusMode = DiagnosticLedState.StatusUnknown;
}
iHead.ConfigStruct.Version = headService.GetVersion(iHead);
return true;
}
else
{
return false;
}
}
catch (Exception ex)
{
return false;
}
}
}
}

View File

@ -18,7 +18,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication
this.serialDriver = serialDriver;
}
public string ReadRequest_PCB(IperlHead iHead)
public string ReadRequest_PCB(ref IperlHead iHead)
{
if (!serialDriver.IsOpen())
{
@ -40,13 +40,161 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication
IperlHatResponse decoded = parser.Parse(rawData);
if (decoded.IsOk)
{
return decoded.GetAsciiPayload();
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();
public string SetTestMode(IperlHead iHead)
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);
// 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);
if (decoded.IsOk)
{
return decoded.GetAsciiPayload();
}
return "";
}
public bool SetActivityMode_Active(IperlHead iHead)
{
if (!serialDriver.IsOpen())
{
serialDriver.Open();
}
//Set LED to state 4
byte[] request = new IperlHatFrameBuilder()
.RequestResponse(true)
.AddCommand(ProtocolCommand.SetState)
.AddSubCommand(ProtocolStatuses.Active) // Active
.BuildBytes();
byte[] rawData = serialDriver.SendAndWait(request, 2000);
if (rawData == null)
return false;
// parse rawData
var parser = new IperlHatFrameParser();
IperlHatResponse decoded = parser.Parse(rawData);
return decoded.IsOk;
}
public bool SetActivityMode_Idle(IperlHead iHead)
{
if (!serialDriver.IsOpen())
{
serialDriver.Open();
}
//Set Activity State Idle
byte[] request = new IperlHatFrameBuilder()
.RequestResponse(true)
.AddCommand(ProtocolCommand.SetState)
.AddSubCommand(ProtocolStatuses.Idle)
.BuildBytes();
byte[] rawData = serialDriver.SendAndWait(request, 2000);
if (rawData == null)
return false;
// parse rawData
var parser = new IperlHatFrameParser();
IperlHatResponse decoded = parser.Parse(rawData);
return decoded.IsOk;
}
public bool SetOptTestMode(IperlHead iHead)
{
if (!serialDriver.IsOpen())
{
@ -60,23 +208,13 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication
byte[] rawData = serialDriver.SendAndWait(request, 1000);
if (rawData == null)
return null;
return false;
// parse rawData
var parser = new IperlHatFrameParser();
IperlHatResponse decoded = parser.Parse(rawData);
if (decoded.IsOk)
{
//correct or incorrect response
//okResponse, errorResponse
return "Set Test Mode - OK";
}
return "Set Test Mode - FAILED";
return decoded.IsOk;
}
@ -85,7 +223,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication
/// </summary>
/// <param name="iHead"></param>
/// <returns></returns>
public string SetActiveMode(IperlHead iHead)
public bool SetOptActiveMode(IperlHead iHead)
{
if (!serialDriver.IsOpen())
{
@ -97,21 +235,15 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication
.AddDiagnosticLedState(DiagnosticLedState.StateOFF)
.BuildBytes();
byte[] rawData = serialDriver.SendAndWait(request, 1000);
byte[] rawData = serialDriver.SendAndWait(request, 2000);
if (rawData == null)
return null;
return false;
// parse rawData
var parser = new IperlHatFrameParser();
IperlHatResponse decoded = parser.Parse(rawData);
if (decoded.IsOk)
{
return "Set Active Mode - OK";
}
return "Set Active Mode - FAILED";
return decoded.IsOk;
}
}
}

View File

@ -204,13 +204,13 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication.Utils
byte readByte = (byte)_serialPort.ReadByte();
//I have START
if (readByte == TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.Constants.Start)
if (readByte == TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.Start)
{
iWordCounter++;
isStart = true;
}
// I have QUESTION
if (readByte == TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.Constants.Question)
if (readByte == TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.Question)
{
iWordCounter++;
isQuestion = true;
@ -236,7 +236,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication.Utils
break;
}
//if we read END
if (isQuestion && readByte == TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.Constants.End)
if (isQuestion && readByte == TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.End)
{
break;
}

View File

@ -24,7 +24,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication
public override void InitializeAll()
{
Activity = "Read Configuration";
Activity = iPerlCommunicationForm.ReadConfigurationStr;
SimultWithPrevious = false;
SimultWithNext = false;
}

View File

@ -3,264 +3,141 @@
///
using System;
using System.IO;
using System.Text;
using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed;
using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.protocolCommons;
namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead
{
public class ConfigStruct
{
public const int Length = 32;
//public const int Length = 32; // dynamic
public Byte Version; /// 0: 1 byte
public MeterState MeterState; /// 1: 1 byte
public UInt32 TargetTimeVeryLowBatt; /// 2: 4 bytes in seconds
public UInt32 TargetTimeLowBatt; /// 6: 4 bytes, in seconds
public UInt32 TestModeTime; /// 10: 4 bytes, Max. test mode time in seconds
public UInt16 EmptyPipeThreshold; /// 14: 2 bytes
public byte[] PCBNumber; /// 16: 5 bytes
public byte TestModeConfig; /// 21: 1 byte
public UInt32 RadioAddress; /// 22: 4 bytes
public UInt16 TempCalibration; /// 26: 2 bytes
public UInt16 AlarmMask; /// 28: 2 bytes, Default 0xA3F7
public UInt16 ConfigCheckSum; /// 30: 2 bytes
//public Byte Version; // 0: 1 byte
public string PCBNumberString; // dynamic
public ProtocolStatuses StatusMode; // byte
public DiagnosticLedState OpthoStatusMode;// byte
public string Version; // dynamic
public ConfigStruct()
{
PCBNumber = new byte[5];
}
public byte[] ToByteArray()
//Optho test status mode
public DiagnosticLedState TestModeConfig
{
byte[] result = new byte[Length];
result[0] = Version;
result[1] = (byte)MeterState;
result[2] = (byte)(TargetTimeVeryLowBatt & 0x000000FF);
result[3] = (byte)((TargetTimeVeryLowBatt >> 8) & 0x000000FF);
result[4] = (byte)((TargetTimeVeryLowBatt >> 16) & 0x000000FF);
result[5] = (byte)((TargetTimeVeryLowBatt >> 24) & 0x000000FF);
result[6] = (byte)(TargetTimeLowBatt & 0x000000FF);
result[7] = (byte)((TargetTimeLowBatt >> 8) & 0x000000FF);
result[8] = (byte)((TargetTimeLowBatt >> 16) & 0x000000FF);
result[9] = (byte)((TargetTimeLowBatt >> 24) & 0x000000FF);
result[10] = (byte)(TestModeTime & 0x000000FF);
result[11] = (byte)((TestModeTime >> 8) & 0x000000FF);
result[12] = (byte)((TestModeTime >> 16) & 0x000000FF);
result[13] = (byte)((TestModeTime >> 24) & 0x000000FF);
result[14] = (byte)(EmptyPipeThreshold & 0x00FF);
result[15] = (byte)((EmptyPipeThreshold >> 8) & 0x00FF);
result[16] = PCBNumber[0];
result[17] = PCBNumber[1];
result[18] = PCBNumber[2];
result[19] = PCBNumber[3];
result[20] = PCBNumber[4];
result[21] = TestModeConfig;
result[22] = (byte)(RadioAddress & 0x000000FF);
result[23] = (byte)((RadioAddress >> 8) & 0x000000FF);
result[24] = (byte)((RadioAddress >> 16) & 0x000000FF);
result[25] = (byte)((RadioAddress >> 24) & 0x000000FF);
result[26] = (byte)(TempCalibration & 0x00FF);
result[27] = (byte)((TempCalibration >> 8) & 0x00FF);
result[28] = (byte)(AlarmMask & 0x00FF);
result[29] = (byte)((AlarmMask >> 8) & 0x00FF);
result[30] = (byte)(ConfigCheckSum & 0x00FF);
result[31] = (byte)((ConfigCheckSum >> 8) & 0x00FF);
return result;
get { return OpthoStatusMode; }
}
/// <summary>
/// Create a configuration structure from a complete byte array
/// </summary>
/// <param name="data">A complete byte array data</param>
/// <returns>ConfigStruct or null when byte array was not complete</returns>
public static ConfigStruct FromByteArray(byte[] data)
//Activity test status mode
public ProtocolStatuses MeterState
{
if (data.Length != Length) return null;
ConfigStruct result = new ConfigStruct();
result.Version = data[0];
result.MeterState = (MeterState)data[1];
result.TargetTimeVeryLowBatt = (((UInt32)data[5] * 256 + data[4]) * 256 + data[3]) * 256 + data[2];
result.TargetTimeLowBatt = (((UInt32)data[9] * 256 + data[8]) * 256 + data[7]) * 256 + data[6];
result.TestModeTime = (((UInt32)data[13] * 256 + data[12]) * 256 + data[11]) * 256 + data[10];
result.EmptyPipeThreshold = (UInt16)(data[15] * 256 + data[14]);
result.PCBNumber[0] = data[16];
result.PCBNumber[1] = data[17];
result.PCBNumber[2] = data[18];
result.PCBNumber[3] = data[19];
result.PCBNumber[4] = data[20];
result.TestModeConfig = data[21];
result.RadioAddress = (((UInt32)data[25] * 256 + data[24]) * 256 + data[23]) * 256 + data[22];
result.TempCalibration = (UInt16)(data[27] * 256 + data[26]);
result.AlarmMask = (UInt16)(data[29] * 256 + data[28]);
result.ConfigCheckSum = (UInt16)(data[31] * 256 + data[30]);
return result;
get
{
return StatusMode;
}
}
/// <summary>
/// <summary>
/// Update the configuration structure from an incomplete byte array
/// </summary>
/// <param name="offset">Offset of byte array data in ConfigStruct</param>
/// <param name="data">Byte array data</param>
/// <returns>true when successful, false when data are not appropriate</returns>
public bool Update(int offset, byte[] data)
{
if (offset == 0 && data.Length == 2)
{
/// iPerl mode of function
Version = data[0];
MeterState = (MeterState)data[1];
return true;
}
else if (offset == 0 && data.Length == 4)
{
/// iPerl mode of function and extra 2 bytes
Version = data[0];
MeterState = (MeterState)data[1];
return true;
}
else if (offset == 21 && data.Length == 1)
{
/// TestModeConfig value
TestModeConfig = data[21 - offset];
return true;
}
else if (offset == 0 && data.Length == Length)
{
/// Complete ConfigStruct
Version = data[0];
MeterState = (MeterState)data[1];
TargetTimeVeryLowBatt = (((UInt32)data[5] * 256 + data[4]) * 256 + data[3]) * 256 + data[2];
TargetTimeLowBatt = (((UInt32)data[9] * 256 + data[8]) * 256 + data[7]) * 256 + data[6];
TestModeTime = (((UInt32)data[13] * 256 + data[12]) * 256 + data[11]) * 256 + data[10];
EmptyPipeThreshold = (UInt16)(data[15] * 256 + data[14]);
PCBNumber[0] = data[16];
PCBNumber[1] = data[17];
PCBNumber[2] = data[18];
PCBNumber[3] = data[19];
PCBNumber[4] = data[20];
TestModeConfig = data[21];
RadioAddress = (((UInt32)data[25] * 256 + data[24]) * 256 + data[23]) * 256 + data[22];
TempCalibration = (UInt16)(data[27] * 256 + data[26]);
AlarmMask = (UInt16)(data[29] * 256 + data[28]);
ConfigCheckSum = (UInt16)(data[31] * 256 + data[30]);
return true;
}
else
return false;
}
// public bool Update(int offset, )
// {
//
// /// Complete ConfigStruct
// Version = data[0];
// MeterState = (MeterState)data[1];
// TargetTimeVeryLowBatt = (((UInt32)data[5] * 256 + data[4]) * 256 + data[3]) * 256 + data[2];
// TargetTimeLowBatt = (((UInt32)data[9] * 256 + data[8]) * 256 + data[7]) * 256 + data[6];
// TestModeTime = (((UInt32)data[13] * 256 + data[12]) * 256 + data[11]) * 256 + data[10];
// EmptyPipeThreshold = (UInt16)(data[15] * 256 + data[14]);
// PCBNumberString
// TestModeConfig = data[21];
// RadioAddress = (((UInt32)data[25] * 256 + data[24]) * 256 + data[23]) * 256 + data[22];
// TempCalibration = (UInt16)(data[27] * 256 + data[26]);
// AlarmMask = (UInt16)(data[29] * 256 + data[28]);
// ConfigCheckSum = (UInt16)(data[31] * 256 + data[30]);
// return true;
// }
// else
// return false;
// }
/// <summary>
/// Returns PCB number string (12 characters, 12 decimal digits)
/// </summary>
/// <returns>PCB number STRING</returns>
public string GetPcbNrString()
{
return PCBNumber2String(this.PCBNumber);
}
public string GetPcbNrString(){
return PCBNumberString;
}
/// <summary>
/// Converts PCBNumber to string (12 characters, 12 decimal digits)
/// </summary>
/// <param name="pcbNumber"></param>
/// <returns>PCB number string</returns>
public static string PCBNumber2String(byte[] pcbNumber)
{
if (pcbNumber.Length != 5) return string.Empty;
Int64 number = 0;
for (int i = 4; i >= 0; i--)
{
number = 256 * number + (Int64)pcbNumber[i];
}
return number.ToString();
}
public override string ToString()
{
return string.Format("Config: V{0} State={1} VLoBattT={2}s LoBattT={3}s TestModeT={4}s EPThld={5} PCB#={6} TMCfg={7} RadioAddr={8} TempCalib={9} AlarmMask={10} CfgCheckSum={11}",
Version,
MeterState,
TargetTimeVeryLowBatt,
TargetTimeLowBatt,
TestModeTime,
EmptyPipeThreshold,
GetPcbNrString(),
TestModeConfig.ToString("X2"),
RadioAddress,
TempCalibration,
AlarmMask.ToString("X4"),
ConfigCheckSum.ToString("X4"));
return string.Format(
"Config: V{0} PCB#={1} StatusMode={2}",
Version,
GetPcbNrString(),
StatusMode
);
}
public string ToString(int sel)
{
return string.Format("{1} PCB#={6} TMCfg={7}",
return string.Format("{0} PCB#={1} StatusMode={2}",
Version,
MeterState,
TargetTimeVeryLowBatt,
TargetTimeLowBatt,
TestModeTime,
EmptyPipeThreshold,
GetPcbNrString(),
TestModeConfig.ToString("X2"),
RadioAddress,
TempCalibration,
AlarmMask.ToString("X4"),
ConfigCheckSum.ToString("X4"));
StatusMode
);
}
public virtual void WriteBinary(BinaryWriter writer)
{
writer.Write(Version);
writer.Write((byte)MeterState);
writer.Write(TargetTimeVeryLowBatt);
writer.Write(TargetTimeLowBatt);
writer.Write(TestModeTime);
writer.Write(EmptyPipeThreshold);
writer.Write(PCBNumber[0]);
writer.Write(PCBNumber[1]);
writer.Write(PCBNumber[2]);
writer.Write(PCBNumber[3]);
writer.Write(PCBNumber[4]);
writer.Write(TestModeConfig);
writer.Write(RadioAddress);
writer.Write(TempCalibration);
writer.Write(AlarmMask);
writer.Write(ConfigCheckSum);
writer.Write(0x11); // mark new type of verison
// Convert string to bytes (UTF8 is standard)
byte[] versionBytes = Encoding.UTF8.GetBytes(Version);
// 1) write length
writer.Write(versionBytes.Length);
// 2) write string bytes
writer.Write(versionBytes);
//writer.Write(Version);
writer.Write((byte)StatusMode);
byte[] PCBNumberStringBytes = Encoding.UTF8.GetBytes(PCBNumberString);
// 1) write length
writer.Write(PCBNumberStringBytes.Length);
// 2) write string bytes
writer.Write(PCBNumberStringBytes);
}
public virtual void ReadBinary(BinaryReader reader)
{
Version = reader.ReadByte();
MeterState = (MeterState)reader.ReadByte();
TargetTimeVeryLowBatt = reader.ReadUInt32();
TargetTimeLowBatt = reader.ReadUInt32();
TestModeTime = reader.ReadUInt32();
EmptyPipeThreshold = reader.ReadUInt16();
PCBNumber[0] = reader.ReadByte();
PCBNumber[1] = reader.ReadByte();
PCBNumber[2] = reader.ReadByte();
PCBNumber[3] = reader.ReadByte();
PCBNumber[4] = reader.ReadByte();
TestModeConfig = reader.ReadByte();
RadioAddress = reader.ReadUInt32();
TempCalibration = reader.ReadUInt16();
AlarmMask = reader.ReadUInt16();
ConfigCheckSum = reader.ReadUInt16();
// ---- Test Data type ----
var readByte = reader.ReadByte();
if (readByte != 0x11) return; // not correct version
// ---- Version ----
// 1) read length
int length = reader.ReadInt32();
// 2) read string bytes
byte[] versionBytes = reader.ReadBytes(length);
// 3) convert back to string
Version = Encoding.UTF8.GetString(versionBytes);
// ---- PCB Number ----
// 1) read length
int lengthPCB = reader.ReadInt32();
// 2) read string bytes
byte[] bytesPCB = reader.ReadBytes(lengthPCB);
// 3) convert back to string
PCBNumberString = Encoding.UTF8.GetString(bytesPCB);
}
}
}

View File

@ -1050,7 +1050,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead
string line = optoSerialPort.ReadLine(); // string
byte[] bytes = optoSerialPort.Encoding.GetBytes(line);
received = HexFormatter.ToSerialHex(bytes);
Console.WriteLine("RX ← " + received);
log.Debug("RX ← " + received);
}
return received;
}

View File

@ -79,13 +79,14 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead
{
ListItem rfidListItem = new ListItem();
rfidListItem.Attributes.Add("style", "font-weight:bold");
bool isTestModeSuccessful = false;
switch (rfidCommandComboBox.SelectedValue)
{
case "ReadPCB":
rfidListItem.Text = $"PCB: {OptoHeadTest.ReadRequest_PCB(iPerlHead)}";
rfidListItem.Text = $"PCB: {OptoHeadTest.ReadRequest_PCB(ref iPerlHead)}";
break;
case "SetTestMode":
rfidListItem.Text = OptoHeadTest.SetTestMode(iPerlHead);
rfidListItem.Text = OptoHeadTest.SetTestMode(ref iPerlHead, ref isTestModeSuccessful);
optoListBox.Items.Clear();
stopWorkerThread = false;
optoThread = new Thread(OptoWorker);
@ -96,7 +97,8 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead
}
break;
case "SetActiveMode":
rfidListItem.Text = OptoHeadTest.SetActiveMode(iPerlHead);
rfidListItem.Text = OptoHeadTest.SetActiveMode(ref iPerlHead, ref isTestModeSuccessful);
stopWorkerThread = true;
iPerlHead.StopDataStreamProcessing(); // close opto port
break;

View File

@ -1,5 +1,8 @@
using System;
using System.IO;
using System.Linq;
using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed;
using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.protocolCommons;
namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead
{
@ -9,9 +12,32 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead
internal static int ReadRequest(TestMethodCfg cfg, IperlHead iperlHead, MessageID messageID, int offset, int length, out byte[] buffer)
{
byte[] configurationBuffer = new byte[ConfigStruct.Length] { 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
string pcbStr = iperlHead.RfidComPortNr.ToString().PadRight(10,'0') + iperlHead.Position.ToString("D2");
long decVal = Convert.ToInt64(pcbStr);
string nHexStr = decVal.ToString("X4");
ConfigStruct configStruct = new ConfigStruct();
configStruct.PCBNumberString = nHexStr;
configStruct.StatusMode = ProtocolStatuses.Active;
configStruct.OpthoStatusMode = DiagnosticLedState.State4;
configStruct.Version = "Good Version: 123456";
byte[] configurationBuffer;
using (var ms = new MemoryStream())
using (var writer = new BinaryWriter(ms))
{
configStruct.WriteBinary(writer);
writer.Flush();
configurationBuffer = ms.ToArray(); // ← this is the binary output
}
byte[] calibrationBuffer = new byte[CalibrationStructV4.Length] { 3, 0, 150, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 0, 0, 150, 10 };
buffer = new byte[length];
return 0;//switch off
if (messageID == MessageID.Configuration)
{

View File

@ -39,7 +39,7 @@
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>TRACE;DEBUG;CAMERA;LANG_PL</DefineConstants>
<DefineConstants>TRACE;DEBUG;CAMERA;LANG_PL;IPERL</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
@ -50,7 +50,7 @@
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE;CAMERA;LANG_PL</DefineConstants>
<DefineConstants>TRACE;CAMERA;LANG_PL;IPERL</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>AnyCPU</PlatformTarget>
@ -60,7 +60,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>TRACE;DEBUG;CAMERA;LANG_PL</DefineConstants>
<DefineConstants>TRACE;DEBUG;CAMERA;LANG_PL;IPERL</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
@ -70,7 +70,7 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE;CAMERA;LANG_PL</DefineConstants>
<DefineConstants>TRACE;CAMERA;LANG_PL;IPERL</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
@ -1465,7 +1465,7 @@
<Compile Include="Rig\TestMethods\iPerlCommunication\communication\C4\hexLogger\IperlHatLogger.cs" />
<Compile Include="Rig\TestMethods\iPerlCommunication\communication\C4\hexLogger\TouchReadControlDecoder.cs" />
<Compile Include="Rig\TestMethods\iPerlCommunication\communication\C4\hexLogger\TouchReadLogger.cs" />
<Compile Include="Rig\TestMethods\iPerlCommunication\communication\C4\IperlHatProtocol\Constants.cs" />
<Compile Include="Rig\TestMethods\iPerlCommunication\communication\C4\IperlHatProtocol\IperlHatProtocolConstants.cs" />
<Compile Include="Rig\TestMethods\iPerlCommunication\communication\C4\IperlHatProtocol\IperlHatFrame.cs" />
<Compile Include="Rig\TestMethods\iPerlCommunication\communication\C4\IperlHatProtocol\IperlHatFrameBuilder.cs" />
<Compile Include="Rig\TestMethods\iPerlCommunication\communication\C4\IperlHatProtocol\IperlHatFrameParser.cs" />