# -*- coding: utf-8 -*- u"""建「PCI-E x4 金手指」器件(R2 刀片的 `J1`)。 金手指不是买来的连接器,是**刀片 PCB 板边本身**: · 符号借用系统库 `PCIE-064-02-F-D-TH`(Samtec x4 插座)的 64 脚符号 —— 脚号正好就是 `A1~A32` / `B1~B32`,和 CEM 的命名一一对应,不用自己画。 · 封装是**自建金手指**(64 个板边焊盘,1.0 mm 间距,正反两面), ⛔ **还没画**,属于 M4 的活 —— 但 **T3 已定(2026-09-08)**:做斜边 20°/1.0 mm、 金手指区**电镀硬金**(不是 ENIG)、板厚 1.6 mm,所以前置条件已经清空。 ⚠ 斜边吃掉手指前端约 1.0 mm 的镀层 ⇒ 金手指长度按 PCIe CEM 画,别自己缩短。 · 不进 BOM(没有东西可买),进 PCB(要出板边焊盘)。 用法: /c/Python314/python .claude/r2/dev_edge.py # 只查 /c/Python314/python .claude/r2/dev_edge.py --push # 建器件 + 写回 eda-parts.json """ import io import json import os import sys import time HERE = os.path.dirname(os.path.abspath(__file__)) # ⚠ `.claude` 下有和 r2 同名的 R1 脚本(pcb_pour / pcb_rules / pcb_place)。 # 只插父目录的话,**后面任何一个 `import pcb_rules` 都会拿到 R1 那一份**, # 而且不报错,只在调到 R2 专有的函数时才炸(2026-09-08 踩过)。 # 规矩:两行都要写,HERE 后插(在 sys.path 最前)。 sys.path.insert(0, os.path.dirname(HERE)) sys.path.insert(0, HERE) from eda import run # noqa: E402 LIB_ME = '543725e8f0454017a5691e7e570aeef6' # 个人库 LIB_SYS = '0819f05c4eef4c71ace90d822a990e87' # 立创系统库 DEV_NAME = 'PCIE-X4-EDGE-64P' SYM_SRC = '55d057aaabd3475584df3055eba749d6' # PCIE-064-02-F-D-TH 的符号(A1~A32/B1~B32) PARTS_JSON = os.path.join(os.path.dirname(HERE), 'eda-parts.json') DESC = (u'PCI-E x4 金手指(刀片板边,非采购件)。符号借用 Samtec PCIE-064-02-F-D-TH,' u'脚号 A1~A32/B1~B32 对齐 PCIe CEM。封装待建(M4)。') def call(js, timeout=120): r = run(js, timeout=timeout) if not r.get('success'): raise RuntimeError(json.dumps(r, ensure_ascii=False)[:600]) return r['result'] def find_dev(retries=6): for _i in range(retries): r = call("const r = await eda.lib_Device.search('%s', '%s', undefined, undefined, 20, 1);" "return (r||[]).map(d => [d.uuid, d.name, d.libraryUuid]);" % (DEV_NAME, LIB_ME)) for u, n, _l in r: if n == DEV_NAME: return u time.sleep(2) return None def push(): dev = find_dev(retries=2) if not dev: # ⚠️ create() 返回 undefined 但器件已建(skill §9y),判据是 search call("try { await eda.lib_Device.create('%s', '%s', undefined, " "{symbol: {uuid: '%s', libraryUuid: '%s'}}, %s); } catch (e) {}" "return 1;" % (LIB_ME, DEV_NAME, SYM_SRC, LIB_SYS, json.dumps(DESC, ensure_ascii=False)), timeout=60) dev = find_dev() assert dev, u'器件建了但搜不到' print(u'器件已建: %s %s' % (DEV_NAME, dev)) else: print(u'器件已存在: %s %s' % (DEV_NAME, dev)) prop = {'name': DEV_NAME, 'designator': 'J?', 'addIntoBom': 'no', 'addIntoPcb': 'yes', 'manufacturer': '-', 'manufacturerId': 'PCB edge finger', 'otherProperty': {'Note': u'刀片板边金手指,不采购;封装待建(M4)'}} call("try { await eda.lib_Device.modify('%s', '%s', undefined, undefined, undefined, undefined, %s); }" "catch (e) {} return 1;" % (dev, LIB_ME, json.dumps(prop, ensure_ascii=False)), timeout=60) g = call("const d = await eda.lib_Device.get('%s', '%s'); return {assoc: d.association, prop: d.property};" % (dev, LIB_ME)) a, p = g['assoc'], g['prop'] sym = (a.get('symbol') or {}).get('uuid') print(u'读回:符号 %s / 封装 %s / designator %s / BOM %s / PCB %s' % (sym, (a.get('footprint') or {}).get('uuid'), p.get('designator'), p.get('addIntoBom'), p.get('addIntoPcb'))) # ⚠ create() 会把系统库符号**复制一份进个人库**(uuid 变了,不是引用), # 所以判据是「有符号 + 放下去 64 个脚对得上」,不是「uuid 等于源符号」。 assert sym, u'符号没挂上' if sym != SYM_SRC: print(u' (符号已复制进个人库:%s ← %s)' % (sym, SYM_SRC)) if p.get('addIntoBom') != 'no': print(u'⚠ addIntoBom 仍是 %s —— 和 MI8-KEY-PAD 一样,BOM 字段 API 改不动,' u'要在客户端手工改(否则 BOM 里会多一颗买不到的东西)' % p.get('addIntoBom')) d = json.load(io.open(PARTS_JSON, encoding='utf-8')) d['parts'][DEV_NAME] = { 'name': DEV_NAME, 'uuid': dev, 'lib': LIB_ME, 'lib_note': u'个人库,不是系统库 —— 放元件时 libraryUuid 要用这个', 'symbol': sym, 'role': (u'R2 刀片 J1:PCI-E x4 金手指(板边本身,不采购)。符号借自系统库 ' u'PCIE-064-02-F-D-TH,脚号 A1~A32 在左列(自上而下,pitch 10)、' u'B1~B32 在右列,与 PCIe CEM 命名一一对应。' u'⛔ 封装还没建(64 个板边焊盘,1.0 mm 间距,正反两面),等 T3 定了斜边再画,属 M4。'), } with io.open(PARTS_JSON, 'w', encoding='utf-8') as f: f.write(json.dumps(d, ensure_ascii=False, indent=1)) print(u'已写回 eda-parts.json') return dev if __name__ == '__main__': if '--push' in sys.argv: push() else: print(u'当前: %s' % find_dev(retries=1))