#!/usr/bin/env python3
"""Testet die Live-IQ-Verarbeitungskette (cw_live.grc) headless gegen eine
echte KiwiSDR-Aufnahme. Anders als test_chain.py gibt es hier keinen
bekannten Klartext als Ground Truth - das Skript dient der Verifikation der
Front-End-Architektur (Stereo-WAV -> Float-to-Complex -> Freq-Xlating-CCF)
und der Dokumentation des tatsaechlichen Decodier-Ergebnisses, nicht einem
Pass/Fail-Test."""
import sys
import numpy as np
from gnuradio import gr, blocks, filter as grfilter
from gnuradio.filter import firdes
from gnuradio.fft import window
import pmt

sys.path.insert(0, '.')
from epy_noise_floor import blk as NoiseFloorBlk
from epy_element_tagger import blk as TaggerBlk
from epy_decoder import blk as DecoderBlk
from epy_afc import blk as AfcBlk

WAV = "SND.kiwisdr.dynpc.net_2026-08-05T07_34_42Z_7033.98_iq.wav"


class TextSink(gr.basic_block):
    def __init__(self):
        gr.basic_block.__init__(self, name="TextSink", in_sig=None, out_sig=None)
        self.message_port_register_in(pmt.intern("in"))
        self.set_msg_handler(pmt.intern("in"), self.handle)
        self.last = ""

    def handle(self, msg):
        self.last = pmt.to_python(msg)


def run(pitch, wpm, samp_rate=12000, decim=12, acq_margin=80.0, verbose=True):
    tb = gr.top_block()
    src = blocks.wavfile_source(WAV, False)
    f2c = blocks.float_to_complex(1)

    bw = max(4.0 * wpm, 100.0) + acq_margin
    working_rate = samp_rate / decim
    xlate = grfilter.freq_xlating_fir_filter_ccf(
        decim, firdes.low_pass(1.0, samp_rate, bw / 2, bw / 2, window.WIN_HAMMING),
        pitch, samp_rate)

    c2mag = blocks.complex_to_mag(1)
    noise_floor = NoiseFloorBlk(samp_rate=working_rate, ref_wpm=30.0, num_bins=20)
    thresh = blocks.threshold_ff(3.0, 6.0, 0)
    tagger = TaggerBlk(samp_rate=working_rate, wpm=wpm)
    decoder = DecoderBlk()
    sink_text = TextSink()
    afc = AfcBlk(samp_rate=working_rate, pitch=pitch, loop_gain=0.05)

    tb.connect(src, (f2c, 0))
    tb.connect((src, 1), (f2c, 1))
    tb.connect(f2c, xlate, c2mag, noise_floor, thresh, tagger, decoder)
    tb.connect(xlate, afc)
    tb.msg_connect(decoder, "out", sink_text, "in")
    tb.msg_connect(afc, "freq", xlate, "freq")

    tb.run()

    if verbose:
        print(f"--- {WAV} (pitch={pitch} Hz, wpm-Startschaetzung={wpm}, "
              f"bw={bw:.1f} Hz, working_rate={working_rate:.0f} Sa/s) ---")
        print("Decodiert:", repr(sink_text.last))
        print("Finale Mark-Periode T/b:", f"{tagger.mark.T/working_rate*1000:.1f} ms / "
              f"{tagger.mark.b/working_rate*1000:.1f} ms bias")
    return sink_text.last


if __name__ == '__main__':
    run(pitch=4510.6, wpm=18)
