#!/usr/bin/env python3
"""PM_K-1 audio chain - Stage 1: balanced LINE input receiver + protection (SKiDL).

Code-defined schematic. Run INSIDE the EDA container:
    cd hardware/eda && ./run.sh python3 ../eda/circuits/stage1_input.py
Outputs ERC results + a KiCad netlist at hardware/kicad/stage1_input.net,
which imports into Pcbnew for layout.

VERIFIED against datasheets:
  * THAT1240 = 0 dB (unity-gain) line receiver; SO-8 pinout per THAT doc 600035
    rev 05: 1=Ref 2=In- 3=In+ 4=Vee 5=Sense 6=Vout 7=Vcc 8=NC. Supply 6-36V
    (our +/-15V is in range). Pin-compatible 2nd sources: INA134 / SSM2141.
  * clamp-diode orientation per KiCad Device:D (pin1=K cathode, pin2=A anode).
Open at BOM time only: exact clamp-diode part (fast low-leakage small-signal;
1N4148WS is a placeholder).
"""
import os
from skidl import *

set_default_tool(KICAD9)

# ---------- passive templates ----------
R = Part("Device", "R", dest=TEMPLATE, footprint="Resistor_SMD:R_0805_2012Metric")
C = Part("Device", "C", dest=TEMPLATE, footprint="Capacitor_SMD:C_0805_2012Metric")
D = Part("Device", "D", dest=TEMPLATE, footprint="Diode_SMD:D_SOD-323")

# ---------- power rails (global nets; marked POWER-driven for ERC) ----------
# No power-flag *symbols* -- they carry no footprint and SKiDL errors on that.
# The rails arrive from the power block; here we just declare + drive them.
p15, n15, gnd = Net("+15V"), Net("-15V"), Net("GND")
for n in (p15, n15, gnd):
    n.drive = POWER

# ---------- THAT1240 balanced line receiver (0 dB) : pinout VERIFIED ----------
RX = Part(name="THAT1240", tool=SKIDL, dest=TEMPLATE, ref_prefix="U",
    footprint="Package_SO:SOIC-8_3.9x4.9mm_P1.27mm",
    pins=[
        Pin(num=1, name="REF",   func=Pin.types.INPUT),
        Pin(num=2, name="IN-",   func=Pin.types.INPUT),
        Pin(num=3, name="IN+",   func=Pin.types.INPUT),
        Pin(num=4, name="V-",    func=Pin.types.PWRIN),
        Pin(num=5, name="SENSE", func=Pin.types.PASSIVE),
        Pin(num=6, name="OUT",   func=Pin.types.OUTPUT),
        Pin(num=7, name="V+",    func=Pin.types.PWRIN),
        Pin(num=8, name="NC",    func=Pin.types.NOCONNECT),
    ])
rx = RX(ref="U1")

# ---------- nets ----------
ain_hot, ain_cold, rxout = Net("AIN_HOT"), Net("AIN_COLD"), Net("RX_OUT")

def protected_input(src, node_name):
    """series DC-block cap (blocks +48V phantom) -> series R -> node;
    bias R to gnd; clamp diodes to the +/-15V rails (orientation TODO-VERIFY)."""
    cblk = C(value="2.2uF", footprint="Capacitor_SMD:C_1206_3216Metric")  # film
    rs, rb = R(value="1k"), R(value="1Meg")
    dp, dn = D(value="1N4148WS"), D(value="1N4148WS")
    node = Net(node_name)
    src += cblk[1]; cblk[2] += rs[1]; rs[2] += node
    rb[1] += node; rb[2] += gnd
    # clamp diodes: KiCad Device:D is pin1=K (cathode), pin2=A (anode).
    dp[1] += p15; dp[2] += node      # high clamp: conducts when node > +15
    dn[1] += node; dn[2] += n15      # low clamp:  conducts when node < -15
    return node

rx["IN+"] += protected_input(ain_hot,  "RXIN_P")
rx["IN-"] += protected_input(ain_cold, "RXIN_N")
rx["REF"] += gnd
rx["SENSE"] += rxout      # sense tied to output (local feedback)
rx["OUT"]   += rxout
rx["V+"] += p15
rx["V-"] += n15

# supply decoupling at the receiver
for rail in (p15, n15):
    c = C(value="100nF")
    rail += c[1]; c[2] += gnd

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