feat: implement SavePump/SaveAlarms, fix config round-trip bugs, redesign PDF reports
Config system fixes: - Implement SavePump() — full XML serialization with insert/update by pump ID - Add CanBusParameter.ToPumpXml() for legacy P1-P6 pump param format - Fix LastRotationDirection never loaded in LoadSettings() - Add SaveAlarms() to ConfigurationService and IConfigurationService - Remove dead fields AppSettings.Clients and AppSettings.PumpIds PDF report redesign: - Professional layout with charts, verdict badges, and tolerance bands - Add ReportChartRenderer (SVG) and ReportTheme styling constants - Embed default_logo.png as fallback report logo Documentation: - Add gap analysis docs (config validation, ford unlock, missing features) - Update CLAUDE.md architecture, known gaps, and debt tracking Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -190,7 +190,84 @@ namespace HC_APTBS.Services.Impl
|
||||
/// <inheritdoc/>
|
||||
public void SavePump(PumpDefinition pump)
|
||||
{
|
||||
_log.Info(LogId, $"SavePump({pump.Id}) — not yet implemented.");
|
||||
try
|
||||
{
|
||||
XDocument xdoc;
|
||||
if (File.Exists(PumpsXml))
|
||||
{
|
||||
xdoc = XDocument.Load(PumpsXml);
|
||||
}
|
||||
else
|
||||
{
|
||||
xdoc = new XDocument(new XElement("Config", new XElement("Pumps")));
|
||||
}
|
||||
|
||||
var root = xdoc.Root!;
|
||||
var pumpsNode = root.Element("Pumps");
|
||||
if (pumpsNode == null)
|
||||
{
|
||||
pumpsNode = new XElement("Pumps");
|
||||
root.Add(pumpsNode);
|
||||
}
|
||||
|
||||
// Build the <Pump> element mirroring ParsePumpElement's expected format.
|
||||
var xpump = new XElement("Pump",
|
||||
new XAttribute("id", pump.Id),
|
||||
new XAttribute("model", pump.Model),
|
||||
new XAttribute("text", pump.EcuText),
|
||||
new XAttribute("chaveta", pump.Chaveta),
|
||||
new XAttribute("rotation", pump.Rotation),
|
||||
new XAttribute("info", pump.Info),
|
||||
new XAttribute("preinjection", pump.HasPreInjection.ToString().ToLowerInvariant()),
|
||||
new XAttribute("cilinders4", pump.Is4Cylinder.ToString().ToLowerInvariant()),
|
||||
new XAttribute("unlock", pump.UnlockType),
|
||||
new XAttribute("baudrate", pump.CanBaudrate == Peak.Can.Basic.TPCANBaudrate.PCAN_BAUD_250K ? "250" : "500"),
|
||||
new XAttribute("lockangle", pump.LockAngle.ToString(CultureInfo.InvariantCulture)));
|
||||
|
||||
// PumpID child element — GetPumpIds() finds these via Descendants("PumpID").
|
||||
xpump.Add(new XElement("PumpID", pump.Id));
|
||||
|
||||
// ── Serialise <Params> (pump CAN params use legacy P1–P6 format) ──
|
||||
if (pump.ParametersByName.Count > 0)
|
||||
{
|
||||
var xparams = new XElement("Params");
|
||||
foreach (var param in pump.ParametersByName.Values)
|
||||
xparams.Add(param.ToPumpXml());
|
||||
xpump.Add(xparams);
|
||||
}
|
||||
|
||||
// ── Serialise <Tests> ──
|
||||
if (pump.Tests.Count > 0)
|
||||
{
|
||||
var xtests = new XElement("Tests");
|
||||
foreach (var test in pump.Tests)
|
||||
xtests.Add(test.ToXml());
|
||||
xpump.Add(xtests);
|
||||
}
|
||||
|
||||
// ── Find existing pump by ID and replace, or append ──
|
||||
XElement? existing = null;
|
||||
foreach (var child in pumpsNode.Elements("Pump"))
|
||||
{
|
||||
if (child.Attribute("id")?.Value == pump.Id)
|
||||
{
|
||||
existing = child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (existing != null)
|
||||
existing.ReplaceWith(xpump);
|
||||
else
|
||||
pumpsNode.Add(xpump);
|
||||
|
||||
xdoc.Save(PumpsXml);
|
||||
_log.Info(LogId, $"SavePump({pump.Id}) — saved to pumps.xml.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Error(LogId, $"SavePump({pump.Id}) failed: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
// ── IConfigurationService: Clients ────────────────────────────────────────
|
||||
@@ -241,6 +318,25 @@ namespace HC_APTBS.Services.Impl
|
||||
}
|
||||
}
|
||||
|
||||
// ── IConfigurationService: Alarms ─────────────────────────────────────────
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void SaveAlarms()
|
||||
{
|
||||
try
|
||||
{
|
||||
var root = new XElement("Alarms");
|
||||
foreach (var alarm in Settings.Alarms)
|
||||
root.Add(alarm.ToXml());
|
||||
new XDocument(root).Save(AlarmsXml);
|
||||
_log.Info(LogId, "Alarms saved.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Error(LogId, $"SaveAlarms failed: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
// ── Pump status definitions ───────────────────────────────────────────────
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -349,6 +445,7 @@ namespace HC_APTBS.Services.Impl
|
||||
TryInt(r, "MaxRpm", v => _settings.MaxRpm = v);
|
||||
TryBool(r, "RightRelayValue", v => _settings.RightRelayValue = v);
|
||||
TryBool(r, "DefaultIgnoreTin", v => _settings.DefaultIgnoreTin = v);
|
||||
TryInt(r, "LastRotationDir", v => _settings.LastRotationDirection = (short)v);
|
||||
TryInt(r, "DaysKeepLogs", v => _settings.DaysKeepLogs = v);
|
||||
TryString(r, "CompanyName", v => _settings.CompanyName = v);
|
||||
TryString(r, "CompanyInfo", v => _settings.CompanyInfo = v);
|
||||
|
||||
Reference in New Issue
Block a user