/*
    * Sdr.hpp
    * Generic software-defined radio (SDR) receive subsystem.
    *
    * Hardware-agnostic registry of radio receivers.  A concrete driver (e.g. the
    * RTL-SDR USB driver) registers itself as a receiver by supplying an ops table
    * and a private context pointer; it then pushes demodulated baseband I/Q
    * samples into a per-receiver ring buffer via PushSamples().  Userspace reaches
    * this layer through the SYS_SDR_* syscalls and drains the ring with Read().
    *
    * The native sample format is CU8 -- 8-bit unsigned interleaved I/Q -- which is
    * what the RTL2832U produces; other formats can be advertised per receiver via
    * SdrDeviceInfo.sampleFormat.
    * Copyright (c) 2026 Daniel Hammer
*/

#pragma once
#include <cstdint>
#include <CppLib/Spinlock.hpp>
#include <Api/Syscall.hpp>

namespace Drivers::Radio::Sdr {

    static constexpr int MAX_RECEIVERS = 4;
    static constexpr int MAX_GAINS     = 32;

    // -------------------------------------------------------------------------
    // Receiver ops table -- implemented by a concrete driver.
    // All calls happen in process/syscall context (never from the sample
    // callback), so they may block on USB control transfers.  Each returns 0 on
    // success, negative on error.  ctx is the receiver's private pointer.
    // -------------------------------------------------------------------------

    struct ReceiverOps {
        int (*SetFreq)(void* ctx, uint64_t hz);
        int (*SetSampleRate)(void* ctx, uint32_t hz);
        int (*SetGainMode)(void* ctx, int manual);      // 0 = auto/AGC, 1 = manual
        int (*SetGain)(void* ctx, int tenthsDb);
        int (*SetFreqCorrection)(void* ctx, int ppm);
        int (*SetAgc)(void* ctx, int on);               // demod digital AGC
        int (*SetDirectSampling)(void* ctx, int mode);  // 0=off,1=I,2=Q
        int (*Start)(void* ctx);                         // arm streaming
        int (*Stop)(void* ctx);                          // halt streaming
        // Optional: process-context housekeeping invoked from Read() while
        // streaming (e.g. USB stall recovery that cannot run in the ISR).  May
        // be null.
        void (*Service)(void* ctx);
    };

    // Static description a driver supplies at registration time.
    struct ReceiverDesc {
        const char* name;        // e.g. "Realtek RTL2832U"
        const char* tuner;       // e.g. "Rafael Micro R820T2"
        const char* serial;      // bus location / serial string (may be null)
        uint64_t    freqMin;     // Hz
        uint64_t    freqMax;     // Hz
        uint32_t    sampleRateMin;
        uint32_t    sampleRateMax;
        const int*  gains;       // table of tenths-of-dB gain steps (may be null)
        uint32_t    numGains;
        uint8_t     format;      // montauk::abi::SDR_FORMAT_*
        ReceiverOps ops;
        void*       ctx;
    };

    // =========================================================================
    // Driver-facing API
    // =========================================================================

    // Register a receiver.  Returns its index [0, MAX_RECEIVERS) or -1 if full.
    int Register(const ReceiverDesc& desc);

    // Remove a receiver (e.g. on USB unplug).  Stops streaming and frees the
    // ring.  Safe to call with an out-of-range / already-removed index.
    void Unregister(int idx);

    // Push baseband sample bytes into a receiver's ring buffer.  Called from the
    // driver's USB completion callback (possibly interrupt context); never
    // allocates or blocks.  Bytes that do not fit are dropped (counted).
    void PushSamples(int idx, const uint8_t* data, uint32_t len);

    // True if the receiver is currently in the streaming state (used by drivers
    // to decide whether to re-arm USB transfers).
    bool IsStreaming(int idx);

    // =========================================================================
    // Syscall-facing API
    // =========================================================================

    // Number of registered receivers.
    int Count();

    // Fill out an info struct for receiver idx.  Returns false if idx invalid.
    bool GetInfo(int idx, montauk::abi::SdrDeviceInfo* out);

    // Claim a receiver for use.  Returns a handle (== idx) or -1 on failure.
    int Open(int idx);

    // Release a receiver (stops streaming).  Returns 0 on success.
    int Close(int handle);

    // Begin / end sample delivery.  Returns 0 on success, negative on error.
    int Start(int handle);
    int Stop(int handle);

    // Copy up to len bytes of buffered I/Q out of the ring.  Non-blocking;
    // returns the number of bytes copied (0 when nothing is queued).
    int Read(int handle, uint8_t* buf, uint32_t len);

    // Number of sample bytes currently queued in the ring.
    uint32_t Available(int handle);

    // Set / get a tunable parameter (montauk::abi::SDR_PARAM_*).  SetParam
    // returns 0 on success; GetParam returns the cached value or negative on
    // error.
    int64_t SetParam(int handle, int param, uint64_t value);
    int64_t GetParam(int handle, int param);

}
