/* tty2.c - minimal MCU link test */
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <time.h>
#include <errno.h>

static uint8_t calc_cs(const uint8_t* d, int len) {
    int s = 0; for (int i = 0; i < len; i++) s += d[i]; return (~s) & 0xFF;
}

int main() {
    int fd = open("/dev/ttyS7", O_RDWR | O_NOCTTY | O_NDELAY);
    fcntl(fd, F_SETFL, 0);
    struct termios t; memset(&t, 0, sizeof(t)); tcgetattr(fd, &t);
    cfsetospeed(&t, B460800); cfsetispeed(&t, B460800);
    t.c_cflag |= CLOCAL|CREAD; t.c_cflag &= ~(PARENB|CSTOPB|CSIZE); t.c_cflag |= CS8;
    t.c_lflag &= ~(ICANON|ECHO|ECHOE|ISIG); t.c_oflag &= ~OPOST;
    t.c_iflag &= ~(IXON|IXOFF|IXANY|ICRNL); tcsetattr(fd, TCSANOW, &t);
    printf("[OPEN] OK\n");

    uint8_t buf[4096]; int pos = 0;

    /* Listen for 1s to see what MCU sends */
    uint64_t t0 = 0;
    struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts);
    t0 = ts.tv_sec*1000ULL+ts.tv_nsec/1000000ULL;
    while ((ts.tv_sec*1000ULL+ts.tv_nsec/1000000ULL)-t0 < 1000) {
        fd_set rfds; FD_ZERO(&rfds); FD_SET(fd, &rfds);
        struct timeval tv = {0, 100000};
        if (select(fd+1, &rfds, NULL, NULL, &tv) > 0) {
            int n = read(fd, buf+pos, sizeof(buf)-pos);
            if (n > 0) pos += n;
        }
        clock_gettime(CLOCK_MONOTONIC, &ts);
    }
    printf("[LISTEN] MCU sent %d bytes\n", pos);
    for (int i = 0; i < pos; i++) printf("%02X ", buf[i]);
    if (pos > 0) printf("\n");

    /* Send Setup */
    uint8_t setup[7] = {0xFF, 0xAA, 0x00, 0x07, 0x01, 0x01, 0xF6};
    write(fd, setup, 7); tcdrain(fd);
    printf("[TX] Setup\n");

    /* Listen 2s */
    pos = 0;
    clock_gettime(CLOCK_MONOTONIC, &ts);
    t0 = ts.tv_sec*1000ULL+ts.tv_nsec/1000000ULL;
    while ((ts.tv_sec*1000ULL+ts.tv_nsec/1000000ULL)-t0 < 2000) {
        fd_set rfds; FD_ZERO(&rfds); FD_SET(fd, &rfds);
        struct timeval tv = {0, 100000};
        if (select(fd+1, &rfds, NULL, NULL, &tv) > 0) {
            int n = read(fd, buf+pos, sizeof(buf)-pos);
            if (n > 0) pos += n;
        }
        clock_gettime(CLOCK_MONOTONIC, &ts);
    }
    printf("[RX1] %d bytes: ", pos);
    for (int i = 0; i < pos; i++) printf("%02X ", buf[i]);
    printf("\n");

    /* ACK first SetupAck */
    for (int i = 0; i < pos-6; i++) {
        if (buf[i]==0xFF && buf[i+1]==0xAA && buf[i+5]==0x03) {
            uint8_t seq = buf[i+4];
            uint8_t ack[7] = {0xFF,0xAA,0x00,0x07,seq,0x02,0x00};
            ack[6] = calc_cs(ack+2, 4);
            write(fd, ack, 7); tcdrain(fd);
            printf("[TX] ACK to SetupAck seq=0x%02X\n", seq);
            break;
        }
    }

    /* Listen 3s more */
    pos = 0; usleep(200000);
    clock_gettime(CLOCK_MONOTONIC, &ts);
    t0 = ts.tv_sec*1000ULL+ts.tv_nsec/1000000ULL;
    while ((ts.tv_sec*1000ULL+ts.tv_nsec/1000000ULL)-t0 < 3000) {
        fd_set rfds; FD_ZERO(&rfds); FD_SET(fd, &rfds);
        struct timeval tv = {0, 100000};
        if (select(fd+1, &rfds, NULL, NULL, &tv) > 0) {
            int n = read(fd, buf+pos, sizeof(buf)-pos);
            if (n > 0) {
                pos += n;
                printf("[RX2] %d: ", pos);
                for (int j = 0; j < 20 && j < pos; j++) printf("%02X ", buf[j]);
                printf("...\n");
            }
        }
        clock_gettime(CLOCK_MONOTONIC, &ts);
    }
    printf("[DONE] Total RX after ACK: %d bytes\n", pos);
    int has_data = 0;
    for (int i = 0; i < pos-6; i++) {
        if (buf[i]==0xFF && buf[i+1]==0xAA && buf[i+5]>=0x06 && buf[i+5]<=0x07)
            has_data = 1;
    }
    printf("[RESULT] %s\n", has_data ? "LINK UP - MCU sends data frames" : "LINK FAIL - MCU still broadcasting SetupAck");
    close(fd);
    return has_data ? 0 : 1;
}
