<# .SYNOPSIS Parses BIP-STATUS sections from PSG5-PI CFG files and injects 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 " " foreach ($d in $configB) { $en = if ($d.Enabled) { 'true' } else { 'false' } $hex = '0x{0:X4}' -f [int]$d.HexPattern $desc= $d.Description Write-Host (" {5}" -f $d.Index, $en, $hex, $d.Reaction, $d.SpecialFunction, $desc) } Write-Host " " 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 , 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 ""