#Requires -Version 5.1 <# .SYNOPSIS Complete TwinCAT EL6695 Primary deployment from scratch. .DESCRIPTION Creates a fresh TwinCAT project with: 1. Hardware scan (EtherCAT devices) 2. PDO configuration (1024-byte IO) 3. PLC program (GVL + MAIN) 4. Activation + restart Based on reference scripts in ethercat-linux/scripts/ #> param( [string]$ProjectDir = 'C:\Users\tonycao\work\twincat3-auto-cli\TwinCAT_EL6695_Primary', [string]$Solution = 'C:\Users\tonycao\work\twincat3-auto-cli\TwinCAT_EL6695_Primary\TwinCATProject1.sln', [string]$Tsproj = 'C:\Users\tonycao\work\twincat3-auto-cli\TwinCAT_EL6695_Primary\TwinCATProject1.tsproj', [string]$TargetNetId = '169.254.176.217.1.1', [int]$PayloadBytes = 1024, [switch]$SkipScan, [switch]$Visible ) $ErrorActionPreference = 'Continue' $LogDir = Join-Path $ProjectDir 'Logs' New-Item -ItemType Directory -Force -Path $LogDir | Out-Null $LogFile = Join-Path $LogDir "full-deploy_$(Get-Date -Format 'yyyyMMdd_HHmmss').log" function Log($m) { $line = (Get-Date -Format 'HH:mm:ss') + " $m" Add-Content -Path $LogFile -Value $line -Encoding utf8 -ErrorAction SilentlyContinue Write-Host $line } function LogSection($m) { Log ''; Log ('='*60); Log " $m"; Log ('='*60) } Log '=== TwinCAT EL6695 Full Deploy ===' Log "ProjectDir: $ProjectDir" Log "TargetNetId: $TargetNetId" Log "PayloadBytes: $PayloadBytes" # ---- Step 1: Check/Fix PDO in tsproj ---- LogSection 'Step 1/6: Verify PDO configuration' if (-not (Test-Path $Tsproj)) { Log "ERROR: tsproj not found: $Tsproj" exit 1 } $content = [System.IO.File]::ReadAllText($Tsproj, [System.Text.Encoding]::UTF8) # Check if PDO already has 1024-byte entries $has1024 = $content -match 'ARRAY \[0\.\.1023\] OF BYTE' if ($has1024) { Log " PDO already has 1024-byte entries" } else { Log " Adding 1024-byte PDO entries..." $lastSub = "{0:X4}" -f ($PayloadBytes - 1) $oldPdoIn = '' $newPdoIn = @" ARRAY [0..$lastSub] OF BYTE "@ if ($content -match [regex]::Escape($oldPdoIn)) { $content = $content -replace [regex]::Escape($oldPdoIn), $newPdoIn Log " IO Inputs PDO fixed" } else { Log " WARN: IO Inputs PDO pattern not found" } $oldPdoOut = '' $newPdoOut = @" ARRAY [0..$lastSub] OF BYTE "@ if ($content -match [regex]::Escape($oldPdoOut)) { $content = $content -replace [regex]::Escape($oldPdoOut), $newPdoOut Log " IO Outputs PDO fixed" } else { Log " WARN: IO Outputs PDO pattern not found" } [System.IO.File]::WriteAllText($Tsproj, $content, [System.Text.Encoding]::UTF8) } # ---- Step 2: Verify PLC code exists ---- LogSection 'Step 2/6: Verify PLC code' $plcFiles = @( "$ProjectDir\PlcSync\GVLs\GVL_Sync.TcGVL", "$ProjectDir\PlcSync\POUs\MAIN.TcPOU", "$ProjectDir\PlcSync\DUTs\DUT_EL6695_IO.TcDUT", "$ProjectDir\PlcSync\DUTs\U_EL6695_IO.TcDUT" ) $allOk = $true foreach ($f in $plcFiles) { if (Test-Path $f) { Log " OK: $(Split-Path $f -Leaf)" } else { Log " MISSING: $(Split-Path $f -Leaf)"; $allOk = $false } } if (-not $allOk) { Log "ERROR: PLC files missing. Run project setup first." exit 1 } # ---- Step 3: Build project ---- LogSection 'Step 3/6: Build project' $dte = $null try { $dte = New-Object -ComObject TcXaeShell.DTE.17.0 } catch { try { $dte = New-Object -ComObject TcXaeShell.DTE.15.0 } catch { Log "FATAL: No TcXaeShell"; exit 1 } } $dte.SuppressUI = -not $Visible $dte.MainWindow.Visible = $Visible Log " Opening solution..." $dte.Solution.Open($Solution) $timeout = 120 for ($i = 1; $i -le $timeout; $i++) { Start-Sleep -Seconds 1 if ($dte.Solution.IsOpen) { Log " Solution open after ${i}s"; break } } if (-not $dte.Solution.IsOpen) { Log "ERROR: Solution did not open"; $dte.Quit(); exit 1 } # Wait for System Manager Log " Waiting for System Manager..." Start-Sleep -Seconds 15 $sm = $null for ($i = 1; $i -le 30; $i++) { try { $sm = $dte.Solution.Projects.Item(1).Object if ($sm) { Log " SysManager ready after ${i}s"; break } } catch { } Start-Sleep -Seconds 2 } if (-not $sm) { Log "ERROR: SysManager not ready"; $dte.Quit(); exit 1 } # Set target try { $sm.SetTargetNetId($TargetNetId); Log " SetTargetNetId OK" } catch { Log " SetTargetNetId err: $_" } # Build Log " Building..." try { $dte.ExecuteCommand('Build.BuildSolution') } catch { Log " Build command err: $_" } Start-Sleep -Seconds 30 # Check build state $sb = $dte.Solution.SolutionBuild $buildState = $sb.BuildState $buildInfo = $sb.LastBuildInfo Log " BuildState=$buildState, LastBuildInfo=$buildInfo" if ($buildState -ne 1) { Log "WARN: Build not complete, waiting more..." Start-Sleep -Seconds 30 } # ---- Step 4: Hardware scan (optional) ---- if (-not $SkipScan) { LogSection 'Step 4/6: Hardware scan' Log " Scanning EtherCAT devices..." try { $sm.ActivateConfiguration() Log " Pre-activate OK" Start-Sleep -Seconds 10 } catch { Log " Pre-activate err: $_" } # Try to reload devices $bytes = @(0xE9,0x87,0x8D,0xE6,0x96,0xB0,0xE5,0x8A,0xA0,0xE8,0xBD,0xBD,0xE8,0xAE,0xBE,0xE5,0xA4,0x87) $reloadCmd = 'TwinCAT.' + [System.Text.Encoding]::UTF8.GetString($bytes) try { $dte.ExecuteCommand($reloadCmd); Log " Reload devices OK" } catch { Log " Reload err: $_" } Start-Sleep -Seconds 15 } # ---- Step 5: Activate configuration ---- LogSection 'Step 5/6: Activate configuration' Log " Saving configuration..." try { $sm.SaveConfiguration() } catch { Log " Save err: $_" } Log " Activating..." try { $sm.ActivateConfiguration() Log " ActivateConfiguration OK" } catch { Log " ActivateConfiguration err: $_" } Start-Sleep -Seconds 15 # ---- Step 6: Start TwinCAT runtime ---- LogSection 'Step 6/6: Start TwinCAT runtime' Log " Starting TwinCAT..." try { $sm.StartRestartTwinCAT() Log " StartRestartTwinCAT executed" } catch { Log " StartRestartTwinCAT err: $_" } # Wait for RUN state $adsDll = 'C:\Program Files (x86)\Beckhoff\TwinCAT\3.1\Components\Base\v170\TwinCAT.Ads.dll' Add-Type -Path $adsDll -ErrorAction SilentlyContinue function Get-TcState { try { $c = New-Object TwinCAT.Ads.TcAdsClient $c.Connect($TargetNetId, 10000) $s = $c.ReadState() $c.Dispose() return "$($s.AdsState)" } catch { return "ERR" } } for ($i = 1; $i -le 20; $i++) { Start-Sleep -Seconds 5 $st = Get-TcState Log " state +$($i*5)s: $st" if ($st -eq 'Run') { break } if ($st -eq 'Config') { Log " Still in Config mode..." } } Log "Final state: $(Get-TcState)" # Save and cleanup try { $dte.Solution.SaveAs($Solution) } catch { } try { $dte.Quit() } catch { } LogSection 'Deploy complete' Log "Log file: $LogFile"