#!/usr/bin/env python3 """ Transform firstpcb.kicad_sch: 1. Remove the L7805 voltage regulator and associated components 2. Insert the TPS61088 5V→12V boost converter circuit 3. Keep all other components intact The +5V and +12V nets connect automatically via KiCad global power symbols. """ import re import uuid import sys def uid(): return str(uuid.uuid4()) ROOT_UUID = "4ce690e5-6d5b-4693-bd2e-f4090f26df1f" # ── UUIDs of components to REMOVE (L7805 circuit) ── REMOVE_UUIDS = { # L7805 regulator "b5b8c784-5cbd-46af-b962-5f07e5e5ce66", # C1 (0.33uF) - output cap "be10cf51-2c79-49d9-968c-f16a919adeee", # C2 (0.1uF) - input cap "58617ce4-1b01-4ae9-be22-0491e474e52d", # #PWR15 (+5V at L7805 output) "dd887245-ee3f-48b0-ab57-caf2a8bdfdef", # #PWR19 (+5V at C2) "fd8b730d-5d7d-4216-98e6-0f769c039626", # #PWR14 (+12V at L7805 input) "ea5b2f5d-6233-46fc-93b4-4b52ebc256b5", # #PWR17 (+12V at C1) "ec47b49b-69a3-415f-b119-7b90e03df83a", # #PWR16 (GND under L7805) "940ddbc7-3e82-42b5-ad91-3df87e10ff89", # #PWR18 (GND under C1) "565f28b7-cc4b-427c-be9a-9e09337daabd", # #PWR20 (GND under C2) "e7fe0926-923d-41aa-92e6-413304613139", } REMOVE_WIRE_UUIDS = { # Wire: C2 top to L7805 output rail "dba247d2-ddb5-46ff-a6bd-5fb718c4599e", # Wire: L7805 input to +12V symbol "e3772378-2aa5-420d-92e3-94a8234f86b5", # Wire: C1 to +12V symbol "ee45c424-04dc-4913-92e9-0eec7ac6b273", # Wire: L7805 output to +5V symbol "48aefa74-f6f4-40ae-9135-90c2565ceadc", } # Also remove the L7805 lib_symbol definition REMOVE_LIB_SYMBOL = "Regulator_Linear:L7805" def find_block_end(text, start_pos): """Find the end of a parenthesized block starting at start_pos. start_pos should point to the opening '('.""" depth = 0 i = start_pos while i < len(text): if text[i] == '(': depth += 1 elif text[i] == ')': depth -= 1 if depth == 0: return i i += 1 return -1 def remove_blocks_by_uuid(text, uuids): """Remove top-level blocks (symbol, wire, junction) containing matching UUIDs.""" for u in uuids: # Find the UUID in the text pattern = f'(uuid "{u}")' idx = text.find(pattern) if idx == -1: print(f" WARNING: UUID {u} not found, skipping", file=sys.stderr) continue # Walk backward from UUID to find the containing block's opening # Look for a tab-indented opening paren: \n\t(symbol, \n\t(wire, etc. search_start = idx block_start = -1 while search_start > 0: # Find the previous newline nl = text.rfind('\n', 0, search_start) if nl == -1: break line = text[nl+1:search_start] # Check if this line starts a top-level block stripped = line.lstrip() if stripped.startswith('(symbol') or stripped.startswith('(wire') or \ stripped.startswith('(junction') or stripped.startswith('(no_connect'): block_start = nl + 1 # Find the start of the actual paren paren_pos = text.index('(', block_start) block_start = paren_pos break search_start = nl if block_start == -1: print(f" WARNING: Could not find block start for UUID {u}", file=sys.stderr) continue block_end = find_block_end(text, block_start) if block_end == -1: print(f" WARNING: Could not find block end for UUID {u}", file=sys.stderr) continue # Remove the block (including trailing newline) end = block_end + 1 if end < len(text) and text[end] == '\n': end += 1 # Also remove leading whitespace/tabs on the same line while block_start > 0 and text[block_start-1] in '\t ': block_start -= 1 print(f" Removing block with UUID {u[:12]}... ({end - block_start} chars)") text = text[:block_start] + text[end:] return text def remove_lib_symbol(text, lib_id): """Remove a lib_symbol definition from the lib_symbols section.""" pattern = f'(symbol "{lib_id}"' idx = text.find(pattern) if idx == -1: print(f" WARNING: lib_symbol {lib_id} not found", file=sys.stderr) return text # Find the containing (symbol block - walk back to find the right indentation # In lib_symbols, entries are indented with two tabs search = idx while search > 0 and text[search-1] != '\n': search -= 1 block_start = search block_paren = text.index('(', block_start) block_end = find_block_end(text, block_paren) end = block_end + 1 if end < len(text) and text[end] == '\n': end += 1 print(f" Removing lib_symbol {lib_id}") text = text[:block_start] + text[end:] return text # ── TPS61088 boost converter circuit to INSERT ── def gen_symbol(lib_id, ref, value, x, y, rot=0, pins=None, extra_props=""): """Generate a symbol placement block.""" u = uid() if pins is None: pins = {} pin_str = "" for pnum in sorted(pins.keys(), key=lambda k: int(k) if k.isdigit() else k): pin_str += f'\t\t(pin "{pnum}"\n\t\t\t(uuid "{pins[pnum]}")\n\t\t)\n' return f"""\t(symbol \t\t(lib_id "{lib_id}") \t\t(at {round(x, 2)} {round(y, 2)} {rot}) \t\t(unit 1) \t\t(exclude_from_sim no) \t\t(in_bom yes) \t\t(on_board yes) \t\t(dnp no) \t\t(uuid "{u}") \t\t(property "Reference" "{ref}" \t\t\t(at {round(x + 2.54, 2)} {round(y - 2.54, 2)} 0) \t\t\t(effects \t\t\t\t(font \t\t\t\t\t(size 1.27 1.27) \t\t\t\t) \t\t\t\t(justify left) \t\t\t) \t\t) \t\t(property "Value" "{value}" \t\t\t(at {round(x + 2.54, 2)} {round(y + 2.54, 2)} 0) \t\t\t(effects \t\t\t\t(font \t\t\t\t\t(size 1.27 1.27) \t\t\t\t) \t\t\t\t(justify left) \t\t\t) \t\t) \t\t(property "Footprint" "" \t\t\t(at {round(x, 2)} {round(y, 2)} 0) \t\t\t(effects \t\t\t\t(font \t\t\t\t\t(size 1.27 1.27) \t\t\t\t) \t\t\t\t(hide yes) \t\t\t) \t\t) \t\t(property "Datasheet" "" \t\t\t(at {round(x, 2)} {round(y, 2)} 0) \t\t\t(effects \t\t\t\t(font \t\t\t\t\t(size 1.27 1.27) \t\t\t\t) \t\t\t\t(hide yes) \t\t\t) \t\t) \t\t(property "Description" "" \t\t\t(at {round(x, 2)} {round(y, 2)} 0) \t\t\t(effects \t\t\t\t(font \t\t\t\t\t(size 1.27 1.27) \t\t\t\t) \t\t\t\t(hide yes) \t\t\t) \t\t){extra_props} {pin_str}\t\t(instances \t\t\t(project "" \t\t\t\t(path "/{ROOT_UUID}" \t\t\t\t\t(reference "{ref}") \t\t\t\t\t(unit 1) \t\t\t\t) \t\t\t) \t\t) \t)""" def gen_pwr(lib_id, value, x, y, ref): """Generate a power symbol block.""" return f"""\t(symbol \t\t(lib_id "{lib_id}") \t\t(at {round(x, 2)} {round(y, 2)} 0) \t\t(unit 1) \t\t(exclude_from_sim no) \t\t(in_bom yes) \t\t(on_board yes) \t\t(dnp no) \t\t(uuid "{uid()}") \t\t(property "Reference" "{ref}" \t\t\t(at {round(x, 2)} {round(y - 2.54, 2)} 0) \t\t\t(effects \t\t\t\t(font \t\t\t\t\t(size 1.27 1.27) \t\t\t\t) \t\t\t\t(hide yes) \t\t\t) \t\t) \t\t(property "Value" "{value}" \t\t\t(at {round(x, 2)} {round(y + 3.81, 2)} 0) \t\t\t(effects \t\t\t\t(font \t\t\t\t\t(size 1.27 1.27) \t\t\t\t) \t\t\t) \t\t) \t\t(property "Footprint" "" \t\t\t(at {round(x, 2)} {round(y, 2)} 0) \t\t\t(effects \t\t\t\t(font \t\t\t\t\t(size 1.27 1.27) \t\t\t\t) \t\t\t\t(hide yes) \t\t\t) \t\t) \t\t(property "Datasheet" "" \t\t\t(at {round(x, 2)} {round(y, 2)} 0) \t\t\t(effects \t\t\t\t(font \t\t\t\t\t(size 1.27 1.27) \t\t\t\t) \t\t\t\t(hide yes) \t\t\t) \t\t) \t\t(property "Description" "" \t\t\t(at {round(x, 2)} {round(y, 2)} 0) \t\t\t(effects \t\t\t\t(font \t\t\t\t\t(size 1.27 1.27) \t\t\t\t) \t\t\t\t(hide yes) \t\t\t) \t\t) \t\t(pin "1" \t\t\t(uuid "{uid()}") \t\t) \t\t(instances \t\t\t(project "" \t\t\t\t(path "/{ROOT_UUID}" \t\t\t\t\t(reference "{ref}") \t\t\t\t\t(unit 1) \t\t\t\t) \t\t\t) \t\t) \t)""" def gen_wire(x1, y1, x2, y2): return f"""\t(wire \t\t(pts \t\t\t(xy {round(x1, 2)} {round(y1, 2)}) (xy {round(x2, 2)} {round(y2, 2)}) \t\t) \t\t(stroke \t\t\t(width 0) \t\t\t(type default) \t\t) \t\t(uuid "{uid()}") \t)""" def gen_junction(x, y): return f"""\t(junction \t\t(at {round(x, 2)} {round(y, 2)}) \t\t(diameter 0) \t\t(color 0 0 0 0) \t\t(uuid "{uid()}") \t)""" def gen_label(x, y, name, rot=0): return f"""\t(label "{name}" \t\t(at {round(x, 2)} {round(y, 2)} {rot}) \t\t(effects \t\t\t(font \t\t\t\t(size 1.27 1.27) \t\t\t) \t\t) \t\t(uuid "{uid()}") \t)""" def gen_no_connect(x, y): return f"""\t(no_connect \t\t(at {round(x, 2)} {round(y, 2)}) \t\t(uuid "{uid()}") \t)""" def gen_text(x, y, text): return f"""\t(text "{text}" \t\t(exclude_from_sim no) \t\t(at {round(x, 2)} {round(y, 2)} 0) \t\t(effects \t\t\t(font \t\t\t\t(size 1.27 1.27) \t\t\t) \t\t\t(justify left) \t\t) \t\t(uuid "{uid()}") \t)""" # ── TPS61088 lib_symbol definition ── TPS61088_LIB_SYMBOL = """\t\t(symbol "TPS61088:TPS61088" \t\t\t(exclude_from_sim no) \t\t\t(in_bom yes) \t\t\t(on_board yes) \t\t\t(property "Reference" "U" \t\t\t\t(at 0 16.51 0) \t\t\t\t(effects (font (size 1.27 1.27))) \t\t\t) \t\t\t(property "Value" "TPS61088" \t\t\t\t(at 0 13.97 0) \t\t\t\t(effects (font (size 1.27 1.27))) \t\t\t) \t\t\t(property "Footprint" "Package_DFN_QFN:QFN-20-1EP_3.5x3.5mm_P0.5mm_EP2.1x2.1mm" \t\t\t\t(at 0 -20.32 0) \t\t\t\t(effects (font (size 1.27 1.27)) (hide yes)) \t\t\t) \t\t\t(property "Datasheet" "https://www.ti.com/lit/ds/symlink/tps61088.pdf" \t\t\t\t(at 0 -22.86 0) \t\t\t\t(effects (font (size 1.27 1.27)) (hide yes)) \t\t\t) \t\t\t(property "Description" "10A Fully-Integrated Synchronous Boost Converter" \t\t\t\t(at 0 -25.4 0) \t\t\t\t(effects (font (size 1.27 1.27)) (hide yes)) \t\t\t) \t\t\t(symbol "TPS61088_0_1" \t\t\t\t(rectangle \t\t\t\t\t(start -10.16 12.7) \t\t\t\t\t(end 10.16 -12.7) \t\t\t\t\t(stroke (width 0.254) (type default)) \t\t\t\t\t(fill (type background)) \t\t\t\t) \t\t\t) \t\t\t(symbol "TPS61088_1_1" \t\t\t\t(pin power_in line \t\t\t\t\t(at -12.7 10.16 0) (length 2.54) \t\t\t\t\t(name "VIN" (effects (font (size 1.27 1.27)))) \t\t\t\t\t(number "1" (effects (font (size 1.27 1.27)))) \t\t\t\t) \t\t\t\t(pin input line \t\t\t\t\t(at -12.7 5.08 0) (length 2.54) \t\t\t\t\t(name "EN" (effects (font (size 1.27 1.27)))) \t\t\t\t\t(number "3" (effects (font (size 1.27 1.27)))) \t\t\t\t) \t\t\t\t(pin passive line \t\t\t\t\t(at -12.7 0 0) (length 2.54) \t\t\t\t\t(name "SS/TR" (effects (font (size 1.27 1.27)))) \t\t\t\t\t(number "4" (effects (font (size 1.27 1.27)))) \t\t\t\t) \t\t\t\t(pin passive line \t\t\t\t\t(at -12.7 -5.08 0) (length 2.54) \t\t\t\t\t(name "COMP" (effects (font (size 1.27 1.27)))) \t\t\t\t\t(number "5" (effects (font (size 1.27 1.27)))) \t\t\t\t) \t\t\t\t(pin input line \t\t\t\t\t(at -12.7 -10.16 0) (length 2.54) \t\t\t\t\t(name "FB" (effects (font (size 1.27 1.27)))) \t\t\t\t\t(number "6" (effects (font (size 1.27 1.27)))) \t\t\t\t) \t\t\t\t(pin passive line \t\t\t\t\t(at 12.7 10.16 180) (length 2.54) \t\t\t\t\t(name "SW" (effects (font (size 1.27 1.27)))) \t\t\t\t\t(number "12" (effects (font (size 1.27 1.27)))) \t\t\t\t) \t\t\t\t(pin passive line \t\t\t\t\t(at 12.7 5.08 180) (length 2.54) \t\t\t\t\t(name "BST" (effects (font (size 1.27 1.27)))) \t\t\t\t\t(number "11" (effects (font (size 1.27 1.27)))) \t\t\t\t) \t\t\t\t(pin power_out line \t\t\t\t\t(at 12.7 0 180) (length 2.54) \t\t\t\t\t(name "VOUT" (effects (font (size 1.27 1.27)))) \t\t\t\t\t(number "9" (effects (font (size 1.27 1.27)))) \t\t\t\t) \t\t\t\t(pin open_collector line \t\t\t\t\t(at 12.7 -5.08 180) (length 2.54) \t\t\t\t\t(name "PGOOD" (effects (font (size 1.27 1.27)))) \t\t\t\t\t(number "8" (effects (font (size 1.27 1.27)))) \t\t\t\t) \t\t\t\t(pin power_in line \t\t\t\t\t(at 0 -15.24 90) (length 2.54) \t\t\t\t\t(name "PGND" (effects (font (size 1.27 1.27)))) \t\t\t\t\t(number "15" (effects (font (size 1.27 1.27)))) \t\t\t\t) \t\t\t\t(pin power_in line \t\t\t\t\t(at -5.08 -15.24 90) (length 2.54) \t\t\t\t\t(name "AGND" (effects (font (size 1.27 1.27)))) \t\t\t\t\t(number "7" (effects (font (size 1.27 1.27)))) \t\t\t\t) \t\t\t) \t\t\t(embedded_fonts no) \t\t)""" def generate_boost_circuit(): """Generate all the schematic elements for the TPS61088 boost converter. Returns (junctions, wires, labels, no_connects, texts, symbols) as lists of strings. Placed below the main circuit, centered around (80, 140). """ junctions = [] wires = [] labels = [] no_connects = [] texts = [] symbols = [] pwr_idx = [30] # start well after existing power refs (existing go up to #PWR23) def next_pwr(): pwr_idx[0] += 1 return f"#PWR{pwr_idx[0]:02d}" # IC center cx, cy = 80.01, 140.97 # Pin absolute positions VIN = (cx - 12.7, cy - 10.16) EN = (cx - 12.7, cy - 5.08) SS = (cx - 12.7, cy) COMP = (cx - 12.7, cy + 5.08) FB = (cx - 12.7, cy + 10.16) SW = (cx + 12.7, cy - 10.16) BST = (cx + 12.7, cy - 5.08) VOUT = (cx + 12.7, cy) PG = (cx + 12.7, cy + 5.08) PGND = (cx, cy + 15.24) AGND = (cx - 5.08, cy + 15.24) # Place TPS61088 IC ic_pins = {str(i): uid() for i in [1, 3, 4, 5, 6, 7, 8, 9, 11, 12, 15]} symbols.append(gen_symbol("TPS61088:TPS61088", "U1", "TPS61088", cx, cy, pins=ic_pins)) # ── INPUT SECTION ── vin_rail_y = VIN[1] pwr5v_x = 39.37 c1_x = 44.45 c2_x = 52.07 en_tap_x = 59.69 # +5V source ref = next_pwr() symbols.append(gen_pwr("power:+5V", "+5V", pwr5v_x, vin_rail_y - 5.08, ref)) wires.append(gen_wire(pwr5v_x, vin_rail_y - 5.08, pwr5v_x, vin_rail_y)) # VIN rail (segmented) wires.append(gen_wire(pwr5v_x, vin_rail_y, c1_x, vin_rail_y)) wires.append(gen_wire(c1_x, vin_rail_y, c2_x, vin_rail_y)) wires.append(gen_wire(c2_x, vin_rail_y, en_tap_x, vin_rail_y)) wires.append(gen_wire(en_tap_x, vin_rail_y, VIN[0], vin_rail_y)) # C1 input cap (22µF) — using Device:C (pins at ±3.81) c1_cy = vin_rail_y + 6.35 symbols.append(gen_symbol("Device:C", "C4", "22uF", c1_x, c1_cy, pins={"1": uid(), "2": uid()})) wires.append(gen_wire(c1_x, c1_cy - 3.81, c1_x, vin_rail_y)) ref = next_pwr() symbols.append(gen_pwr("power:GND", "GND", c1_x, c1_cy + 6.35, ref)) wires.append(gen_wire(c1_x, c1_cy + 3.81, c1_x, c1_cy + 6.35)) # C2 input cap (22µF) c2_cy = vin_rail_y + 6.35 symbols.append(gen_symbol("Device:C", "C5", "22uF", c2_x, c2_cy, pins={"1": uid(), "2": uid()})) wires.append(gen_wire(c2_x, c2_cy - 3.81, c2_x, vin_rail_y)) ref = next_pwr() symbols.append(gen_pwr("power:GND", "GND", c2_x, c2_cy + 6.35, ref)) wires.append(gen_wire(c2_x, c2_cy + 3.81, c2_x, c2_cy + 6.35)) # EN tied to VIN wires.append(gen_wire(EN[0], EN[1], en_tap_x, EN[1])) wires.append(gen_wire(en_tap_x, EN[1], en_tap_x, vin_rail_y)) # ── SOFT-START ── ss_x = 59.69 c3_cy = SS[1] + 6.35 wires.append(gen_wire(SS[0], SS[1], ss_x, SS[1])) symbols.append(gen_symbol("Device:C", "C6", "22nF", ss_x, c3_cy, pins={"1": uid(), "2": uid()})) wires.append(gen_wire(ss_x, SS[1], ss_x, c3_cy - 3.81)) ref = next_pwr() symbols.append(gen_pwr("power:GND", "GND", ss_x, c3_cy + 6.35, ref)) wires.append(gen_wire(ss_x, c3_cy + 3.81, ss_x, c3_cy + 6.35)) # ── COMPENSATION ── comp_x = 52.07 r1_y = COMP[1] + 6.35 wires.append(gen_wire(COMP[0], COMP[1], comp_x, COMP[1])) symbols.append(gen_symbol("Device:R", "R3", "30.1k", comp_x, r1_y, # COMP resistor pins={"1": uid(), "2": uid()})) wires.append(gen_wire(comp_x, COMP[1], comp_x, r1_y - 3.81)) c4_y = r1_y + 10.16 symbols.append(gen_symbol("Device:C", "C8", "47pF", comp_x, c4_y, pins={"1": uid(), "2": uid()})) wires.append(gen_wire(comp_x, r1_y + 3.81, comp_x, c4_y - 3.81)) ref = next_pwr() symbols.append(gen_pwr("power:GND", "GND", comp_x, c4_y + 6.35, ref)) wires.append(gen_wire(comp_x, c4_y + 3.81, comp_x, c4_y + 6.35)) # ── IC GROUND ── gnd_y = PGND[1] + 5.08 ref = next_pwr() symbols.append(gen_pwr("power:GND", "GND", PGND[0], gnd_y, ref)) wires.append(gen_wire(PGND[0], PGND[1], PGND[0], gnd_y)) wires.append(gen_wire(AGND[0], AGND[1], AGND[0], gnd_y)) wires.append(gen_wire(AGND[0], gnd_y, PGND[0], gnd_y)) junctions.append(gen_junction(PGND[0], gnd_y)) # ── OUTPUT SECTION ── c5_x = 97.79 l1_x = 102.87 l1_y = SW[1] l1_pin1 = (l1_x - 3.81, l1_y) l1_pin2 = (l1_x + 3.81, l1_y) symbols.append(gen_symbol("Device:L", "L1", "2.2uH", l1_x, l1_y, rot=90, pins={"1": uid(), "2": uid()})) # SW → C5 junction → L1 wires.append(gen_wire(SW[0], SW[1], c5_x, SW[1])) wires.append(gen_wire(c5_x, SW[1], l1_pin1[0], l1_pin1[1])) # Bootstrap cap C5 (100nF) c5_cy = SW[1] + 3.81 symbols.append(gen_symbol("Device:C", "C9", "100nF", c5_x, c5_cy, pins={"1": uid(), "2": uid()})) junctions.append(gen_junction(c5_x, SW[1])) wires.append(gen_wire(c5_x, c5_cy + 3.81, BST[0], BST[1])) # VOUT rail vout_rail_x = 115.57 wires.append(gen_wire(l1_pin2[0], l1_pin2[1], vout_rail_x, l1_y)) wires.append(gen_wire(VOUT[0], VOUT[1], vout_rail_x, VOUT[1])) wires.append(gen_wire(vout_rail_x, l1_y, vout_rail_x, VOUT[1])) # Output caps c6_x = 120.65 c7_x = 128.27 wires.append(gen_wire(vout_rail_x, l1_y, c6_x, l1_y)) wires.append(gen_wire(c6_x, l1_y, c7_x, l1_y)) c6_cy = l1_y + 6.35 symbols.append(gen_symbol("Device:C", "C10", "22uF", c6_x, c6_cy, pins={"1": uid(), "2": uid()})) wires.append(gen_wire(c6_x, c6_cy - 3.81, c6_x, l1_y)) ref = next_pwr() symbols.append(gen_pwr("power:GND", "GND", c6_x, c6_cy + 6.35, ref)) wires.append(gen_wire(c6_x, c6_cy + 3.81, c6_x, c6_cy + 6.35)) c7_cy = l1_y + 6.35 symbols.append(gen_symbol("Device:C", "C11", "22uF", c7_x, c7_cy, pins={"1": uid(), "2": uid()})) wires.append(gen_wire(c7_x, c7_cy - 3.81, c7_x, l1_y)) ref = next_pwr() symbols.append(gen_pwr("power:GND", "GND", c7_x, c7_cy + 6.35, ref)) wires.append(gen_wire(c7_x, c7_cy + 3.81, c7_x, c7_cy + 6.35)) # +12V output ref = next_pwr() symbols.append(gen_pwr("power:+12V", "+12V", c7_x, l1_y - 5.08, ref)) wires.append(gen_wire(c7_x, l1_y, c7_x, l1_y - 5.08)) junctions.append(gen_junction(c7_x, l1_y)) # ── FEEDBACK DIVIDER ── fb_x = vout_rail_x r2_y = VOUT[1] + 6.35 symbols.append(gen_symbol("Device:R", "R4", "190k", fb_x, r2_y, pins={"1": uid(), "2": uid()})) wires.append(gen_wire(fb_x, VOUT[1], fb_x, r2_y - 3.81)) junctions.append(gen_junction(fb_x, VOUT[1])) r3_y = r2_y + 10.16 symbols.append(gen_symbol("Device:R", "R5", "10k", fb_x, r3_y, pins={"1": uid(), "2": uid()})) wires.append(gen_wire(fb_x, r2_y + 3.81, fb_x, r3_y - 3.81)) # FB tap label fb_tap_y = r2_y + 3.81 wires.append(gen_wire(fb_x, fb_tap_y, fb_x + 5.08, fb_tap_y)) labels.append(gen_label(fb_x + 5.08, fb_tap_y, "FB")) junctions.append(gen_junction(fb_x, fb_tap_y)) # FB label at IC wires.append(gen_wire(FB[0], FB[1], FB[0] - 5.08, FB[1])) labels.append(gen_label(FB[0] - 5.08, FB[1], "FB", rot=180)) # R3 to GND ref = next_pwr() symbols.append(gen_pwr("power:GND", "GND", fb_x, r3_y + 6.35, ref)) wires.append(gen_wire(fb_x, r3_y + 3.81, fb_x, r3_y + 6.35)) # PGOOD no connect no_connects.append(gen_no_connect(PG[0], PG[1])) # ── NOTES ── nx = 39.37 ny = 177.8 texts.append(gen_text(nx, ny, "TPS61088 Boost: 5V to 12V @ 2A")) texts.append(gen_text(nx, ny + 3.81, "VOUT = 0.6V x (1 + 190k/10k) = 12.06V")) return junctions, wires, labels, no_connects, texts, symbols def main(): infile = "firstpcb.kicad_sch" outfile = "firstpcb.kicad_sch" print(f"Reading {infile}...") with open(infile, "r") as f: text = f.read() # Step 1: Remove L7805 lib_symbol print("\nRemoving L7805 lib_symbol...") text = remove_lib_symbol(text, REMOVE_LIB_SYMBOL) # Step 2: Remove wires first (they reference removed components) print("\nRemoving L7805 circuit wires...") text = remove_blocks_by_uuid(text, REMOVE_WIRE_UUIDS) # Step 3: Remove components and power symbols print("\nRemoving L7805 circuit components...") text = remove_blocks_by_uuid(text, REMOVE_UUIDS) # Step 4: Add TPS61088 lib_symbol to lib_symbols section print("\nAdding TPS61088 lib_symbol...") # Find end of lib_symbols section (look for the closing paren before first junction/wire/label/symbol) # The lib_symbols section ends with a line like "\t)" # Find the pattern: a tab + ) that comes after all symbol definitions lib_end_marker = "\n\t)\n" # Find the FIRST occurrence of this pattern after "(lib_symbols" lib_start = text.find("(lib_symbols") if lib_start == -1: print("ERROR: Could not find lib_symbols section", file=sys.stderr) sys.exit(1) # Find the end of lib_symbols by tracking paren depth lib_paren = text.index("(", lib_start) lib_end = find_block_end(text, lib_paren) # Insert before the closing paren insert_pos = lib_end # Read Device:L lib_symbol from KiCad library (not embedded in this schematic) device_l_sym = "" kicad_sym_paths = [ "/nix/store/pbwczj1nsp823njj1kkw75a99jmkz958-kicad-symbols-884133df0a/share/kicad/symbols/Device.kicad_sym", "/nix/store/6yiq36yhskjhga4mw63ypbw2wcb4f4m9-kicad-symbols-884133df0a/share/kicad/symbols/Device.kicad_sym", ] for path in kicad_sym_paths: try: with open(path) as lf: ltext = lf.read() ls = ltext.find('\n\t(symbol "L"') if ls != -1: ls += 1 li = ls while ltext[li] != '(': li += 1 ldepth = 0 lpos = li while lpos < len(ltext): if ltext[lpos] == '(': ldepth += 1 elif ltext[lpos] == ')': ldepth -= 1 if ldepth == 0: device_l_sym = ltext[ls:lpos+1] device_l_sym = device_l_sym.replace('(symbol "L"', '(symbol "Device:L"', 1) # Add extra tab for nesting inside lib_symbols device_l_sym = '\n'.join('\t' + line for line in device_l_sym.split('\n')) print(f" Loaded Device:L from {path}") break lpos += 1 if device_l_sym: break except FileNotFoundError: continue text = text[:insert_pos] + "\n" + TPS61088_LIB_SYMBOL + "\n" + device_l_sym + "\n\t" + text[insert_pos:] # Step 5: Generate and insert boost converter circuit print("\nGenerating TPS61088 boost converter circuit...") juncs, wires, lbls, ncs, txts, syms = generate_boost_circuit() # Insert before (sheet_instances sheet_marker = "\t(sheet_instances" sheet_pos = text.find(sheet_marker) if sheet_pos == -1: print("ERROR: Could not find sheet_instances", file=sys.stderr) sys.exit(1) insert_blocks = [] insert_blocks.extend(juncs) insert_blocks.extend(ncs) insert_blocks.extend(wires) insert_blocks.extend(lbls) insert_blocks.extend(txts) insert_blocks.extend(syms) insert_text = "\n".join(insert_blocks) + "\n" text = text[:sheet_pos] + insert_text + text[sheet_pos:] # Step 6: Write output print(f"\nWriting {outfile}...") with open(outfile, "w") as f: f.write(text) print("Done! Open in KiCad to review.") if __name__ == "__main__": main()