"""Minimal serial plotter for Firefox/Safari users, or for logging longer sessions.

    pip install pyserial numpy matplotlib
    python serial_plot.py /dev/ttyUSB0 250

Reads comma-separated numbers, one line per sample, and shows the last 5 s of channel 1 with its spectrum.
Press Ctrl-C to stop; a CSV is written next to the script.
"""
import sys, time, csv
import numpy as np
import serial
import matplotlib.pyplot as plt

port = sys.argv[1] if len(sys.argv) > 1 else "/dev/ttyUSB0"
fs = float(sys.argv[2]) if len(sys.argv) > 2 else 250.0
win = int(5 * fs)

ser = serial.Serial(port, 115200, timeout=1)
buf = np.zeros(win)
rows = []
plt.ion()
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(9, 6))
(line,) = ax1.plot(np.arange(win) / fs, buf)
ax1.set_xlabel("s"); ax1.set_ylabel("ADC counts")
(spec,) = ax2.plot([], [])
ax2.set_xlim(0, 70); ax2.set_xlabel("Hz"); ax2.set_ylabel("power (dB)")
t0 = time.time()
try:
    while True:
        raw = ser.readline().decode(errors="ignore").strip()
        if not raw:
            continue
        try:
            vals = [float(v) for v in raw.replace("\t", ",").split(",") if v]
        except ValueError:
            continue
        rows.append([time.time() - t0] + vals)
        buf = np.roll(buf, -1); buf[-1] = vals[0]
        if len(rows) % int(fs / 10) == 0:
            line.set_ydata(buf); ax1.relim(); ax1.autoscale_view()
            x = buf - buf.mean()
            p = np.abs(np.fft.rfft(x * np.hanning(win))) ** 2
            f = np.fft.rfftfreq(win, 1 / fs)
            spec.set_data(f, 10 * np.log10(p + 1e-12)); ax2.relim(); ax2.autoscale_view()
            plt.pause(0.001)
except KeyboardInterrupt:
    pass
finally:
    ser.close()
    name = time.strftime("recording-%Y%m%d-%H%M%S.csv")
    with open(name, "w", newline="") as fh:
        w = csv.writer(fh); w.writerow(["t_s"] + [f"ch{i+1}" for i in range(len(rows[0]) - 1)]); w.writerows(rows)
    print("saved", name, len(rows), "samples")
