param( [switch]$Test, [string]$Compiler = 'gcc' ) $ErrorActionPreference = 'Stop' $projectRoot = Split-Path -Parent $PSScriptRoot $protocolInclude = Join-Path $projectRoot '104' $businessInclude = Join-Path $protocolInclude 'business' $commonInclude = Join-Path $projectRoot 'common' $exampleBuild = Join-Path $projectRoot '.build/slave-example' New-Item -ItemType Directory -Path $exampleBuild -Force | Out-Null Get-Command $Compiler -ErrorAction Stop | Out-Null # Shared dependencies; the example adds the actual TCP and Windows Net implementations. $libraryNames = @( '104/business/IEC104_Interrogation.c', '104/business/IEC104_GeneralInterrogation.c', '104/business/IEC104_CounterInterrogation.c', '104/business/IEC104_ClockSynchronization.c', '104/business/IEC104_Command.c', '104/IEC104_Slave.c', 'common/IEC60870_Slave.c', 'common/IEC60870_Asdu.c', 'common/IEC60870_InformationObjects.c', 'common/IEC60870_Time.c', 'common/IEC60870_Clock.c', 'common/IEC60870_Codec.c', '104/IEC104_Connection.c', '104/IEC104_Receiver.c', '104/IEC104_SendManager.c', '104/IEC104_SendBuffer.c', '104/IEC104_AsduQueue.c', '104/IEC104_Codec.c', '104/IEC104_Link.c', '104/IEC104_Link_Slave_StartStop.c' ) $librarySources = @($libraryNames | ForEach-Object { Join-Path $projectRoot $_ }) $compileFlags = @('-std=c11', '-O2', '-Wall', '-Wextra', '-Werror', "-I$protocolInclude", "-I$businessInclude", "-I$commonInclude") $exampleOutput = Join-Path $exampleBuild 'iec104_slave_example.exe' $exampleSources = @( (Join-Path $projectRoot 'examples/iec104_slave_example.c'), (Join-Path $projectRoot '104/IEC104_TcpServer.c'), (Join-Path $projectRoot '104/IEC104_Net_Windows.c') ) + $librarySources & $Compiler @compileFlags @exampleSources -o $exampleOutput -lws2_32 if ($LASTEXITCODE -ne 0) { throw 'Slave example build failed' } Write-Output "Built: $exampleOutput" if ($Test) { # Shared Station/Slave APIs, including isolation between two independent services. foreach ($capacity in @(1, 2)) { $slaveTestOutput = Join-Path $exampleBuild "iec104_slave_test_$capacity.exe" $slaveTestSources = @((Join-Path $projectRoot 'test/iec104_slave_test.c')) + $librarySources & $Compiler @compileFlags "-DIEC104_TCP_SERVER_CAPACITY=$capacity" @slaveTestSources -o $slaveTestOutput if ($LASTEXITCODE -ne 0) { throw 'Slave/Station test build failed' } & $slaveTestOutput if ($LASTEXITCODE -ne 0) { throw 'Slave/Station tests failed' } } # The controlled-backend test includes TcpServer.c itself. Do not link a second TCP/Net implementation. $testSources = @((Join-Path $projectRoot 'test/iec104_slave_example_test.c')) + $librarySources foreach ($capacity in @(1, 2)) { $testOutput = Join-Path $exampleBuild "iec104_slave_example_test_$capacity.exe" & $Compiler @compileFlags "-DIEC104_TCP_SERVER_CAPACITY=$capacity" -DIEC104_TCP_HIGH_CAPACITY=251 -DIEC104_INTERROGATION_EVENT_CAPACITY=2 @testSources -o $testOutput if ($LASTEXITCODE -ne 0) { throw 'Slave example test build failed' } & $testOutput if ($LASTEXITCODE -ne 0) { throw 'Slave example tests failed' } } # Command transactions use one fixed slot and a bounded independent reply pool. # The controlled backend includes TcpServer.c; do not link TCP/Windows Net again. $commandTestSources = @((Join-Path $projectRoot 'test/iec104_command_test.c')) + $librarySources foreach ($capacity in @(1, 2)) { foreach ($replyCapacity in @(1, 4)) { $commandOutput = Join-Path $exampleBuild "iec104_command_test_${capacity}_${replyCapacity}.exe" & $Compiler @compileFlags "-DIEC104_TCP_SERVER_CAPACITY=$capacity" "-DIEC104_COMMAND_REPLY_CAPACITY=$replyCapacity" -DIEC104_TCP_HIGH_CAPACITY=251 @commandTestSources -o $commandOutput if ($LASTEXITCODE -ne 0) { throw 'Command test build failed' } & $commandOutput if ($LASTEXITCODE -ne 0) { throw 'Command tests failed' } } } $rulesOutput = Join-Path $exampleBuild 'iec104_interrogation_rules_test.exe' $rulesSources = @( (Join-Path $projectRoot 'test/iec104_interrogation_rules_test.c'), (Join-Path $projectRoot '104/IEC104_TcpServer.c'), (Join-Path $projectRoot '104/IEC104_Net_Windows.c') ) + $librarySources & $Compiler @compileFlags @rulesSources -o $rulesOutput -lws2_32 if ($LASTEXITCODE -ne 0) { throw 'Interrogation rules test build failed' } & $rulesOutput if ($LASTEXITCODE -ne 0) { throw 'Interrogation rules tests failed' } Get-Command node -ErrorAction Stop | Out-Null & node (Join-Path $projectRoot 'test/slave_example_loopback_test.cjs') $exampleOutput if ($LASTEXITCODE -ne 0) { throw 'Slave example TCP loopback test failed' } }