#!/usr/bin/env python3
"""PM_K-1 audio chain - Stage 3: summing node (selected input + click) (SKiDL).

Run INSIDE the EDA container:
    cd hardware/eda && ./run.sh python3 ../eda/circuits/stage3_sum.py
Outputs ERC + a KiCad netlist at hardware/kicad/stage3_sum.net.

WHAT THIS STAGE DOES
  Inverting summing amp (OPA1612 section) mixes STAGE1_OUT (the line/instrument input,
  unity) and CLICK_OUT (the filtered DAC click). Each source enters through its own
  10k resistor into the op-amp's virtual-ground node, so the two never interact. The
  "digital mix" lives upstream: click level is set by the DAC; the input passes at
  unity. Output MIX_OUT -> Stage 4 balanced driver.
    Vout = -(STAGE1_OUT + CLICK_OUT)   (Rf = Ri = 10k)

  POLARITY: an inverting summer flips phase. That is corrected for free at the Stage 4
  balanced driver by assigning hot/cold accordingly (absolute polarity preserved).

  OPA1612 dual: standard JEDEC pinout (1=OUTA 2=-INA 3=+INA 4=V- 5=+INB 6=-INB 7=OUTB
  8=V+). At INTEGRATION this summer can use the PARKED 2nd half of the Stage 2 filter's
  OPA1612 (U4) instead of a separate package -- noted for the merge step.
"""
import os
from skidl import *

set_default_tool(KICAD9)

R = Part("Device", "R", dest=TEMPLATE, footprint="Resistor_SMD:R_0805_2012Metric")
C = Part("Device", "C", dest=TEMPLATE, footprint="Capacitor_SMD:C_0805_2012Metric")

p15, n15, gnd = Net("+15V"), Net("-15V"), Net("GND")
for n in (p15, n15, gnd):
    n.drive = POWER
stage1_out = Net("STAGE1_OUT")   # from Stage 1b relay (selected input)
click_out  = Net("CLICK_OUT")    # from Stage 2 reconstruction filter
mix_out    = Net("MIX_OUT")      # -> Stage 4 balanced driver

OPA2 = Part(name="OPA1612", tool=SKIDL, dest=TEMPLATE, ref_prefix="U",
    footprint="Package_SO:SOIC-8_3.9x4.9mm_P1.27mm",
    pins=[
        Pin(num=1, name="OUTA", func=Pin.types.OUTPUT),
        Pin(num=2, name="-INA", func=Pin.types.INPUT),
        Pin(num=3, name="+INA", func=Pin.types.INPUT),
        Pin(num=4, name="V-",   func=Pin.types.PWRIN),
        Pin(num=5, name="+INB", func=Pin.types.INPUT),
        Pin(num=6, name="-INB", func=Pin.types.INPUT),
        Pin(num=7, name="OUTB", func=Pin.types.OUTPUT),
        Pin(num=8, name="V+",   func=Pin.types.PWRIN),
    ])
u = OPA2(ref="U5")

# inverting summer: each source -> 10k -> virtual-ground (-INA); Rf 10k; +INA -> gnd
ri_in, ri_clk, rf = R(value="10k"), R(value="10k"), R(value="10k")
stage1_out += ri_in[1];  ri_in[2]  += u["-INA"]
click_out  += ri_clk[1]; ri_clk[2] += u["-INA"]
rf[1] += u["-INA"]; rf[2] += u["OUTA"]
u["+INA"] += gnd
u["OUTA"] += mix_out

# supplies + decoupling; park unused section B
u["V+"] += p15; u["V-"] += n15
for rail in (p15, n15):
    c = C(value="100nF"); rail += c[1]; c[2] += gnd
u["+INB"] += gnd; u["OUTB"] += u["-INB"]   # parked follower

ERC()
out = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "kicad", "stage3_sum.net"))
generate_netlist(file_=out)
print("Stage 3 netlist ->", out)
