#!/usr/bin/env python3
"""
Generate a KiCad 9 schematic for a TPS61088 5V-to-12V boost converter.

Reference design for driving a stepper motor (via A4988) at 12V/2A
from a 5V Raspberry Pi power bus.

Layout: clean left-to-right power flow, modeled after TI datasheet Fig 8-1.

Output: tps61088_boost.kicad_sch
"""

import uuid


def uid():
    return str(uuid.uuid4())


# ── Symbol library definitions ──────────────────────────────────────

LIB_TPS61088 = """\
    (symbol "custom:TPS61088"
      (exclude_from_sim no)
      (in_bom yes)
      (on_board yes)
      (property "Reference" "U"
        (at 0 16.51 0)
        (effects (font (size 1.27 1.27)))
      )
      (property "Value" "TPS61088"
        (at 0 13.97 0)
        (effects (font (size 1.27 1.27)))
      )
      (property "Footprint" "Package_DFN_QFN:QFN-20-1EP_3.5x3.5mm_P0.5mm_EP2.1x2.1mm"
        (at 0 -20.32 0)
        (effects (font (size 1.27 1.27)) (hide yes))
      )
      (property "Datasheet" "https://www.ti.com/lit/ds/symlink/tps61088.pdf"
        (at 0 -22.86 0)
        (effects (font (size 1.27 1.27)) (hide yes))
      )
      (property "Description" "10A Fully-Integrated Synchronous Boost Converter"
        (at 0 -25.4 0)
        (effects (font (size 1.27 1.27)) (hide yes))
      )
      (symbol "TPS61088_0_1"
        (rectangle
          (start -10.16 12.7)
          (end 10.16 -12.7)
          (stroke (width 0.254) (type default))
          (fill (type background))
        )
      )
      (symbol "TPS61088_1_1"
        (pin power_in line
          (at -12.7 10.16 0) (length 2.54)
          (name "VIN" (effects (font (size 1.27 1.27))))
          (number "1" (effects (font (size 1.27 1.27))))
        )
        (pin input line
          (at -12.7 5.08 0) (length 2.54)
          (name "EN" (effects (font (size 1.27 1.27))))
          (number "3" (effects (font (size 1.27 1.27))))
        )
        (pin passive line
          (at -12.7 0 0) (length 2.54)
          (name "SS/TR" (effects (font (size 1.27 1.27))))
          (number "4" (effects (font (size 1.27 1.27))))
        )
        (pin passive line
          (at -12.7 -5.08 0) (length 2.54)
          (name "COMP" (effects (font (size 1.27 1.27))))
          (number "5" (effects (font (size 1.27 1.27))))
        )
        (pin input line
          (at -12.7 -10.16 0) (length 2.54)
          (name "FB" (effects (font (size 1.27 1.27))))
          (number "6" (effects (font (size 1.27 1.27))))
        )
        (pin passive line
          (at 12.7 10.16 180) (length 2.54)
          (name "SW" (effects (font (size 1.27 1.27))))
          (number "12" (effects (font (size 1.27 1.27))))
        )
        (pin passive line
          (at 12.7 5.08 180) (length 2.54)
          (name "BST" (effects (font (size 1.27 1.27))))
          (number "11" (effects (font (size 1.27 1.27))))
        )
        (pin power_out line
          (at 12.7 0 180) (length 2.54)
          (name "VOUT" (effects (font (size 1.27 1.27))))
          (number "9" (effects (font (size 1.27 1.27))))
        )
        (pin open_collector line
          (at 12.7 -5.08 180) (length 2.54)
          (name "PGOOD" (effects (font (size 1.27 1.27))))
          (number "8" (effects (font (size 1.27 1.27))))
        )
        (pin power_in line
          (at 0 -15.24 90) (length 2.54)
          (name "PGND" (effects (font (size 1.27 1.27))))
          (number "15" (effects (font (size 1.27 1.27))))
        )
        (pin power_in line
          (at -5.08 -15.24 90) (length 2.54)
          (name "AGND" (effects (font (size 1.27 1.27))))
          (number "7" (effects (font (size 1.27 1.27))))
        )
      )
    )"""

LIB_CAPACITOR = """\
    (symbol "Device:C"
      (exclude_from_sim no)
      (in_bom yes)
      (on_board yes)
      (property "Reference" "C"
        (at 1.27 0 0)
        (effects (font (size 1.27 1.27)) (justify left))
      )
      (property "Value" "C"
        (at 1.27 -2.54 0)
        (effects (font (size 1.27 1.27)) (justify left))
      )
      (property "Footprint" ""
        (at 0 0 0)
        (effects (font (size 1.27 1.27)) (hide yes))
      )
      (property "Datasheet" "~"
        (at 0 0 0)
        (effects (font (size 1.27 1.27)) (hide yes))
      )
      (property "Description" "Unpolarized capacitor"
        (at 0 0 0)
        (effects (font (size 1.27 1.27)) (hide yes))
      )
      (symbol "C_0_1"
        (polyline
          (pts (xy -2.032 -0.762) (xy 2.032 -0.762))
          (stroke (width 0.508) (type default))
          (fill (type none))
        )
        (polyline
          (pts (xy -2.032 0.762) (xy 2.032 0.762))
          (stroke (width 0.508) (type default))
          (fill (type none))
        )
      )
      (symbol "C_1_1"
        (pin passive line
          (at 0 3.81 270) (length 2.794)
          (name "~" (effects (font (size 1.27 1.27))))
          (number "1" (effects (font (size 1.27 1.27))))
        )
        (pin passive line
          (at 0 -3.81 90) (length 2.794)
          (name "~" (effects (font (size 1.27 1.27))))
          (number "2" (effects (font (size 1.27 1.27))))
        )
      )
    )"""

LIB_RESISTOR = """\
    (symbol "Device:R"
      (exclude_from_sim no)
      (in_bom yes)
      (on_board yes)
      (property "Reference" "R"
        (at 2.032 0 90)
        (effects (font (size 1.27 1.27)))
      )
      (property "Value" "R"
        (at 0 0 90)
        (effects (font (size 1.27 1.27)))
      )
      (property "Footprint" ""
        (at 0 0 0)
        (effects (font (size 1.27 1.27)) (hide yes))
      )
      (property "Datasheet" "~"
        (at 0 0 0)
        (effects (font (size 1.27 1.27)) (hide yes))
      )
      (property "Description" "Resistor"
        (at 0 0 0)
        (effects (font (size 1.27 1.27)) (hide yes))
      )
      (symbol "R_0_1"
        (rectangle
          (start -1.016 -2.54)
          (end 1.016 2.54)
          (stroke (width 0.254) (type default))
          (fill (type none))
        )
      )
      (symbol "R_1_1"
        (pin passive line
          (at 0 3.81 270) (length 1.27)
          (name "~" (effects (font (size 1.27 1.27))))
          (number "1" (effects (font (size 1.27 1.27))))
        )
        (pin passive line
          (at 0 -3.81 90) (length 1.27)
          (name "~" (effects (font (size 1.27 1.27))))
          (number "2" (effects (font (size 1.27 1.27))))
        )
      )
    )"""

LIB_INDUCTOR = """\
    (symbol "Device:L"
      (exclude_from_sim no)
      (in_bom yes)
      (on_board yes)
      (property "Reference" "L"
        (at -1.016 0 90)
        (effects (font (size 1.27 1.27)))
      )
      (property "Value" "L"
        (at 1.016 0 90)
        (effects (font (size 1.27 1.27)))
      )
      (property "Footprint" ""
        (at 0 0 0)
        (effects (font (size 1.27 1.27)) (hide yes))
      )
      (property "Datasheet" "~"
        (at 0 0 0)
        (effects (font (size 1.27 1.27)) (hide yes))
      )
      (property "Description" "Inductor"
        (at 0 0 0)
        (effects (font (size 1.27 1.27)) (hide yes))
      )
      (symbol "L_0_1"
        (arc
          (start 0 -2.54) (mid 0.6323 -1.905) (end 0 -1.27)
          (stroke (width 0) (type default))
          (fill (type none))
        )
        (arc
          (start 0 -1.27) (mid 0.6323 -0.635) (end 0 0)
          (stroke (width 0) (type default))
          (fill (type none))
        )
        (arc
          (start 0 0) (mid 0.6323 0.635) (end 0 1.27)
          (stroke (width 0) (type default))
          (fill (type none))
        )
        (arc
          (start 0 1.27) (mid 0.6323 1.905) (end 0 2.54)
          (stroke (width 0) (type default))
          (fill (type none))
        )
      )
      (symbol "L_1_1"
        (pin passive line
          (at 0 3.81 270) (length 1.27)
          (name "~" (effects (font (size 1.27 1.27))))
          (number "1" (effects (font (size 1.27 1.27))))
        )
        (pin passive line
          (at 0 -3.81 90) (length 1.27)
          (name "~" (effects (font (size 1.27 1.27))))
          (number "2" (effects (font (size 1.27 1.27))))
        )
      )
    )"""


def lib_power(name, shape_text):
    return f"""\
    (symbol "power:{name}"
      (power)
      (exclude_from_sim no)
      (in_bom yes)
      (on_board yes)
      (property "Reference" "#PWR"
        (at 0 -3.81 0)
        (effects (font (size 1.27 1.27)) (hide yes))
      )
      (property "Value" "{name}"
        (at 0 3.81 0)
        (effects (font (size 1.27 1.27)))
      )
      (property "Footprint" ""
        (at 0 0 0)
        (effects (font (size 1.27 1.27)) (hide yes))
      )
      (property "Datasheet" ""
        (at 0 0 0)
        (effects (font (size 1.27 1.27)) (hide yes))
      )
      (property "Description" "Power symbol creates a global label with name \\"{name}\\""
        (at 0 0 0)
        (effects (font (size 1.27 1.27)) (hide yes))
      )
{shape_text}
    )"""


POWER_UP_SHAPE = """\
      (symbol "{name}_0_1"
        (polyline
          (pts (xy -0.762 1.27) (xy 0 2.54))
          (stroke (width 0) (type default))
          (fill (type none))
        )
        (polyline
          (pts (xy 0 0) (xy 0 2.54))
          (stroke (width 0) (type default))
          (fill (type none))
        )
        (polyline
          (pts (xy 0 2.54) (xy 0.762 1.27))
          (stroke (width 0) (type default))
          (fill (type none))
        )
      )
      (symbol "{name}_1_1"
        (pin power_in line
          (at 0 0 90) (length 0)
          (name "{name}" (effects (font (size 1.27 1.27))))
          (number "1" (effects (font (size 1.27 1.27))))
        )
      )"""

GND_SHAPE = """\
      (symbol "GND_0_1"
        (polyline
          (pts (xy 0 0) (xy 0 -1.27) (xy 1.27 -1.27) (xy 0 -2.54) (xy -1.27 -1.27) (xy 0 -1.27))
          (stroke (width 0) (type default))
          (fill (type none))
        )
      )
      (symbol "GND_1_1"
        (pin power_in line
          (at 0 0 270) (length 0)
          (name "GND" (effects (font (size 1.27 1.27))))
          (number "1" (effects (font (size 1.27 1.27))))
        )
      )"""

LIB_PLUS5V = lib_power("+5V", POWER_UP_SHAPE.format(name="+5V"))
LIB_PLUS12V = lib_power("+12V", POWER_UP_SHAPE.format(name="+12V"))
LIB_GND = lib_power("GND", GND_SHAPE)

LIB_PWR_FLAG = """\
    (symbol "power:PWR_FLAG"
      (power)
      (exclude_from_sim no)
      (in_bom yes)
      (on_board yes)
      (property "Reference" "#FLG"
        (at 0 1.905 0)
        (effects (font (size 1.27 1.27)) (hide yes))
      )
      (property "Value" "PWR_FLAG"
        (at 0 3.81 0)
        (effects (font (size 1.27 1.27)))
      )
      (property "Footprint" ""
        (at 0 0 0)
        (effects (font (size 1.27 1.27)) (hide yes))
      )
      (property "Datasheet" "~"
        (at 0 0 0)
        (effects (font (size 1.27 1.27)) (hide yes))
      )
      (property "Description" "Special symbol for telling ERC where power comes from"
        (at 0 0 0)
        (effects (font (size 1.27 1.27)) (hide yes))
      )
      (symbol "PWR_FLAG_0_0"
        (pin power_out line
          (at 0 0 90) (length 0)
          (name "pwr" (effects (font (size 1.27 1.27))))
          (number "1" (effects (font (size 1.27 1.27))))
        )
      )
      (symbol "PWR_FLAG_0_1"
        (polyline
          (pts (xy 0 0) (xy 0 1.27) (xy -1.016 1.905) (xy 0 2.54) (xy 1.016 1.905) (xy 0 1.27))
          (stroke (width 0) (type default))
          (fill (type none))
        )
      )
    )"""


# ── Schematic builder ───────────────────────────────────────────────

class Schematic:
    def __init__(self):
        self.root_uuid = uid()
        self.symbols = []
        self.wires = []
        self.junctions = []
        self.labels = []
        self.notes = []
        self.no_connects = []
        self._pwr_idx = 0
        self._flg_idx = 0

    def _next_pwr(self):
        self._pwr_idx += 1
        return f"#PWR{self._pwr_idx:02d}"

    def place(self, lib_id, ref, value, x, y, rot=0, pins=None):
        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'      (pin "{pnum}"\n        (uuid "{pins[pnum]}")\n      )\n'

        self.symbols.append(f"""\
    (symbol
      (lib_id "{lib_id}")
      (at {x} {y} {rot})
      (unit 1)
      (exclude_from_sim no)
      (in_bom yes)
      (on_board yes)
      (dnp no)
      (uuid "{u}")
      (property "Reference" "{ref}"
        (at {x + 2.54} {y - 2.54} 0)
        (effects (font (size 1.27 1.27)) (justify left))
      )
      (property "Value" "{value}"
        (at {x + 2.54} {y + 2.54} 0)
        (effects (font (size 1.27 1.27)) (justify left))
      )
      (property "Footprint" ""
        (at {x} {y} 0)
        (effects (font (size 1.27 1.27)) (hide yes))
      )
      (property "Datasheet" ""
        (at {x} {y} 0)
        (effects (font (size 1.27 1.27)) (hide yes))
      )
      (property "Description" ""
        (at {x} {y} 0)
        (effects (font (size 1.27 1.27)) (hide yes))
      )
{pin_str}\
      (instances
        (project ""
          (path "/{self.root_uuid}"
            (reference "{ref}")
            (unit 1)
          )
        )
      )
    )""")

    def pwr(self, lib_id, value, x, y):
        ref = self._next_pwr()
        u = uid()
        self.symbols.append(f"""\
    (symbol
      (lib_id "{lib_id}")
      (at {x} {y} 0)
      (unit 1)
      (exclude_from_sim no)
      (in_bom yes)
      (on_board yes)
      (dnp no)
      (uuid "{u}")
      (property "Reference" "{ref}"
        (at {x} {y - 2.54} 0)
        (effects (font (size 1.27 1.27)) (hide yes))
      )
      (property "Value" "{value}"
        (at {x} {y + 3.81} 0)
        (effects (font (size 1.27 1.27)))
      )
      (property "Footprint" ""
        (at {x} {y} 0)
        (effects (font (size 1.27 1.27)) (hide yes))
      )
      (property "Datasheet" ""
        (at {x} {y} 0)
        (effects (font (size 1.27 1.27)) (hide yes))
      )
      (property "Description" ""
        (at {x} {y} 0)
        (effects (font (size 1.27 1.27)) (hide yes))
      )
      (pin "1"
        (uuid "{uid()}")
      )
      (instances
        (project ""
          (path "/{self.root_uuid}"
            (reference "{ref}")
            (unit 1)
          )
        )
      )
    )""")

    def pwr_flag(self, x, y):
        self._flg_idx += 1
        ref = f"#FLG{self._flg_idx:02d}"
        u = uid()
        self.symbols.append(f"""\
    (symbol
      (lib_id "power:PWR_FLAG")
      (at {x} {y} 0)
      (unit 1)
      (exclude_from_sim no)
      (in_bom yes)
      (on_board yes)
      (dnp no)
      (uuid "{u}")
      (property "Reference" "{ref}"
        (at {x} {y - 2.54} 0)
        (effects (font (size 1.27 1.27)) (hide yes))
      )
      (property "Value" "PWR_FLAG"
        (at {x} {y + 3.81} 0)
        (effects (font (size 1.27 1.27)))
      )
      (property "Footprint" ""
        (at {x} {y} 0)
        (effects (font (size 1.27 1.27)) (hide yes))
      )
      (property "Datasheet" ""
        (at {x} {y} 0)
        (effects (font (size 1.27 1.27)) (hide yes))
      )
      (property "Description" ""
        (at {x} {y} 0)
        (effects (font (size 1.27 1.27)) (hide yes))
      )
      (pin "1"
        (uuid "{uid()}")
      )
      (instances
        (project ""
          (path "/{self.root_uuid}"
            (reference "{ref}")
            (unit 1)
          )
        )
      )
    )""")

    def wire(self, x1, y1, x2, y2):
        self.wires.append(f"""\
    (wire
      (pts (xy {x1} {y1}) (xy {x2} {y2}))
      (stroke (width 0) (type default))
      (uuid "{uid()}")
    )""")

    def junc(self, x, y):
        self.junctions.append(f"""\
    (junction
      (at {x} {y})
      (diameter 0)
      (color 0 0 0 0)
      (uuid "{uid()}")
    )""")

    def label(self, x, y, name, rot=0):
        self.labels.append(f"""\
    (label "{name}"
      (at {x} {y} {rot})
      (effects (font (size 1.27 1.27)))
      (uuid "{uid()}")
    )""")

    def note(self, x, y, text):
        self.notes.append(f"""\
    (text "{text}"
      (exclude_from_sim no)
      (at {x} {y} 0)
      (effects (font (size 1.27 1.27)) (justify left))
      (uuid "{uid()}")
    )""")

    def no_connect(self, x, y):
        self.no_connects.append(f"""\
    (no_connect
      (at {x} {y})
      (uuid "{uid()}")
    )""")

    def cap_down(self, ref, value, x, rail_y):
        """Place a cap hanging down from a rail. Top pin on rail, GND below.
        Cap pins at ±3.81 from center (matching KiCad Device:C library)."""
        cy = rail_y + 6.35  # cap center (so top pin at cy-3.81 = rail_y+2.54)
        self.place("Device:C", ref, value, x, cy,
                   pins={"1": uid(), "2": uid()})
        self.wire(x, cy - 3.81, x, rail_y)    # top pin to rail
        self.pwr("power:GND", "GND", x, cy + 6.35)
        self.wire(x, cy + 3.81, x, cy + 6.35)  # bottom pin to GND

    def render(self):
        sections = []
        sections.append(f"""\
(kicad_sch
  (version 20250114)
  (generator "python_gen")
  (generator_version "9.0")
  (uuid "{self.root_uuid}")
  (paper "A3")
  (lib_symbols
{LIB_TPS61088}
{LIB_CAPACITOR}
{LIB_RESISTOR}
{LIB_INDUCTOR}
{LIB_PLUS5V}
{LIB_PLUS12V}
{LIB_GND}
{LIB_PWR_FLAG}
  )""")
        for j in self.junctions:
            sections.append(j)
        for nc in self.no_connects:
            sections.append(nc)
        for w in self.wires:
            sections.append(w)
        for lb in self.labels:
            sections.append(lb)
        for n in self.notes:
            sections.append(n)
        for sym in self.symbols:
            sections.append(sym)
        sections.append("""\
  (sheet_instances
    (path "/"
      (page "1")
    )
  )
  (embedded_fonts no)
)""")
        return "\n".join(sections)


# ── Schematic layout ───────────────────────────────────────────────

def generate():
    s = Schematic()

    # ================================================================
    # IC placement — center of schematic
    # ================================================================
    cx, cy = 127.0, 76.2

    # IC pin absolute positions
    VIN  = (cx - 12.7, cy - 10.16)   # (114.3,  66.04)
    EN   = (cx - 12.7, cy - 5.08)    # (114.3,  71.12)
    SS   = (cx - 12.7, cy)           # (114.3,  76.2)
    COMP = (cx - 12.7, cy + 5.08)    # (114.3,  81.28)
    FB   = (cx - 12.7, cy + 10.16)   # (114.3,  86.36)
    SW   = (cx + 12.7, cy - 10.16)   # (139.7,  66.04)
    BST  = (cx + 12.7, cy - 5.08)    # (139.7,  71.12)
    VOUT = (cx + 12.7, cy)           # (139.7,  76.2)
    PG   = (cx + 12.7, cy + 5.08)    # (139.7,  81.28)
    PGND = (cx,        cy + 15.24)   # (127.0,  91.44)
    AGND = (cx - 5.08, cy + 15.24)   # (121.92, 91.44)

    # Place IC
    ic_pins = {str(i): uid() for i in
               [1, 3, 4, 5, 6, 7, 8, 9, 11, 12, 15]}
    s.place("custom:TPS61088", "U1", "TPS61088", cx, cy, pins=ic_pins)

    # ================================================================
    # INPUT SECTION — left side, +5V rail flowing right into VIN
    # ================================================================
    vin_rail_y = VIN[1]  # 66.04 — horizontal rail

    # +5V source (far left)
    pwr5v_x = 86.36
    s.pwr("power:+5V", "+5V", pwr5v_x, vin_rail_y - 5.08)
    s.wire(pwr5v_x, vin_rail_y - 5.08, pwr5v_x, vin_rail_y)

    # PWR_FLAG on +5V net (tells ERC this is externally supplied)
    s.pwr_flag(pwr5v_x + 5.08, vin_rail_y)
    s.wire(pwr5v_x, vin_rail_y, pwr5v_x + 5.08, vin_rail_y)

    # Component X positions (declared before wiring)
    c1_x = 91.44
    c2_x = 99.06
    en_tap_x = 106.68

    # VIN rail: segmented so each T-junction is at a wire endpoint
    s.wire(pwr5v_x, vin_rail_y, c1_x, vin_rail_y)
    s.wire(c1_x, vin_rail_y, c2_x, vin_rail_y)
    s.wire(c2_x, vin_rail_y, en_tap_x, vin_rail_y)
    s.wire(en_tap_x, vin_rail_y, VIN[0], vin_rail_y)

    # Input cap C1 (22µF) — hanging down from rail
    s.cap_down("C1", "22uF", c1_x, vin_rail_y)

    # Input cap C2 (22µF) — second cap, spaced right
    s.cap_down("C2", "22uF", c2_x, vin_rail_y)

    # PWR_FLAG on GND net (on C1's GND connection)
    c1_gnd_y = vin_rail_y + 6.35 + 6.35  # cap center + GND offset
    s.pwr_flag(c1_x + 5.08, c1_gnd_y)
    s.wire(c1_x, c1_gnd_y, c1_x + 5.08, c1_gnd_y)
    s.junc(c1_x, c1_gnd_y)

    # EN tied to VIN rail (always enabled)
    s.wire(EN[0], EN[1], en_tap_x, EN[1])    # EN pin left to tap point
    s.wire(en_tap_x, EN[1], en_tap_x, vin_rail_y)  # tap up to rail

    # ================================================================
    # SOFT-START — C3 hanging below SS pin
    # ================================================================
    ss_wire_x = 106.68
    s.wire(SS[0], SS[1], ss_wire_x, SS[1])  # SS pin left to C3
    c3_y = SS[1] + 6.35  # cap center (top pin at c3_y - 3.81)
    s.place("Device:C", "C3", "22nF", ss_wire_x, c3_y,
            pins={"1": uid(), "2": uid()})
    s.wire(ss_wire_x, SS[1], ss_wire_x, c3_y - 3.81)  # wire to cap top
    s.pwr("power:GND", "GND", ss_wire_x, c3_y + 6.35)
    s.wire(ss_wire_x, c3_y + 3.81, ss_wire_x, c3_y + 6.35)

    # ================================================================
    # COMPENSATION — R1 + C4 series from COMP pin to GND
    # ================================================================
    comp_wire_x = 99.06
    s.wire(COMP[0], COMP[1], comp_wire_x, COMP[1])  # COMP pin left

    # R1 below COMP
    r1_y = COMP[1] + 6.35  # 87.63
    s.place("Device:R", "R1", "30.1k", comp_wire_x, r1_y,
            pins={"1": uid(), "2": uid()})
    s.wire(comp_wire_x, COMP[1], comp_wire_x, r1_y - 3.81)  # to R1 top

    # C4 below R1
    c4_y = r1_y + 10.16  # enough space for R1 bottom pin + gap + C4 top pin
    s.place("Device:C", "C4", "47pF", comp_wire_x, c4_y,
            pins={"1": uid(), "2": uid()})
    s.wire(comp_wire_x, r1_y + 3.81, comp_wire_x, c4_y - 3.81)  # R1 bot to C4 top
    s.pwr("power:GND", "GND", comp_wire_x, c4_y + 6.35)
    s.wire(comp_wire_x, c4_y + 3.81, comp_wire_x, c4_y + 6.35)

    # ================================================================
    # IC GROUND — PGND and AGND tied together
    # ================================================================
    gnd_y = PGND[1] + 5.08  # 96.52
    s.pwr("power:GND", "GND", PGND[0], gnd_y)
    s.wire(PGND[0], PGND[1], PGND[0], gnd_y)
    s.wire(AGND[0], AGND[1], AGND[0], gnd_y)
    s.wire(AGND[0], gnd_y, PGND[0], gnd_y)
    s.junc(PGND[0], gnd_y)

    # ================================================================
    # OUTPUT SECTION — SW → L1 → VOUT rail → +12V
    # ================================================================

    # Inductor L1 (2.2µH, horizontal, between SW and VOUT rail)
    # Rotated 90°: pin1 at (x-3.81, y), pin2 at (x+3.81, y)
    # (90° CCW rotation: original top pin goes left)
    l1_x = 149.86
    l1_y = SW[1]  # 66.04
    l1_pin1 = (l1_x - 3.81, l1_y)  # 146.05 — connects to SW net
    l1_pin2 = (l1_x + 3.81, l1_y)  # 153.67 — connects to VOUT rail
    s.place("Device:L", "L1", "2.2uH 10A", l1_x, l1_y, rot=90,
            pins={"1": uid(), "2": uid()})

    # Bootstrap cap C5 (100nF) — vertical, between SW wire and BST pin
    c5_x = 144.78

    # Wire SW pin → through C5 junction → to L1 pin1 (segmented)
    s.wire(SW[0], SW[1], c5_x, SW[1])
    s.wire(c5_x, SW[1], l1_pin1[0], l1_pin1[1])
    c5_y = SW[1] + 3.81  # center so top pin (c5_y-3.81) lands on SW wire
    s.place("Device:C", "C5", "100nF", c5_x, c5_y,
            pins={"1": uid(), "2": uid()})
    # C5 top pin at (c5_x, SW[1]) sits on SW wire
    s.junc(c5_x, SW[1])
    # C5 bottom pin at (c5_x, c5_y+3.81) — wire to BST pin
    s.wire(c5_x, c5_y + 3.81, BST[0], BST[1])

    # VOUT rail — vertical line on the right
    vout_rail_x = 162.56
    # L1 output → VOUT rail top
    s.wire(l1_pin2[0], l1_pin2[1], vout_rail_x, l1_y)
    # VOUT pin → VOUT rail bottom
    s.wire(VOUT[0], VOUT[1], vout_rail_x, VOUT[1])
    # Connect top to bottom
    s.wire(vout_rail_x, l1_y, vout_rail_x, VOUT[1])

    # Output caps and +12V — segmented output rail
    c6_x = 167.64
    c7_x = 175.26

    # Output rail segments
    s.wire(vout_rail_x, l1_y, c6_x, l1_y)
    s.wire(c6_x, l1_y, c7_x, l1_y)

    # Output cap C6 (22µF)
    s.cap_down("C6", "22uF", c6_x, l1_y)

    # Output cap C7 (22µF)
    s.cap_down("C7", "22uF", c7_x, l1_y)

    # +12V output symbol
    s.pwr("power:+12V", "+12V", c7_x, l1_y - 5.08)
    s.wire(c7_x, l1_y, c7_x, l1_y - 5.08)
    s.junc(c7_x, l1_y)

    # ================================================================
    # FEEDBACK DIVIDER — R2 (190k) / R3 (10k) sets VOUT = 12V
    # Connected to FB pin via label (avoids long crossing wire)
    # ================================================================
    fb_x = vout_rail_x  # 162.56 — hangs off VOUT rail

    # R2 (top resistor, VOUT to FB tap)
    r2_y = VOUT[1] + 6.35  # 82.55
    s.place("Device:R", "R2", "190k", fb_x, r2_y,
            pins={"1": uid(), "2": uid()})
    s.wire(fb_x, VOUT[1], fb_x, r2_y - 3.81)  # VOUT rail down to R2 top
    s.junc(fb_x, VOUT[1])  # T-junction on VOUT vertical rail

    # R3 (bottom resistor, FB tap to GND)
    r3_y = r2_y + 10.16  # 92.71
    s.place("Device:R", "R3", "10k", fb_x, r3_y,
            pins={"1": uid(), "2": uid()})
    s.wire(fb_x, r2_y + 3.81, fb_x, r3_y - 3.81)  # R2 bottom to R3 top

    # FB tap label at divider midpoint
    fb_tap_y = r2_y + 3.81  # 86.36 — R2 bottom pin
    s.wire(fb_x, fb_tap_y, fb_x + 5.08, fb_tap_y)
    s.label(fb_x + 5.08, fb_tap_y, "FB")
    s.junc(fb_x, fb_tap_y)

    # FB label at IC pin (connects by name)
    s.wire(FB[0], FB[1], FB[0] - 5.08, FB[1])
    s.label(FB[0] - 5.08, FB[1], "FB", rot=180)

    # R3 bottom to GND
    s.pwr("power:GND", "GND", fb_x, r3_y + 6.35)
    s.wire(fb_x, r3_y + 3.81, fb_x, r3_y + 6.35)

    # ================================================================
    # PGOOD — no connect (optional, wire if monitoring needed)
    # ================================================================
    s.no_connect(PG[0], PG[1])

    # ================================================================
    # DESIGN NOTES — below the circuit, well separated
    # ================================================================
    nx = 78.74
    ny = 116.84

    s.note(nx, ny,      "TPS61088 Boost Converter Reference Design")
    s.note(nx, ny + 5,  "Input:  +5V from Raspberry Pi 5V bus")
    s.note(nx, ny + 8,  "Output: +12V @ 2A for A4988 stepper driver (VMOT)")
    s.note(nx, ny + 13, "VOUT = 0.6V x (1 + R2/R3) = 0.6 x (1 + 190k/10k) = 12.06V")
    s.note(nx, ny + 18, "Component Selection:")
    s.note(nx, ny + 21, "  L1:  2.2uH, >=10A Isat, low DCR (Coilcraft XAL7030-222ME)")
    s.note(nx, ny + 24, "  C1-C2, C6-C7: 22uF 25V X5R ceramic (input & output)")
    s.note(nx, ny + 27, "  C5:  100nF bootstrap (ceramic)")
    s.note(nx, ny + 30, "  C3:  22nF soft-start (sets startup ramp time)")
    s.note(nx, ny + 33, "  R1, C4: Loop compensation (see TPS61088 datasheet Table 2)")
    s.note(nx, ny + 38, "PCB Layout Notes:")
    s.note(nx, ny + 41, "  - Keep SW node, BST cap, and inductor loop as tight as possible")
    s.note(nx, ny + 44, "  - Place input and output caps directly adjacent to IC pins")
    s.note(nx, ny + 47, "  - Solid ground plane under IC with thermal vias to EP pad")
    s.note(nx, ny + 50, "  - Route FB trace far from SW/inductor (sensitive to noise)")

    return s.render()


if __name__ == "__main__":
    sch = generate()
    outfile = "tps61088_boost.kicad_sch"
    with open(outfile, "w") as f:
        f.write(sch)
    print(f"Generated {outfile}")
    print("Open in KiCad Schematic Editor to review.")
