Bundles several feature streams that have been iterating on the working tree: - Developer Tools page (Debug-only via DEVELOPER_TOOLS symbol): hosts the identification card, manual KWP write + transaction log, ROM/EEPROM dump card with progress banner and completion message, persisted custom-commands library, persisted EEPROM passwords library. New service primitives: IKwpService.SendRawCustomAsync / ReadEepromAsync / ReadRomEepromAsync. Persistence mirrors the Clients XML pattern in two new files (custom_commands.xml, eeprom_passwords.xml). - Auto-test orchestrator (IAutoTestOrchestrator + AutoTestState): linear K-Line read -> unlock -> bench-on -> test sequence with snackbar UI and progress dialog VM, gated on dashboard alarms. - BIP-STATUS display: BipDisplayViewModel + BipDisplayView, RAM read at 0x0106 via IKwpService.ReadBipStatusAsync; status definitions in BipStatusDefinition. - Tests page redesign: TestSectionCard + PhaseTileView replacing the old TestPlanView/TestRunningView/TestDoneView/TestPreconditionsView/ TestSectionView controls and their VMs. - Pump command sliders: Fluent thick-track style with overhang thumb, click-anywhere-and-drag, mouse-wheel adjustment. - Window startup: app.manifest declares PerMonitorV2 DPI awareness, MainWindow installs a WM_GETMINMAXINFO hook in OnSourceInitialized and maximizes there (after the hook is in place) so the app fits the work area exactly on any display configuration. - Misc: PercentToPixelsConverter, seed_aliases.py one-shot pump-alias importer, tools/Import-BipStatus.ps1, kline_eeprom_spec.md and dump-functions reference docs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
124 lines
4.5 KiB
Python
124 lines
4.5 KiB
Python
"""One-shot seeder: inject <Aliases> blocks into pumps.xml from the legacy
|
|
KlineIDs comma-string at old_source/Herlic2.0/App.config.
|
|
|
|
Reads canonical -> [aliases] map (hard-coded below from the legacy default),
|
|
finds each <Pump id="..."> in pumps.xml, and inserts an <Aliases><KlineId>...
|
|
block as the first child of that <Pump> element.
|
|
|
|
Idempotent: if a <Pump> already has an <Aliases> child, the script merges new
|
|
aliases into it without creating duplicates.
|
|
"""
|
|
import sys
|
|
from pathlib import Path
|
|
import xml.etree.ElementTree as ET
|
|
|
|
# Source: old_source/Herlic2.0/App.config -> KlineIDs setting (default value).
|
|
# Format: "klineID:canonicalPumpID,..."
|
|
LEGACY_KLINEIDS = (
|
|
"0470004007:0470004002,0470004008:0470004006,0470004012:0470004004,"
|
|
"1093412060:0470504028,1093412050:0470504012,1093424041:0470504034,"
|
|
"0986444003:0470504004,1093412071:0470504033,1093423001:0470504027,"
|
|
"0986444012:0470504011,1093412070:0470504033,0986444005:0470504009,"
|
|
"1093424051:0470504046,1093424025:1093424026,0986444002:0470504003,"
|
|
"1093424027:1093424026,1093423002:0470504027,1093424024:1093424026,"
|
|
"0986444006:0470506002,0986444011:0470504010,0986444044:0470506037,"
|
|
"1093421004:0470504026,1093412072:0470504033,1093411003:0470504030,"
|
|
"1093424040:0470504034,0986444019:0470504020,0986444004:0470504005,"
|
|
"1093411022:0470504037,0986444042:0470506017,0986444014:0470504015,"
|
|
"1093421006:0470504026,1093421005:0470504026,1093424080:0470504046,"
|
|
"0986444026:0470506030,1093411004:0470504030,0986444010:0470506009,"
|
|
"0986444008:0470506006,"
|
|
)
|
|
|
|
PUMPS_XML = Path.home() / ".HC_APTBS" / "config" / "pumps.xml"
|
|
|
|
|
|
def parse_legacy(s: str) -> dict[str, list[str]]:
|
|
"""Group legacy entries by canonical pump ID."""
|
|
aliases_by_canonical: dict[str, list[str]] = {}
|
|
for entry in s.split(","):
|
|
entry = entry.strip()
|
|
if not entry or ":" not in entry:
|
|
continue
|
|
kline_id, canonical = entry.split(":", 1)
|
|
kline_id = kline_id.strip()
|
|
canonical = canonical.strip()
|
|
if not kline_id or not canonical:
|
|
continue
|
|
bucket = aliases_by_canonical.setdefault(canonical, [])
|
|
if kline_id not in bucket:
|
|
bucket.append(kline_id)
|
|
return aliases_by_canonical
|
|
|
|
|
|
def main() -> int:
|
|
aliases_by_canonical = parse_legacy(LEGACY_KLINEIDS)
|
|
print(f"Parsed {sum(len(v) for v in aliases_by_canonical.values())} aliases "
|
|
f"across {len(aliases_by_canonical)} canonical pumps.")
|
|
|
|
if not PUMPS_XML.exists():
|
|
print(f"ERROR: {PUMPS_XML} does not exist.", file=sys.stderr)
|
|
return 1
|
|
|
|
tree = ET.parse(PUMPS_XML)
|
|
root = tree.getroot()
|
|
|
|
pumps_by_id: dict[str, ET.Element] = {}
|
|
for pump in root.iter("Pump"):
|
|
pid = pump.attrib.get("id")
|
|
if pid:
|
|
pumps_by_id[pid] = pump
|
|
|
|
missing = sorted(set(aliases_by_canonical) - set(pumps_by_id))
|
|
if missing:
|
|
print(f"WARNING: {len(missing)} canonical pumps from legacy data not in "
|
|
f"pumps.xml — skipping: {missing}", file=sys.stderr)
|
|
|
|
injected_pumps = 0
|
|
injected_aliases = 0
|
|
skipped_existing = 0
|
|
|
|
for canonical, kline_ids in sorted(aliases_by_canonical.items()):
|
|
pump = pumps_by_id.get(canonical)
|
|
if pump is None:
|
|
continue
|
|
|
|
existing = pump.find("Aliases")
|
|
if existing is None:
|
|
existing = ET.Element("Aliases")
|
|
pump.insert(0, existing)
|
|
existing.text = "\n "
|
|
existing.tail = "\n "
|
|
|
|
already = {(c.tag, (c.text or "").strip())
|
|
for c in existing if c.tag in ("KlineId", "ModelRef")}
|
|
|
|
added_here = 0
|
|
for k in kline_ids:
|
|
key = ("KlineId", k)
|
|
if key in already:
|
|
skipped_existing += 1
|
|
continue
|
|
kid = ET.SubElement(existing, "KlineId")
|
|
kid.text = k
|
|
kid.tail = "\n "
|
|
already.add(key)
|
|
added_here += 1
|
|
injected_aliases += 1
|
|
|
|
if added_here:
|
|
injected_pumps += 1
|
|
# Fix the tail of the last child so the closing tag is on its own line.
|
|
last = list(existing)[-1]
|
|
last.tail = "\n "
|
|
|
|
tree.write(PUMPS_XML, encoding="utf-8", xml_declaration=True)
|
|
print(f"Injected {injected_aliases} aliases into {injected_pumps} pumps.")
|
|
if skipped_existing:
|
|
print(f" ({skipped_existing} aliases were already present, skipped.)")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|