feat: redesign bench calibration (factor/offset), add Ttank/P2 displays, fix sensor calibration
- Replace P1-P6 rational transfer function with factor/offset model for bench params - Add explicit rx/tx direction flags in bench XML configuration - Add T.Tank (BenchTemp) and P2 (AnalogSensor2) to temperature/pressure display - Apply SensorConfiguration calibration to pressure channels, fix empty sensors.xml fallback - Add live value labels to flowmeter charts - Hide pump live values and PSG encoder standalone label - Add K-Line connection state model, improve KWP service and status displays - Restructure .claude/skills into subdirectory format Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -409,24 +409,28 @@ namespace HC_APTBS.Services.Impl
|
||||
private void LoadSensors()
|
||||
{
|
||||
_settings ??= new AppSettings();
|
||||
if (!File.Exists(SensorsXml))
|
||||
if (File.Exists(SensorsXml))
|
||||
{
|
||||
_settings.Sensors[1] = SensorConfiguration.DefaultPressureSensor();
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
var xdoc = XDocument.Load(SensorsXml);
|
||||
foreach (var xs in xdoc.Root!.Elements("sensor"))
|
||||
try
|
||||
{
|
||||
var sc = SensorConfiguration.FromXml(xs);
|
||||
_settings.Sensors[sc.Number] = sc;
|
||||
var xdoc = XDocument.Load(SensorsXml);
|
||||
foreach (var xs in xdoc.Root!.Elements("sensor"))
|
||||
{
|
||||
var sc = SensorConfiguration.FromXml(xs);
|
||||
_settings.Sensors[sc.Number] = sc;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Error(LogId, $"LoadSensors failed: {ex.Message}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Error(LogId, $"LoadSensors failed: {ex.Message}");
|
||||
}
|
||||
|
||||
// Ensure default calibrations exist for the two analogue channels.
|
||||
if (!_settings.Sensors.ContainsKey(1))
|
||||
_settings.Sensors[1] = SensorConfiguration.DefaultPressureSensor();
|
||||
if (!_settings.Sensors.ContainsKey(2))
|
||||
_settings.Sensors[2] = new SensorConfiguration { Number = 2, SensorName = "AnalogSensor2" };
|
||||
}
|
||||
|
||||
private void LoadClients()
|
||||
@@ -463,37 +467,28 @@ namespace HC_APTBS.Services.Impl
|
||||
|
||||
// ── Parsing helpers ───────────────────────────────────────────────────────
|
||||
|
||||
/// <summary>
|
||||
/// Parses a bench CAN parameter from an XML element.
|
||||
/// Uses the clean factor/offset calibration model with explicit direction flags.
|
||||
/// </summary>
|
||||
private static CanBusParameter ParseParamElement(XElement xe)
|
||||
{
|
||||
var p = new CanBusParameter
|
||||
string direction = xe.Attribute("direction")?.Value ?? "rx";
|
||||
|
||||
return new CanBusParameter
|
||||
{
|
||||
Name = xe.Name.LocalName,
|
||||
MessageId = Convert.ToUInt32(xe.Attribute("id")?.Value ?? "0", 16),
|
||||
ByteH = ushort.Parse(xe.Attribute("byteh")?.Value ?? "0"),
|
||||
ByteL = ushort.Parse(xe.Attribute("bytel")?.Value ?? "0"),
|
||||
Alpha = double.Parse(xe.Attribute("filter")?.Value ?? "1",
|
||||
System.Globalization.CultureInfo.InvariantCulture),
|
||||
DisableCalibration = bool.Parse(xe.Attribute("disableparams")?.Value ?? "true"),
|
||||
// Bench params default to receive unless explicitly marked send="true".
|
||||
IsReceive = !string.Equals(xe.Attribute("send")?.Value, "true",
|
||||
StringComparison.OrdinalIgnoreCase)
|
||||
Alpha = CanBusParameter.ParseDecimal(xe.Attribute("filter")?.Value, 1.0),
|
||||
IsReceive = string.Equals(direction, "rx", StringComparison.OrdinalIgnoreCase),
|
||||
Factor = CanBusParameter.ParseDecimal(xe.Attribute("factor")?.Value, 1.0),
|
||||
Offset = CanBusParameter.ParseDecimal(xe.Attribute("offset")?.Value, 0.0),
|
||||
IsInverse = string.Equals(xe.Attribute("type")?.Value, "inverse",
|
||||
StringComparison.OrdinalIgnoreCase),
|
||||
UseLegacyTransform = false,
|
||||
};
|
||||
|
||||
if (!p.DisableCalibration)
|
||||
{
|
||||
p.P1 = double.Parse(xe.Attribute("p1")?.Value ?? "1", System.Globalization.CultureInfo.InvariantCulture);
|
||||
p.P2 = double.Parse(xe.Attribute("p2")?.Value ?? "0", System.Globalization.CultureInfo.InvariantCulture);
|
||||
p.P3 = double.Parse(xe.Attribute("p3")?.Value ?? "0", System.Globalization.CultureInfo.InvariantCulture);
|
||||
p.P4 = double.Parse(xe.Attribute("p4")?.Value ?? "1", System.Globalization.CultureInfo.InvariantCulture);
|
||||
p.P5 = double.Parse(xe.Attribute("p5")?.Value ?? "0", System.Globalization.CultureInfo.InvariantCulture);
|
||||
p.P6 = double.Parse(xe.Attribute("p6")?.Value ?? "0", System.Globalization.CultureInfo.InvariantCulture);
|
||||
}
|
||||
else
|
||||
{
|
||||
p.SetIdentityCalibration();
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
private void ParseRelayElement(XElement xr)
|
||||
@@ -576,30 +571,37 @@ namespace HC_APTBS.Services.Impl
|
||||
|
||||
// ── Default bench XML ─────────────────────────────────────────────────────
|
||||
|
||||
/// <summary>Returns the factory-default bench parameter XML used when bench.xml is absent.</summary>
|
||||
/// <summary>
|
||||
/// Returns the factory-default bench parameter XML used when bench.xml is absent.
|
||||
/// Uses direction/factor/offset calibration model. Defaults: direction="rx", factor=1, offset=0, type="linear".
|
||||
/// </summary>
|
||||
private static string DefaultBenchXml() => @"<?xml version=""1.0"" encoding=""utf-8""?>
|
||||
<Bench>
|
||||
<RPM id=""10"" byteh=""1"" bytel=""0"" filter=""1"" disableparams=""true"" send=""true"" />
|
||||
<Counter id=""11"" byteh=""1"" bytel=""0"" filter=""1"" disableparams=""true"" send=""true"" />
|
||||
<BaudRate id=""55"" byteh=""0"" bytel=""0"" filter=""1"" disableparams=""true"" send=""true"" />
|
||||
<BenchRPM id=""13"" byteh=""1"" bytel=""0"" filter=""1"" disableparams=""true"" />
|
||||
<BenchCounter id=""13"" byteh=""3"" bytel=""2"" filter=""1"" disableparams=""true"" />
|
||||
<BenchTemp id=""14"" byteh=""1"" bytel=""0"" filter=""1"" disableparams=""false"" p1=""1"" p2=""0"" p3=""0"" p4=""10"" p5=""-20"" p6=""0"" />
|
||||
<T-in id=""14"" byteh=""3"" bytel=""2"" filter=""1"" disableparams=""false"" p1=""1"" p2=""0"" p3=""0"" p4=""10"" p5=""-20"" p6=""0"" />
|
||||
<T-out id=""14"" byteh=""5"" bytel=""4"" filter=""1"" disableparams=""false"" p1=""1"" p2=""0"" p3=""0"" p4=""10"" p5=""-20"" p6=""0"" />
|
||||
<T4 id=""14"" byteh=""7"" bytel=""6"" filter=""1"" disableparams=""false"" p1=""1"" p2=""0"" p3=""0"" p4=""10"" p5=""-20"" p6=""0"" />
|
||||
<QDelivery id=""8"" byteh=""5"" bytel=""3"" filter=""0.01"" disableparams=""false"" p1=""0"" p2=""2.03"" p3=""1E-06"" p4=""0"" p5=""0"" p6=""0"" />
|
||||
<QOver id=""8"" byteh=""2"" bytel=""0"" filter=""0.11"" disableparams=""false"" p1=""0"" p2=""0.51"" p3=""1E-06"" p4=""0"" p5=""0"" p6=""0"" />
|
||||
<PSGEncoderValue id=""50"" byteh=""4"" bytel=""5"" filter=""1"" disableparams=""false"" p1=""1"" p2=""0"" p3=""0"" p4=""1"" p5=""0"" p6=""0"" />
|
||||
<PSGEncoderWorking id=""50"" byteh=""7"" bytel=""7"" filter=""1"" disableparams=""true"" />
|
||||
<InyectorEncoderValue id=""50"" byteh=""2"" bytel=""3"" filter=""1"" disableparams=""false"" p1=""1"" p2=""0"" p3=""0"" p4=""1"" p5=""0"" p6=""0"" />
|
||||
<InyectorEncoderWorking id=""50"" byteh=""6"" bytel=""6"" filter=""1"" disableparams=""false"" p1=""1"" p2=""0"" p3=""0"" p4=""1"" p5=""0"" p6=""0"" />
|
||||
<ManualEncoderValue id=""50"" byteh=""0"" bytel=""1"" filter=""1"" disableparams=""false"" p1=""1"" p2=""0"" p3=""0"" p4=""1"" p5=""0"" p6=""0"" />
|
||||
<EncoderResolution id=""51"" byteh=""6"" bytel=""7"" filter=""1"" disableparams=""true"" send=""true"" />
|
||||
<ElectronicMsg id=""51"" byteh=""0"" bytel=""0"" filter=""1"" disableparams=""true"" send=""true"" />
|
||||
<Alarms id=""8"" byteh=""7"" bytel=""6"" filter=""1"" disableparams=""true"" />
|
||||
<Pressure id=""13"" byteh=""4"" bytel=""5"" filter=""1"" disableparams=""true"" />
|
||||
<AnalogicSensor2 id=""13"" byteh=""6"" bytel=""7"" filter=""1"" disableparams=""true"" />
|
||||
<!-- TX: values sent from software to bench controller -->
|
||||
<RPM id=""10"" byteh=""1"" bytel=""0"" direction=""tx"" />
|
||||
<Counter id=""11"" byteh=""1"" bytel=""0"" direction=""tx"" />
|
||||
<BaudRate id=""55"" byteh=""0"" bytel=""0"" direction=""tx"" />
|
||||
<EncoderResolution id=""51"" byteh=""6"" bytel=""7"" direction=""tx"" />
|
||||
<ElectronicMsg id=""51"" byteh=""0"" bytel=""0"" direction=""tx"" />
|
||||
|
||||
<!-- RX: values received from bench controller (direction=""rx"" is the default) -->
|
||||
<BenchRPM id=""13"" byteh=""1"" bytel=""0"" />
|
||||
<BenchCounter id=""13"" byteh=""3"" bytel=""2"" />
|
||||
<BenchTemp id=""14"" byteh=""1"" bytel=""0"" factor=""0.1"" offset=""-20"" />
|
||||
<T-in id=""14"" byteh=""3"" bytel=""2"" factor=""0.1"" offset=""-20"" />
|
||||
<T-out id=""14"" byteh=""5"" bytel=""4"" factor=""0.1"" offset=""-20"" />
|
||||
<T4 id=""14"" byteh=""7"" bytel=""6"" factor=""0.1"" offset=""-20"" />
|
||||
<QDelivery id=""8"" byteh=""5"" bytel=""3"" factor=""2030000"" type=""inverse"" filter=""0.01"" />
|
||||
<QOver id=""8"" byteh=""2"" bytel=""0"" factor=""510000"" type=""inverse"" filter=""0.11"" />
|
||||
<PSGEncoderValue id=""50"" byteh=""4"" bytel=""5"" />
|
||||
<PSGEncoderWorking id=""50"" byteh=""7"" bytel=""7"" />
|
||||
<InyectorEncoderValue id=""50"" byteh=""2"" bytel=""3"" />
|
||||
<InyectorEncoderWorking id=""50"" byteh=""6"" bytel=""6"" />
|
||||
<ManualEncoderValue id=""50"" byteh=""0"" bytel=""1"" />
|
||||
<Alarms id=""8"" byteh=""7"" bytel=""6"" />
|
||||
<Pressure id=""13"" byteh=""4"" bytel=""5"" />
|
||||
<AnalogicSensor2 id=""13"" byteh=""6"" bytel=""7"" />
|
||||
|
||||
<Reles>
|
||||
<Rele name=""Electronic"" id=""15"" bit=""0"" />
|
||||
<Rele name=""OilPump"" id=""15"" bit=""4"" />
|
||||
|
||||
Reference in New Issue
Block a user