"""Apply the reviewed R1 annotation layout without changing electrical geometry.""" from schematic_maintenance import ROOT, parse, child, children, properties from revise_four_wire_fans import uid, quote def apply_edits(path, source, edits): for start, end, replacement in sorted(edits, reverse=True): source = source[:start] + replacement + source[end:] path.write_text(source, encoding='utf-8', newline='\n') def main(): path = ROOT/'PhoneRail-Board1/P6-FAN-EDL.kicad_sch' source = path.read_text(encoding='utf-8') root = parse(source) edits = [] for sym in children(root, 'symbol'): x, y, angle = map(float, child(sym, 'at')[1:]) if angle not in [90, 270]: continue for name, dy in [('Reference', -2.54), ('Value', 0)]: p = properties(sym)[name] edits.append((p.start, p.end, f'(property "{name}" {quote(p[2])} (at {x+(22.86 if properties(sym)["Reference"][2] in {"C738", "D2"} else 10.16):g} {y+dy:g} {360-angle:g}) ' '(effects (font (size 1.27 1.27))))')) left_nets = {'FAN_EN', 'FAN_PWM', 'FAN_IN_TACH_RAW', 'FAN_OUT_TACH_RAW', 'FAN_12V_SW', 'FAN_PWM_OD', 'GND'} for n in children(root, 'label') + children(root, 'global_label'): x, y, _ = map(float, child(n, 'at')[1:]) # Only the left-facing connector/input stubs; receiver labels stay put. if n[1] not in left_nets or not (x in [271.78, 365.76, 58.42]): continue raw = source[n.start:n.end].replace(f'(at {x:g} {y:g} 0)', f'(at {x:g} {y:g} 180)').replace('(justify left bottom)', '(justify right bottom)') edits.append((n.start, n.end, raw)) for n in children(root, 'text'): if n[1].startswith('RAW high:'): at = child(n, 'at') edits.append((at.start, at.end, '(at 223.52 177.8 0)')) if n[1].startswith('Electrical limits, hot-plug/ESD'): edits.append((n.start, n.end, '')) apply_edits(path, source, edits) path = ROOT/'PhoneRail-Board1/P3-CONTROL.kicad_sch' source = path.read_text(encoding='utf-8') root = parse(source) edits = [(n.start, n.end, '') for n in children(root, 'text')] notes = [ (15.24, 15.24, 'U20 / ESP32-S3'), (15.24, 21.59, '3V3 / EN RC reset'), (15.24, 118.11, 'J22 / USB debug'), (165.1, 40.64, 'I2C 4.7k / open-drain pullups'), (165.1, 99.06, 'NTC: 10k B3380 / 10k / 100nF'), (12.7, 168.91, 'FAN: EN=GPIO5, PWM=GPIO18 (inverted), TACH_IN=GPIO16, TACH_OUT=GPIO4.'), (12.7, 175.26, 'IO4/IO5 assigned; IO7 spare. Other unconnected pins remain under review.'), (12.7, 181.61, 'IO39-42/47/48 assigned; historical spare/JTAG map is obsolete.'), (12.7, 187.96, 'USB debug requires main 12V. IO0/UART recovery test points are not yet fitted.'), (12.7, 194.31, 'IO35-37 reserved for R8 PSRAM. Strap pins: IO0/3/45/46. See FAN_CIRCUIT.md.'), ] text = '\n'.join(f'(text {quote(t)} (at {x:g} {y:g} 0) (effects (font (size 1.27 1.27)) (justify left bottom)) (uuid "{uid(t)}"))' for x, y, t in notes) edits.append((root.end-1, root.end-1, text+'\n')) apply_edits(path, source, edits) if __name__ == '__main__': main()