Files
HC_APTBS/tools/Import-BipStatus.ps1
LucianoDev 827b811b39 feat: developer tools page, auto-test orchestrator, BIP display, tests redesign
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>
2026-05-07 13:59:50 +02:00

231 lines
8.1 KiB
PowerShell

<#
.SYNOPSIS
Parses BIP-STATUS sections from PSG5-PI CFG files and injects
<BipStatus> blocks into every preinjection="true" pump in pumps.xml.
.DESCRIPTION
Applies the 7-def Config B (T15014 family) to every preinjection=true pump.
Reactions are forced to 0 (display-only pass per implementation plan).
A timestamped backup of pumps.xml is created before modification.
.PARAMETER CfgDir
Directory containing the CFG files.
.PARAMETER PumpsXml
Path to pumps.xml. Defaults to %USERPROFILE%\.HC_APTBS\config\pumps.xml.
.PARAMETER DryRun
Print the generated XML only; do NOT modify pumps.xml.
.EXAMPLE
powershell -ExecutionPolicy Bypass -File Import-BipStatus.ps1
powershell -ExecutionPolicy Bypass -File Import-BipStatus.ps1 -DryRun
#>
param(
[string]$CfgDir = (Join-Path $PSScriptRoot '..\old_source\HerlicScripts\CFGs'),
[string]$PumpsXml = (Join-Path $env:USERPROFILE '.HC_APTBS\config\pumps.xml'),
[switch]$DryRun
)
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
$BipCfgFiles = @(
'T15009.CFG','T15014.CFG','T15017.CFG','T15018.CFG','T15019.CFG',
'T15021.CFG','T18309.CFG','T18603.CFG','T18607.CFG','T31804.CFG'
)
# ---- Parse one CFG file -------------------------------------------------------
function Parse-BipConfig {
param([string]$cfgPath)
$defMap = @{}
$vector = $null
$lines = [System.IO.File]::ReadAllLines($cfgPath, [System.Text.Encoding]::GetEncoding('ISO-8859-1'))
foreach ($line in $lines) {
$raw = ($line -split '\\')[0].Trim()
if (-not $raw) { continue }
$cols = $raw -split '\|' | ForEach-Object { $_.Trim() }
$key = $cols[0]
if ($key -eq 'BIP-STATUS') {
if ($cols.Count -ge 5) { $vector = $cols[4].Trim() }
}
elseif ($key -match '^BIP-STATUS(\d+)-DEF$') {
$idx = [int]$Matches[1]
$hexStr = if ($cols.Count -ge 5) { $cols[4].Trim() } else { '0000' }
$spfnRaw = if ($cols.Count -ge 7) { $cols[6].Trim() } else { '9' }
$spfn = if ($spfnRaw -eq 'B') { 11 } else {
$n = 9; [int]::TryParse($spfnRaw, [ref]$n) | Out-Null; $n
}
$defMap[$idx] = [ordered]@{
Index = $idx
Enabled = $true
HexPattern = [Convert]::ToUInt16($hexStr, 16)
Reaction = 0
SpecialFunction= $spfn
Description = ''
}
}
elseif ($key -match '^BIP-STATUS(\d+)$') {
$idx = [int]$Matches[1]
$desc = if ($cols.Count -ge 5) { $cols[4].Trim() } else { '' }
if ($defMap.ContainsKey($idx)) { $defMap[$idx].Description = $desc }
}
}
# Apply enable vector: char at position i = '1' means bit i enabled
if ($vector) {
$vArr = $vector.ToCharArray()
foreach ($idx in @($defMap.Keys)) {
if ($idx -lt $vArr.Count) {
$defMap[$idx].Enabled = ($vArr[$idx] -eq '1')
}
}
}
return @($defMap.GetEnumerator() | Sort-Object { $_.Key } | ForEach-Object { $_.Value })
}
# ---- Parse all CFG files ------------------------------------------------------
Write-Host ""
Write-Host "=== Parsing CFG files from: $CfgDir ===" -ForegroundColor Cyan
Write-Host ""
$configs = @{}
foreach ($cfgName in $BipCfgFiles) {
$cfgPath = Join-Path $CfgDir $cfgName
if (-not (Test-Path $cfgPath)) {
Write-Warning "CFG not found, skipping: $cfgPath"
continue
}
$parsed = Parse-BipConfig -cfgPath $cfgPath
$cnt = $parsed.Count
Write-Host " $cfgName -- $cnt BIP definitions"
$configs[$cfgName] = $parsed
}
# T15014 = 7-def Config B (most complete; safe to apply to all preinjection pumps)
$configB = $null
if ($configs.ContainsKey('T15014.CFG')) { $configB = $configs['T15014.CFG'] }
if ($null -eq $configB) {
# Fallback: any 7-def config
foreach ($k in $configs.Keys) {
if ($configs[$k].Count -eq 7) { $configB = $configs[$k]; break }
}
}
if ($null -eq $configB -and $configs.ContainsKey('T15009.CFG')) {
$configB = $configs['T15009.CFG']
}
if ($null -eq $configB) {
Write-Error "No BIP config could be parsed. Aborting."
exit 1
}
$defCount = $configB.Count
Write-Host ""
Write-Host "Using $defCount-def Config B (T15014 family) for all preinjection pumps." -ForegroundColor Green
# ---- Generate preview XML -----------------------------------------------------
if ($DryRun) {
Write-Host ""
Write-Host "=== Generated BipStatus XML (DryRun -- pumps.xml NOT modified) ===" -ForegroundColor Yellow
Write-Host " <BipStatus>"
foreach ($d in $configB) {
$en = if ($d.Enabled) { 'true' } else { 'false' }
$hex = '0x{0:X4}' -f [int]$d.HexPattern
$desc= $d.Description
Write-Host (" <Bit index=""{0}"" enabled=""{1}"" hex=""{2}"" reaction=""{3}"" specialFunction=""{4}"">{5}</Bit>" -f $d.Index, $en, $hex, $d.Reaction, $d.SpecialFunction, $desc)
}
Write-Host " </BipStatus>"
Write-Host ""
exit 0
}
# ---- Load pumps.xml -----------------------------------------------------------
if (-not (Test-Path $PumpsXml)) {
Write-Error "pumps.xml not found: $PumpsXml"
exit 1
}
$backup = $PumpsXml -replace '\.xml$', ('_bip_backup_{0}.xml' -f (Get-Date -Format 'yyyyMMdd_HHmmss'))
Copy-Item $PumpsXml $backup -Force
Write-Host "Backed up pumps.xml -> $backup" -ForegroundColor DarkGray
[System.Reflection.Assembly]::LoadWithPartialName('System.Xml.Linq') | Out-Null
$xdoc = [System.Xml.Linq.XDocument]::Load($PumpsXml)
$pumps = @($xdoc.Descendants([System.Xml.Linq.XName]'Pump') | Where-Object {
$attr = $_.Attribute('preinjection')
($null -ne $attr) -and ($attr.Value -eq 'true')
})
Write-Host ""
Write-Host "Found $($pumps.Count) preinjection=true pump(s) in pumps.xml." -ForegroundColor Cyan
$updated = 0
foreach ($pump in $pumps) {
$idAttr = $pump.Attribute('id')
$pumpId = if ($null -ne $idAttr) { $idAttr.Value } else { '(unknown)' }
# Remove any existing BipStatus
$existing = $pump.Element([System.Xml.Linq.XName]'BipStatus')
if ($null -ne $existing) {
$existing.Remove()
Write-Host " Replaced BipStatus on pump $pumpId"
} else {
Write-Host " Added BipStatus on pump $pumpId"
}
# Build new BipStatus element
$bipElem = [System.Xml.Linq.XElement]::new([System.Xml.Linq.XName]'BipStatus')
foreach ($d in $configB) {
$en = if ($d.Enabled) { 'true' } else { 'false' }
$hex = '0x{0:X4}' -f [int]$d.HexPattern
$bit = [System.Xml.Linq.XElement]::new([System.Xml.Linq.XName]'Bit',
[System.Xml.Linq.XAttribute]::new('index', [string]$d.Index),
[System.Xml.Linq.XAttribute]::new('enabled', $en),
[System.Xml.Linq.XAttribute]::new('hex', $hex),
[System.Xml.Linq.XAttribute]::new('reaction', [string]$d.Reaction),
[System.Xml.Linq.XAttribute]::new('specialFunction', [string]$d.SpecialFunction),
[System.Xml.Linq.XText]::new($d.Description)
)
$bipElem.Add($bit)
}
# Insert after <Params>, or append if absent
$paramsElem = $pump.Element([System.Xml.Linq.XName]'Params')
if ($null -ne $paramsElem) {
$paramsElem.AddAfterSelf($bipElem)
} else {
$pump.Add($bipElem)
}
$updated++
}
if ($updated -eq 0) {
Write-Warning "No pumps updated. Restoring backup."
Copy-Item $backup $PumpsXml -Force
exit 0
}
# Save UTF-8 without BOM
$settings = [System.Xml.XmlWriterSettings]::new()
$settings.Encoding = [System.Text.UTF8Encoding]::new($false)
$settings.Indent = $true
$settings.IndentChars = ' '
$settings.OmitXmlDeclaration = $false
$writer = [System.Xml.XmlWriter]::Create($PumpsXml, $settings)
try { $xdoc.Save($writer) } finally { $writer.Close() }
Write-Host ""
Write-Host "Done. Updated $updated pump(s) in pumps.xml." -ForegroundColor Green
Write-Host "Backup: $backup" -ForegroundColor DarkGray
Write-Host ""
Write-Host "Next: run the app, select a preinjection pump, and verify BipDisplayView shows $defCount BIP rows." -ForegroundColor Cyan
Write-Host ""