// serial_to_wav.c
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <signal.h>

#define SERIAL_PORT "/dev/ttyESP32_A"
#define BAUD_RATE   B1500000
#define RATE        16000
#define CHANNELS    2
#define BPS         16
#define BLOCK_SIZE  512        // PCM bytes per block (128 stereo frames)
#define MAGIC       0xABCD     // header marker

static volatile sig_atomic_t stop_flag = 0;
void on_sigint(int sig) { (void)sig; stop_flag = 1; }

void write_wav_header(FILE *f, uint32_t data_bytes) {
    uint32_t byte_rate   = RATE * CHANNELS * (BPS/8);
    uint16_t block_align = CHANNELS * (BPS/8);
    uint32_t riff_size   = 36 + data_bytes;

    fseek(f, 0, SEEK_SET);
    fwrite("RIFF", 1, 4, f);
    fwrite(&riff_size, 4, 1, f);
    fwrite("WAVE", 1, 4, f);

    fwrite("fmt ", 1, 4, f);
    uint32_t fmt_size = 16;
    fwrite(&fmt_size, 4, 1, f);
    uint16_t audio_fmt = 1;
    fwrite(&audio_fmt, 2, 1, f);
    uint16_t ch = CHANNELS;
    fwrite(&ch, 2, 1, f);
    uint32_t sr = RATE;
    fwrite(&sr, 4, 1, f);
    fwrite(&byte_rate, 4, 1, f);
    fwrite(&block_align, 2, 1, f);
    uint16_t bits = BPS;
    fwrite(&bits, 2, 1, f);

    fwrite("data", 1, 4, f);
    fwrite(&data_bytes, 4, 1, f);
}

int open_serial(const char *path) {
    int fd = open(path, O_RDONLY | O_NOCTTY);
    if (fd < 0) { perror("open"); return -1; }

    struct termios tio;
    if (tcgetattr(fd, &tio) != 0) { perror("tcgetattr"); close(fd); return -1; }

    cfsetispeed(&tio, BAUD_RATE);
    cfsetospeed(&tio, BAUD_RATE);

    tio.c_iflag &= ~(IGNBRK | BRKINT | ICRNL | INLCR | IXON | IXOFF | IXANY |
                     PARMRK | INPCK | ISTRIP);
    tio.c_oflag &= ~(OPOST);
    tio.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN | ISIG);
    tio.c_cflag &= ~(CSIZE | PARENB | CSTOPB | CRTSCTS);
    tio.c_cflag |= (CS8 | CLOCAL | CREAD);

    tio.c_cc[VMIN]  = 1;
    tio.c_cc[VTIME] = 0;

    if (tcsetattr(fd, TCSANOW, &tio) != 0) { perror("tcsetattr"); close(fd); return -1; }

    return fd;
}

int main() {
    signal(SIGINT, on_sigint);

    int fd = open_serial(SERIAL_PORT);
    if (fd < 0) return 1;

    FILE *out = fopen("capture.wav", "wb+");
    if (!out) { perror("fopen"); close(fd); return 1; }

    uint32_t data_bytes = 0;
    fseek(out, 44, SEEK_SET);

    while (!stop_flag) {
        // Read header bytes explicitly
        uint8_t hbuf[2];
        ssize_t hn = read(fd, hbuf, 2);
        if (hn != 2) continue;

        uint16_t hdr = hbuf[0] | (hbuf[1] << 8); // little-endian decode
        if (hdr != MAGIC) {
            // Not aligned, skip one byte and retry
            continue;
        }

        // Accumulate one full PCM block
        uint8_t block[BLOCK_SIZE];
        size_t got = 0;
        while (got < BLOCK_SIZE && !stop_flag) {
            ssize_t m = read(fd, block + got, BLOCK_SIZE - got);
            if (m > 0) got += (size_t)m;
        }

        if (got == BLOCK_SIZE) {
            fwrite(block, 1, BLOCK_SIZE, out);
            data_bytes += BLOCK_SIZE;
        }
    }

    write_wav_header(out, data_bytes);
    fflush(out);
    fclose(out);
    close(fd);

    fprintf(stderr, "Saved capture.wav with %u bytes of audio\n", data_bytes);
    return 0;
}
