# -*- coding: utf-8 -*- u"""P3 / P3B / P6 三页的**图面文字整页重写**。 /c/Python314/python .claude/sch_text.py # 只看现状与计划 /c/Python314/python .claude/sch_text.py --push # 删光旧文字 -> 写一套新的 ## 为什么要整页重写 2026-09-06 读回来发现这三页的 `sch_PrimitiveText` **层层叠了好几代**: P3 有 44 条、P3B 64 条、P6 76 条,其中大量是**同一坐标同一内容的完全重复** (历代脚本只 `create` 不 `delete`),还有互相矛盾的旧说明叠在一起。 渲染出来就是那一坨看不清的黑块 —— 而且 `verify_sch` / `xpage` / DRC **四道验证一条都不管文字**,所以它烂了很久也没人发现。 ⚠️ 判据:`sch_PrimitiveText` 只有图面注释,**标题栏不是它** (标题栏字段是图框自己的,`getAll()` 里根本不出现),所以整页删干净是安全的。 顺带把 2026-09-06 换脚之后**变成假话**的几条改掉: `IO39~IO42 留给 JTAG`、`IO47/IO48 备用`、`U22.Q7 = HUB_RST`、 `QA~QE = EDL_EN1~5;QF/QG/QH 备用不接`、`风扇座 KF2510-3A`。 """ import json import os import sys HERE = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, HERE) from eda import run # noqa: E402 PAGE = {'P3': '12f74666e70167e4', 'P3B': 'f42285b3728794d0', 'P6': 'fd00f13e59336392'} TEXT = { 'P3': [ (45, 806, u'【A】ESP32-S3-WROOM-1 主控(U20)'), (45, 795, u'3V3 由 P1 的 U19 辅助 Buck 供给;EN 端 10k + 100nF 上电复位'), (45, 395, u'【B】USB-C 调试口 —— ESP32-S3 原生 USB-Serial-JTAG(IO19/IO20)'), (45, 384, u'VBUS 故意不接:板子由 12V 供电,避免 USB 反灌。CC1/CC2 各 5.1k 下拉作 UFP。'), (645, 700, u'【C】I2C 上拉 4.7k + 三路开漏上拉'), (645, 470, u'【D】NTC 温度采样(10k B3380 + 10k 分压 + 100nF)'), # ⚠️ 右下角标题栏的左边界约在 x=476,y<210 那一片的文字末端必须 < 470 # (宽度按 CJK 12 / ASCII 6 估;`sch_text.py --push` 前会自己核一遍) (45, 205, u'引脚按 PCB 几何重排(2026-09-06,§26.18):'), (45, 194, u'除 USB(IO19/IO20 硬连线)与两路 NTC(要 ADC1)'), (45, 183, u'外,全部信号走 GPIO matrix,落哪个脚都行 ——'), (45, 172, u'按「出线方向 = 目的地方向」重排。'), (45, 158, u'IO39~IO42 原留给引脚 JTAG,现改作 GPIO:'), (45, 147, u'调试走原生 USB-Serial-JTAG(出厂 eFuse 默认),'), (45, 136, u'板上没有 JTAG 排针。别烧 DIS_USB_JTAG。'), (45, 122, u'有意不接:IO0/IO3/IO45/IO46 是 strapping;'), (45, 111, u'IO35~IO37 留 R8 版 PSRAM;TXD0/RXD0 引到测试点;'), (45, 100, u'IO4/IO5/IO7 空出来备用(三个都带 ADC1)。'), ], 'P3B': [ # ⚠️ 这三行右边 x=445 起是【B】PCA9555 那一块,末端要留在 430 以内 (45, 806, u'【A】(已搬走)74HC595 ×3 与 15 颗按键 MOS 2026-09-06 整窝挪到载板'), (45, 795, u'(载板 C6-KEYS / C4-SITEn,§26.23)。KEY_SER/SRCLK/RCLK/OE#'), (45, 784, u'四根线从 P3 的 ESP32 直接去 P5-BTB 的 J25 北排 3~6 行。'), (445, 790, u'【B】PCA9555 输入扩展 —— 地址 0x20(A0/A1/A2 全接地)'), (445, 779, u'IO0_7 与 IO1_5~7 备用脚直接接地:上电默认即输入,'), (445, 768, u'固件严禁把 Port0[7] / Port1[7:5] 配成输出。'), (45, 205, u'【C】DAC63204 ×2 —— 5 路调压'), (45, 194, u'U6 = 0x4A(A0→SDA),U7 = 0x4B(A0→SCL)'), (45, 180, u'三处 datasheet 强制要求,接错也不报错:'), (45, 169, u' 1) FBx 必须接回 OUTx(电压模式的闭环反馈)'), (45, 158, u' 2) CAP 接 2.2uF 到 AGND(LDO 旁路 0.5~15uF)'), (45, 147, u' 3) VREF 空置时 100nF 到地 + 10k 上拉 VDD'), (45, 136, u'内部基准 1.212V,×2 -> 满量程 2.424V(不是 2.5V)'), (45, 122, u'通道按几何重排(§26.18):U6 = VDAC2/4/1(去西半板),'), (45, 111, u'U7 = VDAC3/5(去东半板)。四通道对等,只改固件通道号。'), ], 'P6': [ (45, 806, u'【A】(已搬走)第三片 74HC595(U33)2026-09-06 随整条链挪到载板 C6-KEYS(§26.23)。'), (45, 790, u'EDL_EN1~5 / HUB_RST 从此是载板内部网络,不再过排针。这一页只剩风扇。'), (45, 520, u'【B】风扇:低边 N-MOS + PWM,5 个风扇并一路(§22.6)'), (45, 500, u'Q6 AO3400A 切风扇回流,D2 SS34 做续流 —— 风扇是感性负载,'), (45, 484, u'少了它 MOS 会被反峰打穿。FAN_PWM = IO18(模块脚 11),FAN_TACH = IO16(模块脚 9)。'), (45, 468, u'5 个 TACH 并联做线或,停一个频率掉约 1/5(分不出是哪一个)。'), (45, 444, u'TACH 必须分压:低边 PWM 关断时风扇地被抬到 12V,'), (45, 428, u'TACH 是集电极开路,也跟着到 12V —— 直连 GPIO 会打穿 ESP32。'), (45, 412, u'10k 上拉到 12V + 10k/3.3k 分压 -> 最高 2.98V。'), (45, 396, u'关断期间读到稳定高电平(测不到转速),导通期间才有脉冲 ——'), (45, 380, u'这是低边调速的固有限制,不是接线错。'), (45, 190, u'风扇电流 4x0.10 + 1x0.30 = 0.70A @12V;'), (45, 176, u'12V 输入预算 7.6 -> 8.3A,10A 适配器仍有余量。'), (45, 162, u'风扇座 2510-3A 直针(C2803349):'), (45, 148, u'pin1 = +12V,pin2 = 风扇回流(MOS 漏极),pin3 = TACH。'), ], } JS = u""" await eda.dmt_EditorControl.openDocument('%s'); await new Promise(r => setTimeout(r, 1500)); const old = await eda.sch_PrimitiveText.getAll(); const ids = old.map(t => t.getState_PrimitiveId()); %s const T = %s; %s await eda.sch_Document.save(); await new Promise(r => setTimeout(r, 800)); return {removed: ids.length, made: %d, now: (await eda.sch_PrimitiveText.getAll()).length}; """ DEL = u"if (ids.length) await eda.sch_PrimitiveText.delete(ids);" MAKE = u"for (const t of T) await eda.sch_PrimitiveText.create(t[0], t[1], t[2], 0, null, null, 12);" if __name__ == '__main__': go = '--push' in sys.argv for pg in ('P3', 'P3B', 'P6'): rows = [[x, y, s] for x, y, s in TEXT[pg]] print(u'%-4s 新文字 %d 条' % (pg, len(rows))) if not go: continue r = run(JS % (PAGE[pg], DEL, json.dumps(rows, ensure_ascii=False), MAKE, len(rows)), timeout=600) assert r.get('success'), json.dumps(r, ensure_ascii=False)[:400] q = r['result'] print(u' 删 %d / 建 %d / 现在 %d %s' % (q['removed'], q['made'], q['now'], u'✅' if q['now'] == len(rows) else u'❌')) if not go: print(u'(未加 --push,没有改动)')