# -*- coding: utf-8 -*- u"""C2-HUB 补一个上游 VBUS 检测分压:VBUS_UP(5V) -> 10k/20k -> UP_VBUS_DET -> 下板 IO44。 用法: /c/Python314/python .claude/c2_vbusdet.py [--push] 为什么要分压:J23 的 VBUS 是 5V,而排针那头接的是 ESP32 的 IO44(3.3V 域)。 10k/20k 得到 5×20/30 = 3.33V;USB 上限 5.25V 时是 3.5V,仍在 ESP32 的 绝对最大值 3.6V 以内,而且远高于 VIH(≈2.48V)。 主机没插时 VBUS=0 -> 读到 0,这正是这个信号要的判据。 """ import json import os import sys HERE = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, HERE) from eda import run PAGE = '472c9bdbd7180ac4' # C2-HUB LIB = '0819f05c4eef4c71ace90d822a990e87' R10K = 'c3b9baa5ef2e4070a4c0f9e9cd04fe6e' # C25744 R20K = '3a163ef2745c43cd822f855b5ea3efa4' # C25765 Y = 120 R721, R722 = (880, Y), (980, Y) # 上臂 10k / 下臂 20k EXPECT = {'R721': [(860, Y), (900, Y)], 'R722': [(960, Y), (1000, Y)]} def call(js, timeout=180): r = run(js, timeout=timeout) if not r.get('success'): raise RuntimeError(json.dumps(r, ensure_ascii=False)[:800]) return r['result'] def main(): if '--push' not in sys.argv: print(u'待加:R721 10k / R722 20k + VBUS_UP 端口 + UP_VBUS_DET 端口 + 地旗(加 --push)') return call(""" await eda.dmt_EditorControl.openDocument('%s'); await new Promise(r=>setTimeout(r,900)); const n=(await eda.dmt_Schematic.getCurrentSchematicPageInfo()).name; if (n!=='C2-HUB') throw new Error('page='+n); // 重跑安全:先把上一轮加的东西删掉 for (const c of await eda.sch_PrimitiveComponent.getAll()){ const t=c.getState_ComponentType(); if (t==='part' && ['R721','R722'].includes(c.getState_Designator())){ await eda.sch_PrimitiveComponent.delete(c.getState_PrimitiveId()); continue; } if (t!=='netflag' && t!=='netport') continue; let nn=''; try{nn=c.getState_Net()||''}catch(e){} const x=Math.round(c.getState_X()), y=Math.round(c.getState_Y()); if (x>=700 && y<=180 && (nn==='UP_VBUS_DET' || nn==='GND' || nn==='VBUS_UP')) await eda.sch_PrimitiveComponent.delete(c.getState_PrimitiveId()); } for (const w of await eda.sch_PrimitiveWire.getAll()){ const a=w.getState_Line(); let hit=false; for (let i=0;i=700 && a[i+1]<=180) hit=true; if (hit) await eda.sch_PrimitiveWire.delete(w.getState_PrimitiveId()); } return 1; """ % PAGE) call(""" for (const [d,uuid,x,y] of %s){ await eda.sch_PrimitiveComponent.create({libraryUuid:'%s', uuid}, x, y, undefined, 0, false, true, true); for (const c of await eda.sch_PrimitiveComponent.getAll()){ if (c.getState_ComponentType()!=='part') continue; if (Math.round(c.getState_X())!==x || Math.round(c.getState_Y())!==y) continue; await c.toAsync().setState_Designator(d).done(); } } return 1; """ % (json.dumps([['R721', R10K, R721[0], R721[1]], ['R722', R20K, R722[0], R722[1]]]), LIB)) pins = call(""" const out={}; for (const c of await eda.sch_PrimitiveComponent.getAll()){ if (c.getState_ComponentType()!=='part') continue; const d=c.getState_Designator(); if (d!=='R721' && d!=='R722') continue; out[d]=(await c.getAllPins()).map(p=>[Math.round(p.getState_X()),Math.round(p.getState_Y())]); } return out; """) bad = [u'%s 期望 %s 实测 %s' % (d, EXPECT[d], sorted(map(tuple, pins.get(d, [])))) for d in EXPECT if sorted(map(tuple, pins.get(d, []))) != EXPECT[d]] if bad: raise SystemExit(u'引脚坐标对不上:\n ' + '\n '.join(bad)) print(u'引脚坐标核对通过') W = [[800, Y, 860, Y], # VBUS_UP -> R721 [900, Y, 960, Y], # R721 -> R722(中点就在这一段上) [930, Y, 930, 60], # 中点 -> UP_VBUS_DET [1000, Y, 1050, Y], [1050, Y, 1050, 90]] PT = [['BI', 'VBUS_UP', 800, Y, 180], ['BI', 'UP_VBUS_DET', 930, 60, 0]] F = [['Ground', 'GND', 1050, 90, 0]] TX = [(700, 175, u'上游 VBUS 检测:5V 经 10k/20k 分到 3.33V 送 IO44(§22.2)。主机没插时读 0。', 10)] call("for (const s of %s) await eda.sch_PrimitiveWire.create(s); return 1;" % json.dumps(W)) call("for (const p of %s) await eda.sch_PrimitiveComponent.createNetPort(p[0],p[1],p[2],p[3],p[4],false); return 1;" % json.dumps(PT)) call("for (const f of %s) await eda.sch_PrimitiveComponent.createNetFlag(f[0],f[1],f[2],f[3],f[4],false); return 1;" % json.dumps(F)) call("for (const t of %s) await eda.sch_PrimitiveText.create(t[0],t[1],t[2],0,null,null,t[3],false,false,false,0); return 1;" % json.dumps([list(t) for t in TX], ensure_ascii=False)) print(u'推送完成') if __name__ == '__main__': main()