// serial_to_stdout.c
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>

#define DEFAULT_PORT "/dev/ttyESP32_A"
#define DEFAULT_BAUD B1500000
#define BLOCK_SIZE   512        // PCM bytes per block
#define MAGIC        0xABCD     // header marker

int open_serial(const char *path, speed_t baud) {
    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);
    cfsetospeed(&tio, baud);

    // Raw mode
    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(int argc, char *argv[]) {
    const char *port = (argc > 1) ? argv[1] : DEFAULT_PORT;
    speed_t baud = DEFAULT_BAUD;

    int fd = -1;

    while (1) {
        if (fd < 0) {
            // Try to open serial port
            fd = open_serial(port, baud);
            if (fd < 0) {
                fprintf(stderr, "Waiting for device %s...\n", port);
                sleep(2);
                continue;
            }
            fprintf(stderr, "Connected to %s\n", port);
        }

        // Read header
        uint8_t hbuf[2];
        ssize_t hn = read(fd, hbuf, 2);
        if (hn != 2) {
            // Error or disconnect
            if (hn == 0 || (hn < 0 && errno != EINTR)) {
                fprintf(stderr, "Device disconnected, retrying...\n");
                close(fd);
                fd = -1;
                sleep(2);
            }
            continue;
        }

        uint16_t hdr = hbuf[0] | (hbuf[1] << 8);
        if (hdr != MAGIC) {
            // Not aligned, skip
            continue;
        }

        // Accumulate one full PCM block
        uint8_t block[BLOCK_SIZE];
        size_t got = 0;
        while (got < BLOCK_SIZE) {
            ssize_t m = read(fd, block + got, BLOCK_SIZE - got);
            if (m <= 0) {
                // Disconnect mid-block
                fprintf(stderr, "Read error/disconnect mid-block, retrying...\n");
                close(fd);
                fd = -1;
                break;
            }
            got += (size_t)m;
        }

        if (fd >= 0 && got == BLOCK_SIZE) {
            fwrite(block, 1, BLOCK_SIZE, stdout);
            fflush(stdout);
        }
    }

    return 0;
}
