#ifndef QSJNIC_MCU_PROTOCOL_H
#define QSJNIC_MCU_PROTOCOL_H

/*
 * L1 — protocol primitives ported verbatim from
 * test_Update/mcu_structured_test.c (Layer 1).
 *
 * Pure functions: frame build/decode, stream parser, sequence rules,
 * link state machine outcome computation. No I/O.
 */

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

#define MCU_MAX_FRAME_LEN       2048
#define MCU_MAX_PAYLOAD_LEN     (MCU_MAX_FRAME_LEN - 7)
#define MCU_PARSER_BUFFER_LEN   (MCU_MAX_FRAME_LEN * 2)

#define MCU_FRAME_HEAD_0        0xFFu
#define MCU_FRAME_HEAD_1        0xAAu

/* Frame types (Byte5). */
enum {
    FT_SETUP    = 0x01,
    FT_ACK      = 0x02,
    FT_SETUPACK = 0x03,
    FT_CLOSE    = 0x04,
    FT_HB       = 0x05,
    FT_DATA     = 0x06,
    FT_TRANSFER = 0x07,
    FT_BOOT     = 0x08,
};

/* Module types (payload[0]). */
enum {
    MT_PUBLIC = 0x01,
    MT_RADIO  = 0x05,
    MT_UPDATE = 0x07,
};

/* Update commands (payload[1]) — MCU->ARM / ARM->MCU. */
enum {
    UPDATE_M2A_UPDATE_ACK        = 0x01,
    UPDATE_M2A_UPDATE_LEN        = 0x02,
    UPDATE_M2A_UPDATE_IND_AQUIRE = 0x03,
    UPDATE_A2M_UPDATE_REQ        = 0x80,
    UPDATE_A2M_UPDATE_BEGIN      = 0x81,
    UPDATE_A2M_UPDATE_DATA       = 0x82,
    UPDATE_A2M_UPDATE_END        = 0x83,
};

enum {
    UPDATE_STATE_MCU_UPGRADE_REQ = 0x04,
};

enum {
    ACK_UPDATE_NONE              = 0x00,
    ACK_UPDATE_REJECT            = 0x01,
    ACK_UPDATE_REQUEST           = 0x02,
    ACK_UPDATE_SUCCESS           = 0x03,
    ACK_UPDATE_FAIL              = 0x04,
    ACK_UPDATE_RX_LAST_FRAME_OK  = 0x05,
};

typedef enum {
    LINK_IDLE = 0,
    LINK_SETUP_SENT,
    LINK_LINKED,
} LinkState;

typedef struct {
    uint8_t  raw[MCU_MAX_FRAME_LEN];
    size_t   raw_len;
    uint8_t  seq;
    uint8_t  ft;
    uint8_t  payload[MCU_MAX_PAYLOAD_LEN];
    size_t   payload_len;
} McuFrame;

typedef struct {
    uint8_t buffer[MCU_PARSER_BUFFER_LEN];
    size_t  len;
} FrameParser;

typedef struct {
    LinkState link_state;
    uint8_t   recv_seq;
    uint8_t   send_seq;
} ProtocolState;

typedef struct {
    bool    matched_ack;
    uint8_t ack_seq;
    bool    got_setupack;
    uint8_t setupack_seq;
    bool    send_ack;
    bool    link_up;
    bool    link_down;
    bool    duplicate_rx;
} ProtocolOutcome;

/* parser_feed consumer callback. Return true to keep consuming, false to stop
 * after the current frame (transport pauses to publish the event). */
typedef bool (*FrameConsumer)(void *opaque, const McuFrame *frame);

/* ---------------- utility ---------------- */

uint64_t mcu_now_ms(void);
void     mcu_sleep_ms(int delay_ms);
uint8_t  mcu_seq_next(uint8_t seq);
uint8_t  mcu_calc_checksum(const uint8_t *data, size_t len);
uint16_t mcu_crc16_ccitt_update(uint16_t crc, const uint8_t *data, size_t len);
bool     mcu_is_power_of_two_u16(uint16_t value);
bool     mcu_fill_upgrade_project_bytes(const uint8_t project_bytes[5]);

const char *mcu_frame_type_name(uint8_t ft);
const char *mcu_upgrade_cmd_name(uint8_t cmd);
const char *mcu_upgrade_ack_name(uint8_t ack_type);
const char *mcu_radio_band_name(uint8_t band);
const char *mcu_radio_seek_name(uint8_t seek_type);

/* ---------------- frame build / decode ---------------- */

size_t mcu_build_frame_bytes(uint8_t *out, size_t out_cap,
                             uint8_t seq, uint8_t ft,
                             const uint8_t *payload, size_t payload_len);
bool   mcu_decode_complete_frame(const uint8_t *raw, size_t raw_len, McuFrame *frame);

/* Stream parser. Returns the number of frames consumed via the callback. */
size_t mcu_parser_feed(FrameParser *parser, const uint8_t *data, size_t len,
                       FrameConsumer consumer, void *opaque);

/* ---------------- protocol state machine ---------------- */

void            mcu_protocol_state_reset(ProtocolState *state);
ProtocolOutcome mcu_protocol_on_frame(ProtocolState *state, const McuFrame *frame);

/* ---------------- upgrade payload builders ---------------- */

size_t mcu_build_upgrade_request_payload(uint8_t *payload, size_t capacity,
                                         const uint8_t project_bytes[5], uint32_t bin_size);
size_t mcu_build_upgrade_begin_payload(uint8_t *payload, size_t capacity,
                                       const uint8_t project_bytes[5], uint32_t bin_size);
size_t mcu_build_upgrade_data_payload(uint8_t *payload, size_t capacity,
                                      uint16_t index, const uint8_t *chunk, size_t chunk_len);
size_t mcu_build_upgrade_end_payload(uint8_t *payload, size_t capacity, uint16_t crc16);

#ifdef __cplusplus
}
#endif

#endif /* QSJNIC_MCU_PROTOCOL_H */
