diff --git a/deploy_800b_dc.log b/deploy_800b_dc.log new file mode 100644 index 0000000..3b37c54 Binary files /dev/null and b/deploy_800b_dc.log differ diff --git a/deploy_800b_dc2.log b/deploy_800b_dc2.log new file mode 100644 index 0000000..3b37c54 Binary files /dev/null and b/deploy_800b_dc2.log differ diff --git a/deploy_800b_elevated.log b/deploy_800b_elevated.log new file mode 100644 index 0000000..a862872 Binary files /dev/null and b/deploy_800b_elevated.log differ diff --git a/deploy_800b_regress.log b/deploy_800b_regress.log new file mode 100644 index 0000000..3b37c54 Binary files /dev/null and b/deploy_800b_regress.log differ diff --git a/deploy_800b_regress2.log b/deploy_800b_regress2.log new file mode 100644 index 0000000..3b37c54 Binary files /dev/null and b/deploy_800b_regress2.log differ diff --git a/deploy_800b_regress3.log b/deploy_800b_regress3.log new file mode 100644 index 0000000..3b37c54 Binary files /dev/null and b/deploy_800b_regress3.log differ diff --git a/docs/8b-bridge-design.md b/docs/8b-bridge-design.md index 301c9df..e47770b 100644 --- a/docs/8b-bridge-design.md +++ b/docs/8b-bridge-design.md @@ -276,6 +276,7 @@ blob = [27 (u16 LE)] |---|---|---|---| | 8 | 激活时 EL6695 SAFEOP 失败,AL 状态码 0x0003 | **激活与 J1900 ticker 会话并发**:relink 激活时 ticker 正在跑,桥两侧主站会话冲突 | 激活必须在 J1900 空闲时进行;失败后空载重新激活即恢复 | | 9 | 数据通但 PLC bSync=False,每周期固定 16 字节失配 | 图案区 [16..799] 与 J1900 统计字段 [264..279] 重叠 | 图案区改为 [16..263]+[280..799](见 §8.3) | +| 10 | 手写 `` 十六进制被 TwinCAT 归一化为全零 | DC 模式选择不接受 legacy hex 直写 | **用 XSD 结构化形式 ``**,TwinCAT 读取后自动生成正确 DcData(`2003...`,即 0x0320)并启用 DC-Synchron(2026-08-09 已验证) | ### 8.5 800B 实测性能 diff --git a/scripts/tc-ads-quick.ps1 b/scripts/tc-ads-quick.ps1 new file mode 100644 index 0000000..a7f52de --- /dev/null +++ b/scripts/tc-ads-quick.ps1 @@ -0,0 +1,13 @@ +$ErrorActionPreference = 'Continue' +Add-Type -Path 'C:\Program Files (x86)\Beckhoff\TwinCAT\3.1\Components\Base\v170\TwinCAT.Ads.dll' +$c = New-Object TwinCAT.Ads.TcAdsClient +$c.Connect('169.254.176.217.1.1', 851) +$h = $c.CreateVariableHandle('GVL_Sync.nCycles') +$n1 = $c.ReadAny($h, [uint64]) +Start-Sleep -Milliseconds 5000 +$n2 = $c.ReadAny($h, [uint64]) +$c.DeleteVariableHandle($h) +Write-Host ("nCycles rate = {0} Hz" -f [math]::Round(($n2 - $n1) / 5.0, 1)) +$bs = $c.ReadAny($c.CreateVariableHandle('GVL_Sync.bSync'), [bool]) +Write-Host "bSync = $bs" +$c.Dispose() diff --git a/scripts/tc-ads-setrun.ps1 b/scripts/tc-ads-setrun.ps1 new file mode 100644 index 0000000..9afde0b --- /dev/null +++ b/scripts/tc-ads-setrun.ps1 @@ -0,0 +1,15 @@ +$ErrorActionPreference = 'Continue' +Add-Type -Path 'C:\Program Files (x86)\Beckhoff\TwinCAT\3.1\Components\Base\v170\TwinCAT.Ads.dll' +$c = New-Object TwinCAT.Ads.TcAdsClient +$c.Connect('169.254.176.217.1.1', 10000) +Write-Host "before: $($c.ReadState().AdsState)" +try { + $c.WriteControl((New-Object TwinCAT.Ads.StateInfo([TwinCAT.Ads.AdsState]::Run, 0))) + Write-Host "WriteControl Run sent" +} catch { Write-Host "err: $_" } +$c.Dispose() +Start-Sleep 10 +$c2 = New-Object TwinCAT.Ads.TcAdsClient +$c2.Connect('169.254.176.217.1.1', 10000) +Write-Host "after: $($c2.ReadState().AdsState)" +$c2.Dispose() diff --git a/scripts/tc-ads-state.ps1 b/scripts/tc-ads-state.ps1 new file mode 100644 index 0000000..cc7c3f3 --- /dev/null +++ b/scripts/tc-ads-state.ps1 @@ -0,0 +1,13 @@ +$ErrorActionPreference = 'Continue' +Add-Type -Path 'C:\Program Files (x86)\Beckhoff\TwinCAT\3.1\Components\Base\v170\TwinCAT.Ads.dll' +foreach ($port in @(10000, 851)) { + try { + $c = New-Object TwinCAT.Ads.TcAdsClient + $c.Connect('169.254.176.217.1.1', $port) + $st = $c.ReadState() + Write-Host "port $port : AdsState=$($st.AdsState) DeviceState=$($st.DeviceState)" + $c.Dispose() + } catch { + Write-Host "port $port : ERR $($_.Exception.Message)" + } +} diff --git a/scripts/tc-open-project-800b.ps1 b/scripts/tc-open-project-800b.ps1 new file mode 100644 index 0000000..40ef305 --- /dev/null +++ b/scripts/tc-open-project-800b.ps1 @@ -0,0 +1,18 @@ +#Requires -RunAsAdministrator +$ErrorActionPreference = 'Continue' +# Open project in visible XAE and leave it running for interactive inspection. +$dte = New-Object -ComObject TcXaeShell.DTE.17.0 +$dte.MainWindow.Visible = $true +try { $dte.SuppressUI = $false } catch {} +$dte.Solution.Open('C:\Users\tonycao\work\twincat3-auto-cli\TwinCAT_EL6695_Primary_800B\TwinCATProject1.sln') +Start-Sleep 25 +$sm = $null +for ($i = 0; $i -lt 20; $i++) { + try { $sm = $dte.Solution.Projects.Item(1).Object; if ($sm) { break } } catch {} + Start-Sleep 3 +} +if (-not $sm) { Write-Host 'no sysmgr'; exit 1 } +try { $sm.SetTargetNetId('169.254.176.217.1.1'); Write-Host 'target set' } catch { Write-Host "target: $_" } +Start-Sleep 3 +try { Write-Host "IsTwinCATStarted=$($sm.IsTwinCATStarted)" } catch {} +Write-Host 'XAE left open. Inspect: TIID -> 设备 1 (EtherCAT) -> 模块 3 (EK1100) -> 模块 10 (EL6695) -> IO Inputs / IO Outputs -> Online tab' diff --git a/uia_dump.py b/uia_dump.py new file mode 100644 index 0000000..e143d88 --- /dev/null +++ b/uia_dump.py @@ -0,0 +1,18 @@ +import sys, time +sys.stdout.reconfigure(encoding='utf-8', errors='replace') +from pywinauto import Application + +app = Application(backend='uia').connect(process=11748, timeout=10) +wins = app.windows() +print('windows:', len(wins)) +for w in wins: + try: + t = w.window_text() + if not t: + continue + print('---', t) + tabs = [x.window_text() for x in w.descendants(control_type='TabItem')] + if tabs: + print(' tabs:', tabs) + except Exception: + pass diff --git a/uia_find_dc.py b/uia_find_dc.py new file mode 100644 index 0000000..2ac1149 --- /dev/null +++ b/uia_find_dc.py @@ -0,0 +1,15 @@ +import sys, time +sys.stdout.reconfigure(encoding='utf-8', errors='replace') +from pywinauto import Application + +app = Application(backend='uia').connect(process=int(sys.argv[1]), timeout=10) +win = app.top_window() +# look for DC-related text and combo boxes anywhere +texts = win.descendants(control_type='Text') +interesting = [t.window_text() for t in texts if t.window_text() and any(k in t.window_text() for k in ['FreeRun', 'DC', 'Synchron', 'EtherCAT', 'Sync'])] +print('interesting texts:', interesting[:40]) +combos = win.descendants(control_type='ComboBox') +print('combos:', [c.window_text() for c in combos]) +listitems = win.descendants(control_type='ListItem') +li = [l.window_text() for l in listitems if l.window_text()] +print('listitems:', li[:30]) diff --git a/uia_open_el6695.py b/uia_open_el6695.py new file mode 100644 index 0000000..820ed87 --- /dev/null +++ b/uia_open_el6695.py @@ -0,0 +1,44 @@ +import sys, time +sys.stdout.reconfigure(encoding='utf-8', errors='replace') +from pywinauto import Application +from pywinauto.mouse import click, double_click + +app = Application(backend='uia').connect(process=int(sys.argv[1]), timeout=10) +win = app.top_window() +tree = win.descendants(control_type='Tree')[0] + +def expand_children(item): + try: + item.expand(); time.sleep(0.4) + except Exception: + pass + return list(item.children()) + +nodes = [] +for root in tree.children(): + nodes.extend(expand_children(root)) +for name in ['TwinCATProject1', 'I/O', '设备', '设备 1 (EtherCAT)', '模块 3 (EK1100)']: + nxt = None + for n in nodes: + try: + if n.window_text() == name: + nxt = n + break + except Exception: + pass + if nxt is None: + print('missing:', name); sys.exit(1) + nodes = expand_children(nxt) +target = None +for n in nodes: + if n.window_text() == '模块 10 (EL6695)': + target = n + break +if not target: + print('EL6695 not found'); sys.exit(1) +r = target.rectangle() +double_click(coords=(int((r.left + r.right) / 2), int((r.top + r.bottom) / 2))) +time.sleep(4) +win.set_focus() +tabs = [t.window_text() for t in win.descendants(control_type='TabItem')] +print('tabs:', tabs)