# -*- coding: utf-8 -*- """P2 五路母版生成器。 几何来自 `p2-ch1.json`(CH1 页的回读快照),本文件负责按通道号改写: 1. 位号百位 R/C/Q/L/Rs 1xx -> nxx;U1->Un、U8->U(7+n)、U14->U(13+n);J2->J(1+n)、J7->J(6+n) 2. 网络名 VOn / VDACn / EFUSE_ENn / EFUSE_FLTn / EFUSE_PGn / Kn_PWR|VUP|VDN (GND / +12V / +3V3 / SDA / SCL / BUCK_PG / INA_ALERT 五路共用,不加后缀) 3. INA226 地址跳线(A1/A0 的去向) ⚠️ 端口的 dir(IN/OUT/BI)**读不回来**(API 里没有对应的 getState_), 而 dir 决定标签画在引脚左边还是右边(见 easyeda-sch-geometry §8b), 所以 PORTS 是显式声明的,不是从页面回读的。 """ import io, json, os HERE = os.path.dirname(os.path.abspath(__file__)) SNAP = json.load(io.open(os.path.join(HERE, 'p2-ch1.json'), encoding='utf-8')) # ── 端口:显式声明 (net, x, y, rotation, dir) ────────────────────────── # 标签朝向 = 远离导线来的方向。BI/OUT: rot0→右, rot180→左;IN 正好相反。 PORTS = [ ('BUCK_PG', 370, 760, 0, 'OUT'), # 标签在右 ('VO1', 465, 705, 0, 'BI'), # 标签在右 ('VO1', 180, 385, 0, 'IN'), # 标签在左(页面左边缘) ('VDAC1', 420, 340, 180, 'IN'), # 标签在右;挪到向上的支线末端,避开 K1_PWR ('EFUSE_EN1', 530, 600, 0, 'IN'), # 标签在左 ('EFUSE_FLT1', 600, 375, 0, 'OUT'), # 标签在右 ('EFUSE_PG1', 760, 530, 180, 'OUT'), # 标签在左(右边是 R115) ('INA_ALERT', 700, 460, 180, 'OUT'), # 标签在左 ('SDA', 700, 400, 180, 'BI'), # 标签在左 ('SCL', 750, 395, 0, 'BI'), # 标签在右 ('EFUSE_EN1', 1055, 445, 0, 'IN'), # 标签在左 ('K1_PWR', 510, 340, 180, 'IN'), # 标签在右 ('K1_VUP', 700, 340, 180, 'IN'), # 标签在右 ('K1_VDN', 860, 340, 180, 'IN'), # 标签在右 ('VO1_P', 960, 745, 0, 'OUT'), # 标签在右;给 P5-HARNESS 的手机侧电容组用 ] # VO1_P 原来只是页内的一段无名网络(Rs101 -> J2 / Q102 / U8.VIN-)。 # P5-HARNESS 上的手机侧电容组要挂在这个节点上,跨页就必须有名字, # 所以从 y=695 那根横线上引一段 50 长的支线,末端放 VO1_P 端口(§8a:不能直接压在引脚上)。 VOP_STUB = [((960, 695), (960, 745))] # 三个按键端口改走「向上 40 的短支线」(原来直接压在栅极电阻的引脚上)。 # 原因有两个:① K1_VUP 的端口引脚和 R122.1 是同一个坐标,靠一段**零长度导线**"连着", # 几何验证会报悬空——真按这个网表打样,那一路音量+ 可能根本没连上; # ② 三个标签原来朝左,正好压在前一级 MOS 的符号上。 # 支线末端 y=340 这一行 x=625/660/820/980 有竖线穿过,所以四个标签都朝右, # 各自落在 420-500 / 510-590 / 700-780 / 860-940 四段空隙里。 KEY_STUB_DROP = [((560, 300), (580, 300)), ((900, 300), (905, 300))] KEY_STUB_ADD = [((510, 300), (580, 300)), ((510, 300), (510, 340)), ((700, 300), (740, 300)), ((700, 300), (700, 340)), ((860, 300), (900, 300)), ((860, 300), (860, 340))] # J7 那个地旗原来在 (1010,330),它的 "GND" 文字正好压在 Q105 的位号 + 型号上 # (渲染出来是 "G5)5" 这种看不懂的东西)。往下再引 40,落到空行里。 # 往上 / 往左都走不通:x=980 那根竖线(VDN 漏极去 J7)和 y=360/370/380 三根按键线把路堵死了。 J7_GND_DROP = ('GND', 1010, 330, 0) J7_GND_ADD_WIRE = ((1010, 330), (1010, 290)) J7_GND_ADD_FLAG = ('GND', 1010, 290, 0) # ── INA226 地址跳线 ─────────────────────────────────────────────────── # A1 支线终点 (700,495),A0 支线终点 (660,490)。两条支线都从下方接进旗。 # 地址表:A1=GND 时 A0=GND/VS/SDA/SCL -> 0x40/0x41/0x42/0x43 # A1=VS 时 -> 0x44/0x45/0x46/0x47 # 只有 CH5 需要 A0 接 SDA(A0 走 (690,470)->(690,450)->(700,450) 搭到 SDA 线上,0 交叉)。 ADDR = { # n: (A1 去向, A0 去向, 地址, 说明) 1: ('GND', 'GND', 0x40, 'A1=A0=GND -> 0x40'), 2: ('GND', '+3V3', 0x41, 'A1=GND A0=VS -> 0x41'), 3: ('+3V3', 'GND', 0x44, 'A1=VS A0=GND -> 0x44'), 4: ('+3V3', '+3V3', 0x45, 'A1=A0=VS -> 0x45'), 5: ('GND', 'SDA', 0x42, 'A1=GND A0=SDA -> 0x42'), } PAGE_SUFFIX = {1: '', 2: 'B', 3: 'C', 4: 'D', 5: 'E'} def des_map(n): """CH1 位号 -> CHn 位号。""" m = {'U1': 'U%d' % n, 'U8': 'U%d' % (7 + n), 'U14': 'U%d' % (13 + n), 'J2': 'J%d' % (1 + n), 'J7': 'J%d' % (6 + n)} for d, _mfr, _sub, _x, _y, _r, _mir in SNAP['parts']: if d in m: continue pre = 'Rs' if d.startswith('Rs') else d[0] num = d[len(pre):] assert num.isdigit() and len(num) == 3 and num[0] == '1', d m[d] = '%s%d%s' % (pre, n, num[1:]) return m def net_map(n): m = {} for base in ('VO1', 'VO1_F', 'VO1_P', 'VDAC1', 'EFUSE_EN1', 'EFUSE_FLT1', 'EFUSE_PG1'): m[base] = base[:-1] + str(n) if base[-1] == '1' else base.replace('1_', '%d_' % n) m['VO1_F'] = 'VO%d_F' % n m['VO1_P'] = 'VO%d_P' % n for k in ('PWR', 'VUP', 'VDN'): m['K1_' + k] = 'K%d_%s' % (n, k) return m def channel(n): """返回 CHn 的完整图页内容。""" nm = net_map(n) a1, a0, addr, addr_txt = ADDR[n] drop = {tuple(sorted(w)) for w in KEY_STUB_DROP} wires = [tuple(map(tuple, w)) for w in SNAP['wires'] if tuple(sorted(map(tuple, w))) not in drop] assert len(wires) == len(SNAP['wires']) - len(drop), '按键支线的旧导线没删干净' wires += KEY_STUB_ADD + [J7_GND_ADD_WIRE] + VOP_STUB flags = [tuple(f) for f in SNAP['flags'] if tuple(f) != J7_GND_DROP] assert len(flags) == len(SNAP['flags']) - 1, 'J7 地旗没找到' flags.append(J7_GND_ADD_FLAG) # 地址跳线:A1 一律往上引到 (700,495) wires += [((770, 480), (700, 480)), ((700, 480), (700, 495))] flags.append((a1, 700, 495, 180 if a1 == 'GND' else 0)) if a0 == 'SDA': # 直接搭到 SDA 线上,不用旗 wires += [((770, 470), (690, 470)), ((690, 470), (690, 450)), ((690, 450), (700, 450))] else: wires += [((770, 470), (660, 470)), ((660, 470), (660, 490))] flags.append((a0, 660, 490, 180 if a0 == 'GND' else 0)) ports = [(nm.get(net, net), x, y, rot, d) for net, x, y, rot, d in PORTS] title = ('P2 CH1 单路通道(五路母版:复制后只改位号 / 网络名 / INA226 地址)' if n == 1 else 'P2%s CH%d 单路通道(与 CH1 完全相同,仅位号 / 网络名 / INA226 地址不同)' % (PAGE_SUFFIX[n], n)) texts = [ (title, 185, 785, 16), ('TPS54622: Vref 0.6V, fsw 480kHz(R%d03=100k), Vout = 4.222 - 0.2813*Vd' % n, 60, 185, 11), ('TPS25940A: OVP 4.36V(R%d09/R%d10), ILIM 4.45A(R%d11), dVdT 33nF -> 0.36V/ms' % (n, n, n), 60, 165, 11), ('缓启动 11.5ms / 涌流 0.8A ; INA226 CH%d: %s' % (n, addr_txt), 60, 145, 11), ('放电互锁: EN 低 -> Q%d01 截止 -> Q%d02 导通 -> R%d19 10R 泄放手机侧 2200uF' % (n, n, n), 60, 125, 11), ] return {'wires': wires, 'flags': flags, 'ports': ports, 'texts': texts, 'des': des_map(n), 'addr': addr, 'page': 'P2-CHANNEL' if n == 1 else 'P2%s-CH%d' % (PAGE_SUFFIX[n], n)} if __name__ == '__main__': for n in range(1, 6): c = channel(n) print('%-10s 导线 %3d 旗 %2d 端口 %2d 文字 %d INA226 0x%02X' % (c['page'], len(c['wires']), len(c['flags']), len(c['ports']), len(c['texts']), c['addr'])) m = des_map(3) print('CH3 位号样例:', {k: m[k] for k in ('U1', 'U8', 'U14', 'J2', 'J7', 'R101', 'Rs101', 'C114', 'Q105', 'L101')}) print('CH3 网络样例:', net_map(3))