/* mcu_wake_test.c - Try various commands to wake MCU from bus sleep */
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <time.h>

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

static int fd;
static uint8_t g_seq = 1;

static void tx(uint8_t ft, const uint8_t* payload, int plen) {
    uint8_t frame[2050];
    int total = 9 + plen;
    frame[0] = 0xFF; frame[1] = 0xAA;
    frame[2] = (total>>8)&0xFF; frame[3] = total&0xFF;
    frame[4] = g_seq++; frame[5] = ft;
    if (payload) memcpy(frame+6, payload, plen);
    frame[total-1] = cs(frame+2, total-3);
    write(fd, frame, total); tcdrain(fd);
}

static void tx_ctrl(uint8_t ft) {
    uint8_t f[7] = {0xFF,0xAA,0x00,0x07,g_seq++,ft,0};
    f[6] = cs(f+2,4);
    write(fd, f, 7); tcdrain(fd);
}

/* Send a Public command: MsgType=0x01 */
static void tx_public(uint8_t cmd, const uint8_t* payload, int plen) {
    uint8_t pkt[256];
    pkt[0] = 0x01; /* MsgType = Public */
    pkt[1] = cmd;
    if (payload && plen > 0) memcpy(pkt+2, payload, plen);
    tx(0x06, pkt, 2 + plen);
}

/* Send an Update command: MsgType=0x07 */
static void tx_update(uint8_t cmd, const uint8_t* payload, int plen) {
    uint8_t pkt[256];
    pkt[0] = 0x07; /* MsgType = Update */
    pkt[1] = cmd;
    if (payload && plen > 0) memcpy(pkt+2, payload, plen);
    tx(0x06, pkt, 2 + plen);
}

/* Check for incoming data */
static int rx_poll(int timeout_ms, uint8_t* buf, int bufsize) {
    fd_set rfds; FD_ZERO(&rfds); FD_SET(fd, &rfds);
    struct timeval tv = {timeout_ms/1000, (timeout_ms%1000)*1000};
    if (select(fd+1, &rfds, NULL, NULL, &tv) > 0)
        return read(fd, buf, bufsize);
    return 0;
}

int main() {
    fd = open("/dev/ttyS7", O_RDWR | O_NOCTTY | O_NDELAY);
    if (fd < 0) return 1;
    fcntl(fd, F_SETFL, 0);
    struct termios 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);

    uint8_t rx[4096];

    printf("=== MCU Wake-up Test ===\n");

    /* Phase 1: Send Setup + ACK */
    printf("[1] Sending Setup...\n");
    tx_ctrl(0x01);
    usleep(500000);

    int n = rx_poll(1000, rx, sizeof(rx));
    if (n > 0) {
        printf("[RX] %d bytes: ", n);
        for (int i = 0; i < n && i < 20; i++) printf("%02X ", rx[i]);
        printf("\n");
    }

    /* Send ACK to first SetupAck */
    tx_ctrl(0x02);

    /* Phase 2: Send KEY_PWR_STATUS (0x8D) - simulate power button press */
    printf("[2] Sending KEY_PWR_STATUS (power ON)...\n");
    uint8_t key_on[] = {0x01, 0x8D, 0x01}; /* P0=1 = power ON */
    tx_public(0x8D, key_on+1, 2); /* skip mt */
    usleep(200000);

    /* Phase 3: Send REQ_TYPE_INFO (0x86) for version */
    printf("[3] Sending REQ_TYPE_INFO (version)...\n");
    uint8_t ver_cmd[] = {0x01, 0x86, 0x02}; /* type=0x02 = version */
    tx_public(0x86, ver_cmd+1, 2);
    usleep(200000);

    /* Phase 4: Try 0x80 UPDATE_REQ */
    printf("[4] Sending 0x80 UPDATE_REQ...\n");
    uint8_t proj[5] = {0x45,0x31,0x31,0x32,0x43};
    uint8_t req[12];
    req[0] = 0x07; req[1] = 0x80; /* mt=0x07, cmd=0x80 */
    req[2] = 0x04; /* P0=4 MCU upgrade */
    memcpy(req+3, proj, 5); /* project ID */
    req[8] = 0x00; req[9] = 0x03; req[10] = 0x50; req[11] = 0x00; /* iBinLength */
    tx(0x06, req, 12);

    /* Listen for response */
    printf("[5] Listening for MCU response...\n");
    for (int t = 0; t < 30; t++) {
        n = rx_poll(500, rx, sizeof(rx));
        if (n > 0) {
            printf("[RX] %d bytes: ", n);
            for (int i = 0; i < n && i < 32; i++) printf("%02X ", rx[i]);
            printf("\n");
            /* Check if it's a meaningful frame */
            for (int i = 0; i < n-6; i++) {
                if (rx[i]==0xFF && rx[i+1]==0xAA) {
                    int ft = rx[i+5];
                    if (ft == 0x02) printf("  → Link ACK!\n");
                    if (ft == 0x06) printf("  → Data frame! MCU is alive!\n");
                    if (ft == 0x07) printf("  → Notify frame! MCU is active!\n");
                }
            }
        }
        /* Periodically send wake commands */
        if (t % 5 == 0) {
            tx_ctrl(0x02); /* ACK */
            usleep(100000);
        }
        if (t == 15) {
            /* Try 0x81 too */
            printf("[6] Sending 0x81 UPDATE_BEGIN...\n");
            uint8_t begin[11];
            begin[0] = 0x07; begin[1] = 0x81;
            begin[2] = 0x00; begin[3] = 0x03; begin[4] = 0x50; begin[5] = 0x00;
            memcpy(begin+6, proj, 5);
            tx(0x06, begin, 11);
        }
    }

    printf("[DONE] Test complete\n");
    close(fd);
    return 0;
}
