#ifndef AUDIO_H
#define AUDIO_H

#include <stdint.h>
#include <stdbool.h>

/*
 * audio.h — I2S audio output driver (Issue #143)
 *
 * Hardware: SPI3 repurposed as I2S3 master TX (blackbox flash not used
 * on balance bot).  Supports MAX98357A (I2S class-D amp) and PCM5102A
 * (I2S DAC + external amp) — both use standard Philips I2S.
 *
 * Pin assignment (SPI3 / I2S3, defined in config.h):
 *   PC10  I2S3_CK  (BCLK)   AF6
 *   PA15  I2S3_WS  (LRCLK)  AF6
 *   PB5   I2S3_SD  (DIN)    AF6
 *   PC5   AUDIO_MUTE (GPIO) active-high = enabled; low = muted/shutdown
 *
 * PLLI2S: N=192, R=2 → 96 MHz I2S clock → 22058 Hz (< 0.04% from 22050)
 * DMA1 Stream7 Channel0 (SPI3_TX), circular, double-buffer ping-pong.
 *
 * Mixer priority (highest to lowest):
 *   1. PCM audio chunks from Jetson (via JLINK_CMD_AUDIO, written to FIFO)
 *   2. Notification tones (queued by audio_play_tone)
 *   3. Silence
 *
 * Volume applies to all sources via integer sample scaling (0–100).
 */

/* Maximum int16_t samples per JLINK_CMD_AUDIO frame (252-byte payload / 2) */
#define AUDIO_CHUNK_MAX_SAMPLES  126u

/* Pre-defined notification tones */
typedef enum {
    AUDIO_TONE_BEEP_SHORT = 0,  /* 880 Hz, 100 ms — acknowledge / UI feedback  */
    AUDIO_TONE_BEEP_LONG  = 1,  /* 880 Hz, 500 ms — generic warning            */
    AUDIO_TONE_STARTUP    = 2,  /* C5→E5→G5 arpeggio (3 × 120 ms)             */
    AUDIO_TONE_ARM        = 3,  /* 880 Hz→1047 Hz two-beep ascending           */
    AUDIO_TONE_DISARM     = 4,  /* 880 Hz→659 Hz two-beep descending           */
    AUDIO_TONE_FAULT      = 5,  /* 200 Hz buzz, 500 ms — tilt/safety fault     */
    AUDIO_TONE_COUNT
} AudioTone;

/*
 * audio_init()
 *
 * Configure PLLI2S, GPIO, DMA1 Stream7, and SPI3/I2S3.
 * Pre-fills DMA buffer with silence, starts circular DMA TX, then
 * unmutes the amp.  Call once before safety_init().
 */
void audio_init(void);

/*
 * audio_mute(mute)
 *
 * Drive AUDIO_MUTE_PIN: false = hardware-muted (SD/XSMT low),
 * true = active (amp enabled).  Does NOT stop DMA; allows instant
 * un-mute without DMA restart clicks.
 */
void audio_mute(bool active);

/*
 * audio_set_volume(vol)
 *
 * Software volume 0–100.  Applied in ISR fill path via integer scaling.
 * 0 = silence, 100 = full scale (±16384 for square wave, passthrough for PCM).
 */
void audio_set_volume(uint8_t vol);

/*
 * audio_play_tone(tone)
 *
 * Queue a pre-defined notification tone.  The tone plays after any tones
 * already in the queue.  Returns false if the tone queue is full (depth 4).
 * Tones are pre-empted by incoming PCM audio from the Jetson.
 */
bool audio_play_tone(AudioTone tone);

/*
 * audio_write_pcm(samples, n)
 *
 * Write mono 16-bit 22050 Hz PCM samples into the Jetson PCM FIFO.
 * Called from jlink_process() dispatch on JLINK_CMD_AUDIO (main-loop context).
 * Returns the number of samples actually accepted (0 if FIFO is full).
 */
uint16_t audio_write_pcm(const int16_t *samples, uint16_t n);

/*
 * audio_tick(now_ms)
 *
 * Advance the tone sequencer state machine.  Must be called every 1 ms
 * from the main loop.  Manages step transitions and gap timing; updates
 * the volatile active-tone parameters read by the ISR fill path.
 */
void audio_tick(uint32_t now_ms);

/*
 * audio_is_playing()
 *
 * Returns true if the DMA is running (always true after audio_init()
 * unless the amp is hardware-muted or the I2S peripheral has an error).
 */
bool audio_is_playing(void);

#endif /* AUDIO_H */
