IperlASIC - added aditional parameters

Add support for reading additional common parameters in OptoHeadTest. Enhance `RadioService` and `VersionTypeResult` with new parsing logic. Update related constants and UI elements for functionality integration.
This commit is contained in:
Michal Buzik 2026-08-05 10:57:34 +02:00
parent 7a8ce7b6ab
commit 4d9ddef3ca
6 changed files with 634 additions and 120 deletions

View File

@ -2,134 +2,128 @@ using System.Text.RegularExpressions;
namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.protocolCommons
{
using System;
using System.Text.RegularExpressions;
namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol
public class VersionTypeResult
{
public class VersionTypeResult
public string TouchReadVersion { get; set; }
public string MeterDeviceType { get; set; }
public string MeterFirmwareVersion { get; set; }
public static VersionTypeResult ParseVersionTypePayload(
string payload)
{
public string TouchReadVersion { get; set; }
public string MeterDeviceType { get; set; }
public string MeterFirmwareVersion { get; set; }
public static VersionTypeResult ParseVersionTypePayload(
string payload)
if (string.IsNullOrWhiteSpace(payload))
{
if (string.IsNullOrWhiteSpace(payload))
{
return null;
}
string normalizedPayload = payload
.Trim('\0', '\r', '\n', ' ');
VersionTypeResult result =
ParseCompactPayload(normalizedPayload);
if (result != null)
{
return result;
}
return ParseLegacyPayload(normalizedPayload);
return null;
}
private static VersionTypeResult ParseCompactPayload(
string payload)
string normalizedPayload = payload
.Trim('\0', '\r', '\n', ' ');
VersionTypeResult result =
ParseCompactPayload(normalizedPayload);
if (result != null)
{
// Expected format:
// B1.23,SWM004,1.00
string[] parts = payload.Split(',');
if (parts.Length != 3)
{
return null;
}
string touchReadVersion = parts[0].Trim();
string meterDeviceType = parts[1].Trim();
string meterFirmwareVersion = parts[2].Trim();
if (string.IsNullOrWhiteSpace(touchReadVersion) ||
string.IsNullOrWhiteSpace(meterDeviceType) ||
string.IsNullOrWhiteSpace(meterFirmwareVersion))
{
return null;
}
return new VersionTypeResult
{
TouchReadVersion = touchReadVersion,
MeterDeviceType = meterDeviceType,
MeterFirmwareVersion = meterFirmwareVersion
};
return result;
}
private static VersionTypeResult ParseLegacyPayload(
string payload)
return ParseLegacyPayload(normalizedPayload);
}
private static VersionTypeResult ParseCompactPayload(
string payload)
{
// Expected format:
// B1.23,SWM004,1.00
string[] parts = payload.Split(',');
if (parts.Length != 3)
{
// Expected example:
//
// vers: Harry T:B800, V:06.06.01, FW:190215,
// 7ECE, B1.6.01, HW:4, Serial:0
Match deviceTypeMatch = Regex.Match(
payload,
@"(?:^|[\s,])T\s*:\s*([^,\s]+)",
RegexOptions.IgnoreCase);
Match versionMatch = Regex.Match(
payload,
@"(?:^|[\s,])V\s*:\s*([^,\s]+)",
RegexOptions.IgnoreCase);
Match firmwareMatch = Regex.Match(
payload,
@"(?:^|[\s,])FW\s*:\s*([^,\s]+)",
RegexOptions.IgnoreCase);
if (!deviceTypeMatch.Success ||
!versionMatch.Success ||
!firmwareMatch.Success)
{
return null;
}
string meterDeviceType =
deviceTypeMatch.Groups[1].Value.Trim();
string touchReadVersion =
versionMatch.Groups[1].Value.Trim();
string meterFirmwareVersion =
firmwareMatch.Groups[1].Value.Trim();
if (string.IsNullOrWhiteSpace(touchReadVersion) ||
string.IsNullOrWhiteSpace(meterDeviceType) ||
string.IsNullOrWhiteSpace(meterFirmwareVersion))
{
return null;
}
return new VersionTypeResult
{
TouchReadVersion = touchReadVersion,
MeterDeviceType = meterDeviceType,
MeterFirmwareVersion = meterFirmwareVersion
};
return null;
}
public override string ToString()
string touchReadVersion = parts[0].Trim();
string meterDeviceType = parts[1].Trim();
string meterFirmwareVersion = parts[2].Trim();
if (string.IsNullOrWhiteSpace(touchReadVersion) ||
string.IsNullOrWhiteSpace(meterDeviceType) ||
string.IsNullOrWhiteSpace(meterFirmwareVersion))
{
return
$"TouchReadVersion={TouchReadVersion}, " +
$"MeterDeviceType={MeterDeviceType}, " +
$"MeterFirmwareVersion={MeterFirmwareVersion}";
return null;
}
return new VersionTypeResult
{
TouchReadVersion = touchReadVersion,
MeterDeviceType = meterDeviceType,
MeterFirmwareVersion = meterFirmwareVersion
};
}
private static VersionTypeResult ParseLegacyPayload(
string payload)
{
// Expected example:
//
// vers: Harry T:B800, V:06.06.01, FW:190215,
// 7ECE, B1.6.01, HW:4, Serial:0
Match deviceTypeMatch = Regex.Match(
payload,
@"(?:^|[\s,])T\s*:\s*([^,\s]+)",
RegexOptions.IgnoreCase);
Match versionMatch = Regex.Match(
payload,
@"(?:^|[\s,])V\s*:\s*([^,\s]+)",
RegexOptions.IgnoreCase);
Match firmwareMatch = Regex.Match(
payload,
@"(?:^|[\s,])FW\s*:\s*([^,\s]+)",
RegexOptions.IgnoreCase);
if (!deviceTypeMatch.Success ||
!versionMatch.Success ||
!firmwareMatch.Success)
{
return null;
}
string meterDeviceType =
deviceTypeMatch.Groups[1].Value.Trim();
string touchReadVersion =
versionMatch.Groups[1].Value.Trim();
string meterFirmwareVersion =
firmwareMatch.Groups[1].Value.Trim();
if (string.IsNullOrWhiteSpace(touchReadVersion) ||
string.IsNullOrWhiteSpace(meterDeviceType) ||
string.IsNullOrWhiteSpace(meterFirmwareVersion))
{
return null;
}
return new VersionTypeResult
{
TouchReadVersion = touchReadVersion,
MeterDeviceType = meterDeviceType,
MeterFirmwareVersion = meterFirmwareVersion
};
}
public override string ToString()
{
return
$"TouchReadVersion={TouchReadVersion}, " +
$"MeterDeviceType={MeterDeviceType}, " +
$"MeterFirmwareVersion={MeterFirmwareVersion}";
}
}
}

View File

@ -5,6 +5,7 @@ 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
{
@ -365,5 +366,466 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication
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>
/// 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:
/// version and type, reading units, flip mode
/// and calibration factor.
/// </summary>
/// <param name="resultStr">
/// Result intended for GUI and test-process output.
/// </param>
/// <returns>
/// True when all parameters were read successfully.
/// </returns>
public bool ReadAdditionalCommonParameters(
out string resultStr)
{
resultStr = string.Empty;
if (iperlHead == null)
{
resultStr =
"Read additional common parameters: iPerl head is null.";
log.Warn(resultStr);
return false;
}
if (iperlHead.DebugLevel == DebugMode.Simulate)
{
resultStr =
"Version/type: SIMULATED; " +
"Reading units: CubicMeters; " +
"Flip mode: 0x00; " +
"Calibration: 4096 (100.0000 %, correction 0.0000 %)";
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);
bool successful =
versionType != null &&
readingUnits.HasValue &&
flipMode.HasValue &&
calibration != null;
string versionTypeText =
versionType == null
? "FAILED"
: versionType.ToString();
string readingUnitsText =
readingUnits.HasValue
? string.Format(
"{0} (0x{1:X2})",
readingUnits.Value,
Convert.ToByte(readingUnits.Value))
: "FAILED";
string flipModeText =
flipMode.HasValue
? string.Format(
"{0} (0x{1:X2})",
flipMode.Value,
Convert.ToByte(flipMode.Value))
: "FAILED";
string calibrationText;
if (calibration == null)
{
calibrationText = "FAILED";
}
else
{
calibrationText = string.Format(
"{0} ({1:F4} %, correction {2:+0.0000;-0.0000;0.0000} %)",
calibration.RawValue,
calibration.Percentage,
calibration.CorrectionPercentage);
}
resultStr =
"Version/type: " + versionTypeText +
"; Reading units: " + readingUnitsText +
"; Flip mode: " + flipModeText +
"; Calibration: " + calibrationText;
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;
}
}
}
}

View File

@ -1,11 +1,9 @@
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.protocolCommons.TBF.Rig.TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol;
using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.wiredProtocol;
using TBF.Rig.TestMethods.iPerlCommunication.communication.Utils;
using TBF.Rig.TestMethods.iPerlCommunication.iPerlHead;

View File

@ -20,9 +20,10 @@ using TBF.Rig.TestMethods.iPerlCommunication.iPerlHead;
using Results.Entities;
using static Sensus.iPerl.NfcHandler.MCI_Protocol;
using System.Threading.Tasks;
using TBF.Rig.TestMethods.iPerlCommunication.communication;
using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed;
using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.protocolCommons;
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication;
namespace TBF.Rig.TestMethods.iPerlCommunication
{
@ -61,8 +62,8 @@ namespace TBF.Rig.TestMethods.iPerlCommunication
const int Q2CorrFactorsAddrLR = 0x1878;
const int Q2CorrFactorsAddrRL = 0x1879;
public const string ReadConfigurationStr = "Read configuration"; /// Example: "Read configuration" or "Read configuration if enabled"
public const string SetTestModeStr = "Set Test mode"; /// Example: "Set Test mode" or "Set Test mode A0" (hexadecimal number is the required 'testModeConfig'
public const string ReadConfigurationStr = "Read configuration"; // Example: "Read configuration" or "Read configuration if enabled"
public const string SetTestModeStr = "Set Test mode"; // Example: "Set Test mode" or "Set Test mode A0" (hexadecimal number is the required 'testModeConfig'
public const string SetActiveModeStr = "Set Active mode";
public const string ReadSerialNrStr = "Read SerialNr";
public const string SetIdleModeStr = "Set Idle mode";
@ -237,6 +238,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication
#if IPERL
ContextMenu cm = new ContextMenu();
cm.MenuItems.Add(NewMenuItem("Read PCB Number" , "ReadPCB"));
cm.MenuItems.Add(NewMenuItem( iPerlCommunicationConstants.ReadAdditionalCommonParametersStr, "ReadAdditionalCommonParameters"));
cm.MenuItems.Add(NewMenuItem("Enter Test Mode" , "StartTestMode"));
cm.MenuItems.Add(NewMenuItem("Turn Off Test Mode (Enter Active Mode)", "TurnOffTestMode"));
cm.MenuItems.Add(NewMenuItem("Set Production Mode (Radio not start with flow)" , "SetProductionMode"));
@ -715,6 +717,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication
else if (currentActivity.ToLower().Equals(SetActiveModeStr.ToLower())) error = SetActiveMode(threadID, ihead, ref resultStr);
else if (currentActivity.ToLower().Equals(SetIdleModeStr.ToLower())) error = SetIdleMode(threadID, ihead, ref resultStr);
else if (currentActivity.ToLower().Contains(ReadConfigurationStr.ToLower())) error = ReadConfiguration(ihead, wm, ref resultStr);
else if (currentActivity.ToLower().Contains( iPerlCommunicationConstants.ReadAdditionalCommonParametersStr.ToLower())) error = ReadAdditionalCommonParameters( ihead, ref resultStr);
///
/// RFID communication functions below require a reference to water meter entity (wm != null)
///
@ -1012,6 +1015,41 @@ namespace TBF.Rig.TestMethods.iPerlCommunication
return error;
}
/// <summary>
/// Reads additional common parameters through the optical head.
/// </summary>
private static CommErr ReadAdditionalCommonParameters( IperlHead ihead, ref string resultStr)
{
if (ihead == null)
{
resultStr = "Read additional common parameters: iPerl head is null.";
return CommErr.CommFailed;
}
if (ihead.CommFailed)
{
resultStr = "Read additional common parameters: previous communication failed.";
return CommErr.CommFailed;
}
if (ihead.OptoHeadTest == null)
{
resultStr = "Read additional common parameters: OptoHeadTest is not available.";
return CommErr.CommFailed;
}
try
{
bool successful = ihead.OptoHeadTest.ReadAdditionalCommonParameters( out resultStr);
return successful ? CommErr.None : CommErr.Read;
}
catch (Exception ex)
{
resultStr = "Read additional common parameters failed: " + ex.Message;
log.Error( "ReadAdditionalCommonParameters failed.", ex);
return CommErr.Read;
}
}
/// <summary>
/// Read a complete calibration structure from the watermeter
@ -2719,6 +2757,22 @@ namespace TBF.Rig.TestMethods.iPerlCommunication
case "ReadPCB":
txt = iHead.OptoHeadTest.ReadRequest_PCB();
break;
case "ReadAdditionalCommonParameters":
{
if (iHead.OptoHeadTest == null)
{
txt = "OptoHeadTest is not available.";
break;
}
success = iHead.OptoHeadTest .ReadAdditionalCommonParameters( out txt);
if (!success && string.IsNullOrWhiteSpace(txt))
{
txt = "Failed to read additional common parameters.";
}
break;
}
case "WriteRequestPort_u8_Customer_Text":
txt = "Not Supported NOW!";//OpticalHeadTest.WriteRequestPort_u8_Customer_Text(iHead);
break;
@ -2743,6 +2797,9 @@ namespace TBF.Rig.TestMethods.iPerlCommunication
case "SetNFC":
txt = "Not Supported NOW!";//OpticalHeadTest.SetNfcMode(iHead);
break;
default:
txt = "Unsupported operation: " + Convert.ToString(tag);
break;
}
return txt;
}
@ -2862,5 +2919,6 @@ namespace TBF.Rig.TestMethods.iPerlCommunication
e.Cancel = true;
}
}
}
}

View File

@ -10,6 +10,7 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
public const int Q2CorrFactorsAddrRL = 0x1879;
public const string ReadConfigurationStr = "Read configuration"; /// Example: "Read configuration" or "Read configuration if enabled"
public const string ReadAdditionalCommonParametersStr = "Read Additional Common Parameters";
public const string SetTestModeStr = "Set Test mode"; /// Example: "Set Test mode" or "Set Test mode A0" (hexadecimal number is the required 'testModeConfig'
public const string SetActiveModeStr = "Set Active mode";
public const string ReadCalibrationStr = "Read calibration";

View File

@ -44,6 +44,7 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
{
var retVal = new List<string>();
retVal.Add(iPerlCommunicationConstants.ReadConfigurationStr);
retVal.Add(iPerlCommunicationConstants.ReadAdditionalCommonParametersStr);
retVal.Add(string.Format("{0} A0", iPerlCommunicationConstants.SetTestModeStr));
retVal.Add(string.Format("{0} A4", iPerlCommunicationConstants.SetTestModeStr));
retVal.Add(iPerlCommunicationConstants.ReadCalibrationStr);