From aabfe31526fa333a47e4647b1026cc2e8da932f0 Mon Sep 17 00:00:00 2001 From: Tony Cao Date: Sun, 9 Aug 2026 15:32:56 +0800 Subject: [PATCH] Enable EL6695 DC-Synchron mode (AssignActivate 0x320) - DC selection must use the structured XSD element; legacy DcData hex writes get normalized to zeros by TwinCAT - TwinCAT converts it to DcData '2003...' (0x0320) on save: SYNC0/SYNC1 cyclic + SYNC0 activate for the bridge - Verified: clean activation, ticker OP, bSync=True, 90k cycles 0 errors, timing unchanged (jitter 7.3us mean) - docs: pitfall #10 (DC selection method) --- deploy_800b_dc.log | Bin 0 -> 526 bytes deploy_800b_dc2.log | Bin 0 -> 526 bytes deploy_800b_elevated.log | Bin 0 -> 478 bytes deploy_800b_regress.log | Bin 0 -> 526 bytes deploy_800b_regress2.log | Bin 0 -> 526 bytes deploy_800b_regress3.log | Bin 0 -> 526 bytes docs/8b-bridge-design.md | 1 + scripts/tc-ads-quick.ps1 | 13 +++++++++ scripts/tc-ads-setrun.ps1 | 15 +++++++++++ scripts/tc-ads-state.ps1 | 13 +++++++++ scripts/tc-open-project-800b.ps1 | 18 +++++++++++++ uia_dump.py | 18 +++++++++++++ uia_find_dc.py | 15 +++++++++++ uia_open_el6695.py | 44 +++++++++++++++++++++++++++++++ 14 files changed, 137 insertions(+) create mode 100644 deploy_800b_dc.log create mode 100644 deploy_800b_dc2.log create mode 100644 deploy_800b_elevated.log create mode 100644 deploy_800b_regress.log create mode 100644 deploy_800b_regress2.log create mode 100644 deploy_800b_regress3.log create mode 100644 scripts/tc-ads-quick.ps1 create mode 100644 scripts/tc-ads-setrun.ps1 create mode 100644 scripts/tc-ads-state.ps1 create mode 100644 scripts/tc-open-project-800b.ps1 create mode 100644 uia_dump.py create mode 100644 uia_find_dc.py create mode 100644 uia_open_el6695.py diff --git a/deploy_800b_dc.log b/deploy_800b_dc.log new file mode 100644 index 0000000000000000000000000000000000000000..3b37c5461d0cfed8703398e2b40accc7e82219b0 GIT binary patch literal 526 zcmaixu};H45Jaa&;vcRg4WdXvkDnrQm^gpCz=f9248^Pw`Tr;1W?zE=}4&xwjY$McQRUgPb!c1ovSyuzBx1aq>F_74hn|3v(LsqKylTPm@f`LA)kyGgr?{=bK<4*&QM?p#kDnrQm^gpCz=f9248^Pw`Tr;1W?zE=}4&xwjY$McQRUgPb!c1ovSyuzBx1aq>F_74hn|3v(LsqKylTPm@f`LA)kyGgr?{=bK<4*&QM?p#7xl5QL|Wly|r?X(9>=8W;I#5J(`%3pnADSQvw_4dUe?-`Fyib<*DM&CLGY z?V89Z=tEHl<=X2)G|?OOtW1^u@K##to%;x@!kW`6AN8OTRjwK&!z;k{#8_ecPB&WP?wbEV{|=&n;v!G2&Q8tEBMN>ssioiSWz zb998`x13te5cJJt5xd1Nu^BzP>$c+*#PgiU=zG}T5bZSHj&r9}>NMV2joR@Jyq|H% i4&WuHzIQMs`fUE7VE3>1>w9ijOq$uc|LeEZ|I0tNOi$kDnrQm^gpCz=f9248^Pw`Tr;1W?zE=}4&xwjY$McQRUgPb!c1ovSyuzBx1aq>F_74hn|3v(LsqKylTPm@f`LA)kyGgr?{=bK<4*&QM?p#kDnrQm^gpCz=f9248^Pw`Tr;1W?zE=}4&xwjY$McQRUgPb!c1ovSyuzBx1aq>F_74hn|3v(LsqKylTPm@f`LA)kyGgr?{=bK<4*&QM?p#kDnrQm^gpCz=f9248^Pw`Tr;1W?zE=}4&xwjY$McQRUgPb!c1ovSyuzBx1aq>F_74hn|3v(LsqKylTPm@f`LA)kyGgr?{=bK<4*&QM?p#` 十六进制被 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)