traceforge-pcb 1.0.0__py3-none-any.whl

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.
Files changed (219) hide show
  1. traceforge/__init__.py +3 -0
  2. traceforge/__main__.py +3 -0
  3. traceforge/acp_server.py +570 -0
  4. traceforge/agent.py +680 -0
  5. traceforge/altium/__init__.py +6 -0
  6. traceforge/altium/cfb.py +70 -0
  7. traceforge/altium/cli.py +60 -0
  8. traceforge/altium/model.py +163 -0
  9. traceforge/altium/outputs.py +24 -0
  10. traceforge/altium/pcb.py +301 -0
  11. traceforge/altium/project.py +328 -0
  12. traceforge/altium/schematic.py +400 -0
  13. traceforge/altium/tools.py +166 -0
  14. traceforge/approval.py +219 -0
  15. traceforge/attachments.py +346 -0
  16. traceforge/background.py +253 -0
  17. traceforge/bench/__init__.py +5 -0
  18. traceforge/bench/adapters.py +337 -0
  19. traceforge/bench/checks.py +410 -0
  20. traceforge/bench/cli.py +121 -0
  21. traceforge/bench/design.py +439 -0
  22. traceforge/bench/kicad.py +99 -0
  23. traceforge/bench/partscheck.py +159 -0
  24. traceforge/bench/review.py +100 -0
  25. traceforge/bench/runner.py +226 -0
  26. traceforge/bench/score.py +204 -0
  27. traceforge/bench/tasks.py +102 -0
  28. traceforge/chat.py +1185 -0
  29. traceforge/checks.py +328 -0
  30. traceforge/checks_sides.py +118 -0
  31. traceforge/cli.py +2224 -0
  32. traceforge/clipboard.py +107 -0
  33. traceforge/config.py +299 -0
  34. traceforge/context.py +276 -0
  35. traceforge/design/__init__.py +1 -0
  36. traceforge/design/constraints.py +397 -0
  37. traceforge/design/generate.py +1789 -0
  38. traceforge/design/outline.py +905 -0
  39. traceforge/design/schematic_layout.py +932 -0
  40. traceforge/design/schematic_lint.py +329 -0
  41. traceforge/design/schematic_route.py +207 -0
  42. traceforge/design/sheets.py +854 -0
  43. traceforge/design/sides.py +328 -0
  44. traceforge/design/spec.py +462 -0
  45. traceforge/design/specsheet.py +2351 -0
  46. traceforge/design/specsheet_render.py +183 -0
  47. traceforge/desktop/__init__.py +109 -0
  48. traceforge/desktop/keys.py +90 -0
  49. traceforge/desktop/project.py +443 -0
  50. traceforge/desktop/review.py +20 -0
  51. traceforge/desktop/server.py +1277 -0
  52. traceforge/desktop/static/app.css +223 -0
  53. traceforge/desktop/static/app.js +683 -0
  54. traceforge/desktop/static/highlight.js +77 -0
  55. traceforge/desktop/static/index.html +89 -0
  56. traceforge/desktop/static/md.js +90 -0
  57. traceforge/desktop/static/viewer.js +213 -0
  58. traceforge/desktop/symbols.py +212 -0
  59. traceforge/desktop/update.py +65 -0
  60. traceforge/diagnostics.py +67 -0
  61. traceforge/errata.py +219 -0
  62. traceforge/fab.py +108 -0
  63. traceforge/fab_layers.py +44 -0
  64. traceforge/features/__init__.py +6 -0
  65. traceforge/features/candidates.py +117 -0
  66. traceforge/features/cli.py +200 -0
  67. traceforge/features/package.py +433 -0
  68. traceforge/features/revdiff.py +224 -0
  69. traceforge/features/sarif.py +145 -0
  70. traceforge/features/viewer.py +265 -0
  71. traceforge/firmware/__init__.py +3 -0
  72. traceforge/firmware/cli.py +174 -0
  73. traceforge/firmware/drivers.py +372 -0
  74. traceforge/firmware/drivers_data.py +256 -0
  75. traceforge/firmware/mcus.py +177 -0
  76. traceforge/firmware/netlist.py +55 -0
  77. traceforge/firmware/pinmap.py +296 -0
  78. traceforge/firmware/scaffold.py +466 -0
  79. traceforge/firmware/toolchain.py +262 -0
  80. traceforge/hooks.py +237 -0
  81. traceforge/kicad/__init__.py +0 -0
  82. traceforge/kicad/cli.py +519 -0
  83. traceforge/kicad/diffpair.py +174 -0
  84. traceforge/kicad/edgegeom.py +191 -0
  85. traceforge/kicad/edit.py +405 -0
  86. traceforge/kicad/escape.py +1410 -0
  87. traceforge/kicad/formats.py +1073 -0
  88. traceforge/kicad/impedance.py +320 -0
  89. traceforge/kicad/install.py +75 -0
  90. traceforge/kicad/libraries.py +490 -0
  91. traceforge/kicad/models3d.py +942 -0
  92. traceforge/kicad/outputs.py +81 -0
  93. traceforge/kicad/pcb.py +787 -0
  94. traceforge/kicad/planes.py +1242 -0
  95. traceforge/kicad/project.py +136 -0
  96. traceforge/kicad/route.py +2698 -0
  97. traceforge/kicad/routegeom.py +164 -0
  98. traceforge/kicad/schematic.py +268 -0
  99. traceforge/kicad/sides.py +34 -0
  100. traceforge/kicad/stackup.py +424 -0
  101. traceforge/kicad_plugin/__init__.py +12 -0
  102. traceforge/kicad_plugin/actions.py +92 -0
  103. traceforge/kicad_plugin/cli.py +66 -0
  104. traceforge/kicad_plugin/client.py +86 -0
  105. traceforge/kicad_plugin/context.py +257 -0
  106. traceforge/kicad_plugin/discovery.py +81 -0
  107. traceforge/kicad_plugin/install.py +203 -0
  108. traceforge/kicad_plugin/overlay.py +60 -0
  109. traceforge/kicad_plugin/payload/action_plugin.py +65 -0
  110. traceforge/kicad_plugin/payload/ipc_main.py +42 -0
  111. traceforge/kicad_plugin/payload/plugin.json +90 -0
  112. traceforge/kicad_plugin/payload/requirements.txt +1 -0
  113. traceforge/kicad_plugin/views.py +202 -0
  114. traceforge/langchain.py +57 -0
  115. traceforge/local.py +580 -0
  116. traceforge/mcp_server.py +304 -0
  117. traceforge/models.py +310 -0
  118. traceforge/next_steps.py +110 -0
  119. traceforge/parts/__init__.py +52 -0
  120. traceforge/parts/alternates.py +488 -0
  121. traceforge/parts/bom.py +423 -0
  122. traceforge/parts/brief.py +705 -0
  123. traceforge/parts/catalog.py +297 -0
  124. traceforge/parts/cli_sourcing.py +156 -0
  125. traceforge/parts/data/duty_rates.yaml +37 -0
  126. traceforge/parts/data/hs_codes.yaml +103 -0
  127. traceforge/parts/datasheet.py +278 -0
  128. traceforge/parts/fx.py +100 -0
  129. traceforge/parts/model.py +185 -0
  130. traceforge/parts/net.py +187 -0
  131. traceforge/parts/offers.py +46 -0
  132. traceforge/parts/packages.py +397 -0
  133. traceforge/parts/pinout.py +714 -0
  134. traceforge/parts/providers/__init__.py +17 -0
  135. traceforge/parts/providers/base.py +100 -0
  136. traceforge/parts/providers/jlc.py +364 -0
  137. traceforge/parts/providers/keyed.py +661 -0
  138. traceforge/parts/report.py +508 -0
  139. traceforge/parts/supply.py +330 -0
  140. traceforge/parts/verify.py +455 -0
  141. traceforge/parts/web.py +575 -0
  142. traceforge/plans.py +70 -0
  143. traceforge/preferences.py +127 -0
  144. traceforge/prices.py +130 -0
  145. traceforge/prices.yaml +28 -0
  146. traceforge/prompts/__init__.py +54 -0
  147. traceforge/prompts/system.md +103 -0
  148. traceforge/providers.py +764 -0
  149. traceforge/remote/__init__.py +33 -0
  150. traceforge/remote/client.py +422 -0
  151. traceforge/remote/oidc.py +240 -0
  152. traceforge/remote/orgs.py +510 -0
  153. traceforge/remote/server.py +690 -0
  154. traceforge/remote/store.py +100 -0
  155. traceforge/review_changes.py +187 -0
  156. traceforge/routing.py +99 -0
  157. traceforge/runtime.py +435 -0
  158. traceforge/sessions.py +324 -0
  159. traceforge/sexpr.py +279 -0
  160. traceforge/sim/__init__.py +17 -0
  161. traceforge/sim/acmath.py +234 -0
  162. traceforge/sim/circuit.py +499 -0
  163. traceforge/sim/cli.py +162 -0
  164. traceforge/sim/engine.py +172 -0
  165. traceforge/sim/ltspice.py +175 -0
  166. traceforge/sim/measure.py +123 -0
  167. traceforge/sim/models.py +76 -0
  168. traceforge/sim/project.py +218 -0
  169. traceforge/sim/rawfile.py +123 -0
  170. traceforge/sim/results.py +298 -0
  171. traceforge/sim/tune.py +172 -0
  172. traceforge/skill_commands.py +165 -0
  173. traceforge/skill_library/circuit-simulation/SKILL.md +30 -0
  174. traceforge/skill_library/compliance-review/SKILL.md +51 -0
  175. traceforge/skill_library/design-review/SKILL.md +47 -0
  176. traceforge/skill_library/errata-hunt/SKILL.md +30 -0
  177. traceforge/skill_library/firmware/SKILL.md +26 -0
  178. traceforge/skill_library/power-budget/SKILL.md +27 -0
  179. traceforge/skill_library/release-package/SKILL.md +29 -0
  180. traceforge/skill_library/sourcing-brief/SKILL.md +24 -0
  181. traceforge/skill_library/thermal-review/SKILL.md +15 -0
  182. traceforge/skills.py +131 -0
  183. traceforge/thermal.py +557 -0
  184. traceforge/tools/__init__.py +48 -0
  185. traceforge/tools/agent_tools.py +213 -0
  186. traceforge/tools/base.py +303 -0
  187. traceforge/tools/batch.py +155 -0
  188. traceforge/tools/connections.py +245 -0
  189. traceforge/tools/files.py +777 -0
  190. traceforge/tools/firmware_tools.py +218 -0
  191. traceforge/tools/kicad_tools.py +1072 -0
  192. traceforge/tools/models3d_tools.py +141 -0
  193. traceforge/tools/parts_tools.py +473 -0
  194. traceforge/tools/processes.py +246 -0
  195. traceforge/tools/review_tools.py +178 -0
  196. traceforge/tools/sim_tools.py +230 -0
  197. traceforge/tui.py +620 -0
  198. traceforge/updates.py +124 -0
  199. traceforge/validate/__init__.py +77 -0
  200. traceforge/validate/builtins.py +1091 -0
  201. traceforge/validate/circuits.py +1240 -0
  202. traceforge/validate/config.py +410 -0
  203. traceforge/validate/default.yaml +113 -0
  204. traceforge/validate/design.py +191 -0
  205. traceforge/validate/explain.py +112 -0
  206. traceforge/validate/grounding.py +169 -0
  207. traceforge/validate/ipc2221.py +350 -0
  208. traceforge/validate/multilayer.py +805 -0
  209. traceforge/validate/netmodel.py +261 -0
  210. traceforge/validate/partcheck.py +472 -0
  211. traceforge/validate/report.py +280 -0
  212. traceforge/validate/review.py +322 -0
  213. traceforge/validate/runner.py +662 -0
  214. traceforge/workspace.py +171 -0
  215. traceforge_pcb-1.0.0.dist-info/METADATA +463 -0
  216. traceforge_pcb-1.0.0.dist-info/RECORD +219 -0
  217. traceforge_pcb-1.0.0.dist-info/WHEEL +4 -0
  218. traceforge_pcb-1.0.0.dist-info/entry_points.txt +2 -0
  219. traceforge_pcb-1.0.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,218 @@
1
+ """Firmware tools: pin map from the netlist, scaffolds, driver snippets, build and flash."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+ from typing import Any
7
+
8
+ from traceforge.firmware.drivers import generate_driver, supported_parts
9
+ from traceforge.firmware.netlist import NetlistError, load_netlist
10
+ from traceforge.firmware.pinmap import HEADER_FILES, PinMap, build_pinmap, render_header
11
+ from traceforge.firmware.scaffold import TARGETS, ScaffoldError, scaffold
12
+ from traceforge.firmware.toolchain import (
13
+ INSTALL_GUIDANCE,
14
+ compile_project,
15
+ detect_tools,
16
+ flash_command,
17
+ flash_project,
18
+ size_project,
19
+ )
20
+ from traceforge.tools.base import Tool, ToolContext, ToolError, ToolKind
21
+ from traceforge.tools.kicad_tools import _schematic_path
22
+
23
+
24
+ def _design(args: dict[str, Any], ctx: ToolContext) -> Path:
25
+ if args.get("design"):
26
+ return ctx.resolve(args["design"], must_exist=True)
27
+ return _schematic_path(args, ctx)
28
+
29
+
30
+ def _pinmap(args: dict[str, Any], ctx: ToolContext) -> tuple[PinMap, Path]:
31
+ design = _design(args, ctx)
32
+ try:
33
+ return build_pinmap(load_netlist(design), args.get("ref"), args.get("mcu")), design
34
+ except NetlistError as exc:
35
+ raise ToolError(str(exc)) from exc
36
+
37
+
38
+ def firmware_pins(args: dict[str, Any], ctx: ToolContext) -> dict:
39
+ pm, design = _pinmap(args, ctx)
40
+ result = pm.as_dict()
41
+ style = args.get("style")
42
+ if style:
43
+ if style not in HEADER_FILES:
44
+ raise ToolError(f"style must be one of {', '.join(HEADER_FILES)}")
45
+ result["header"] = render_header(pm, style, ctx.display(design))
46
+ return result
47
+
48
+
49
+ def firmware_scaffold(args: dict[str, Any], ctx: ToolContext) -> dict:
50
+ pm, design = _pinmap(args, ctx)
51
+ out = ctx.resolve(args.get("out") or "firmware", for_write=True)
52
+ try:
53
+ files = scaffold(
54
+ pm, out, args.get("target"), args.get("name"), args.get("drivers") or [],
55
+ ctx.display(design), bool(args.get("overwrite")),
56
+ ) # fmt: skip
57
+ except (ScaffoldError, KeyError) as exc:
58
+ raise ToolError(str(exc)) from exc
59
+ return {"written": [ctx.display(f) for f in files], "warnings": pm.warnings}
60
+
61
+
62
+ def firmware_driver(args: dict[str, Any], ctx: ToolContext) -> dict:
63
+ if not args.get("part"):
64
+ return {"parts": supported_parts()}
65
+ try:
66
+ files = generate_driver(args["part"], args.get("address"))
67
+ except KeyError as exc:
68
+ raise ToolError(exc.args[0]) from exc
69
+ if args.get("out"):
70
+ out = ctx.resolve(args["out"], for_write=True)
71
+ out.mkdir(parents=True, exist_ok=True)
72
+ for name, text in files.items():
73
+ (out / name).write_text(text, encoding="utf-8")
74
+ return {"written": [ctx.display(out / n) for n in files]}
75
+ return {"files": files}
76
+
77
+
78
+ def firmware_toolchain(args: dict[str, Any], ctx: ToolContext) -> dict:
79
+ return {
80
+ "tools": [
81
+ {"name": t.name, "found": t.found, "path": t.path, "version": t.version,
82
+ "install": t.guidance}
83
+ for t in detect_tools()
84
+ ]
85
+ } # fmt: skip
86
+
87
+
88
+ def firmware_build(args: dict[str, Any], ctx: ToolContext) -> dict:
89
+ project = ctx.resolve(args.get("project") or ".", must_exist=True)
90
+ action = args.get("action", "compile")
91
+ timeout = float(args.get("timeout", 1800))
92
+ try:
93
+ if action == "size":
94
+ result = size_project(project, timeout)
95
+ elif action == "compile":
96
+ result = compile_project(project, timeout)
97
+ else:
98
+ raise ToolError("action must be compile or size")
99
+ except ValueError as exc:
100
+ raise ToolError(str(exc)) from exc
101
+ data = result.as_dict()
102
+ data["output_tail"] = result.output[-3000:]
103
+ if result.returncode == 127:
104
+ data["install"] = INSTALL_GUIDANCE.get(result.tool, "")
105
+ return data
106
+
107
+
108
+ def firmware_flash(args: dict[str, Any], ctx: ToolContext) -> dict:
109
+ """Runs only because the tool is SHELL kind: the host asks the user before it executes."""
110
+ project = ctx.resolve(args.get("project") or ".", must_exist=True)
111
+ try:
112
+ if args.get("dry_run", False):
113
+ return {"command": flash_command(project, args.get("port"))}
114
+ result = flash_project(project, args.get("port"), approved=True)
115
+ except ValueError as exc:
116
+ raise ToolError(str(exc)) from exc
117
+ data = result.as_dict()
118
+ data["output_tail"] = result.output[-2000:]
119
+ return data
120
+
121
+
122
+ _DESIGN = {
123
+ "design": {"type": "string", "description": "design spec (.yaml), .kicad_sch or .net"},
124
+ "schematic": {"type": "string", "description": "schematic when 'design' is not given"},
125
+ "ref": {"type": "string", "description": "MCU reference, e.g. U1 (auto-detected)"},
126
+ "mcu": {"type": "string", "description": "attiny85 | esp32s3 | stm32f103 (auto-detected)"},
127
+ }
128
+
129
+ FIRMWARE_TOOLS = [
130
+ Tool(
131
+ "firmware_pins",
132
+ "Pin map from the netlist: every non-power net on the MCU mapped to its pin, GPIO "
133
+ "number and peripheral (UART/SPI/I2C/PWM/ADC) using the datasheet pin table; "
134
+ "warns on strapping/reserved pins and functions the pin cannot do. With 'style' "
135
+ "(c | cpp | rust) also returns the pins.h / pins.hpp / board_pins.rs text.",
136
+ {"type": "object", "properties": {**_DESIGN, "style": {"type": "string"}}},
137
+ firmware_pins,
138
+ ToolKind.READ,
139
+ ),
140
+ Tool(
141
+ "firmware_scaffold",
142
+ "Write a firmware project for the design: target arduino | platformio | esp-idf | "
143
+ "stm32 | avr, with the generated pin header, a small main, and optional drivers "
144
+ "(see firmware_driver).",
145
+ {
146
+ "type": "object",
147
+ "properties": {
148
+ **_DESIGN,
149
+ "target": {"type": "string", "enum": list(TARGETS)},
150
+ "out": {"type": "string", "description": "output folder (default firmware)"},
151
+ "name": {"type": "string"},
152
+ "drivers": {"type": "array", "items": {"type": "string"}},
153
+ "overwrite": {"type": "boolean"},
154
+ },
155
+ },
156
+ firmware_scaffold,
157
+ ToolKind.WRITE,
158
+ target_arg="out",
159
+ ),
160
+ Tool(
161
+ "firmware_driver",
162
+ "Generate init/read driver C code for an I2C/SPI/single-wire part from its register "
163
+ "table (BME280, SHT31, MCP23017, PCF85063A, DHT11, LM75, SSD1306). Without 'part' "
164
+ "lists the parts. Returns the text, or writes it to 'out'.",
165
+ {
166
+ "type": "object",
167
+ "properties": {
168
+ "part": {"type": "string"},
169
+ "address": {"type": "integer", "description": "7-bit address override"},
170
+ "out": {"type": "string"},
171
+ },
172
+ },
173
+ firmware_driver,
174
+ ToolKind.WRITE,
175
+ target_arg="out",
176
+ ),
177
+ Tool(
178
+ "firmware_toolchain",
179
+ "Which firmware tools are installed (arduino-cli, platformio, idf.py, avr-gcc, "
180
+ "arm-none-eabi-gcc), their versions, and install guidance for the missing ones.",
181
+ {"type": "object", "properties": {}},
182
+ firmware_toolchain,
183
+ ToolKind.READ,
184
+ ),
185
+ Tool(
186
+ "firmware_build",
187
+ "Compile (action compile) or report memory use (action size) of a firmware project "
188
+ "made by firmware_scaffold, with the real toolchain; returns parsed errors and "
189
+ "flash/RAM use.",
190
+ {
191
+ "type": "object",
192
+ "properties": {
193
+ "project": {"type": "string"},
194
+ "action": {"type": "string", "enum": ["compile", "size"]},
195
+ "timeout": {"type": "number"},
196
+ },
197
+ },
198
+ firmware_build,
199
+ ToolKind.SHELL,
200
+ target_arg="project",
201
+ ),
202
+ Tool(
203
+ "firmware_flash",
204
+ "Flash the board from a firmware project (asks the user first). With dry_run only "
205
+ "returns the command.",
206
+ {
207
+ "type": "object",
208
+ "properties": {
209
+ "project": {"type": "string"},
210
+ "port": {"type": "string", "description": "serial port, e.g. /dev/ttyUSB0"},
211
+ "dry_run": {"type": "boolean"},
212
+ },
213
+ },
214
+ firmware_flash,
215
+ ToolKind.SHELL,
216
+ target_arg="project",
217
+ ),
218
+ ]