/*
 * mcu_upgrade_test.c - 精确测试 MCU 升级 0x82 数据帧阶段
 *
 * 基于已有协议文档和离职工程师的代码逻辑编写。
 * 目标：验证 0x82 (UPDATE_DATA) 是否被 MCU 接受，定位卡死原因。
 *
 * 编译：
 *   /Users/admin/Library/Android/sdk/ndk/30.0.14904198/toolchains/llvm/prebuilt/darwin-x86_64/bin/aarch64-linux-android21-clang \
 *     mcu_upgrade_test.c -o mcu_upgrade_test -static
 *
 * 运行：
 *   adb push mcu_upgrade_test /data/local/tmp/
 *   adb shell chmod +x /data/local/tmp/mcu_upgrade_test
 *   adb shell /data/local/tmp/mcu_upgrade_test
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/select.h>
#include <stdint.h>
#include <time.h>
#include <errno.h>

/* ============================================================
 * 配置参数
 * ============================================================ */
#define SERIAL_PORT     "/dev/ttyS7"
#define BAUDRATE        B460800
#define BIN_PATH        "/data/local/tmp/mcu_app.bin"

/* 项目编号 = "E112C" (5字节ASCII, 从MCU版本信息中提取) */
static const uint8_t g_project_id[] = {0x45, 0x31, 0x31, 0x32, 0x43};
#define PROJ_ID_LEN     5

/* 超时 */
#define ACK_TIMEOUT_MS  5000
#define LONG_TIMEOUT_MS 15000

/* ============================================================
 * 全局变量
 * ============================================================ */
static int g_fd = -1;
static uint8_t g_seq = 1;       /* ARM 发送序列号 */
static uint8_t g_mcu_seq = 0;   /* MCU 最新使用的序列号 */
static int g_verbose = 1;

static uint8_t* g_bin_data = NULL;
static int g_bin_size = 0;
static int g_pkt_size = 0;      /* 从 MCU 0x02 回复获取 */

/* ============================================================
 * 工具函数
 * ============================================================ */
static uint64_t now_ms(void) {
    struct timespec ts;
    clock_gettime(CLOCK_MONOTONIC, &ts);
    return (uint64_t)ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
}

static uint8_t calc_checksum(const uint8_t* data, int len) {
    uint32_t sum = 0;
    for (int i = 0; i < len; i++) sum += data[i];
    return (~sum) & 0xFF;
}

static void hex_dump(const uint8_t* data, int len, const char* prefix) {
    printf("%s [%d bytes] ", prefix, len);
    int show = len > 64 ? 64 : len;
    for (int i = 0; i < show; i++) printf("%02X ", data[i]);
    if (len > 64) printf("...");
    printf("\n");
}

/* ============================================================
 * 串口操作
 * ============================================================ */
static int serial_open(const char* port) {
    int fd = open(port, O_RDWR | O_NOCTTY | O_NDELAY);
    if (fd < 0) { perror("open"); return -1; }
    fcntl(fd, F_SETFL, 0);  /* switch to blocking mode (required on RTD1861) */

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

    cfsetospeed(&tty, BAUDRATE);
    cfsetispeed(&tty, BAUDRATE);

    tty.c_cflag &= ~PARENB;     /* 8N1 */
    tty.c_cflag &= ~CSTOPB;
    tty.c_cflag &= ~CSIZE;
    tty.c_cflag |= CS8;
    tty.c_cflag &= ~CRTSCTS;    /* 无流控 */
    tty.c_cflag |= CREAD | CLOCAL;

    tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHONL | ISIG);
    tty.c_iflag &= ~(IXON | IXOFF | IXANY);
    tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL);
    tty.c_oflag &= ~(OPOST | ONLCR);

    tty.c_cc[VTIME] = 0;    /* 非阻塞 */
    tty.c_cc[VMIN]  = 0;

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

    printf("[UART] Opened %s @ 460800 8N1\n", port);
    return fd;
}

static int serial_write(const uint8_t* data, int len) {
    int total = 0;
    while (total < len) {
        int n = (int)write(g_fd, data + total, len - total);
        if (n < 0) {
            if (errno == EAGAIN || errno == EWOULDBLOCK) { usleep(1000); continue; }
            perror("write");
            return total > 0 ? total : -1;
        }
        if (n == 0) break;
        total += n;
    }
    tcdrain(g_fd);
    return total;
}

/* 清空接收缓冲区 */
static void drain_rx(void) {
    uint8_t tmp[256];
    fd_set rfds;
    struct timeval tv = {0, 20000}; /* 20ms */
    while (1) {
        FD_ZERO(&rfds); FD_SET(g_fd, &rfds);
        int ret = select(g_fd + 1, &rfds, NULL, NULL, &tv);
        if (ret > 0) {
            int n = (int)read(g_fd, tmp, sizeof(tmp));
            if (n <= 0) break;
        } else {
            break;
        }
    }
}

/* ============================================================
 * 帧构建
 * ============================================================ */
/* 构建完整帧 (不含头部同步检查, 直接写入 buffer) */
static int build_frame(uint8_t* out, uint8_t seq, uint8_t frame_type,
                       uint8_t msg_type, uint8_t cmd,
                       const uint8_t* payload, int payload_len) {
    int total = 9 + payload_len;  /* Head1+Head2+Len(2)+Seq+FT+MT+Cmd+Payload+CS */
    out[0] = 0xFF;
    out[1] = 0xAA;
    out[2] = (total >> 8) & 0xFF;
    out[3] = total & 0xFF;
    out[4] = seq;
    out[5] = frame_type;
    out[6] = msg_type;
    out[7] = cmd;
    if (payload_len > 0 && payload) {
        memcpy(out + 8, payload, payload_len);
    }
    out[total - 1] = calc_checksum(out + 2, total - 3);
    return total;
}

static void tx_frame(uint8_t frame_type, uint8_t msg_type, uint8_t cmd,
                     const uint8_t* payload, int payload_len) {
    uint8_t frame[2050];
    int len = build_frame(frame, g_seq++, frame_type, msg_type, cmd, payload, payload_len);
    serial_write(frame, len);
    if (g_verbose) {
        printf("[TX] ");
        hex_dump(frame, len, "");
    }
}

/* ============================================================
 * 接收解析
 * ============================================================ */
/*
 * 从串口读取数据，解析完整帧，返回帧信息。
 * 自动处理以下情况：
 *   - SetupAck(0x03): 自动回复 ACK
 *   - Notify(0x07):   MCU 主动推送，记录但不回复
 *   - HB(0x05):       记录
 *   - ACK(0x02):      记录序列号
 *   - Data(0x06):     解析 MsgType+Cmd
 *
 * 返回: 0=超时, 1=收到目标帧, -1=错误
 */
typedef struct {
    uint8_t  seq;
    uint8_t  frame_type;
    uint8_t  msg_type;
    uint8_t  cmd;
    uint8_t* payload;   /* 指向内部 buffer, 不长期有效 */
    int      payload_len;
    int      valid;     /* 1=有帧数据 */
} RxFrame;

/* 内部接收缓冲区 */
#define RX_BUF_SIZE 4096
static uint8_t g_rx_buf[RX_BUF_SIZE];
static int g_rx_pos = 0;

static void tx_ctrl_frame(uint8_t ft, uint8_t seq);

static int rx_poll(int timeout_ms, RxFrame* out) {
    fd_set rfds;
    struct timeval tv;
    uint64_t deadline = now_ms() + timeout_ms;

    memset(out, 0, sizeof(*out));

    while (now_ms() < deadline) {
        int remaining = (int)(deadline - now_ms());
        if (remaining < 0) remaining = 0;

        FD_ZERO(&rfds); FD_SET(g_fd, &rfds);
        tv.tv_sec  = remaining / 1000;
        tv.tv_usec = (remaining % 1000) * 1000;

        int ret = select(g_fd + 1, &rfds, NULL, NULL, &tv);
        if (ret < 0) { perror("select"); return -1; }
        if (ret > 0) {
            int n = (int)read(g_fd, g_rx_buf + g_rx_pos, RX_BUF_SIZE - g_rx_pos - 1);
            if (n > 0) g_rx_pos += n;
        }

        /* 在接收缓冲区中搜索完整帧 */
        int consumed = 0;
        for (int i = 0; i <= g_rx_pos - 7; i++) {
            if (g_rx_buf[i] != 0xFF || g_rx_buf[i+1] != 0xAA) continue;

            int flen = (g_rx_buf[i+2] << 8) | g_rx_buf[i+3];
            if (flen < 7 || i + flen > g_rx_pos) continue;  /* 帧不完整 */

            uint8_t cs = calc_checksum(g_rx_buf + i + 2, flen - 3);
            if (cs != g_rx_buf[i + flen - 1]) {
                printf("[WARN] Checksum mismatch at pos %d\n", i);
                consumed = i + 1;
                continue;
            }

            /* 解析帧 */
            uint8_t seq   = g_rx_buf[i+4];
            uint8_t ft    = g_rx_buf[i+5];

            if (g_verbose) {
                printf("[RX] ");
                hex_dump(g_rx_buf + i, flen, "");
            }

            /* 记录 MCU 序列号 */
            g_mcu_seq = seq;

            /* 填充输出 */
            out->seq         = seq;
            out->frame_type  = ft;

            if (flen == 7) {
                /* 控制帧: Setup/ACK/HB/Close - 无 MsgType/Cmd */
                out->msg_type    = 0;
                out->cmd         = 0;
                out->payload     = g_rx_buf + i + 6;
                out->payload_len = 0;
            } else {
                /* 数据帧: Data/Notify - 含 MsgType+Cmd */
                out->msg_type    = g_rx_buf[i+6];
                out->cmd         = g_rx_buf[i+7];
                out->payload     = g_rx_buf + i + 8;
                out->payload_len = flen - 9;
            }
            out->valid = 1;

            /* SetupAck handled by do_handshake, not automatically */

            consumed = i + flen;
            return 1;  /* 返回一帧 */
        }

        if (consumed > 0) {
            g_rx_pos -= consumed;
            if (g_rx_pos > 0 && consumed > 0)
                memmove(g_rx_buf, g_rx_buf + consumed, g_rx_pos);
        }
    }

    return 0;  /* 超时 */
}

/* ============================================================
 * 升级流程
 * ============================================================ */

/* 1. 建链 */
/* 发送纯控制帧 (Setup/ACK/HB - 7字节, 无MsgType/Cmd) */
static void tx_ctrl_frame(uint8_t ft, uint8_t seq) {
    uint8_t frame[7] = {0xFF, 0xAA, 0x00, 0x07, seq, ft, 0x00};
    frame[6] = calc_checksum(frame + 2, 4);
    serial_write(frame, 7);
    if (g_verbose) {
        printf("[TX] ");
        hex_dump(frame, 7, "");
    }
}

static void drain_and_keep_alive(int ms) {
    uint64_t deadline = now_ms() + ms;
    uint64_t last_hb = 0;
    while (now_ms() < deadline) {
        RxFrame rx;
        int ret = rx_poll(100, &rx);
        if (ret <= 0) continue;
        /* ACK SetupAck, reply to HB */
        if (rx.frame_type == 0x03) {
            tx_ctrl_frame(0x02, rx.seq);
        }
        if (rx.frame_type == 0x05) {
            tx_ctrl_frame(0x02, rx.seq);
        }
    }
}

static int do_handshake(void) {
    printf("\n===== Step 1: Link Setup =====\n");
    drain_rx();

    /* Send Setup */
    tx_ctrl_frame(0x01, g_seq++);
    usleep(10000);

    /* Wait for MCU broadcast, ACK ONCE, then wait silently for transition */
    uint64_t deadline = now_ms() + 5000;
    int acked = 0;
    int linked = 0;

    while (now_ms() < deadline) {
        RxFrame rx;
        int ret = rx_poll(200, &rx);
        if (ret <= 0) continue;

        if (rx.frame_type == 0x03 && !acked) {
            /* ACK only the FIRST SetupAck */
            tx_ctrl_frame(0x02, rx.seq);
            acked = 1;
            printf("[INFO] ACKed SetupAck seq=0x%02X\n", rx.seq);
            continue;
        }
        /* After ACKing, look for link confirmation */
        if (acked) {
            if (rx.frame_type == 0x02) {
                printf("[OK] MCU ACK received - link up\n");
                linked = 1;
                break;
            }
            if (rx.frame_type == 0x06 || rx.frame_type == 0x07) {
                printf("[OK] MCU data frame received - link active\n");
                linked = 1;
                break;
            }
            /* Ignore further SetupAck broadcasts */
        }
    }

    printf("[INFO] acked=%d linked=%d\n", acked, linked);
    if (!linked) printf("[WARN] Link not confirmed, proceeding anyway\n");
    return 0;
}

/* 2. 发送 0x80 UPDATE_REQ */
static int send_update_req(int bin_len_aligned) {
    printf("\n===== Step 2: 0x80 UPDATE_REQ =====\n");

    /*
     * Payload:
     *   [0]    = P0  = 0x04 (请求MCU升级)
     *   [1~5]  = 项目编号 "E112C"
     *   [6~9]  = iBinLength (大端, 4字节)
     */
    uint8_t payload[10];
    payload[0] = 0x04;                          /* P0 = MCU升级 */
    memcpy(payload + 1, g_project_id, 5);       /* 项目编号 */
    payload[6] = (bin_len_aligned >> 24) & 0xFF;
    payload[7] = (bin_len_aligned >> 16) & 0xFF;
    payload[8] = (bin_len_aligned >> 8) & 0xFF;
    payload[9] = bin_len_aligned & 0xFF;

    printf("[PARAM] Project ID: E112C\n");
    printf("[PARAM] iBinLength: %d (0x%08X)\n", bin_len_aligned, bin_len_aligned);

    tx_frame(0x06, 0x07, 0x80, payload, 10);

    /* 等待链路层 ACK (0x02) + 应用层 UPDATE_ACK (mt=0x07, cmd=0x01) */
    uint64_t deadline = now_ms() + 10000;
    int got_link_ack = 0;
    int got_app_ack = 0;
    uint8_t ack_type = 0;

    while (now_ms() < deadline) {
        RxFrame rx;
        int ret = rx_poll(500, &rx);
        if (ret <= 0) continue;

        if (rx.frame_type == 0x02 && rx.seq == g_seq - 1) {
            got_link_ack = 1;
            printf("[OK] Link-layer ACK for 0x80\n");
        }
        if (rx.frame_type == 0x06 && rx.msg_type == 0x07 && rx.cmd == 0x01) {
            got_app_ack = 1;
            ack_type = rx.payload[0];
            printf("[INFO] App-layer UPDATE_ACK type=%d ", ack_type);
            switch (ack_type) {
                case 2: printf("(REQUEST - MCU同意升级)\n"); break;
                case 1: printf("(REJECT - MCU拒绝升级)\n"); break;
                case 4: printf("(FAIL)\n"); break;
                default: printf("(unknown)\n"); break;
            }
            break;  /* 应用层 ACK 是最终回答，不等了 */
        }
    }

    if (!got_link_ack) {
        printf("[WARN] No link-layer ACK for 0x80 within 10s\n");
    }

    if (got_app_ack && ack_type == 1) {
        printf("[FAIL] MCU REJECTED upgrade request (project ID mismatch?)\n");
        return -1;
    }

    if (got_app_ack && ack_type == 2) {
        printf("[OK] MCU accepted upgrade request\n");
        return 0;
    }

    /* 没收到应用层 ACK - 已知问题，继续尝试 */
    printf("[WARN] No app-layer ACK received (known issue), continuing anyway\n");
    return 0;
}

/* 3. 发送 0x81 UPDATE_BEGIN */
static int send_update_begin(int bin_len_aligned) {
    printf("\n===== Step 3: 0x81 UPDATE_BEGIN =====\n");

    /*
     * Payload:
     *   [0~3]  = iBinLength (大端)
     *   [4~8]  = 项目编号 "E112C"
     */
    uint8_t payload[9];
    payload[0] = (bin_len_aligned >> 24) & 0xFF;
    payload[1] = (bin_len_aligned >> 16) & 0xFF;
    payload[2] = (bin_len_aligned >> 8) & 0xFF;
    payload[3] = bin_len_aligned & 0xFF;
    memcpy(payload + 4, g_project_id, 5);

    tx_frame(0x06, 0x07, 0x81, payload, 9);

    /* 等待链路层 ACK + UPDATE_LEN + IND_AQUIRE */
    printf("[WAIT] Waiting for UPDATE_LEN + IND_AQUIRE...\n");

    uint64_t deadline = now_ms() + LONG_TIMEOUT_MS;
    int got_len = 0, got_ind = 0;
    int pkt_size = 0, req_idx = -1;

    while (now_ms() < deadline) {
        RxFrame rx;
        int ret = rx_poll(500, &rx);
        if (ret <= 0) continue;

        /* 链路 ACK */
        if (rx.frame_type == 0x02 && rx.seq == g_seq - 1) {
            printf("[OK] Link-layer ACK for 0x81\n");
        }

        /* UPDATE_LEN (mt=0x07, cmd=0x02) */
        if (rx.frame_type == 0x06 && rx.msg_type == 0x07 && rx.cmd == 0x02 && rx.payload_len >= 2) {
            pkt_size = (rx.payload[0] << 8) | rx.payload[1];
            printf("[OK] UPDATE_LEN: packet_size = %d\n", pkt_size);
            got_len = 1;
            g_pkt_size = pkt_size;
        }

        /* IND_AQUIRE (mt=0x07, cmd=0x03) */
        if (rx.frame_type == 0x06 && rx.msg_type == 0x07 && rx.cmd == 0x03 && rx.payload_len >= 2) {
            req_idx = (rx.payload[0] << 8) | rx.payload[1];
            printf("[OK] IND_AQUIRE: idx = %d\n", req_idx);
            got_ind = 1;
            break;  /* 收到索引请求，可以发数据了 */
        }
    }

    if (!got_len) {
        printf("[FAIL] No UPDATE_LEN from MCU within timeout\n");
        return -1;
    }
    if (!got_ind) {
        printf("[FAIL] No IND_AQUIRE from MCU within timeout\n");
        return -1;
    }

    printf("[INFO] MCU requested packet idx=%d (pkt_size=%d)\n", req_idx, pkt_size);
    return req_idx;  /* 返回 MCU 请求的索引 */
}

/* 4. 发送 0x82 UPDATE_DATA */
static int send_update_data(int idx, int pkt_size) {
    printf("\n===== Step 4: 0x82 UPDATE_DATA idx=%d =====\n", idx);

    /* 准备 payload: 2字节索引 + pkt_size字节数据 */
    uint8_t payload[2 + 2048];
    if (pkt_size > 2048) {
        printf("[FAIL] Packet size %d too large\n", pkt_size);
        return -1;
    }

    payload[0] = (idx >> 8) & 0xFF;  /* IndexH */
    payload[1] = idx & 0xFF;          /* IndexL */

    /* 填充数据：取 bin 的对应位置，不足补 0xFF */
    int offset = idx * pkt_size;
    int copy_size = pkt_size;
    if (offset + copy_size > g_bin_size) {
        copy_size = g_bin_size - offset;
        if (copy_size < 0) copy_size = 0;
    }

    if (copy_size > 0) {
        memcpy(payload + 2, g_bin_data + offset, copy_size);
    }
    if (copy_size < pkt_size) {
        memset(payload + 2 + copy_size, 0xFF, pkt_size - copy_size);
    }

    printf("[INFO] Data offset=%d, copy=%d, pad=%d\n",
           offset, copy_size, pkt_size - copy_size);

    tx_frame(0x06, 0x07, 0x82, payload, 2 + pkt_size);

    /* 等待 MCU 响应 - 可以是多种 */
    printf("[WAIT] Waiting for MCU response to 0x82...\n");

    uint64_t deadline = now_ms() + 10000;
    while (now_ms() < deadline) {
        RxFrame rx;
        int ret = rx_poll(200, &rx);
        if (ret <= 0) continue;

        /* 链路 ACK */
        if (rx.frame_type == 0x02) {
            printf("[OK] Link-layer ACK seq=0x%02X\n", rx.seq);
            return 0;  /* 至少链路层 ACK 了 */
        }

        /* UPDATE_ACK */
        if (rx.frame_type == 0x06 && rx.msg_type == 0x07 && rx.cmd == 0x01) {
            printf("[INFO] App-layer UPDATE_ACK type=%d\n", rx.payload[0]);
            return 0;
        }

        /* IND_AQUIRE 下一个包 */
        if (rx.frame_type == 0x06 && rx.msg_type == 0x07 && rx.cmd == 0x03) {
            int next_idx = (rx.payload[0] << 8) | rx.payload[1];
            printf("[OK] MCU requested NEXT packet idx=%d\n", next_idx);
            return next_idx;  /* 正数表示MCU要下一包 */
        }

        /* 其他帧 - 记录但不处理 */
        printf("[INFO] Unexpected frame while waiting for DATA response\n");
    }

    printf("[FAIL] No response to 0x82 DATA within timeout\n");
    return -1;
}

/* 获取对齐后的 iBinLength */
static int get_aligned_len(int bin_size, int pkt_size) {
    if (pkt_size <= 0) pkt_size = 1024;  /* 默认值 */
    int aligned = bin_size;
    int remainder = aligned % pkt_size;
    if (remainder != 0) {
        aligned += (pkt_size - remainder);
    }
    return aligned;
}

/* ============================================================
 * 加载 bin 文件
 * ============================================================ */
static int load_bin(const char* path) {
    FILE* f = fopen(path, "rb");
    if (!f) { perror("fopen bin"); return -1; }

    fseek(f, 0, SEEK_END);
    g_bin_size = (int)ftell(f);
    fseek(f, 0, SEEK_SET);

    g_bin_data = (uint8_t*)malloc(g_bin_size);
    if (!g_bin_data) { printf("malloc failed\n"); fclose(f); return -1; }

    int n = (int)fread(g_bin_data, 1, g_bin_size, f);
    fclose(f);

    printf("[BIN] Loaded %s: %d bytes (%.1f KB)\n", path, n, n / 1024.0);
    printf("[BIN] First 4 bytes (SP): %02X %02X %02X %02X\n",
           g_bin_data[0], g_bin_data[1], g_bin_data[2], g_bin_data[3]);
    printf("[BIN] First 8 bytes (ResetVec): %02X %02X %02X %02X\n",
           g_bin_data[4], g_bin_data[5], g_bin_data[6], g_bin_data[7]);

    return n == g_bin_size ? 0 : -1;
}

/* ============================================================
 * 主测试流程
 * ============================================================ */
int main(int argc, char** argv) {
    printf("============================================\n");
    printf("  MCU Upgrade 0x82 Test\n");
    printf("============================================\n");
    printf("Serial: %s @ 460800 8N1\n", SERIAL_PORT);
    printf("Bin:    %s\n", BIN_PATH);

    /* 加载 bin */
    if (load_bin(BIN_PATH) != 0) {
        printf("[FAIL] Cannot load bin file. Please push it first:\n");
        printf("  adb push /Users/admin/workspace/jyq/mcubin/mcu_app.bin %s\n", BIN_PATH);
        return 1;
    }

    /* 打开串口 */
    g_fd = serial_open(SERIAL_PORT);
    if (g_fd < 0) return 1;
    drain_rx();

    /* ========== Phase 1: 建链 ========== */
    if (do_handshake() != 0) { close(g_fd); return 1; }

    /* ========== Phase 2: 计算对齐大小 ========== */
    int pkt_size = 1024;  /* 默认值，后续会被 MCU 的 UPDATE_LEN 覆盖 */
    int aligned_len = get_aligned_len(g_bin_size, pkt_size);
    printf("\n[BIN] Original size=%d, Aligned=%d (pkt=%d)\n",
           g_bin_size, aligned_len, pkt_size);

    /* ========== Phase 3: 发送 0x80 ========== */
    if (send_update_req(aligned_len) != 0) {
        printf("[FAIL] UPDATE_REQ failed\n");
        close(g_fd);
        return 1;
    }

    /* ========== Phase 4: 发送 0x81 ========== */
    int first_idx = send_update_begin(aligned_len);
    if (first_idx < 0) {
        printf("[FAIL] UPDATE_BEGIN failed\n");
        close(g_fd);
        return 1;
    }

    /* ========== Phase 5: 发送 0x82 (第一包) ========== */
    int result = send_update_data(first_idx, g_pkt_size > 0 ? g_pkt_size : 1024);

    printf("\n============================================\n");
    printf("  RESULT: ");
    if (result >= 0) {
        printf("0x82 DATA WAS ACCEPTED (MCU responded)\n");
    } else {
        printf("0x82 DATA FAILED - MCU did not respond\n");
    }
    printf("============================================\n");

    /* Cleanup */
    close(g_fd);
    if (g_bin_data) free(g_bin_data);

    printf("\n[DONE] Test complete.\n");
    return result >= 0 ? 0 : 1;
}
