@fateforge/xpedition-cli 1.0.0
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/.agent/AGENT.md +59 -0
- package/.agent/AGENT_zh.md +59 -0
- package/.agent/CLI-SPEC.md +1073 -0
- package/.agent/CLI-SPEC_zh.md +891 -0
- package/.agent/SEC-SPEC.md +158 -0
- package/.agent/SEC-SPEC_zh.md +132 -0
- package/.agent/SKILL-SPEC.md +266 -0
- package/.agent/SKILL-SPEC_zh.md +221 -0
- package/.agent/SPEC_VERSION +1 -0
- package/AGENTS.md +34 -0
- package/AGENTS_zh.md +33 -0
- package/CHANGELOG.md +795 -0
- package/CODE_OF_CONDUCT.md +35 -0
- package/CODE_OF_CONDUCT_zh.md +35 -0
- package/CONTRIBUTING.md +50 -0
- package/CONTRIBUTING_zh.md +42 -0
- package/LICENSE +21 -0
- package/NOTICE.md +16 -0
- package/NOTICE_zh.md +13 -0
- package/README.md +200 -0
- package/README_zh.md +178 -0
- package/SECURITY.md +108 -0
- package/SECURITY_zh.md +83 -0
- package/docs/AGENT_HARDENING_EVIDENCE.md +102 -0
- package/docs/AGENT_READS.md +74 -0
- package/docs/AGENT_READS_METRICS.json +216 -0
- package/docs/AGENT_READS_VALIDATION.json +13 -0
- package/docs/API_INVENTORY_BINDING_VALIDATION.json +16 -0
- package/docs/API_INVENTORY_DESIGN.md +90 -0
- package/docs/API_INVENTORY_REVIEW.md +59 -0
- package/docs/API_INVENTORY_VALIDATION.json +29 -0
- package/docs/API_INVENTORY_WINDOWS_VALIDATION.json +29 -0
- package/docs/COMPATIBILITY.md +499 -0
- package/docs/CONFIRMATION_CONCURRENCY_VALIDATION.json +33 -0
- package/docs/DIAGNOSTIC_BOUNDARIES.md +33 -0
- package/docs/DIAGNOSTIC_BOUNDARIES_VALIDATION.json +12 -0
- package/docs/E2E.md +445 -0
- package/docs/EVALS.md +134 -0
- package/docs/MCP.md +20 -0
- package/docs/NATIVE_ADAPTER.md +141 -0
- package/docs/OPEN_SOURCE_CHECKLIST.md +61 -0
- package/docs/OPEN_SOURCE_CHECKLIST_zh.md +61 -0
- package/docs/PIN_WORKFLOW_VALIDATION.json +28 -0
- package/docs/PLACEMENT_TASKS.md +99 -0
- package/docs/PLACEMENT_TASKS_VALIDATION.json +36 -0
- package/docs/REFERENCE_ADOPTION.md +67 -0
- package/package.json +48 -0
- package/scripts/run.js +46 -0
- package/skills/xpedition-cli/SKILL.md +300 -0
- package/skills/xpedition-cli/reference/agent-hardening.md +58 -0
- package/skills/xpedition-cli/reference/api-inventory.md +58 -0
- package/skills/xpedition-cli/reference/confirmation-safety.md +55 -0
- package/skills/xpedition-cli/test-prompts.json +62 -0
- package/skills/xpedition-pcb/SKILL.md +244 -0
- package/skills/xpedition-pcb/reference/fabrication.md +26 -0
- package/skills/xpedition-pcb/reference/hand-routing.md +33 -0
- package/skills/xpedition-pcb/reference/pcb-conventions.md +162 -0
- package/skills/xpedition-pcb/reference/placement-tasks.md +28 -0
- package/skills/xpedition-pcb/test-prompts.json +62 -0
- package/skills/xpedition-schematic/SKILL.md +244 -0
- package/skills/xpedition-schematic/reference/pin-assignment.md +61 -0
- package/skills/xpedition-schematic/reference/schematic-conventions.md +306 -0
- package/skills/xpedition-schematic/reference/schematic-design-format.md +219 -0
- package/skills/xpedition-schematic/test-prompts.json +52 -0
|
@@ -0,0 +1,499 @@
|
|
|
1
|
+
# Compatibility matrix
|
|
2
|
+
|
|
3
|
+
This document records the backends that have actually been verified. A
|
|
4
|
+
capability is not advertised as native support until a licensed Xpedition
|
|
5
|
+
environment passes the smoke loop described in [`E2E.md`](E2E.md).
|
|
6
|
+
|
|
7
|
+
| Backend | Version / environment | Status | Notes |
|
|
8
|
+
|---|---|---|---|
|
|
9
|
+
| MockBackend | xpedition-cli 1.0.x, Python 3.10–3.12 | verified | Offline JSON project model, schematic/PCB/constraint/analysis/manufacturing/library reads, ChangeSet validation/preview/apply, snapshot, BOM and review. |
|
|
10
|
+
| NativeBackend — Designer | Xpedition Standard XPED2604 on Windows 11, `Viewdraw.Application`, pywin32 bridge | reads and writes verified | Attach, schematic snapshot, `AddPartInstance` placement, net creation, labels and coordinate read-back all confirmed against a running Designer session. The R1/C1 smoke loop of [`E2E.md`](E2E.md) is recorded against a hand-built minimal library, not the stock one — see below. |
|
|
11
|
+
| NativeBackend — Layout | Xpedition Standard XPED2604, `MGCPCB.ExpeditionPCBApplication` | reads and writes verified | Board creation, forward annotation, `Components`/`Nets` reads, placement, routing by the router and by hand, pours, Batch DRC and fabrication outputs, all through the adapter; recorded in [`E2E.md`](E2E.md) from 2026-09-14 on boards built from a template, with cells generated or converted by the CLI rather than a production library. Bottom-side placement has not been exercised. |
|
|
12
|
+
| ExchangeBackend | JSON / CSV / BOM / IPC-2581 XML | verified | Import and normalization use the normalized project model with dry-run/confirm writes. |
|
|
13
|
+
| ExchangeBackend | PDF / EDN / ODB++ | planned | Format-specific parsers are not enabled yet. |
|
|
14
|
+
|
|
15
|
+
## A stock installation ships no component library
|
|
16
|
+
|
|
17
|
+
Not the CLI, and not COM: **the installation ships no component library**.
|
|
18
|
+
`SDD_HOME/standard/templates/dxdesigner/TemplateLibrary` is a deliberately empty
|
|
19
|
+
skeleton — every category directory (`Resistors`, `Capacitors`, …) exists, but
|
|
20
|
+
every `*.pdb` is a 3296-byte stub, every `*.cel` a 19492-byte stub, and the
|
|
21
|
+
device symbol directories hold zero files. Only borders, builtin symbols,
|
|
22
|
+
`Globals` (power/ground) and `Drawing.cel` carry content. Requesting a resistor
|
|
23
|
+
is answered by Designer itself:
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
6055 Symbol Resistors:R.1 not found, empty or a block.
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The first smoke loop in `E2E.md` therefore ran against a hand-built library, and
|
|
30
|
+
the CLI now generates the parts a design needs (`library build`, with cells from
|
|
31
|
+
`library kicad-import`). Placement against a symbol that *does* exist
|
|
32
|
+
(`builtin:espl1`) succeeds and reads back with correct coordinates, so the write
|
|
33
|
+
path is not what is missing.
|
|
34
|
+
|
|
35
|
+
## Driving the applications by command
|
|
36
|
+
|
|
37
|
+
The COM classes expose only a narrow slice of each product. The full command set
|
|
38
|
+
of every application is catalogued on disk:
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
SDD_HOME/standard/automation/Commands_XpeditionLayout.csv 1041 commands
|
|
42
|
+
SDD_HOME/standard/automation/Commands_Xpedition_Designer.csv
|
|
43
|
+
SDD_HOME/standard/automation/Commands_{Library_Manager,Symbol_Editor,CellEditor}.csv
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Each row carries an id, an internal name, a display name and a description.
|
|
47
|
+
Designer runs them through `ExecuteCommandByID(id)`, `ExecuteCommandByName(name)`
|
|
48
|
+
or `ExecuteCommand(string)`; Layout has the equivalent on `Gui.ProcessCommand` /
|
|
49
|
+
`Gui.ProcessKeyin`. This is how a board gets created — Layout's own COM interface
|
|
50
|
+
has no such entry point, only `OpenDocument` and `OpenReference`.
|
|
51
|
+
|
|
52
|
+
Not every command is automation-friendly. `Package Design for Layout` (35085)
|
|
53
|
+
launches `packagerui.exe`, a separate GUI process that waits for a human, and the
|
|
54
|
+
dialog-suppression switches do not reach it.
|
|
55
|
+
|
|
56
|
+
## Forward annotation without a GUI
|
|
57
|
+
|
|
58
|
+
`package.exe` does the same work as the packager dialog and is a console program,
|
|
59
|
+
so the adapter's `package` method runs it headless and returns structured errors
|
|
60
|
+
read back from `<project>/Integration/PartPkg.log`.
|
|
61
|
+
|
|
62
|
+
It must be started through `common/win64/bin/package.exe`. Launching the real
|
|
63
|
+
binary under `wg/win64/bin` directly skips the release environment and the
|
|
64
|
+
program cannot initialise its Qt platform plugin — it puts up "no Qt platform
|
|
65
|
+
plugin could be initialized" and never runs. Same launcher rule as below.
|
|
66
|
+
|
|
67
|
+
## COM activation needs the launcher
|
|
68
|
+
|
|
69
|
+
Every Xpedition `LocalServer32` registration points at the real binary under
|
|
70
|
+
`SDD_HOME/<product>/win64/bin`, but those binaries depend on the release
|
|
71
|
+
environment that the small launcher in `SDD_HOME/common/win64/bin` sets up.
|
|
72
|
+
Direct COM activation skips the launcher, so `CoCreateInstance` fails with
|
|
73
|
+
`CO_E_SERVER_EXEC_FAILURE` (0x80080005). Start the product through its launcher,
|
|
74
|
+
then attach with `GetActiveObject`. This applies to `LibraryManager` and
|
|
75
|
+
`ExpeditionPCB` alike; the adapter reports the condition as
|
|
76
|
+
`E_BACKEND_UNAVAILABLE` with a launcher hint rather than a bare COM error.
|
|
77
|
+
|
|
78
|
+
## Library tooling present on a stock installation
|
|
79
|
+
|
|
80
|
+
Useful when a library has to be built rather than imported:
|
|
81
|
+
|
|
82
|
+
| Tool | Path under `SDD_HOME` | Automatable? |
|
|
83
|
+
|---|---|---|
|
|
84
|
+
| Library Manager | `common/win64/bin/LibraryManager.exe` | COM `LibraryManager.Application`, **read-only** — the object model exposes no Add/Create for symbols, cells or parts |
|
|
85
|
+
| Cell / Padstack editors | reached via `ActiveLibrary.CellEditor` / `.PadstackEditor` | yes — `OpenDatabase`, `NewPartition`, `NewCell(eCellType)`, `SaveActiveDatabase`, `SuppressTrivialDialogs` |
|
|
86
|
+
| HKP converters | `common/win64/bin/HKP2{PadstackDB,CellDB,PartsDB,LMCDB}.exe` and the `*DB2HKP` reverse | yes — GUI-subsystem binaries with a command line (`-i <hkp> -o <db> -c <lmc> -m -l <log>`; a wrong argument is a message box, not an exit code). `library build` and `library kicad-import` run them; `CellDB2HKP -a` / `PadstackDB2HKP -a` exports are the grammar reference (see "KiCad footprints as cells" below) |
|
|
87
|
+
| PCB Footprint Expert 26 (Siemens) | `lm_fpe/` | IPC-7351B generator with populated `.fpx` libraries for SM/TH discretes, semiconductors, connectors and BGA |
|
|
88
|
+
|
|
89
|
+
Schematic symbols are plain ASCII (`SymbolLibs/<partition>/sym/<name>.<version>`),
|
|
90
|
+
so they can be generated as text; cells and padstacks go through the editor COM
|
|
91
|
+
objects above.
|
|
92
|
+
|
|
93
|
+
## Sheet units and symbol file versions
|
|
94
|
+
|
|
95
|
+
Measured by placing stock symbols through the adapter and reading the pin
|
|
96
|
+
coordinates back:
|
|
97
|
+
|
|
98
|
+
| Object | In the file | Read back on the sheet |
|
|
99
|
+
|---|---|---|
|
|
100
|
+
| `builtin:nc` connection point | `P 16 -254000 0 …`, header `V 54` | 10 units left of the origin |
|
|
101
|
+
| `builtin:Arrow_Blue` pin | `889000`, header `V 54` | 35 units |
|
|
102
|
+
| `builtin:Arrow_Green` pin | `35`, header `V 53` | 35 units |
|
|
103
|
+
| `asheet` border | `D 330200 0 27609800 21590000`, header `V 54` | 8.5 in tall, so 10 nm per file unit |
|
|
104
|
+
|
|
105
|
+
One sheet unit is therefore 10 mil (0.254 mm) and the 100 mil grid is 10 units.
|
|
106
|
+
`V 53` symbol files use sheet units directly; `V 54` files — every stock symbol
|
|
107
|
+
on XPED2604 — are in 10 nm, 254000 per grid step. The `Y` record is the
|
|
108
|
+
symbol type, not a scale: 1 part, 3 annotation, 4 power or ground, 5 border.
|
|
109
|
+
Hand-generated symbols use `V 53`. The xpedition-schematic Skill's
|
|
110
|
+
`reference/schematic-conventions.md` carries the grid, size and sheet-extent
|
|
111
|
+
rules that follow from this.
|
|
112
|
+
|
|
113
|
+
## Drawing a whole schematic
|
|
114
|
+
|
|
115
|
+
`schematic draw --design FILE` plans a readable schematic with
|
|
116
|
+
`xpedition_cli.schematic_layout` (IC blocks with a treatment per pin, vertical
|
|
117
|
+
ladders and horizontal chains of two-terminal parts between power, ground and
|
|
118
|
+
labelled nodes, titles, notes, overview boxes) and executes the plan through the
|
|
119
|
+
adapter method `draw`: `open_sheet`, `wipe_sheet`, `set_sheet`, `place_part`,
|
|
120
|
+
`place_symbol`, `wire`, `box`, `text`, `save`. Symbol files are written into the
|
|
121
|
+
project's central-library partition first, named by content. Afterwards the
|
|
122
|
+
project is reopened and every net is read back and compared with the plan;
|
|
123
|
+
unlabelled junctions are matched through Designer's own net `UID` (`$2N121`).
|
|
124
|
+
The recorded run is in [`E2E.md`](E2E.md).
|
|
125
|
+
|
|
126
|
+
`schematic show --sheet N` (adapter method `show`) activates a sheet, runs
|
|
127
|
+
`Fit All` (32775) and raises Designer's window: `SetForegroundWindow` is refused
|
|
128
|
+
to a background process, but making the window topmost and releasing it works.
|
|
129
|
+
`--output` captures the window through GDI into a PNG encoded in-process.
|
|
130
|
+
|
|
131
|
+
`project init --backend native_xpedition --template TPL.prj --project NEW.prj`
|
|
132
|
+
(adapter method `clone_project`) creates a project the only way Designer allows
|
|
133
|
+
without a GUI: copy a known-good project folder without `Templates`, `Work`,
|
|
134
|
+
`LogFiles`, `ProjectBackup`, `Thumbnail` and `*.bak`, rename the `.prj`, rewrite
|
|
135
|
+
the absolute `CentralLibrary` and `DBCFile` keys that pointed into the template
|
|
136
|
+
folder, and open the copy. The template is closed first if Designer has it
|
|
137
|
+
open, because the iCDB server holds its files. The destination must be an
|
|
138
|
+
ASCII path (see the facts below).
|
|
139
|
+
|
|
140
|
+
## Rendering a schematic to PDF
|
|
141
|
+
|
|
142
|
+
Designer's `Generate PDF` (command 34622) is a dialog, but the installation
|
|
143
|
+
ships `common/win64/bin/sch2pdf.exe`, a console program that renders a project
|
|
144
|
+
straight from its database and works while Designer still has the project
|
|
145
|
+
open. `schematic export --backend native_xpedition --project X.prj --output
|
|
146
|
+
X.pdf` runs it through the adapter method `export_pdf`. Facts that matter:
|
|
147
|
+
|
|
148
|
+
- It prints the area inside each sheet's border and nothing else; objects
|
|
149
|
+
placed outside the border simply do not appear.
|
|
150
|
+
- `-c` selects colour: 0 black on white without black text, 1 colour on white
|
|
151
|
+
(the default), 2 colour on black, 3 black on white, 4 colour on white with
|
|
152
|
+
coloured text. `-schematic NAME` limits the run to one schematic.
|
|
153
|
+
- Every rendered sheet is reported as `Printed <schematic> Sheet <n>`; the
|
|
154
|
+
adapter returns those as `sheets`.
|
|
155
|
+
|
|
156
|
+
## Designer drawing facts verified on XPED2604
|
|
157
|
+
|
|
158
|
+
| Fact | Detail |
|
|
159
|
+
|---|---|
|
|
160
|
+
| `AddPartInstance(partition, part, symbol, x, y)` | the second argument is the part (shown as the instance's Part Number), the third the symbol name |
|
|
161
|
+
| `AddSymbolInstance(partition, symbol, x, y)` | places a refdes-less symbol — stock `Globals:gnd`, `builtin:No_Connect`, generated power symbols — with no refdes step and therefore no orphan |
|
|
162
|
+
| Power and ground nets | a wire ending on the symbol's origin joins the net named by its `NETNAME` attribute, provided the symbol file is type 4 (`Y 4`) like every stock Globals symbol; a type-1 (part) symbol with a `NETNAME` attribute names nothing |
|
|
163
|
+
| Symbol cache | Designer keeps the definition of any symbol it has placed in the open project; a regenerated file with the same name is ignored. Give a changed symbol a new name |
|
|
164
|
+
| `Orientation` on an instance | 0 / 1 / 2 / 3 = 0° / 90° / 180° / 270° counter-clockwise, 4–7 the mirrored set; pin coordinates read back rotated, so read them instead of predicting them |
|
|
165
|
+
| Wiping a sheet | `ExecuteCommandByID(57642)` (Select All) then `Block.DeleteSelected(False)` removes every object and keeps the border; there is no per-object delete |
|
|
166
|
+
| Text | `Block.AddText(text, x, y)`, then `.Size = n` in sheet units |
|
|
167
|
+
| Attributes on an instance | `instance.AddAttribute("VALUE=10k", x, y, 3)` adds a visible attribute; the stock `pwr_bar`'s `NETNAME` cannot be changed this way, its attribute collection is empty |
|
|
168
|
+
| Sheet size | `Block.SheetSize` is the `VDSHEET_*` enum (0 A, 1 B, 2 C, 3 D, 4 E, 5–9 A4–A0, 10 custom); `SchematicSheetDocuments.Add()` and `InsertSheet` add sheets |
|
|
169
|
+
| Drawn wires | free `AddNet` segments that meet at an endpoint, and a segment that starts on the middle of another, all join one net (verified: an L-shaped run plus a T drop read back as one three-pin net); labels go on any segment, once per net (`Net already labeled`, 6035) |
|
|
170
|
+
| More sheets | `ExecuteCommandByID(34165)` (New Sheet) adds and activates a sheet; `SchematicSheetDocuments.Open("Schematic1", "2")` switches, `DeleteSheet("Schematic1", 2)` removes. The COM `Add`/`InsertSheet` calls fail with error 670 |
|
|
171
|
+
| After sheet operations | `GetActiveDesign` reports the schematic (`Schematic1`) instead of the block (`Board1`) and `DesignComponents` fails with a type mismatch until the project is closed and reopened |
|
|
172
|
+
| Off-page connectors | `builtin:OFFPAGE_INPUT` places like any symbol; the net still takes its name from a label on the wire |
|
|
173
|
+
| Pin text on a symbol | pin attributes take absolute symbol coordinates: `A x y size 0 3 3 #=1` shows the pin number, `A x y size 0 3 3 NAME=VIN` the pin name inside the body. An `L` record after a `P` record is not displayed on a part symbol, which is why generated boxes showed a black blob at the origin: every pin number was drawn at the same point |
|
|
174
|
+
| Sheet size and border | `Block.SheetSize = 5` (VDSHEET_A4_SIZE) changes the page; `Block.ChangeBorder("a4sheet")` swaps the border symbol; set the size first, the border second. Either change can leave another sheet's window active, so re-activate the target sheet before drawing on |
|
|
175
|
+
| Sheets open vs sheets existing | `SchematicSheetDocuments` lists the sheet windows that are open; `GetAvailableSheets(schematic)` (an `IStringList`: `GetCount()`, 1-based `GetItem(i)`) lists the sheets that exist. `Open(schematic, n)` activates a sheet only the first time; afterwards call `document.Activate()` on the open document |
|
|
176
|
+
| Attribute text on an instance | `attribute.Orientation = 0` turns a rotated value or refdes horizontal and `attribute.SetLocation(x, y)` moves it; `X`/`Y` are read-only |
|
|
177
|
+
| Chinese text | `AddText` accepts Unicode and Designer draws Chinese titles and notes correctly on screen. The project stores them in the system code page (GBK here), and `sch2pdf` writes those bytes as Latin-1 glyphs, so a PDF shows mojibake; the text is recoverable by re-encoding Latin-1 to GBK, which is what a review pipeline has to do when it extracts notes |
|
|
178
|
+
| Verification | `RunDesignIntegrityChecks` is a database integrity test (22 layer/object tests). The schematic ERC is the `Full Verification` command (34155; `Quick Verification` 46461) with the rules of the project's `Verify.ini`; it writes `LogFiles/vdrc.log` (`SEVERITY` / `GROUP` headers, then `<rule> - [flatnet : X, component: R1($2I5), pin: $1P10] message`) and `LogFiles/grc.log` (graphical checks). The adapter method `verify` runs it and parses both |
|
|
179
|
+
| Reading a design back | `net.LogicalNetName` gives the net name, `net.UID` the `$<sheet>N<id>` id of an unlabelled net; a component's `UID` `$<sheet>I<id>` tells its sheet; `component.Attributes` holds the instance attributes (Part Number, VALUE …) but not the symbol's DEVICE/PART_NAME; pin names and types are not exposed on the connection's pin object; the symbol name of an instance is not exposed at all — a no-connect mark is recognised by geometry, a refdes-less symbol sitting on the pin end |
|
|
180
|
+
| Non-ASCII paths | a project whose folder path contains Chinese characters opens, reads back and shows its sheets, but `AddPartInstance` reports every symbol file written after the copy as `not found, empty or a block`, before and after a reopen; the same project on an ASCII path finds them at once. Keep projects and their central library on ASCII paths; `schematic draw` and `project init --template` refuse others with `E_VALIDATION` |
|
|
181
|
+
| Pins on wire corners | a symbol pin placed where a stub and a bar meet end-to-end does not connect: Designer merges the two segments into one polyline and the pin sits on a vertex. A pin on a free wire end or on a T junction connects. The planner therefore runs a shared ground bar one stub past the last pin and puts the ground symbol on the free end |
|
|
182
|
+
| Creating a project | there is no automation call; copy a project folder as described above. The iCDB `database` folder copies cleanly while the project is closed, and the copy opens under a new `.prj` name |
|
|
183
|
+
| Pin types and ERC | `drc-BI-POWER` / `drc-BI-GROUND` fire for every pin typed `BI` on a net that also carries a `POWER` or `GROUND` typed pin, except on resistors and capacitors, which the verification exempts. Pins typed `ANALOG` pass: the generated inductor, diode, LED, switch, battery, thermistor, MOSFET drain/source and test-point pins are `ANALOG`, and the demo design verifies with no warning |
|
|
184
|
+
| Symbols without pins | a `V 53` part symbol with shapes and no `P` record (a mounting hole) places through `AddPartInstance`, gets a refdes and appears in the BOM |
|
|
185
|
+
|
|
186
|
+
## Creating a board and forward-annotating it (verified on XPED2604)
|
|
187
|
+
|
|
188
|
+
Layout's `File > New` is the Job Management Wizard, a separate program
|
|
189
|
+
(`common/win64/bin/JobWizard.exe`) with a documented command line:
|
|
190
|
+
|
|
191
|
+
```
|
|
192
|
+
JobWizard -createnew [-f] -prj <project.prj> -newpcb <PCB/Name.pcb> -template "<Layout Template Name>" -lib <library.lmc> -l <log>
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
`-f` ignores create warnings, `-l` names the log (otherwise
|
|
196
|
+
`%LOCALAPPDATA%\Temp\JobWizard.log`). It copies `Templates/Layout/<name>` out of
|
|
197
|
+
the central library (58 files for the stock 4-layer template), writes
|
|
198
|
+
`PCBDesignPath` and `LayoutTemplate` into the `.prj`, and needs no Designer
|
|
199
|
+
session. `pcb create` runs it. Facts that cost time:
|
|
200
|
+
|
|
201
|
+
- The command line takes the **first** entry of the `.prj`'s `LIST Designs` and
|
|
202
|
+
stops with "未能从通用数据库中获取设计信息" (failed to get design information
|
|
203
|
+
from the common database) when that is a schematic node (`ConfigType
|
|
204
|
+
"Board1"`) rather than the board design (`ConfigType "PCB"`); the GUI wizard
|
|
205
|
+
picks the board design itself. `pcb create` lists the board design first.
|
|
206
|
+
- Template names are the folders under `<library>/Templates/Layout`. A project
|
|
207
|
+
cloned without that folder (what `project init --template` does, 24 MB per
|
|
208
|
+
template) offers none; `pcb create` copies the requested one from
|
|
209
|
+
`SDD_HOME/standard/templates/dxdesigner/TemplateLibrary/Templates/Layout`.
|
|
210
|
+
- `-l` is the log file; it is not a mode flag. Wrong options show the usage in
|
|
211
|
+
a message box titled `messageBox`.
|
|
212
|
+
- `ExpeditionPCB.exe -create -prj X.prj -design <template.pcb>` opens the
|
|
213
|
+
template itself and asks for a library; `pcbui.exe -p X.prj Board1` is the
|
|
214
|
+
old PADS-style "PCB Interface" netlister, not a board creator.
|
|
215
|
+
|
|
216
|
+
Forward annotation is `Document.ProjectIntegration`, an object without type
|
|
217
|
+
information (`GetTypeInfo` fails, so `EnsureDispatch` cannot wrap it); its
|
|
218
|
+
interface is in `common/win64/lib/ProjectIntegration.dll`: `ForwardAnnotate`,
|
|
219
|
+
`BackAnnotate`, `LoadCES`, `SynchCES`, `IsForwardAnnotationAllowed`,
|
|
220
|
+
`IsBackAnnotationAllowed`, `IsLoadCESAllowed`, `IsSynchCESAllowed`,
|
|
221
|
+
`ProjectFile`, `ForwardAnnotationStatus`, `BackAnnotationStatus`,
|
|
222
|
+
`SynchCESStatus`, `LoadCESStatus` (1 required, 2 in synch, 3 no CES). Through a
|
|
223
|
+
late-bound object every member runs on attribute access and returns a bool.
|
|
224
|
+
`pcb annotate` runs it. Facts:
|
|
225
|
+
|
|
226
|
+
- The board needs the cell partitions in the `.prj`: `LIST 2dCellLibraries`
|
|
227
|
+
with `VALUE "CellDBLibs\<partition>.cel"` entries in the design section, next
|
|
228
|
+
to `LIST PDBs` and `LIST Symbols`. Without it Database Load stops with "No cell
|
|
229
|
+
library search paths found from X.prj — Unable to initialize CellDBUpdate".
|
|
230
|
+
`library build` and `pcb create` register a cell partition for every parts
|
|
231
|
+
partition listed.
|
|
232
|
+
- A cell must have exactly the part's pin count; a 4-pin SOIC placeholder on a
|
|
233
|
+
3-pin regulator is "Cell CLI_SOIC4 has 4 unique Alphanumeric Pin Numbers
|
|
234
|
+
while Part Number XC6206-3.3 has 3" and Database Load terminates.
|
|
235
|
+
- Asking for forward annotation when the status is already 2 (in synch) raises
|
|
236
|
+
`正向标注失败` (1001) without writing the log; the adapter reports `in_synch`
|
|
237
|
+
instead of running.
|
|
238
|
+
- A successful run writes `PCB/LogFiles/ForwardAnnotation.txt` with "N nets were
|
|
239
|
+
found containing M pins", "N components were found" and "Forward-Annotation on
|
|
240
|
+
the Layout Design has been successfully completed"; the run takes about 30 s
|
|
241
|
+
and shows progress boxes (`Packager`, `Database Load`) that need no answer.
|
|
242
|
+
- After opening a board whose front end is newer, Layout asks "新更改已经可以进行
|
|
243
|
+
正向标注。是否要立即进行正向标注?" (是/否); the adapter answers 否 so that the
|
|
244
|
+
annotation stays an explicit command.
|
|
245
|
+
|
|
246
|
+
Opening a board and attaching to Layout:
|
|
247
|
+
|
|
248
|
+
- `OpenDocument` wants a `.pcb`; a `.prj` is "Cannot open document file due to
|
|
249
|
+
invalid file extension" (10211). The board of a project is the design
|
|
250
|
+
section's `PCBDesignPath`, relative to the `.prj`.
|
|
251
|
+
- A Layout that a killed session left behind asks "应用程序已尝试确定设计状态超过
|
|
252
|
+
15 秒了…" (Open/Cancel) and then "数据库恢复" (load the autosave or the
|
|
253
|
+
user-saved database, 确定/取消). Both are Qt windows, not `#32770` dialogs, so
|
|
254
|
+
they are read and answered through UI Automation (`pywinauto`), from a helper
|
|
255
|
+
thread, because the `OpenDocument` call does not return until they are
|
|
256
|
+
answered.
|
|
257
|
+
- An instance started by COM activation (`Dispatch` of the progid) opens the
|
|
258
|
+
board in a hidden window and never registers in the running object table:
|
|
259
|
+
`GetActiveObject` keeps failing and nothing can attach to it. An instance
|
|
260
|
+
started through the launcher registers after start-up (about 50 s on this
|
|
261
|
+
machine). The adapter starts Layout through the launcher and waits.
|
|
262
|
+
- `GetActiveObject` returns a late-bound object without the type library's
|
|
263
|
+
enumerations; `gencache.EnsureDispatch` generates the library (`epcbSelectAll`
|
|
264
|
+
and friends appear in `win32com.client.constants`) but its generated classes
|
|
265
|
+
expose `Document.Components` and `Document.Nets` as parameterised properties
|
|
266
|
+
that reject arguments (`__call__() takes from 1 to 2 positional arguments`),
|
|
267
|
+
and the late-bound object rejects them too ("无效的参数数目"). Read both bare:
|
|
268
|
+
every parameter is optional and defaults to everything.
|
|
269
|
+
- Components arrive unplaced (`Placed` false, position 0/0); `Pins.Count` on the
|
|
270
|
+
document reads 0 even with 95 pins on the board.
|
|
271
|
+
- Designer has a question of the same kind: `OpenProject` for another project
|
|
272
|
+
while sheets are open asks "更改当前项目需要关闭所有打开的文档。是否希望关闭它们
|
|
273
|
+
并继续打开选定的项目?" (Yes/No) and waits. The adapter answers Yes from the
|
|
274
|
+
same helper thread.
|
|
275
|
+
|
|
276
|
+
Placing components (verified on XPED2604, `pcb arrange`):
|
|
277
|
+
|
|
278
|
+
- `Component.Place(dX, dY, dOrientation, bTop, eFixType, eUnit, eAngleUnit)`:
|
|
279
|
+
the fourth argument is "top side" (True), the fifth the fix type (0 none), the
|
|
280
|
+
sixth the unit of the coordinates (`EPcbUnit`: 0 current, 2 mils, 3 inch, 4 mm,
|
|
281
|
+
5 µm), the seventh the angle unit (0 degrees). `Component.Move(dX, dY, eUnit)`,
|
|
282
|
+
`Component.UnPlace()`. `GetPositionX(eUnit)` / `GetPositionY(eUnit)` read the
|
|
283
|
+
position in any unit; the bare `PositionX` is in the document's current unit,
|
|
284
|
+
which is mils on the stock templates (`Document.CurrentUnit` 2).
|
|
285
|
+
- `Component.Side` is 1 on the top and 512 on the bottom (`epcbSideTop`,
|
|
286
|
+
`epcbSideBottom`); `Layer` is 1 for a top-side part as well, so a layer test
|
|
287
|
+
cannot tell the sides apart.
|
|
288
|
+
- `Component.Extrema` (a property) is the footprint's bounding box:
|
|
289
|
+
`GetMinX(eUnit)` … `GetMaxY(eUnit)`. An unplaced component has no extents and
|
|
290
|
+
reading them fails, so a part is measured by placing it, reading and
|
|
291
|
+
unplacing it again. The cell object itself (`Component.Cell`) has no size.
|
|
292
|
+
- `Document.BoardOutline.Geometry` gives the outline: `GetRectMinX(eUnit)` …
|
|
293
|
+
`GetRectMaxY(eUnit)` for the bounding rectangle and `GetPointsArray(eUnit)`
|
|
294
|
+
for the vertices; the stock 4-layer template is a 50.8 mm (2000 mil) square
|
|
295
|
+
with its origin at the bottom-left corner.
|
|
296
|
+
- An unplaced component is not drawn on the board at all; after forward
|
|
297
|
+
annotation the board looks empty although the component navigator counts
|
|
298
|
+
the parts. Placing 39 parts through `Place` and saving takes about 5 s.
|
|
299
|
+
- `Net.Pins` lists only the pins of placed components once a part has been
|
|
300
|
+
unplaced (right after forward annotation the unplaced parts still appear);
|
|
301
|
+
a placement planner that reads connectivity must have every part on the
|
|
302
|
+
board first. `Net.IsPower` is a method and is False for `+3V3` on this board,
|
|
303
|
+
so a supply is better recognised by its member count.
|
|
304
|
+
- Layout's online DRC rejects `Place` with "DRC 违规" (10203) when the part
|
|
305
|
+
would land on another part or on its own old footprint, and when two
|
|
306
|
+
identical footprints share one spot; a part placed outside the board outline
|
|
307
|
+
is accepted. `Document.RespectComponentPlacementDRC` reads False here and
|
|
308
|
+
does not switch that check off. Lift the parts first, then place them.
|
|
309
|
+
- `PutBoardOutline(nPnts, points, width, eUnit)` replaces the outline; the
|
|
310
|
+
route border (`PutRouteBorder`) and manufacturing outline
|
|
311
|
+
(`PutManufacturingOutline`) are separate objects that keep their old size
|
|
312
|
+
until replaced too. Points go as three rows (x, y, radius) with the first
|
|
313
|
+
point repeated to close the polygon.
|
|
314
|
+
- `PutPlaneShape(layer, nPnts, points, net, routeObstruct, hatch, hatchWidth,
|
|
315
|
+
hatchDistance, component, eUnit)` and `PutFabricationLayerText(text, x, y,
|
|
316
|
+
epcbFabSilkscreen=2, epcbSideTop=1, height, rotation, penWidth, font, attr,
|
|
317
|
+
horiz, vert, component, eUnit, angleUnit)` take an optional component object;
|
|
318
|
+
pass `None`, because win32com turns the typelib's default `0` into "The
|
|
319
|
+
Python instance can not be converted to a COM object". Text is anchored at
|
|
320
|
+
its centre: a 1.2 mm string measures about 1.18 mm per character.
|
|
321
|
+
- Routing rules are read-only through Layout's own automation:
|
|
322
|
+
`NetClass.MinTraceWidth(layer, scheme, unit)`, `TypicalTraceWidth`,
|
|
323
|
+
`ExpansionTraceWidth` and `Document.GetClearanceRule(a, b, layerA, layerB, unit)`
|
|
324
|
+
read them (0.254 mm everywhere on the stock 4-layer template, via padstack
|
|
325
|
+
`026VIA`) and nothing there sets them. Constraint Manager's automation does set
|
|
326
|
+
trace widths (`pcb rules`; see "Constraint Manager automation" below); this tool
|
|
327
|
+
does not set clearances. Placeholder cells therefore need pads at least 0.254 mm
|
|
328
|
+
apart: a 0.65 mm pitch with 0.4 mm pads (0.25 mm gap) leaves its nets open.
|
|
329
|
+
|
|
330
|
+
Autorouting (verified on XPED2604, `pcb route`):
|
|
331
|
+
|
|
332
|
+
- `Document.NewRoutePass()` returns a pass object: `PassType(ePassType,
|
|
333
|
+
effortStart, effortEnd, viaGrid, routeGrid)` with the `epcbAR…Pass` values
|
|
334
|
+
(Expand 1, Fanout 2, NoVia 6, RemoveHangers 7, Route 8, Smooth 10, Spread 11,
|
|
335
|
+
ViaMin 14), `Items(epcbARAllNetsItem=0, None)`, `Order(epcbARAutoOrder=0, 0)`,
|
|
336
|
+
`Config(routeDuringFanout, allowCleanup)`, then `Go()`, which returns when the
|
|
337
|
+
pass is done (under a second for 18 nets on this board). `LayerSelect(1, 0)`
|
|
338
|
+
is "参数无效"; without it the pass uses every layer enabled for routing
|
|
339
|
+
(`Document.RouteLayerEnabled(n)`).
|
|
340
|
+
- `Net.IsRouted` and `Net.NumberOfOpens` (both methods) give the state per net;
|
|
341
|
+
`Document.Traces` and `Document.Vias` count the result. A pass on a board
|
|
342
|
+
whose parts are unplaced reports every net routed with no opens.
|
|
343
|
+
- Route passes leave the fine-pitch pads alone and never report why; the
|
|
344
|
+
clearance rule above is the reason.
|
|
345
|
+
|
|
346
|
+
Batch DRC and hazards (verified on XPED2604, `pcb drc`):
|
|
347
|
+
|
|
348
|
+
- No automation call runs Batch DRC. Its engine, `common/win64/bin/DrcDriver.exe`
|
|
349
|
+
(`-p PcbFilename [-q]`), refuses to start from a command line ("无法从命令行运行
|
|
350
|
+
可执行文件"). The menu command does run: `Gui.CommandBars` lists `Document
|
|
351
|
+
Menu Bar > 分析 > 批量 DRC...` with id 32769, and `Gui.ProcessCommand(32769)`
|
|
352
|
+
opens the `批量 DRC` dialog (scheme combo, 确定/取消); `ProcessCommand` takes
|
|
353
|
+
such MFC command ids, not toolbar names. The command-bar control objects have
|
|
354
|
+
no `Execute`. After 确定 a `Processing...` window shows until the checks are
|
|
355
|
+
done (about 10 s here).
|
|
356
|
+
- `Document.GetHazards(eType)` returns the hazards: 0 all, 1 online, 2 batch.
|
|
357
|
+
Each has `Type` (an `epcbHazardType…` value: 67 Proximity, 74 PartialNets,
|
|
358
|
+
75 Dangling, 77 ViasUnderParts, 24 PlacementGrid, 31/34/46/47 length and
|
|
359
|
+
delay summaries…), `Description` (a few lines of Chinese text), `Objects`,
|
|
360
|
+
`GetPositionX/Y(unit)` and, for clearance hazards, `GetRequiredClearance` /
|
|
361
|
+
`GetActualClearance`; the other kinds raise "Property or method not valid
|
|
362
|
+
for selected hazard type" on those.
|
|
363
|
+
- A plane shape made with `PutPlaneShape` is in the Draft state and connects
|
|
364
|
+
nothing (`GeneratedPlanes` 0): every via to it is dangling and its net partial.
|
|
365
|
+
`PlaneAssignment.PlaneDataState = 1` (Dynamic) generates the plane at once;
|
|
366
|
+
vias the router adds afterwards only tie in after the state is toggled to
|
|
367
|
+
Draft (3) and back to Dynamic. `Document.PlaneAssignments` has one entry per
|
|
368
|
+
assigned net and layer.
|
|
369
|
+
- The first Batch DRC on this board reported 18 pad-to-pad proximity
|
|
370
|
+
violations (required 0.254 mm, actual 0) on every dual-row placeholder: the
|
|
371
|
+
pads' long side had been laid along the pitch. Placeholder geometry needs a
|
|
372
|
+
DRC run as much as a real one.
|
|
373
|
+
|
|
374
|
+
Forward annotation after a library change (verified the hard way):
|
|
375
|
+
|
|
376
|
+
- Forward annotation never changes the cell of a component that already exists
|
|
377
|
+
on the board — placed, unplaced, with `ResetCell`, `ResetCellEx`, the `.prj`
|
|
378
|
+
`FwdAnnoRebuildFlag`, or after `Component.Delete` (which is refused silently
|
|
379
|
+
for a schematic part). The local parts cache and the central partition both
|
|
380
|
+
carry the new cell; the board keeps the old one. `ReplaceCell` wants a cell
|
|
381
|
+
object from `Document.Cells`, the board's local library, which only holds
|
|
382
|
+
cells a part has used. The way through is to create the board again
|
|
383
|
+
(`pcb create --replace`); JobWizard's own `-deletePCB` fails with "failed to
|
|
384
|
+
get design information" on these projects.
|
|
385
|
+
- `ForwardAnnotate` failed "in its packaging phase" ("正向标注的封装阶段出现错误",
|
|
386
|
+
while the packager's own log said it finished) on every run from the adapter
|
|
387
|
+
and succeeded from a plain script in the same state. The difference was the
|
|
388
|
+
adapter's prompt-answering thread, which also pressed the default button of
|
|
389
|
+
every `#32770` dialog of the process once a second: that ends the packager's
|
|
390
|
+
progress box and the annotation with it. Only rule-based answers are pressed
|
|
391
|
+
now, and the annotation succeeds at the first attempt on a fresh board. Two
|
|
392
|
+
earlier observations were symptoms of the same thing, not rules: "the second
|
|
393
|
+
call succeeds" and "it works with Designer's project closed". What is real:
|
|
394
|
+
closing Designer's project while Layout is opening the board breaks Layout's
|
|
395
|
+
database session ("iCDB error getting UID manager"), so the adapter reopens
|
|
396
|
+
the board first and only then lets Designer go of the project for the run.
|
|
397
|
+
- With traces on the board, a part whose pins changed needs traces broken
|
|
398
|
+
back, which Layout refuses in its preventive DRC mode ("不能在预防模式下打断导
|
|
399
|
+
线"); `pcb annotate --unroute` deletes traces and vias first.
|
|
400
|
+
- Placed parts can still be invisible: the stock templates open under the
|
|
401
|
+
`Loc: Assembly Bottom` display scheme, which shows nothing of a top-side
|
|
402
|
+
part. `Document.DisplaySchemes` is a tuple of the scheme names (`Loc: …` from
|
|
403
|
+
the design's `Config/*.dcs`, `Sys: …` from the installation) and
|
|
404
|
+
`Document.ActiveView` is the `View` object (`Name` is the view name). The scheme
|
|
405
|
+
setter is `ActiveView.DisplayControl.LoadScheme("Loc: Top View")` (returns True;
|
|
406
|
+
`DisplayControl.Name` reads the current scheme back; `SaveScheme`,
|
|
407
|
+
`LoadUserScheme` beside it), and Fit Board is `ActiveView.SetExtentsToBoard()`
|
|
408
|
+
(`SetExtentsToAll`, `SetExtents(...)` too). `Application.Gui.ProcessCommand(name)`
|
|
409
|
+
runs any command of `SDD_HOME/standard/automation/Commands_XpeditionLayout.csv`
|
|
410
|
+
by its internal name (`VIEW_FITBOARD` → True; a name with arguments is "未找到命令").
|
|
411
|
+
`pcb show` uses these; driving the toolbar combo `CMD_DISPLAY_SCHEMES` through UI
|
|
412
|
+
Automation is only its fallback — on a Layout started by `pcb annotate`,
|
|
413
|
+
pywinauto's `Desktop().window(handle=…).descendants()` came back empty while
|
|
414
|
+
`Application(backend="uia").connect(process=pid).top_window()` saw the tree.
|
|
415
|
+
The scheme picked last is kept in `Config/<user>/Graphics Settings.hkp`
|
|
416
|
+
(`"[Virtual].iDC.SchemeSelectorName"`), which is what the board opens with.
|
|
417
|
+
`Loc: All On` shows outlines, pads, reference designators and the ratsnest.
|
|
418
|
+
|
|
419
|
+
## Layout facts from the placement and routing round
|
|
420
|
+
|
|
421
|
+
| Fact | Detail |
|
|
422
|
+
|---|---|
|
|
423
|
+
| `Component.Extrema` | the placement outline only; the reference designator text above it is not included, so a planner that packs parts by their extents puts the labels of neighbours on top of each other |
|
|
424
|
+
| `RoutePass.LayerSelect(n, bool)` | accepts the **inner** layers only (2 and 3 on a four-layer board); 1 and 4 are "invalid parameters" — the outer layers are always the router's. `pcb route --layers 1,4` therefore disables 2 and 3. A handful of traces still landed on layer 3 in the first run; a second run after `--unroute` is the check |
|
|
425
|
+
| `TraceSegment` | has `Point1X/Y`, `Point2X/Y`, `Geometry`, no `Width`; a `Trace`'s width is `Geometry.LineWidth` (thousandths of an inch). Trace widths cannot be set through Layout's automation (`NetClass.MinTraceWidth` and friends are read-only): see the Constraint Manager section |
|
|
426
|
+
| `PutPlaneShape(..., bRouteObstruct, ...)` | with `bRouteObstruct` true (the earlier default) the shape blocks the autorouter on its layer — a board with pours on the outer layers routed nothing — and laid over traces already routed the call fails with "DRC 违反"; false lets traces through and the plane data flows around them. `PlaneShape.RouteObstructed` can be cleared afterwards too |
|
|
427
|
+
| Outer pours and the router | with the pours in place the router counts a plane net as routed while the regenerated copper leaves pins cut off (5 GND pins here) and a Fanout pass does not add vias for them; pour the outer layers after routing instead |
|
|
428
|
+
| `PointsArray` | three rows (x, y, r) in thousandths of an inch; a row with `r ≠ 0` is the centre of an arc from the previous row to the next, **positive r clockwise, negative counter-clockwise** (a pad's rounded corners come back positive on a clockwise outline; the board outline's corners negative on a counter-clockwise one). `Geometry.IsCircle()` first: a circle has `CircleX/Y/R` and `PointsArray` raises "the geometry for this call is incorrect" |
|
|
429
|
+
| Geometry for a picture | `Pin.Pads` / `Via.Pads` (one per layer: `Layer`, `Name`, `ShapeType`, `Geometries`), `Pin.Holes` / `Via.Holes` / `MountingHole.Holes` (`GetDrillSize(unit)`, `Plated`), `Trace.Geometry`, `PlaneShape.GeneratedPlanes[].Geometry` with `Cutouts`, `FabricationLayerGfxs` (`Type` 1 assembly, 2 silkscreen; `Side`, `Geometry.LineWidth`), `FabricationLayerTexts` (`TextString`, `Format.Height/Orientation/Mirrored`; `StrokeText()` for the vector fonts only), `Component.PlacementOutlines`, `Pin.GetPositionX/Y(unit)` |
|
|
430
|
+
| Window capture | `pcb show --output` captures a black PNG while the desktop is locked (the result says `blank` with that hint); UI Automation still works. `pcb render` draws the board from its geometry instead |
|
|
431
|
+
| Rounded outline | `PutBoardOutline` points array with arcs: per corner the rows `(start, 0)`, `(centre, −r)`, `(end, 0)`; a positive radius on the centre row draws the 270° arc the other way, a radius on the start or end row is an "invalid point array". `Geometry.GetRectMinX` etc. then fail with "the geometry for this call is incorrect": they only serve rectangles; read `Extrema` |
|
|
432
|
+
| Save prompt | while the outline was in that state the adapter's open logic tried to open the board again and Layout asked "your design and local library have changed… save all / library only / don't save / cancel" (four buttons, so the generic answerer leaves it); pressing `取消(C)` through UI Automation recovers |
|
|
433
|
+
| `PutMountingHoleEx(x, y, padstackName, bFromCentralLib, nDepth, bMirrored, pNet, pComponent, eFixed, eUnit)` | places a mounting hole by padstack name; `None` for the two object arguments, `True` to take the padstack from the central library. `MountingHoles` lists them with `GetPositionX/Y(unit)` |
|
|
434
|
+
| Display schemes | `Loc: Placement` shows pads, bodies and designators on a dark background without traces or planes — the picture to judge a placement by; `Loc: All On` shows everything, **but draws plane copper as outlines only** (`"Option.Planes.Data.Fill" "0"` in the scheme) and every layer and text layer at once. `pcb show --scheme` picks either; `--top-view` writes and picks `Loc: Top View` |
|
|
435
|
+
| Scheme files | `PCB/Config/<name>.dcs`, HKP-style text (`.Global_Constants`, `..File_Type Graphics_Scheme`). The `..Trace_Layer_On ( T T … )` arrays and `..Assy_Ref_Des_On True` toggles are the legacy section and this Layout ignores them; what counts is the key-value section: `"LayerControl.N" "d:1" "e:1" …` per layer, item entries such as `"Fabrication.Assembly.Part.Text.RefDes.Top"`, `"Fabrication.Silkscreen.Part.Text.RefDes.Top"`, `"Place.Part.Text.RefDes.Top"` (the designator drawn at the cell, a third copy of the name), `"Part.Cell.Origin.Top"` (the origin marker), `"Part.PlaceOutline.Top"`, `"Fabrication.DrillDrawingThrough"` — an item is drawn only with **both** `d:1` and `e:1` — and `"Option.*"` values (`Planes.Data.Fill`, `Pin.Number.Top`, `Pin.Type.Top`, `Pin.NetName.Top`, `Fabrication.AssemblyItems.Top`). A file added there appears in `Document.DisplaySchemes` at once but in the toolbar combo only after the board reopens |
|
|
436
|
+
| Three names per part | every part carries its designator three times on screen: the silkscreen text (printed on the board), the assembly-layer text (the assembly drawing; 1 mm on KiCad test points, 0.4 mm on the others) and Layout's placement-level designator at the cell. Normal; only the silkscreen one matters for the board. `Loc: Top View` shows that one alone |
|
|
437
|
+
|
|
438
|
+
## Hand routing through the automation (verified 2026-09-15)
|
|
439
|
+
|
|
440
|
+
| Fact | Detail |
|
|
441
|
+
|---|---|
|
|
442
|
+
| `PutTrace(nLayer, pNet, dWidth, nPnts, points, pComponent=None, eFixType=0, eUnit)` | adds a trace; the points array is the three-row `(x, y, r)` form, width and points in the unit given (`UNIT_MM`); returns the trace (`Geometry.LineWidth` in th). A trace that violates a clearance rule fails with "DRC 违反" — Layout's online DRC judges every call |
|
|
443
|
+
| `PutVia(dX, dY, pPadstack, pNet, pComponent=None, eFixed=0, eUnit)` | places a via; `pPadstack` is an object, not a name. `Document.Padstacks` lists only the padstacks in use, so a board whose vias were all deleted has no via padstack: `PutPadstack(1, nLayers, "026VIA", False, True)` pulls one from the central library and returns it; `GetPadstackNames(2, -1, "*", True)` lists the library's via padstacks (`026VIA`, `VC…`). `DefaultViaPadstack` takes other arguments ("无效的参数数目") |
|
|
444
|
+
| Via next to a pad | a via pad within the clearance of a surface-mount pad is refused **even for the same net** (SCL via 0.07 mm from U303.4's pad, VBAT via 0.1 mm from U301.1's); keep 0.254 mm to any pad the via does not sit inside |
|
|
445
|
+
| Test points | `TestPoint_Pad_D1.0mm` cells are surface-mount pads (`SMD-RND1`), so an inner-layer trace ending under one connects nothing and is a "Hangers" hazard; a via beside the pad with a top stub is the connection |
|
|
446
|
+
| `Net.NumberOfOpens`, `Pin.IsConnectedToPathOrAreaOnLayer(n)` | the open count per net and, per pin, whether copper on layer n touches it — enough to tell "pin not reached" from "two islands" |
|
|
447
|
+
| Unconnected pins | Layout shows them as net `(Net0)`; there is no such net in `Nets` (`PutTrace` for it is "the board has no such net") |
|
|
448
|
+
| `RoutePass` type 7 (remove hangers) | `PassType(7, 1, 3, False, False)` is "参数无效"; deleting the hanging trace (`pcb unroute --at`) and drawing it to the via instead is the fix |
|
|
449
|
+
| `Component.FabricationLayerTexts` | the cell's texts; `Type` 2 silkscreen, `TextType` 1 the designator; `Move(x, y, eUnit)` moves one, `Format.Orientation` turns with the part (a designator of a part at 90° stands upright), `Extrema` is its box |
|
|
450
|
+
| `RespectComponentPlacementDRC` | true makes `Component.Place` refuse a spot that touches another part — what `pcb move` wants; `pcb arrange` turns it off while it lifts and re-places everything |
|
|
451
|
+
| Trace-width hazards | the stock `(Default)` class allows exactly one width (min = typical = expansion = 10 th); a 0.3 mm stub is a `TraceWidths` hazard until the expansion width is raised (`pcb rules --class "(Default)" --width 0.254 --min 0.254 --expansion 0.5`; `--width` is required, and `--min` keeps the stock minimum) |
|
|
452
|
+
|
|
453
|
+
## Constraint Manager automation (net classes and trace widths)
|
|
454
|
+
|
|
455
|
+
| Fact | Detail |
|
|
456
|
+
|---|---|
|
|
457
|
+
| Server | `ConstraintsAuto` (late-bound `Dispatch`; `gencache.EnsureDispatch` fails with "can not automate the makepy process"); needs `SDD_HOME` and Layout's `PATH` set first, else "Cannot locate Mentor environment" |
|
|
458
|
+
| Loading | `auto.Design.CreateDesignParams()` → `ProjectFile`, `Board` (the design name, `Board1`), `DesignContext = 1` (layout; 0 answers "设计上下文丢失"), then `design.Load(params)` / `UnLoad()` |
|
|
459
|
+
| Objects | `design.NetClasses` (`Add(name)`, `Item(name)`, `NetClass.AssignNet(net)`), `design.Nets` and `design.PowerNets` (GND lives in the second; each net has `NetClass.Name`), `design.PhysicalRules.Schemes.Item(1)` = `(Master)` → `.NetClasses.Item(name).Layers` (`SIGNAL_1…4`) → `GetConstraints(7)` → constraints with `Name`, `Value`, `ConstraintType` (283 trace width minimum, 439 typical, 183 expansion). Values are thousandths of an inch (0.5 mm = 19.685) and settable; `nc.Constraints` on a net class answers "对象不可约束" |
|
|
460
|
+
| Layout sees it only after | `doc.ProjectIntegration.SynchCES` (returns true); `LoadCES` and reopening the board did not; afterwards `NetClass.TypicalTraceWidth(1, "(Master)", unit)` in Layout reports the new width and the router uses it |
|
|
461
|
+
|
|
462
|
+
## Manufacturing outputs (ODB++, Gerber, NC drill)
|
|
463
|
+
|
|
464
|
+
| Fact | Detail |
|
|
465
|
+
|---|---|
|
|
466
|
+
| No automation call | `IMGCPCBDocument` has `ExportAscii`, `ExportComponentData`, `GenerateEDMOutputs` and nothing for Gerber/ODB++/drill; the Output menu commands are `OUTPUT_ODBPP` 33017, `OUTPUT_GERBER` 33016, `OUTPUT_NCDRILL` 33018, `OUTPUT_SILKSCREEN` 33019 (Silkscreen Generator), `OUTPUT_NEUTRALFILE` 33773, `FILE_EXPORT_IPCD356B` 32938; `Gui.ProcessCommand` opens their dialogs (`ODB++ 设计输出`, `Gerber 输出`, `NC 钻孔生成`), OK is `确定(O)` / `确定` |
|
|
467
|
+
| Settings files | `Config/ODBSetup.ocf` (+ `.eocf`), `Config/PlotSetup.gpf` (+ `GerberPlot.egpf`), `Config/GerberMachineFile1.gmf`, NC drill scheme `Sys: DrillEnglish.dff`: HKP-style text. **The dialogs hold their settings in memory while the board is open and rewrite the files on OK**, so a file edited while the board is open is overwritten; edit it with the board closed and reopen |
|
|
468
|
+
| ODB++ | the stock setup leaves the drill span out (`..NAME "d_1_4"` / `...INCLUDE NO`) and the outline off (`.BOARD_OUTLINE NO`); with both on, the job has a `d_1_4` `TYPE=DRILL` layer with tools and hits and a `profile`. Job folder `Output/ODBpp/<OutputJobName lower-cased>/`, silkscreen `sst` complete, units inch |
|
|
469
|
+
| Gerber silkscreen | `..BoardItem SilkscreenTop` is accepted and writes a header-only file; the installation's sample setups draw the cells: `..CellType <each type>`, `..CellItemsSide Top`, `...CellItemsLayer 1` (bottom: `0`, which the dialog rewrites as the last layer number), `...CellItem SilkscreenOutline`, `...CellItem SilkscreenReferenceDesignator`. `GeneratedSilkscreen*` files need the Silkscreen Generator, whose per-package-group layer checklist is not exposed to UI Automation (clicks toggle blindly) |
|
|
470
|
+
| Gerber output | RS-274X, `Output/Gerber/*.gdo`, coordinates modal (a line may carry only X or Y); the stock 4-layer setup writes the outer copper twice (`EtchLayer1Top` and `EtchLayerTop`) and negative plane files for the inner layers |
|
|
471
|
+
| NC drill | `Output/NCDrill/ThruHolePlated.ncd` and `ThruHoleNonPlated.ncd`, Excellon 2.4 inch trailing-zero, modal coordinates |
|
|
472
|
+
| Files held after the run | NC drill leaves `PCB/LogFiles/DrillPrefs.txt` open in the Layout process after the document closes; `Application.Quit` puts Layout on its start page (`[首页]`) with the file still held, so `pcb create --replace` ends a document-less Layout by its process (`tasklist` / `taskkill`) when the folder will not go |
|
|
473
|
+
| Setups written back | a dialog that was opened earlier in the Layout session writes its in-memory settings over the patched file on OK even after the board was closed and reopened (the ODB++ job came out without `d_1_4` once); `pcb export` reads the setups again after the run and repeats the patch and the dialogs once (`rounds`) |
|
|
474
|
+
| 3D | `WINDOW_3D_VIEW` 33155 opens a `[3D View : <board>]` tab; view commands 53330–53338; `EXP3D_EXPORT` 53325 exports STEP/PDF/PNG; cells without a 3D model are drawn as their placement outline at the cell's height (0 for converted KiCad cells, so flat); `CONDUCTORVIEWRMB_VIEW_PHOTOREALISTIC` 53361 exists |
|
|
475
|
+
|
|
476
|
+
## KiCad footprints as cells
|
|
477
|
+
|
|
478
|
+
KiCad ships its footprint library as text (`share/kicad/footprints/<library>.pretty/*.kicad_mod`,
|
|
479
|
+
155 libraries and 15 450 footprints in KiCad 9 here) under CC-BY-SA 4.0 with the KiCad library
|
|
480
|
+
exception. `xpedition_cli.kicad_footprints` turns each `.pretty` folder into one cell partition
|
|
481
|
+
and `library kicad-import` (the adapter's `kicad_import`) feeds them through
|
|
482
|
+
`HKP2PadstackDB` / `HKP2CellDB`; a design then names a footprint as its package
|
|
483
|
+
(`"packages": {"RES": "kicad:Resistor_SMD:R_0603_1608Metric"}`) and `library build` writes
|
|
484
|
+
parts that reference the cell and registers its partition in `LIST 2dCellLibraries`. The whole
|
|
485
|
+
library takes about a quarter of an hour. Facts that cost time:
|
|
486
|
+
|
|
487
|
+
| Fact | Detail |
|
|
488
|
+
|---|---|
|
|
489
|
+
| Grammar reference | `CellDB2HKP -i X.cel -o X.hkp -a` and `PadstackDB2HKP -i PadstackDB.psk -o X.hkp -a` export what the importers read; the stock `Drawing` and `Starpoints and Tiebars` partitions show text, arcs, circles, rectangles and filled shapes |
|
|
490
|
+
| Pad shapes | `..ROUND ...DIAMETER`, `..SQUARE ...WIDTH`, `..RECTANGLE`/`..OBLONG ...WIDTH ...HEIGHT`, `..RADIUS_CORNER_RECTANGLE ...WIDTH ...HEIGHT ...RADIUS`; holes `..ROUND ...DIAMETER` or `..SLOT ...WIDTH ...HEIGHT`. KiCad `roundrect` maps to the radius-corner rectangle, `oval` to oblong, `custom` to the rectangle around its primitives |
|
|
491
|
+
| Graphics | one path per outline block: `..SILKSCREEN_OUTLINE`/`..ASSEMBLY_OUTLINE`/`..PLACEMENT_OUTLINE` with `...SIDE MNT_SIDE` and `...POLYLINE_PATH` (`....WIDTH`, `....XY (x, y) …`), `...RECT_PATH` (two corners), `...CIRCLE_PATH` (`....XY`, `....RADIUS`) or `...POLYLINE_SHAPE` + `....SHAPE_OPTIONS FILLED`. Any number of silkscreen blocks survive; **only one assembly outline is kept per cell**, so the converter emits the largest closed loop of the fabrication drawing; the placement outline must be one closed shape |
|
|
492
|
+
| Reference designator | `..TEXT "Ref Des"` / `...TEXT_TYPE REF_DES` / `...DISPLAY_ATTR` with `....XY`, `....TEXT_LYR SILKSCREEN_MNT_LYR`, `....HEIGHT`, `....WIDTH`, `....STROKE_WIDTH`, `....ROTATION`, `....FONT "vf_std"` places the refdes at the cell's own size; a cell without it gets Layout's default text, which is what made the placeholder boards look like a sea of "C"s |
|
|
493
|
+
| Holes in package cells | `..MOUNTING_HOLE ...PADSTACK ...XY ...ROTATION` is accepted inside `.PACKAGE_CELL` (a `MOUNTING_HOLE` padstack: clearance pad, mask, hole, no pad); KiCad `np_thru_hole` pads and unnumbered plated pads become these |
|
|
494
|
+
| Mount type | `..MOUNT_TYPE MIXED` is accepted with any package group; the converter derives it from the pads that became pins |
|
|
495
|
+
| Cell names | at most **64 characters**: `HKP2CellDB` logs `无法添加单元 "…"。正在跳到下一个单元。` for longer ones and then **saves nothing** for the whole file (`遇到 N 个错误。将不会保存单元数据库文件。`, exit code 1). 685 KiCad names are longer; they are cut to 56 characters plus `~` and seven hex digits of a SHA-1 of the full name (`kicad_footprints.cell_name`), and `kicad_import` retries a partition once without any cell the log refused |
|
|
496
|
+
| Log noise | every converter log contains `正在检查文件格式错误...` and `未找到文件格式错误。` ("checking for file format errors… none found"); a log check that matches the word "error" alone reports success as failure. `_tool_log` matches a leading `错误`/`error`, `错误:`/`error:`, `无法添加`, `遇到 N 个错误` |
|
|
497
|
+
| Coordinates | KiCad's Y points down, Xpedition's up: every Y is negated; rotations are counter-clockwise on screen in both, so angles stay |
|
|
498
|
+
| Same pad number twice | every copper land of a number stays, as a pad of that pin (a MOSFET's drain leads and paddle), and forward annotation puts them all on its net; only a pad lying wholly inside a larger one of its number (a thermal pad's via or a copper paste window) is dropped, reported as `inside_same_number`; paste-only, back-side and `connect` pads are dropped too |
|
|
499
|
+
| Merge | `HKP2PadstackDB … -m` and `HKP2CellDB … -m` add to what exists, replacing same-named entries and registering the partition in the `.lmc`; Layout and Designer may stay open with the project (Designer's project is closed and reopened by the adapter as for `library build`) |
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"baseline": "d42b226a5b1812b2937ded096bf618b8692c4f9a",
|
|
3
|
+
"run_id": "35248354040",
|
|
4
|
+
"python": "3.12.14 (main, Aug 13 2026, 02:47:42) [GCC 13.3.0]",
|
|
5
|
+
"platform": "Linux-6.17.0-1022-azure-x86_64-with-glibc2.39",
|
|
6
|
+
"baseline_selected": {
|
|
7
|
+
"tests": 6,
|
|
8
|
+
"failures": 6,
|
|
9
|
+
"errors": 0,
|
|
10
|
+
"skipped": 0
|
|
11
|
+
},
|
|
12
|
+
"full_suite": {
|
|
13
|
+
"tests": 240,
|
|
14
|
+
"failures": 0,
|
|
15
|
+
"errors": 0,
|
|
16
|
+
"skipped": 0
|
|
17
|
+
},
|
|
18
|
+
"ruff": "passed",
|
|
19
|
+
"version_sync": "passed",
|
|
20
|
+
"contract_local_only": "passed",
|
|
21
|
+
"native_xpedition_executed": false,
|
|
22
|
+
"limits": [
|
|
23
|
+
"healthy local store; cooperating versions",
|
|
24
|
+
"storage degradation remains permitted",
|
|
25
|
+
"not a project write lock or exactly-once native execution"
|
|
26
|
+
],
|
|
27
|
+
"source_sha256": {
|
|
28
|
+
"xpedition_cli/confirm.py": "67cc748364aa7cc5801b33ba6dacfa24f7cb0fce5c8ff9567a6c193eead967d7",
|
|
29
|
+
"xpedition_cli/confirmation_store.py": "e991a66a8a8d9f97cfa07b59dbff357c90207ba6d70fbb5f88dc9d965fbaa38a",
|
|
30
|
+
"tests/test_confirm_concurrency.py": "e919a74330dac1380bd1517e094aff45a8464d3d24fe46a5094c922f3cb18d7d",
|
|
31
|
+
"tests/test_confirm_cli.py": "629421ef7eb224adb233f51f5e600d45e758ef03476495a79982e59a9a78eec0"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Diagnostic backend boundaries
|
|
2
|
+
|
|
3
|
+
*Historical record: written for pull request #6 before it was merged on 2026-09-18;
|
|
4
|
+
kept as the design and evidence record. The current contract is
|
|
5
|
+
`xpedition-cli reference`.*
|
|
6
|
+
|
|
7
|
+
Two narrow fixes based on `main@d42b226`. This PR is independent of PRs #4 and #5;
|
|
8
|
+
neither existing branch is changed or merged.
|
|
9
|
+
|
|
10
|
+
`agent capabilities` now returns capability metadata before any project load or
|
|
11
|
+
backend requirement check, matching the existing streaming capability method.
|
|
12
|
+
This does not claim the configured native adapter is healthy or licensed. The
|
|
13
|
+
registry may still inspect local capability configuration. Use the appropriate
|
|
14
|
+
runtime diagnostics before operating on a real project.
|
|
15
|
+
|
|
16
|
+
`analysis run` is declared MockBackend-only in the existing reference. Previously,
|
|
17
|
+
selecting NativeBackend loaded a native snapshot and then executed the Mock
|
|
18
|
+
analysis function (the result did label its engine `mock`). The explicit native
|
|
19
|
+
combination now fails with non-retryable `E_BACKEND_UNAVAILABLE` before reading a
|
|
20
|
+
project. This is an intentional compatibility tightening, not a new native engine.
|
|
21
|
+
|
|
22
|
+
Native stored analysis reads (`analysis results/erc/drc/dfm`) are not disabled,
|
|
23
|
+
but the native snapshot never fills `analysis`, so on NativeBackend they return an
|
|
24
|
+
empty list. The native `pcb drc` and `review run` entry points remain separate
|
|
25
|
+
capabilities; they are not interchangeable with every analysis kind, and this patch
|
|
26
|
+
does not claim a native DFM runner exists.
|
|
27
|
+
|
|
28
|
+
The regression tests exercise the public CLI boundary, fail if unsupported
|
|
29
|
+
analysis touches either backend access or the mock analysis function, and ensure
|
|
30
|
+
capability discovery ignores invalid project contents. Stored native reads use
|
|
31
|
+
a fake adapter to protect their existing dispatch path. No licensed Xpedition
|
|
32
|
+
installation or production project is used. The branch workflow records full-suite
|
|
33
|
+
results in `DIAGNOSTIC_BOUNDARIES_VALIDATION.json` only after all checks pass.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"baseline": "d42b226a5b1812b2937ded096bf618b8692c4f9a",
|
|
3
|
+
"run_id": "35233583013",
|
|
4
|
+
"tests": 219,
|
|
5
|
+
"failures": 0,
|
|
6
|
+
"errors": 0,
|
|
7
|
+
"skipped": 0,
|
|
8
|
+
"ruff": "passed",
|
|
9
|
+
"version_sync": "passed",
|
|
10
|
+
"contract_local_only": "passed",
|
|
11
|
+
"native_xpedition_executed": false
|
|
12
|
+
}
|