tbf/TBF/Rig/RegisterReaders/PoseidonCmdStartStop/SerialPortData.cs
Michal Buzik 2fd2697e3b Fix lost 3.9.2204.0 versioning and improve Poseidon CLI diagnostics
- restore the Morrisville release version metadata
- add end-to-end logs for CLI execution, reader state, parsed results,
  and UI updates
- prevent completed Poseidon reads from being started repeatedly in a cycle
- use a fixed CLI directory and reliable working directory
2026-08-28 12:44:42 +02:00

273 lines
8.2 KiB
C#

using System;
using System.IO;
using System.ComponentModel;
using System.Reflection;
using System.Xml.Serialization;
namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
{
public class SerialPortData
{
public const string CliDirectory = @"C:\TBF\Cli";
private Boolean? _cliExists;
public bool CliExists { get {
if (_cliExists == null || !_cliExists.HasValue)
{
_cliExists = File.Exists(SerialPortCmdClientPath);
}
return _cliExists.Value;
} }
public string SerialPortCmdClientPath
{
get
{
// The configured value is a file name, not an executable path.
// Keeping the CLI directory fixed prevents a bench configuration
// from starting an unintended executable or failing due to a
// relative path/current-directory change.
string cliFileName = Path.GetFileName(CmdClientName);
if (string.IsNullOrWhiteSpace(cliFileName))
cliFileName = "HalCli.exe";
return Path.Combine(CliDirectory, cliFileName);
}
}
public string CmdClientName { get; set; } = "HalCli.exe";
public string PortName { get; set; }
// Backward compatibility: old numeric meter type
public int? OldMeterType { get; set; }
// New v2.0 parameters
public HatType Hat { get; set; } = HatType.Mth;
public int TimeoutSeconds { get; set; } = 10;
public string Macro { get; set; } = "readall";
[XmlIgnore]
public MeterProduct Meter { get; set; } = MeterProduct.Poseidon;
[XmlElement("MeterProduct")]
public string MeterXml
{
get { return MeterToString(Meter); }
set { Meter = StringToMeter(value); }
}
public static string MeterToString(MeterProduct meter)
{
switch (meter)
{
case MeterProduct.Poseidon:
return "Poseidon"; //Poseidon
case MeterProduct.Ally:
return "ally";
case MeterProduct.IperlPlus:
return "iperlplus";
case MeterProduct.IperlLegacy:
return "iperllegacy";
default:
return "74";
}
}
public static MeterProduct StringToMeter(string value)
{
if (string.IsNullOrWhiteSpace(value))
return MeterProduct.Poseidon;
// old numeric values: 74, 7889, etc.
if (int.TryParse(value, out _))
return MeterProduct.Poseidon;
if (string.Equals(value, "cTouchRead", StringComparison.OrdinalIgnoreCase))
return MeterProduct.Poseidon;
if (string.Equals(value, "Poseidon", StringComparison.OrdinalIgnoreCase))
return MeterProduct.Poseidon;
if (string.Equals(value, "ally", StringComparison.OrdinalIgnoreCase))
return MeterProduct.Ally;
if (string.Equals(value, "iperlplus", StringComparison.OrdinalIgnoreCase))
return MeterProduct.IperlPlus;
if (string.Equals(value, "iperllegacy", StringComparison.OrdinalIgnoreCase))
return MeterProduct.IperlLegacy;
return MeterProduct.Poseidon;
}
public static bool TryParseMeter(
string description,
out SerialPortData.MeterProduct meter)
{
foreach (SerialPortData.MeterProduct value in
Enum.GetValues(typeof(SerialPortData.MeterProduct)))
{
var attr = value.GetType()
.GetField(value.ToString())
.GetCustomAttribute<DescriptionAttribute>();
if (string.Equals(attr?.Description, description, StringComparison.OrdinalIgnoreCase) ||
string.Equals(value.ToString(), description, StringComparison.OrdinalIgnoreCase))
{
meter = value;
return true;
}
}
meter = SerialPortData.MeterProduct.Poseidon;
return false;
}
public enum MacroTypes
{
[Description("readall")]
readall = 0,
[Description("readmacro1")]
macro1 = 1,
[Description("readmacro2")]
macro2 = 2,
[Description("readmacro3")]
macro3 = 3
}
public enum HatType
{
[Description("Mth")]
Mth = 0,
[Description("Harry")]
Harry = 1
}
public enum MeterProduct
{
[Description("Poseidon")]
[XmlEnum("74")]
Poseidon = 74,
[Description("ally")]
[XmlEnum("ally")]
Ally = 75,
[Description("iperlplus")]
[XmlEnum("iperlplus")]
IperlPlus = 76,
[Description("iperllegacy")]
[XmlEnum("iperllegacy")]
IperlLegacy = 77
}
public enum EMeterArg
{
Calibration = 0,
AllParams = 2,
DeviceId = 3,
// New macro operations - just waste
ReadMacro1 = 10,
ReadMacro2 = 11,
ReadMacro3 = 12
}
public string DefaultArgSettings(EMeterArg eMeterArg)
{
string commonArgs = BuildCommonArgs();
switch (eMeterArg)
{
case EMeterArg.Calibration:
return $"{commonArgs} --operation write --parameter Calibration --value 1";
case EMeterArg.DeviceId:
return $"{commonArgs} --operation read --parameter DeviceId";
case EMeterArg.AllParams:
case EMeterArg.ReadMacro1:
case EMeterArg.ReadMacro2:
case EMeterArg.ReadMacro3:
return $"{commonArgs} --operation {Macro}";
default:
return "";
}
}
private string BuildCommonArgs()
{
return $"-p {PortName} " +
$"-m {GetMeterArgument()} " +
$"--hat {GetHatArgument()} " +
$"--timeout {TimeoutSeconds}";
}
private string GetMeterArgument()
{
// Old compatibility mode
if (OldMeterType.HasValue)
return OldMeterType.Value.ToString();
switch (Meter)
{
case MeterProduct.Poseidon:
return "74"; //return "Poseidon";
case MeterProduct.Ally:
return "ally";
case MeterProduct.IperlPlus:
return "iperlplus";
case MeterProduct.IperlLegacy:
return "iperllegacy";
default:
return "74"; //return "Poseidon";
}
}
private string GetHatArgument()
{
switch (Hat)
{
case HatType.Harry:
return "harry";
case HatType.Mth:
default:
return "mth";
}
}
// New constructor for v2.0
public SerialPortData(
string portName,
string cmdClientName,
MeterProduct meter = MeterProduct.Poseidon,
HatType hat = HatType.Mth,
int timeoutSeconds = 10,
string macro = "readall")
{
PortName = portName;
CmdClientName = cmdClientName;
Meter = meter;
Hat = hat;
TimeoutSeconds = timeoutSeconds;
Macro = macro;
}
// Old constructor kept for backward compatibility
public SerialPortData(
string portName,
string cmdClientName,
int meterType)
{
PortName = portName;
CmdClientName = cmdClientName;
OldMeterType = meterType;
}
}
}