
#ifndef _DARRA_MBX_REGISTRY_H_
#define _DARRA_MBX_REGISTRY_H_

#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

struct dll;

#define MBXPROT_AOE    0x01
#define MBXPROT_EOE    0x02
#define MBXPROT_COE    0x03
#define MBXPROT_FOE    0x04
#define MBXPROT_SOE    0x05
#define MBXPROT_VOE    0x0F
#define MBXPROT_FSOE   0x10
#define MBXPROT_PDO    0x11

#define MBXPROT_MAX    0x20

typedef struct mbx_stats_snapshot {
    uint64_t total_sent;
    uint64_t total_received;
    uint64_t total_timeout;
    uint64_t total_mbx_error;
    uint64_t total_proto_error;
    uint32_t last_error_code;
    double   avg_latency_us;
} mbx_stats_snapshot_t;

typedef int (*mbx_is_supported_fn)(uint16_t master_idx, uint16_t slave_idx);

typedef struct mbx_protocol_info {
    uint8_t                   protocol_type;
    const char*               name;
    mbx_is_supported_fn is_supported;
} mbx_protocol_info_t;

int mbx_register_protocol(const mbx_protocol_info_t* info);

const mbx_protocol_info_t* mbx_get_protocol_info(uint8_t protocol_type);

int mbx_get_registered_count(void);

int mbx_is_protocol_supported(uint8_t  protocol_type,
                                    uint16_t master_idx,
                                    uint16_t slave_idx);

void mbx_init_all_protocols(struct dll* dll);

void mbx_lock(uint16_t slave_idx);
void mbx_unlock(uint16_t slave_idx);

int mbx_get_stats(uint16_t slave_idx,
                         uint8_t  protocol_type,
                         mbx_stats_snapshot_t* out);

typedef enum {
    EC_MBX_STATUS_PENDING        =  0,
    EC_MBX_STATUS_SUCCESS        =  1,
    EC_MBX_STATUS_TIMEOUT        = -1,
    EC_MBX_STATUS_CANCELLED      = -2,
    EC_MBX_STATUS_MBX_ERROR      = -3,
    EC_MBX_STATUS_PROTO_MISMATCH = -4,
    EC_MBX_STATUS_COUNTER_FAIL   = -5,
    EC_MBX_STATUS_WKC_FAIL       = -6,
    EC_MBX_STATUS_NO_MEMORY      = -7,
    EC_MBX_STATUS_INVALID_ARG    = -8,
    EC_MBX_STATUS_NOT_IMPL       = -9
} ec_mbx_status_t;

typedef struct {
    uint64_t total_sent;
    uint64_t total_received;
    uint64_t total_timeout;
    uint64_t total_mbx_error;
    uint64_t total_proto_error;
    uint64_t total_cancelled;
    uint32_t last_error_code;

    uint64_t last_error_time_us;
    uint64_t total_latency_us;
} ec_mbx_stats_t;

typedef struct {

    uint16_t slave;
    uint8_t  protocol_type;
    uint8_t  reserved0;
    uint32_t timeout_us;
    volatile int cancel_flag;

    void*    request_frame;
    uint16_t request_len;
    uint16_t reserved1;

    void*    response_frame;
    uint16_t response_cap;
    uint16_t response_len;

    ec_mbx_status_t status;
    uint32_t error_code;
    uint8_t  response_counter;
    uint8_t  reserved2[3];
    uint64_t submit_time_us;
    uint64_t complete_time_us;
} ec_mbx_transaction_t;

int ec_mbx_get_stats(struct dll* dll, uint16_t master_index, uint16_t slave,
                     uint8_t protocol_type, ec_mbx_stats_t* out_stats);

void ec_mbx_reset_stats(struct dll* dll, uint16_t master_index, uint16_t slave,
                        uint8_t protocol_type);

int ec_mbx_submit_async(struct dll* dll, uint16_t master_index,
                        ec_mbx_transaction_t* txn, uint32_t* out_ticket);

int ec_mbx_wait(struct dll* dll, uint16_t master_index, uint32_t ticket,
                int timeout_ms);

int ec_mbx_cancel(struct dll* dll, uint16_t master_index, uint32_t ticket);

int ec_mbx_get_result(struct dll* dll, uint16_t master_index, uint32_t ticket,
                      ec_mbx_transaction_t* out_txn);

#ifdef __cplusplus
}
#endif

#endif
