@windypro-rourou/dsh-eda 0.1.10 → 0.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.js +55 -47
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -2004,14 +2004,17 @@ function edaExportTool(backend) {
|
|
|
2004
2004
|
|
|
2005
2005
|
/**
|
|
2006
2006
|
* eda_sch_to_pcb:把当前原理图的器件复制到 PCB(替代不可靠的 importChanges)。
|
|
2007
|
-
*
|
|
2007
|
+
* 实测要点:原理图器件用 getState_Component() 取 {libraryUuid, uuid, name},
|
|
2008
|
+
* 但 pcb_PrimitiveComponent.create 需要完整 ILIB_DeviceItem —— 用 component.name
|
|
2009
|
+
* 再 lib_Device.search(name) 得到可放置的 device(3/3 实测通过)。
|
|
2008
2010
|
*/
|
|
2009
2011
|
function edaSchToPcbTool(backend) {
|
|
2010
2012
|
return defineTool({
|
|
2011
2013
|
name: 'eda_sch_to_pcb',
|
|
2012
2014
|
description: 'Copy the components of the CURRENT schematic onto the project PCB (direct placement). ' +
|
|
2013
|
-
'
|
|
2014
|
-
'Reads each schematic component via getState_Component(),
|
|
2015
|
+
'Reliable replacement for PCB_Document.importChanges() (which returns true but places nothing). ' +
|
|
2016
|
+
'Reads each schematic component via getState_Component() (libraryUuid/uuid/name), resolves it with lib_Device.search(name), ' +
|
|
2017
|
+
'opens the project PCB and places it on layer 1 in a grid. ' +
|
|
2015
2018
|
'Triggers: 原理图转PCB, 复制器件到PCB, sch to pcb, 同步原理图到PCB.',
|
|
2016
2019
|
parameters: {
|
|
2017
2020
|
spacing: { type: 'integer', description: '可选:网格间距(mil,默认 900)' },
|
|
@@ -2032,6 +2035,7 @@ function edaSchToPcbTool(backend) {
|
|
|
2032
2035
|
additionalProperties: false,
|
|
2033
2036
|
properties: {
|
|
2034
2037
|
designator: { type: 'string' },
|
|
2038
|
+
name: { type: 'string' },
|
|
2035
2039
|
ok: { type: 'boolean', required: true },
|
|
2036
2040
|
uuid: { type: 'string' },
|
|
2037
2041
|
err: { type: 'string' },
|
|
@@ -2045,7 +2049,9 @@ function edaSchToPcbTool(backend) {
|
|
|
2045
2049
|
render: (_args, value) => {
|
|
2046
2050
|
if (value?.ok !== true) return [{ type: 'text', text: '原理图转 PCB 失败: ' + (value?.error ?? '?') }]
|
|
2047
2051
|
const lines = ['✅ 原理图 → PCB:' + (value.placedOk ?? 0) + '/' + (value.total ?? 0) + ' 个器件已放置到 ' + (value.pcbUuid ?? '')]
|
|
2048
|
-
for (const p of value.placed ?? [])
|
|
2052
|
+
for (const p of value.placed ?? []) {
|
|
2053
|
+
if (!p.ok) lines.push(' ⚠ ' + (p.designator || p.name || '?') + ': ' + (p.err ?? 'failed'))
|
|
2054
|
+
}
|
|
2049
2055
|
if (value.note) lines.push(value.note)
|
|
2050
2056
|
return [{ type: 'text', text: lines.join('\n') }]
|
|
2051
2057
|
},
|
|
@@ -2061,59 +2067,61 @@ function edaSchToPcbTool(backend) {
|
|
|
2061
2067
|
const actId = pushPendingActivity({ sid, tool: 'eda_sch_to_pcb', action: '原理图转PCB', code: 'spacing=' + spacing })
|
|
2062
2068
|
const t0 = Date.now()
|
|
2063
2069
|
try {
|
|
2064
|
-
|
|
2065
|
-
'const comps = await eda.sch_PrimitiveComponent.getAll();' +
|
|
2066
|
-
'const list = [];' +
|
|
2067
|
-
'for (const c of (comps || [])) {' +
|
|
2068
|
-
' let type = ""; try { type = c.getState_ComponentType(); } catch (e) {}' +
|
|
2069
|
-
' if (["sheet","netflag","netport","wire","bus","text"].includes(type)) continue;' +
|
|
2070
|
-
' let device = null; try { device = c.getState_Component ? c.getState_Component() : null; } catch (e) {}' +
|
|
2071
|
-
' if (!device) continue;' +
|
|
2072
|
-
' list.push({ id: (() => { try { return c.getState_PrimitiveId(); } catch (e) { return ""; } })(),' +
|
|
2073
|
-
' designator: (() => { try { return c.getState_Designator(); } catch (e) { return ""; } })() });' +
|
|
2074
|
-
'}' +
|
|
2075
|
-
'const proj = await eda.dmt_Project.getCurrentProjectInfo();' +
|
|
2076
|
-
'const pcbUuid = proj?.data?.[0]?.pcb?.uuid;' +
|
|
2077
|
-
'return { ok: true, count: list.length, pcbUuid }; })();', 30000)
|
|
2078
|
-
let preData = null
|
|
2079
|
-
try { preData = JSON.parse(pre.result ?? 'null') } catch (e) { preData = null }
|
|
2080
|
-
if (!pre.ok || !preData || preData.ok !== true) {
|
|
2081
|
-
updateActivity(actId, { status: 'error', ok: false, action: '原理图转PCB', error: '读取原理图器件失败', durationMs: Date.now() - t0 })
|
|
2082
|
-
return { ok: false, pcbUuid: '', total: 0, placedOk: 0, placed: [], note: '', error: '读取原理图器件失败:' + (pre.error ?? '') }
|
|
2083
|
-
}
|
|
2084
|
-
if (!preData.pcbUuid) {
|
|
2085
|
-
updateActivity(actId, { status: 'error', ok: false, action: '原理图转PCB', error: '当前工程没有 PCB', durationMs: Date.now() - t0 })
|
|
2086
|
-
return { ok: false, pcbUuid: '', total: Number(preData.count ?? 0), placedOk: 0, placed: [], note: '', error: '当前工程没有 PCB(先 createPcb 建板)' }
|
|
2087
|
-
}
|
|
2070
|
+
// 一次性桥代码(与实测脚本一致):打开原理图 → getAll(重试) → 取 component.name → 打开 PCB → search(name)→create → 保存
|
|
2088
2071
|
const code = 'return await (async () => {' +
|
|
2089
2072
|
'const sleep = (ms) => new Promise(r => setTimeout(r, ms));' +
|
|
2090
|
-
'const
|
|
2091
|
-
'const
|
|
2092
|
-
'
|
|
2073
|
+
'const proj = await eda.dmt_Project.getCurrentProjectInfo();' +
|
|
2074
|
+
'const first = (proj?.data || [])[0] || {};' +
|
|
2075
|
+
'const schPage = first?.schematic?.page?.[0]?.uuid;' +
|
|
2076
|
+
'const pcbUuid = first?.pcb?.uuid;' +
|
|
2077
|
+
'if (!schPage) return { ok: false, err: "当前工程没有原理图页" };' +
|
|
2078
|
+
'if (!pcbUuid) return { ok: false, err: "当前工程没有 PCB(先 createPcb 建板)" };' +
|
|
2079
|
+
// 打开原理图
|
|
2080
|
+
'await eda.dmt_EditorControl.openDocument(schPage);' +
|
|
2081
|
+
'await sleep(2200);' +
|
|
2082
|
+
'let comps = null;' +
|
|
2083
|
+
'for (let i = 0; i < 5 && !comps; i++) {' +
|
|
2084
|
+
' try { const r = await eda.sch_PrimitiveComponent.getAll(); if (Array.isArray(r)) comps = r; } catch (e) {}' +
|
|
2085
|
+
' if (!comps) await sleep(800);' +
|
|
2086
|
+
'}' +
|
|
2087
|
+
'if (!comps) return { ok: false, err: "原理图矩形读取失败(getAll 重试 5 次)" };' +
|
|
2088
|
+
'const parts = [];' +
|
|
2089
|
+
'for (const c of comps) {' +
|
|
2093
2090
|
' let type = ""; try { type = c.getState_ComponentType(); } catch (e) {}' +
|
|
2094
|
-
' if (["
|
|
2095
|
-
' let
|
|
2096
|
-
' if (!
|
|
2097
|
-
'
|
|
2091
|
+
' if (!["part", "component"].includes(type)) continue;' +
|
|
2092
|
+
' let comp = null; try { comp = c.getState_Component ? c.getState_Component() : null; } catch (e) {}' +
|
|
2093
|
+
' if (!comp || !comp.name) continue;' +
|
|
2094
|
+
' parts.push({' +
|
|
2095
|
+
' designator: (() => { try { return c.getState_Designator(); } catch (e) { return ""; } })(),' +
|
|
2096
|
+
' name: String(comp.name),' +
|
|
2097
|
+
' libraryUuid: comp.libraryUuid ? String(comp.libraryUuid) : "",' +
|
|
2098
|
+
' uuid: comp.uuid ? String(comp.uuid) : "",' +
|
|
2099
|
+
' });' +
|
|
2098
2100
|
'}' +
|
|
2099
|
-
|
|
2100
|
-
'const pcbUuid = proj?.data?.[0]?.pcb?.uuid;' +
|
|
2101
|
-
'if (!pcbUuid) return { ok: false, err: "no pcb" };' +
|
|
2101
|
+
// 打开 PCB
|
|
2102
2102
|
'await eda.dmt_EditorControl.openDocument(pcbUuid);' +
|
|
2103
|
-
'await sleep(
|
|
2103
|
+
'await sleep(2000);' +
|
|
2104
2104
|
'const spacing = SPACING;' +
|
|
2105
2105
|
'const placed = [];' +
|
|
2106
2106
|
'let x = 1500, y = 1200, col = 0;' +
|
|
2107
|
-
'for (const
|
|
2107
|
+
'for (const p of parts) {' +
|
|
2108
|
+
' const rec = { designator: p.designator, name: p.name };' +
|
|
2108
2109
|
' try {' +
|
|
2109
|
-
' const
|
|
2110
|
-
'
|
|
2111
|
-
'
|
|
2110
|
+
' const items = await eda.lib_Device.search(p.name, undefined, undefined, undefined, 5, 1);' +
|
|
2111
|
+
' const dev = items && items[0];' +
|
|
2112
|
+
' if (!dev) { rec.ok = false; rec.err = "search 无结果"; placed.push(rec); continue; }' +
|
|
2113
|
+
' const c = await eda.pcb_PrimitiveComponent.create(dev, 1, x, y);' +
|
|
2114
|
+
' rec.ok = !!c;' +
|
|
2115
|
+
' if (c && c.getState_PrimitiveId) rec.uuid = c.getState_PrimitiveId();' +
|
|
2116
|
+
' } catch (e) { rec.ok = false; rec.err = String(e && e.message || e).slice(0, 100); }' +
|
|
2117
|
+
' placed.push(rec);' +
|
|
2112
2118
|
' col++; if (col % 6 === 0) { x = 1500; y += spacing; } else x += spacing;' +
|
|
2113
2119
|
' await sleep(120);' +
|
|
2114
2120
|
'}' +
|
|
2115
2121
|
'try { await eda.pcb_Document.save(); } catch (e) {}' +
|
|
2116
|
-
'
|
|
2122
|
+
'const pc = await eda.pcb_PrimitiveComponent.getAll().catch(() => null);' +
|
|
2123
|
+
'return { ok: true, pcbUuid, total: parts.length, placedOk: placed.filter(p => p.ok).length, placed, pcbComponentCount: pc ? pc.length : null };' +
|
|
2124
|
+
'})();'
|
|
2117
2125
|
const r = await backend.execute(code.replace('SPACING', String(spacing)), 120000)
|
|
2118
2126
|
if (!r.ok) {
|
|
2119
2127
|
updateActivity(actId, { status: 'error', ok: false, action: '原理图转PCB', error: r.error, durationMs: Date.now() - t0 })
|
|
@@ -2124,10 +2132,10 @@ function edaSchToPcbTool(backend) {
|
|
|
2124
2132
|
if (!parsed) return { ok: false, pcbUuid: '', total: 0, placedOk: 0, placed: [], note: '', error: '结果解析失败' }
|
|
2125
2133
|
if (parsed.ok !== true) {
|
|
2126
2134
|
updateActivity(actId, { status: 'error', ok: false, action: '原理图转PCB', error: String(parsed.err ?? 'failed'), durationMs: Date.now() - t0 })
|
|
2127
|
-
return { ok: false, pcbUuid: '', total:
|
|
2135
|
+
return { ok: false, pcbUuid: '', total: 0, placedOk: 0, placed: [], note: '', error: String(parsed.err ?? '原理图转 PCB 失败') }
|
|
2128
2136
|
}
|
|
2129
2137
|
const placed = (parsed.placed ?? []).map((p) => {
|
|
2130
|
-
const row = { designator: String(p.designator ?? ''), ok: p.ok === true }
|
|
2138
|
+
const row = { designator: String(p.designator ?? ''), name: String(p.name ?? ''), ok: p.ok === true }
|
|
2131
2139
|
if (p.uuid) row.uuid = String(p.uuid)
|
|
2132
2140
|
if (p.err) row.err = String(p.err)
|
|
2133
2141
|
return row
|
|
@@ -2139,7 +2147,7 @@ function edaSchToPcbTool(backend) {
|
|
|
2139
2147
|
return {
|
|
2140
2148
|
ok: true, pcbUuid: String(parsed.pcbUuid ?? ''), total: Number(parsed.total ?? 0),
|
|
2141
2149
|
placedOk: Number(parsed.placedOk ?? 0), placed,
|
|
2142
|
-
note: '
|
|
2150
|
+
note: '已按 component.name 重新检索器件放置(比 translate device 引用更可靠);位号沿用原理图,坐标=元件原点(封装可能偏移),布线与网络仍需后续处理。',
|
|
2143
2151
|
}
|
|
2144
2152
|
} catch (err) {
|
|
2145
2153
|
const msg = err instanceof Error ? err.message : String(err)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@windypro-rourou/dsh-eda",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.11",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "dsh-lichuang-eda (JCL-EDA): 嘉立创 EDA 助手 DSH 插件 —— 官方 eda.* API 云端实时生成(原理图/PCB)+ 离线标准版 JSON 兜底 + 面板记录式时间线(撤回/清空/紧急保存)。开箱即用:npm i 后 cordis.patch.yml insert 一行即挂载。",
|
|
6
6
|
"packageManager": "pnpm@11.22.0",
|