#!/usr/bin/env python3
"""PM_K-1 SIG/CLIP indicator (SKiDL): peak-detect + LM393 -> SIG_LED / CLIP_LED.

Run INSIDE the EDA container:
    cd hardware/eda && ./run.sh python3 ../eda/circuits/indicator.py
Outputs ERC + hardware/kicad/indicator.net.

Signal-present detect taps STAGE1_OUT; clip detect taps MIX_OUT (pre-driver). Each is
peak-rectified (Schottky + hold cap + bleed R) into an LM393 comparator vs a threshold
divider. Outputs are open-collector, pulled to +3V3, so they drive the face LED line AND
read cleanly on an RP2350 GPIO (SIG_LED=GPIO19, CLIP_LED=GPIO20 in the core).

LM393 powered from +15V (handles the audio common-mode range); open-collector pulled to
+3V3 keeps the logic level RP2350-safe. Threshold-divider values are TUNABLE (set the
signal-present and clip points at bring-up). DNP/optional -- a face fits the LEDs.
LM393 pinout standard: 1=OUT1 2=-IN1 3=+IN1 4=V- 5=+IN2 6=-IN2 7=OUT2 8=V+.
"""
import os
from skidl import *
set_default_tool(KICAD9)
P = Pin.types
R = Part("Device","R", dest=TEMPLATE, footprint="Resistor_SMD:R_0402_1005Metric")
def C(v): return Part("Device","C", value=v, footprint="Capacitor_SMD:C_0402_1005Metric")
DS = Part("Device","D_Schottky", dest=TEMPLATE, footprint="Diode_SMD:D_SOD-323")

p15, p3v3, gnd = Net("+15V"), Net("+3V3"), Net("GND")
for n in (p15, p3v3): n.drive = POWER
gnd.drive = POWER
stage1_out, mix_out = Net("STAGE1_OUT"), Net("MIX_OUT")     # taps (shared by name)
sig_led, clip_led = Net("SIG_LED"), Net("CLIP_LED")          # open-collector -> GPIO + face LED

LM393 = Part(name="LM393", tool=SKIDL, dest=TEMPLATE, ref_prefix="U",
    footprint="Package_SO:SOIC-8_3.9x4.9mm_P1.27mm",
    pins=[Pin(num=1,name="OUT1",func=P.OPENCOLL),Pin(num=2,name="-IN1",func=P.INPUT),Pin(num=3,name="+IN1",func=P.INPUT),
          Pin(num=4,name="V-",func=P.PWRIN),Pin(num=5,name="+IN2",func=P.INPUT),Pin(num=6,name="-IN2",func=P.INPUT),
          Pin(num=7,name="OUT2",func=P.OPENCOLL),Pin(num=8,name="V+",func=P.PWRIN)])
u = LM393(ref="U11")
u["V+"] += p15; u["V-"] += gnd
cdec = C("100nF"); p15 += cdec[1]; cdec[2] += gnd

def peak_detect(src):
    d = DS(value="BAT54"); ch = C("100nF"); rb = R(value="100k")
    node = Net()
    src += d[2]; d[1] += node          # Schottky pin1=K,2=A: anode at src, cathode->node (rectify +peaks)
    ch[1] += node; ch[2] += gnd; rb[1] += node; rb[2] += gnd
    return node

def threshold(div_top, div_bot):
    n = Net(); rt = R(value=div_top); rb = R(value=div_bot)
    rt[1] += p15; rt[2] += n; rb[1] += n; rb[2] += gnd   # rt[1]+=p15 (not p15+=...) to avoid local rebind
    return n

# signal-present: low threshold ; clip: high threshold (TUNABLE)
u["+IN1"] += peak_detect(stage1_out); u["-IN1"] += threshold("1Meg","10k")    # ~0.15V trip
u["+IN2"] += peak_detect(mix_out);    u["-IN2"] += threshold("100k","68k")    # higher (clip)
rs = R(value="10k"); u["OUT1"] += sig_led; sig_led += rs[1]; rs[2] += p3v3    # open-coll pull-ups to 3V3
rc = R(value="10k"); u["OUT2"] += clip_led; clip_led += rc[1]; rc[2] += p3v3

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