187 lines
6.7 KiB
PowerShell
187 lines
6.7 KiB
PowerShell
|
|
#Requires -RunAsAdministrator
|
||
|
|
#Requires -Version 5.1
|
||
|
|
[CmdletBinding()]
|
||
|
|
param(
|
||
|
|
[string]$Solution = $null
|
||
|
|
)
|
||
|
|
|
||
|
|
$ErrorActionPreference = 'Continue'
|
||
|
|
|
||
|
|
. "$PSScriptRoot\tc-common.ps1"
|
||
|
|
if (-not $Solution) { $Solution = $script:DefaultSolution }
|
||
|
|
|
||
|
|
New-Log $script:DefaultLogDir
|
||
|
|
$LogFile = Join-Path $script:DefaultLogDir "check-state.log"
|
||
|
|
|
||
|
|
function Write-Log($Message) {
|
||
|
|
$line = "[{0}] {1}" -f (Get-Date -Format 'HH:mm:ss'), $Message
|
||
|
|
Write-Host $line
|
||
|
|
Add-Content -Path $LogFile -Value $line -Encoding UTF8
|
||
|
|
}
|
||
|
|
|
||
|
|
# Load TwinCAT.Ads
|
||
|
|
$adsDll = 'C:\Program Files (x86)\Beckhoff\TwinCAT\3.1\Components\Base\v170\TwinCAT.Ads.dll'
|
||
|
|
try {
|
||
|
|
Add-Type -Path $adsDll -ErrorAction Stop
|
||
|
|
Write-Log "TwinCAT.Ads loaded from $adsDll"
|
||
|
|
} catch {
|
||
|
|
Write-Log "FATAL: Cannot load TwinCAT.Ads: $_"
|
||
|
|
exit 1
|
||
|
|
}
|
||
|
|
|
||
|
|
# Helper to bind to running XAE DTE via ROT
|
||
|
|
function Get-XaeDte {
|
||
|
|
Add-Type -TypeDefinition @'
|
||
|
|
using System;
|
||
|
|
using System.Runtime.InteropServices;
|
||
|
|
using System.Runtime.InteropServices.ComTypes;
|
||
|
|
public class XaeRot {
|
||
|
|
[DllImport("ole32.dll")] static extern int GetRunningObjectTable(int reserved, out IRunningObjectTable pprot);
|
||
|
|
[DllImport("ole32.dll")] static extern int CreateBindCtx(int reserved, out IBindCtx ppbc);
|
||
|
|
public static object GetDte(string match) {
|
||
|
|
IRunningObjectTable rot; IBindCtx bc;
|
||
|
|
GetRunningObjectTable(0, out rot);
|
||
|
|
CreateBindCtx(0, out bc);
|
||
|
|
IEnumMoniker em; rot.EnumRunning(out em);
|
||
|
|
IMoniker[] mons = new IMoniker[1];
|
||
|
|
IntPtr fetched = IntPtr.Zero;
|
||
|
|
while (em.Next(1, mons, fetched) == 0) {
|
||
|
|
string name; mons[0].GetDisplayName(bc, null, out name);
|
||
|
|
if (name.IndexOf(match, StringComparison.OrdinalIgnoreCase) >= 0) {
|
||
|
|
object o; rot.GetObject(mons[0], out o);
|
||
|
|
return o;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
'@ -ReferencedAssemblies System.Runtime.InteropServices
|
||
|
|
return [XaeRot]::GetDte('TcXaeShell.DTE')
|
||
|
|
}
|
||
|
|
|
||
|
|
function Read-Ads($NetId, $Port, $IGrp, $IOff, $Len) {
|
||
|
|
$c = New-Object TwinCAT.Ads.TcAdsClient
|
||
|
|
try {
|
||
|
|
$c.Connect($NetId, $Port)
|
||
|
|
$buf = New-Object byte[] $Len
|
||
|
|
$n = $c.Read([uint32]$IGrp, [uint32]$IOff, $buf, 0, $Len)
|
||
|
|
$hex = [BitConverter]::ToString($buf, 0, $n)
|
||
|
|
return "OK n=$n : $hex"
|
||
|
|
} catch {
|
||
|
|
return "ERR: $($_.Exception.Message)"
|
||
|
|
} finally {
|
||
|
|
$c.Dispose()
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
Write-Log "=== TwinCAT State Check ==="
|
||
|
|
|
||
|
|
# Try to bind to running XAE DTE
|
||
|
|
$dte = Get-XaeDte
|
||
|
|
if (-not $dte) {
|
||
|
|
Write-Log "No running XAE DTE found. Creating a new one..."
|
||
|
|
try {
|
||
|
|
$dte = New-Object -ComObject TcXaeShell.DTE.17.0 -ErrorAction Stop
|
||
|
|
$dte.MainWindow.Visible = $true
|
||
|
|
} catch {
|
||
|
|
Write-Log "FATAL: Cannot create DTE: $_"
|
||
|
|
exit 1
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (-not $dte.Solution.IsOpen) {
|
||
|
|
Write-Log "Opening solution $Solution"
|
||
|
|
try {
|
||
|
|
$dte.Solution.Open($Solution)
|
||
|
|
for ($i = 1; $i -le 120; $i++) {
|
||
|
|
Start-Sleep -Seconds 1
|
||
|
|
if ($dte.Solution.IsOpen) { break }
|
||
|
|
}
|
||
|
|
} catch {
|
||
|
|
Write-Log "Solution.Open error: $_"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
Write-Log "Solution open: $($dte.Solution.IsOpen)"
|
||
|
|
Write-Log "Solution path: $($dte.Solution.FullName)"
|
||
|
|
|
||
|
|
$sysMgr = $null
|
||
|
|
for ($i = 1; $i -le 40; $i++) {
|
||
|
|
try {
|
||
|
|
$sysMgr = $dte.Solution.Projects.Item(1).Object
|
||
|
|
if ($sysMgr) { break }
|
||
|
|
} catch {}
|
||
|
|
Start-Sleep -Seconds 2
|
||
|
|
}
|
||
|
|
if (-not $sysMgr) {
|
||
|
|
Write-Log "FATAL: Cannot get SysManager"
|
||
|
|
exit 1
|
||
|
|
}
|
||
|
|
Write-Log "SysManager obtained"
|
||
|
|
|
||
|
|
$targetNetId = '169.254.176.217.1.1'
|
||
|
|
$platform = 'TwinCAT RT (x64)'
|
||
|
|
try { $sysMgr.SetTargetNetId($targetNetId); Write-Log "SetTargetNetId $targetNetId OK" } catch { Write-Log "SetTargetNetId error: $_" }
|
||
|
|
try { $sysMgr.ConfigurationManager.ActiveTargetPlatform = $platform; Write-Log "ActiveTargetPlatform set to $platform" } catch { Write-Log "Set platform error: $_" }
|
||
|
|
Start-Sleep -Seconds 3
|
||
|
|
|
||
|
|
# Read state before activation
|
||
|
|
Write-Log "--- State BEFORE activation ---"
|
||
|
|
try { Write-Log "IsTwinCATStarted = $($sysMgr.IsTwinCATStarted)" } catch { Write-Log "IsTwinCATStarted error: $_" }
|
||
|
|
try { Write-Log "CurrentMode = $($sysMgr.CurrentMode)" } catch { Write-Log "CurrentMode error: $_" }
|
||
|
|
try { Write-Log "TargetNetId = $($sysMgr.ConfigurationManager.ActiveConfiguration.TargetNetId)" } catch { Write-Log "TargetNetId error: $_" }
|
||
|
|
try { Write-Log "ActivePlatform = $($sysMgr.ConfigurationManager.ActiveTargetPlatform)" } catch { Write-Log "ActivePlatform error: $_" }
|
||
|
|
|
||
|
|
# Activate
|
||
|
|
Write-Log "Activating configuration..."
|
||
|
|
try { $sysMgr.ActivateConfiguration(); Write-Log "ActivateConfiguration OK" } catch { Write-Log "ActivateConfiguration error: $_" }
|
||
|
|
Start-Sleep -Seconds 5
|
||
|
|
|
||
|
|
# Restart runtime to Run mode
|
||
|
|
Write-Log "Restarting TwinCAT runtime..."
|
||
|
|
try { $sysMgr.StartRestartTwinCAT(); Write-Log "StartRestartTwinCAT OK" } catch { Write-Log "StartRestartTwinCAT error: $_" }
|
||
|
|
Start-Sleep -Seconds 10
|
||
|
|
|
||
|
|
# Read state after restart
|
||
|
|
Write-Log "--- State AFTER activation/restart ---"
|
||
|
|
try { Write-Log "IsTwinCATStarted = $($sysMgr.IsTwinCATStarted)" } catch { Write-Log "IsTwinCATStarted error: $_" }
|
||
|
|
try { Write-Log "CurrentMode = $($sysMgr.CurrentMode)" } catch { Write-Log "CurrentMode error: $_" }
|
||
|
|
try { $msgs = $sysMgr.GetLastErrorMessages(); Write-Log "LastErrorMessages = $msgs" } catch { Write-Log "GetLastErrorMessages error: $_" }
|
||
|
|
|
||
|
|
# ADS diagnostics
|
||
|
|
Write-Log "--- ADS diagnostics ---"
|
||
|
|
Write-Log "System ADS state (169.254.176.217.1.1, port 65535, iGrp 0x0, iOff 0, 4 bytes): $(Read-Ads '169.254.176.217.1.1' 65535 0 0 4)"
|
||
|
|
Write-Log "EtherCAT master 1 state (169.254.176.217.2.1, port 65535, iGrp 0x9, iOff 0, 32 bytes): $(Read-Ads '169.254.176.217.2.1' 65535 0x9 0 32)"
|
||
|
|
|
||
|
|
# Try to export EtherCAT master online XML
|
||
|
|
try {
|
||
|
|
$io = $sysMgr.LookupTreeItem('TIID')
|
||
|
|
$ecat = $null
|
||
|
|
for ($j = 1; $j -le [int]$io.ChildCount; $j++) {
|
||
|
|
try {
|
||
|
|
$ch = $io.Child($j)
|
||
|
|
if ([int]$ch.ItemSubType -eq 111) { $ecat = $ch; break }
|
||
|
|
} catch {}
|
||
|
|
}
|
||
|
|
if ($ecat) {
|
||
|
|
Write-Log "EtherCAT master found: $($ecat.Name)"
|
||
|
|
$xml = $ecat.ProduceXml($true)
|
||
|
|
$xmlFile = Join-Path $script:DefaultLogDir 'check-state_master.xml'
|
||
|
|
[System.IO.File]::WriteAllText($xmlFile, $xml, [System.Text.Encoding]::UTF8)
|
||
|
|
Write-Log "Master Online XML saved: $xmlFile ($($xml.Length) bytes)"
|
||
|
|
|
||
|
|
Write-Log "Enumerating configured boxes under master:"
|
||
|
|
for ($j = 1; $j -le [int]$ecat.ChildCount; $j++) {
|
||
|
|
try {
|
||
|
|
$b = $ecat.Child($j)
|
||
|
|
Write-Log " Box[$j]: name='$($b.Name)' subtype=$($b.ItemSubType)"
|
||
|
|
} catch {}
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
Write-Log "No EtherCAT master found under TIID"
|
||
|
|
}
|
||
|
|
} catch {
|
||
|
|
Write-Log "EtherCAT XML error: $_"
|
||
|
|
}
|
||
|
|
|
||
|
|
Write-Log "=== Check complete ==="
|