#Requires -Version 7.0 <# .SYNOPSIS End-to-end CLI test for the AB CIP driver (ControlLogix / CompactLogix / Micro800 / GuardLogix) bridged through the OtOpcUa server. .DESCRIPTION Mirrors test-modbus.ps1 but against libplctag's ab_server (or a real Logix controller). Five assertions: probe / driver-loopback / forward-bridge / reverse-bridge / subscribe-sees-change. Prereqs: - ab_server container up (tests/.../AbCip.IntegrationTests/Docker/docker-compose.yml, --profile controllogix) OR a real PLC on the network. - OtOpcUa server running with an AB CIP DriverInstance pointing at the same gateway + a Tag published at the -BridgeNodeId you pass. .PARAMETER Gateway ab://host[:port]/cip-path. Default ab://127.0.0.1/1,0 (ab_server ControlLogix). .PARAMETER Family ControlLogix / CompactLogix / Micro800 / GuardLogix (default ControlLogix). .PARAMETER TagPath Logix symbolic path to exercise. Default 'TestDINT' — matches the ab_server --tag=TestDINT:DINT[1] seed. .PARAMETER OpcUaUrl OtOpcUa server endpoint. .PARAMETER BridgeNodeId NodeId at which the server publishes the TagPath. #> param( [string]$Gateway = "ab://127.0.0.1/1,0", [string]$Family = "ControlLogix", [string]$TagPath = "TestDINT", [string]$OpcUaUrl = "opc.tcp://localhost:4840", [Parameter(Mandatory)] [string]$BridgeNodeId ) $ErrorActionPreference = "Stop" . "$PSScriptRoot/_common.ps1" $abcipCli = Get-CliInvocation ` -ProjectFolder "src/ZB.MOM.WW.OtOpcUa.Driver.AbCip.Cli" ` -ExeName "otopcua-abcip-cli" $opcUaCli = Get-CliInvocation ` -ProjectFolder "src/ZB.MOM.WW.OtOpcUa.Client.CLI" ` -ExeName "otopcua-cli" $commonAbCip = @("-g", $Gateway, "-f", $Family) $results = @() # The AbCip driver's TagPath parser rejects CIP attribute syntax like # `@raw_cpu_type` ("malformed TagPath"), so probe uses the real TagPath for # every family. Works against ab_server + real controllers alike. $results += Test-Probe ` -Cli $abcipCli ` -ProbeArgs (@("probe") + $commonAbCip + @("-t", $TagPath, "--type", "DInt")) $writeValue = Get-Random -Minimum 1 -Maximum 9999 $results += Test-DriverLoopback ` -Cli $abcipCli ` -WriteArgs (@("write") + $commonAbCip + @("-t", $TagPath, "--type", "DInt", "-v", $writeValue)) ` -ReadArgs (@("read") + $commonAbCip + @("-t", $TagPath, "--type", "DInt")) ` -ExpectedValue "$writeValue" $bridgeValue = Get-Random -Minimum 10000 -Maximum 19999 $results += Test-ServerBridge ` -DriverCli $abcipCli ` -DriverWriteArgs (@("write") + $commonAbCip + @("-t", $TagPath, "--type", "DInt", "-v", $bridgeValue)) ` -OpcUaCli $opcUaCli ` -OpcUaUrl $OpcUaUrl ` -OpcUaNodeId $BridgeNodeId ` -ExpectedValue "$bridgeValue" $reverseValue = Get-Random -Minimum 20000 -Maximum 29999 $results += Test-OpcUaWriteBridge ` -OpcUaCli $opcUaCli ` -OpcUaUrl $OpcUaUrl ` -OpcUaNodeId $BridgeNodeId ` -DriverCli $abcipCli ` -DriverReadArgs (@("read") + $commonAbCip + @("-t", $TagPath, "--type", "DInt")) ` -ExpectedValue "$reverseValue" $subValue = Get-Random -Minimum 30000 -Maximum 39999 $results += Test-SubscribeSeesChange ` -OpcUaCli $opcUaCli ` -OpcUaUrl $OpcUaUrl ` -OpcUaNodeId $BridgeNodeId ` -DriverCli $abcipCli ` -DriverWriteArgs (@("write") + $commonAbCip + @("-t", $TagPath, "--type", "DInt", "-v", $subValue)) ` -ExpectedValue "$subValue" # PR abcip-3.2 — Symbolic-vs-Logical sanity assertion. Reads the same tag with both # addressing modes through the CLI's --addressing-mode flag. Logical-mode against ab_server # falls back to Symbolic on the wire (libplctag wrapper limitation; see AbCip-Performance.md # §Addressing mode), so the assertion is "both modes complete + return the same value" — not # a perf comparison. Skipped on Micro800 (driver downgrades Logical → Symbolic with warning, # making both reads identical-by-design + uninteresting to compare here). if ($Family -ne "Micro800") { $symValue = Get-Random -Minimum 40000 -Maximum 49999 Write-Host "AB CIP e2e: priming gateway with $symValue then reading via Symbolic + Logical" $writeArgs = @("write") + $commonAbCip + @("-t", $TagPath, "--type", "DInt", "-v", $symValue) & $abcipCli.Exe @($abcipCli.Args + $writeArgs) | Out-Null $symRead = & $abcipCli.Exe @($abcipCli.Args + @("read") + $commonAbCip + @("-t", $TagPath, "--type", "DInt", "--addressing-mode", "Symbolic")) $logRead = & $abcipCli.Exe @($abcipCli.Args + @("read") + $commonAbCip + @("-t", $TagPath, "--type", "DInt", "--addressing-mode", "Logical")) $symMatched = ($symRead -join "`n") -match "$symValue" $logMatched = ($logRead -join "`n") -match "$symValue" $passed = $symMatched -and $logMatched $results += [PSCustomObject]@{ Name = "AddressingModeSanity" Passed = $passed Detail = if ($passed) { "Symbolic + Logical both returned $symValue" } else { "Sym=$symMatched Log=$logMatched" } } } Write-Summary -Title "AB CIP e2e" -Results $results if ($results | Where-Object { -not $_.Passed }) { exit 1 }