← Commit history

v1.9.41: solo layout + designators

John Lauer ·da8de74813 ·1mo ago ·parent 5bc44cf
4 files changed +62−17
BRIDGE_VERSION+1−1
@@ -1 +1 @@-1.9.40\ No newline at end of file+1.9.41\ No newline at end of file
adom-bridge-fusion-manifest.json+4−4
@@ -1,10 +1,10 @@ {     "manifest_version": 1,     "name": "fusion360",-    "version": "1.9.40",-    "url": "https://wiki.adom.inc/download/adom/fusion-bridge/1.9.40/adom-bridge-fusion-v1.9.40.zip",-    "sha256": "5c2fff630059f5e074919373fb50d45b1dc3eb25d48692ea8573952c53cf72bc",-    "size": 385382,+    "version": "1.9.41",+    "url": "https://wiki.adom.inc/download/adom/fusion-bridge/1.9.41/adom-bridge-fusion-v1.9.41.zip",+    "sha256": "eae894d94a8c4d977300b7524114a91ec4690babe0d819bdda7d675f94acc9ea",+    "size": 386088,     "verbPrefixes": [         "fusion_"     ],
bridge.json+1−1
@@ -2,7 +2,7 @@   "manifest_version": 1,   "name": "fusion360",   "displayName": "Autodesk Fusion 360",-  "version": "1.9.40",+  "version": "1.9.41",   "description": "Drive Autodesk Fusion 360 from the cloud: launch Fusion, electronics board layout, design rules, exports (STEP/IGES/STL/3MF/USDZ/OBJ/DXF/DWG/Gerbers/BOM/CPL), fast APS server-indexed cloud search plus browse/recent/file-info/versions, cloud file download/upload and folder creation, and in-app parametric modeling (fusion_run_modeling_script). Never-charge: APS calls are capped to the free tier.",   "homepage": "https://wiki.adom.inc/adom/fusion-bridge",   "author": "Adom Inc.",
server.py+56−11
@@ -6185,6 +6185,7 @@ def _mtp_extract(lbr_text, deviceset):     if not ds:         return None, "deviceset %r not found in the library" % deviceset     gate = re.search(r'<gate name="([^"]+)" symbol="([^"]+)"', ds)+    prefix_m = re.search(r'<deviceset name="[^"]+"[^>]*prefix="([^"]+)"', ds)     dev = re.search(r'<device name="[^"]*" package="([^"]+)"', ds)     if not (gate and dev):         return None, "deviceset %r has no gate/package device mapping" % deviceset@@ -6201,6 +6202,7 @@ def _mtp_extract(lbr_text, deviceset):     layers = re.search(r'<layers>.*?</layers>', lbr_text, re.S)     return {"deviceset": ds, "symbol": sym, "package": pkg, "connects": connects,             "symName": gate.group(2), "gateName": gate.group(1), "pkgName": dev.group(1),+            "prefix": (prefix_m.group(1) if prefix_m else "U"),             "layers": layers.group(0) if layers else ""}, None  @@ -6280,7 +6282,7 @@ def _r3d_cache_write(urn):     _json.dump({"0603WAF3300T5E": urn}, open(os.path.join(d, "r3d-urn.json"), "w"))  -def _mtp_generate(lib_name, ex, part_name, urn="", rex=None, r_urn=""):+def _mtp_generate(lib_name, ex, part_name, urn="", rex=None, r_urn="", solo=True):     """Build the .sch/.brd pair. R1 is the REAL bundled resistor part (rex) when     available, falling back to the legacy synthetic ADOMR. Wiring: R1.pad2-side pin ->     the part's first connected pin; GND -> its second; VCC -> R1's first pin."""@@ -6313,28 +6315,69 @@ def _mtp_generate(lib_name, ex, part_name, urn="", rex=None, r_urn=""):         r_part = '<part name="R1" library="adomdemo" deviceset="ADOMR" device="" value="330"/>'         r_pkg_name = "ADOMR0603"     g = ex["gateName"]+    # Correct EE designator from the deviceset's own prefix (John, 2026-08-16: "why is+    # there a D1 and R1 in a capacitor demo?"): C->C1, D->D1, U->U1; the series resistor+    # is R1, so a resistor-under-test becomes R2.+    pfx = (ex.get("prefix") or "U").strip() or "U"+    part_ref = (pfx + "2") if (pfx.upper() == "R" and not solo) else (pfx + "1")+    if solo:+        # SOLO layout (John, 2026-08-16: "when demoing a single component, you don't need+        # extra components... it's just confusing"): JUST the part - one symbol on the+        # sheet, one element centered on a small board. No resistor, no nets.+        lib_solo = ('<library name="%s"><packages>%s</packages>' % (lib_name, ex["package"])+               + (('<packages3d><package3d name="' + part_name + '" urn="" wip_urn="' + urn + '" locally_modified="yes" type="model">'+                   '<packageinstances><packageinstance name="' + ex["pkgName"] + '"/></packageinstances>'+                   '</package3d></packages3d>') if urn else '')+               + '<symbols>%s</symbols><devicesets>%s</devicesets></library>' % (ex["symbol"], ex["deviceset"]))+        sch = (_MTP_HEAD + _MTP_SCH_LAYERS ++         '<schematic xreflabel="%F%N/%S.%C%R" xrefpart="/%S.%C%R">'+         '<libraries>' + lib_solo + '</libraries>'+         '<attributes/><variantdefs/><classes><class number="0" name="default" width="0" drill="0"/></classes>'+         '<parts><part name="' + part_ref + '" library="' + lib_name + '" deviceset="' + part_name + '" device=""/></parts>'+         '<sheets><sheet><plain>'+         '<text x="0" y="25.4" size="2.54" layer="97">' + part_name + ' - Adom component demo</text>'+         '</plain><instances>'+         '<instance part="' + part_ref + '" gate="' + ex["gateName"] + '" x="25.4" y="12.7"/>'+         '</instances><busses/><nets/></sheet></sheets></schematic></drawing></eagle>\n')+        brd = (_MTP_HEAD + ex["layers"] ++         '<board><plain>'+         '<wire x1="0" y1="0" x2="8" y2="0" width="0.2" layer="20"/>'+         '<wire x1="8" y1="0" x2="8" y2="6" width="0.2" layer="20"/>'+         '<wire x1="8" y1="6" x2="0" y2="6" width="0.2" layer="20"/>'+         '<wire x1="0" y1="6" x2="0" y2="0" width="0.2" layer="20"/></plain>'+         '<libraries><library name="' + lib_name + '"><packages>' + ex["package"] + '</packages>'+         + (('<packages3d><package3d name="' + part_name + '" urn="" wip_urn="' + urn + '" locally_modified="yes" type="model">'+             '<packageinstances><packageinstance name="' + ex["pkgName"] + '"/></packageinstances>'+             '</package3d></packages3d>') if urn else '')+         + '</library></libraries>'+         '<attributes/><variantdefs/><classes><class number="0" name="default" width="0" drill="0"/></classes>'+         '<designrules name="default"/><autorouter/>'+         '<elements><element name="' + part_ref + '" library="' + lib_name + '" package="' + ex["pkgName"] + '" value="" x="4" y="3"'+         + ((' package3d_urn="' + urn + '"') if urn else '') + '/></elements>'+         '<signals/></board></drawing></eagle>\n')+        return sch, brd     sch = (_MTP_HEAD + _MTP_SCH_LAYERS +      '<schematic xreflabel="%F%N/%S.%C%R" xrefpart="/%S.%C%R">'      '<libraries>' + lib + rlib + '</libraries>'      '<attributes/><variantdefs/><classes><class number="0" name="default" width="0" drill="0"/></classes>'      '<parts>'-     '<part name="U1" library="' + lib_name + '" deviceset="' + part_name + '" device=""/>'+     '<part name="' + part_ref + '" library="' + lib_name + '" deviceset="' + part_name + '" device=""/>'      + r_part +      '</parts><sheets><sheet><plain>'      '<text x="0" y="30.48" size="2.54" layer="97">Adom generated test circuit: ' + part_name + '</text>'      '</plain><instances>'      '<instance part="R1" gate="' + r_gate + '" x="12.7" y="12.7"/>'-     '<instance part="U1" gate="' + g + '" x="38.1" y="12.7"/>'+     '<instance part="' + part_ref + '" gate="' + g + '" x="38.1" y="12.7"/>'      '</instances><busses/><nets>'      '<net name="N1" class="0"><segment>'      '<wire x1="17.78" y1="12.7" x2="25.4" y2="12.7" width="0.1524" layer="91"/>'-     '<pinref part="R1" gate="' + r_gate + '" pin="' + r_pin2 + '"/><pinref part="U1" gate="' + g + '" pin="' + p1 + '"/>'+     '<pinref part="R1" gate="' + r_gate + '" pin="' + r_pin2 + '"/><pinref part="' + part_ref + '" gate="' + g + '" pin="' + p1 + '"/>'      '</segment></net>'      '<net name="VCC" class="0"><segment>'      '<wire x1="7.62" y1="12.7" x2="2.54" y2="12.7" width="0.1524" layer="91"/>'      '<pinref part="R1" gate="' + r_gate + '" pin="' + r_pin1 + '"/></segment></net>'      '<net name="GND" class="0"><segment>'-     '<pinref part="U1" gate="' + g + '" pin="' + p2 + '"/></segment></net>'+     '<pinref part="' + part_ref + '" gate="' + g + '" pin="' + p2 + '"/></segment></net>'      '</nets></sheet></sheets></schematic></drawing></eagle>\n')     brd = (_MTP_HEAD + ex["layers"] +      '<board><plain>'@@ -6350,13 +6393,13 @@ def _mtp_generate(lib_name, ex, part_name, urn="", rex=None, r_urn=""):      '<elements>'      '<element name="R1" library="' + r_lib_name + '" package="' + r_pkg_name + '" value="330" x="3.5" y="4.5"'      + ((' package3d_urn="' + r_urn + '"') if (rex and r_urn) else '') + '/>'-     '<element name="U1" library="' + lib_name + '" package="' + ex["pkgName"] + '" value="" x="9.5" y="4.5"'+     '<element name="' + part_ref + '" library="' + lib_name + '" package="' + ex["pkgName"] + '" value="" x="9.5" y="4.5"'      + ((' package3d_urn="' + urn + '"') if urn else '') + '/>'      '</elements><signals>'-     '<signal name="N1"><contactref element="R1" pad="' + r_pads[r_pin2] + '"/><contactref element="U1" pad="' + pads[p1] + '"/>'+     '<signal name="N1"><contactref element="R1" pad="' + r_pads[r_pin2] + '"/><contactref element="' + part_ref + '" pad="' + pads[p1] + '"/>'      '<wire x1="4.35" y1="4.5" x2="8.5" y2="4.5" width="0.3" layer="1"/></signal>'      '<signal name="VCC"><contactref element="R1" pad="' + r_pads[r_pin1] + '"/></signal>'-     '<signal name="GND"><contactref element="U1" pad="' + pads[p2] + '"/></signal>'+     '<signal name="GND"><contactref element="' + part_ref + '" pad="' + pads[p2] + '"/></signal>'      '</signals></board></drawing></eagle>\n')     return sch, brd @@ -6412,10 +6455,11 @@ def _orchestrate_make_test_project(args: dict) -> dict:     # element gets package3d_urn so the 3D PCB renders the REAL component model, not a     # generic extrusion (John caught every test board showing black boxes, 2026-08-15).     urn_m = re.search(r'wip_urn="([^"]+)"', lbr_text)-    rex, _rtxt = _mtp_resistor()+    solo = not bool(args.get("withResistor"))+    rex, _rtxt = (None, None) if solo else _mtp_resistor()     r_urn = _r3d_cached_urn() if rex else ""     sch_text, brd_text = _mtp_generate(lib_name, ex, deviceset,-                                       urn_m.group(1) if urn_m else "", rex=rex, r_urn=r_urn)+                                       urn_m.group(1) if urn_m else "", rex=rex, r_urn=r_urn, solo=solo)     d = os.path.join(tempfile.gettempdir(), "adom-fusion-wrap")     os.makedirs(d, exist_ok=True)     base = "ADOM-TEST-" + re.sub(r"[^A-Za-z0-9_-]", "_", deviceset)[:40]@@ -6453,7 +6497,8 @@ def _orchestrate_make_test_project(args: dict) -> dict:                      "docBase": base.lower()}     out = {"success": True, "schPath": sch_path, "brdPath": brd_path,            "deviceset": deviceset, "steps": steps,-           "circuit": "R1 (330, generated 0603) in series with %s; VCC/GND stubs" % deviceset,+           "circuit": ("JUST %s on a small board (solo demo layout)" % deviceset) if solo+                      else "R1 (330) in series with %s; VCC/GND stubs" % deviceset,            "_hint": ("Test project opened as TWO documents (board instantiated with placed parts, "                      "schematic as its drawn sheet) via the dialog-free Document.newDesignFromLocal "                      "path. The BOARD document is active: fusion_show_2d_board / fusion_show_3d_board "