/*
 * All Rights Reserved (C) 2021-2025
 * Exoligent SARL (Colombes, France)
 * Website: www.exoligent.com
 * Author : Maxime Coroyer <maxime.coroyer@exoligent.com>
 */

#ifndef __STA_H__
#define __STA_H__

#include "common.h"
#include "libpowerfip.h"

/* global handlers */
void tst_pwrfip_var_handler(struct pwrfip_node *node,
                struct pwrfip_var *var, struct pwrfip_event *evt);
void tst_pwrfip_msg_recv_handler(struct pwrfip_node *node,
                struct pwrfip_msg *msg, struct pwrfip_event *evt);
void tst_pwrfip_msg_send_handler(struct pwrfip_node *node,
                struct pwrfip_msg *msg, struct pwrfip_event *evt);
void tst_pwrfip_nor_req_handler(struct pwrfip_node *node,
                struct pwrfip_event *evt);
void tst_pwrfip_ba_state_handler(struct pwrfip_node *node,
                struct pwrfip_event *evt);
void tst_pwrfip_ba_sync_handler(struct pwrfip_node *node,
    struct pwrfip_var *var, struct pwrfip_event *evt);
void tst_pwrfip_error_handler(struct pwrfip_node *node,
                enum pwrfip_error_code code);
void tst_pwrfip_reset_handler(struct pwrfip_node *node);

/* specific handlers */
void tst_pwrfip_msg_recv_spec_handler(struct pwrfip_node *node,
                struct pwrfip_msg *msg, struct pwrfip_event *evt);
void tst_pwrfip_msg_send_spec_handler(struct pwrfip_node *node,
                struct pwrfip_msg *msg, struct pwrfip_event *evt);

void print_sm_mps_infos(struct pwrfip_node *node);
void print_node_infos(struct pwrfip_node *node);

#define TST_MAX_STA_COUNT 2
#define TST_STA0_VAR_COUNT 4
#define TST_STA1_VAR_COUNT 4
static struct pwrfip_var_cfg tst_var_cfg[TST_MAX_STA_COUNT][TST_MAX_VAR_COUNT] = {
    /* station 0 */
    {
        /* [0x3800] (prod) */
        {
            .type = PWRFIP_VAR_TYPE_PROD,
            .id = 0x3800,
            .prod.payload_bsz = 8,
            .prod.flags = \
                /* enable prod status */
                PWRFIP_VAR_FLAGS_REFRESH | \
                /* enable aper var request */
                PWRFIP_VAR_FLAGS_APER_VAR_REQ | \
                /* enable aper msg request */
                PWRFIP_VAR_FLAGS_APER_MSG_REQ,
            .prod.refreshment_ustime = 80000, /* 80ms */
            .prod.evt_type = PWRFIP_EVT_TYPE_NONE,
            .pwrfip_var_handler = NULL,
        },
        /* [0x3801] (cons) */
        {
            .type = PWRFIP_VAR_TYPE_CONS,
            .id = 0x3801,
            .cons.payload_bsz = 8,
            .cons.flags = \
                /* enable prod status */
                PWRFIP_VAR_FLAGS_REFRESH | \
                /* enable promptness checking */
                PWRFIP_VAR_FLAGS_PROMPT | \
                /* enable pdu + len bytes checking */
                PWRFIP_VAR_FLAGS_CHK_PDU_LEN,
            .cons.promptness_ustime = 100000, /* 100ms */
            .cons.evt_type = PWRFIP_EVT_TYPE_NONE,
            .pwrfip_var_handler = NULL,
        },
        /* [0x7800] (prod) */
        {
            .type = PWRFIP_VAR_TYPE_PROD,
            .id = 0x7800,
            .prod.payload_bsz = 8,
            .prod.flags = 0,
            .prod.refreshment_ustime = 0,
            .prod.evt_type = PWRFIP_EVT_TYPE_NONE,
            .pwrfip_var_handler = NULL,
        },
        /* [0x7801] (cons) */
        {
            .type = PWRFIP_VAR_TYPE_CONS,
            .id = 0x7801,
            .cons.payload_bsz = 8,
            .cons.flags = \
                /* enable pdu + len bytes checking */
                PWRFIP_VAR_FLAGS_CHK_PDU_LEN,
            .cons.promptness_ustime = 0,
            .cons.evt_type = PWRFIP_EVT_TYPE_NONE,
            .pwrfip_var_handler = NULL,
        },
    },
    /* station 1 */
    {
        /* [0x3801] (prod) */
        {
            .type = PWRFIP_VAR_TYPE_PROD,
            .id = 0x3801,
            .prod.payload_bsz = 8,
            .prod.flags = \
                /* enable prod status */
                PWRFIP_VAR_FLAGS_REFRESH | \
                /* enable aper var request */
                PWRFIP_VAR_FLAGS_APER_VAR_REQ | \
                /* enable aper msg request */
                PWRFIP_VAR_FLAGS_APER_MSG_REQ,
            .prod.refreshment_ustime = 80000, /* 80ms */
            .prod.evt_type = PWRFIP_EVT_TYPE_NONE,
            .pwrfip_var_handler = NULL,
        },
        /* [0x3800] (cons) */
        {
            .type = PWRFIP_VAR_TYPE_CONS,
            .id = 0x3800,
            .cons.payload_bsz = 8,
            .cons.flags = \
                /* enable prod status */
                PWRFIP_VAR_FLAGS_REFRESH | \
                /* enable promptness checking */
                PWRFIP_VAR_FLAGS_PROMPT | \
                /* enable pdu + len bytes checking */
                PWRFIP_VAR_FLAGS_CHK_PDU_LEN,
            .cons.promptness_ustime = 100000, /* 100ms */
            .cons.evt_type = PWRFIP_EVT_TYPE_NONE,
            .pwrfip_var_handler = NULL,
        },
        /* [0x7801] (prod) */
        {
            .type = PWRFIP_VAR_TYPE_PROD,
            .id = 0x7801,
            .prod.payload_bsz = 8,
            .prod.flags = 0,
            .prod.refreshment_ustime = 0,
            .prod.evt_type = PWRFIP_EVT_TYPE_NONE,
            .pwrfip_var_handler = NULL,
        },
        /* [0x7800] (cons) */
        {
            .type = PWRFIP_VAR_TYPE_CONS,
            .id = 0x7800,
            .cons.payload_bsz = 8,
            .cons.flags = \
                /* enable pdu + len bytes checking */
                PWRFIP_VAR_FLAGS_CHK_PDU_LEN,
            .cons.promptness_ustime = 0,
            .cons.evt_type = PWRFIP_EVT_TYPE_NONE,
            .pwrfip_var_handler = NULL,
        },
    },
};

#define TST_STA0_MSG_COUNT 2
#define TST_STA1_MSG_COUNT 2
static struct pwrfip_msg_cfg tst_msg_cfg[TST_MAX_STA_COUNT][TST_MAX_MSG_COUNT] = {
    /* station 0 */
    {
        /* msg to produce [src=0x0C0000, dst=0x0C0100] */
        {
            .type = PWRFIP_MSG_TYPE_SEND,
            .tx.channel = PWRFIP_MSG_TX_CH_APER,
            .tx.ack_mode = PWRFIP_MSG_TX_ACK_MODE_SDA,
            /* local data link layer address: 0x0C0000 */
            .hdr.src.seg = 0,
            .hdr.src.lsap = 0x0C00, /* ssap */
            /* remote data link layer address: 0x0C0100 */
            .hdr.dst.seg = 0,
            .hdr.dst.lsap = 0x0C01, /* dsap (=target) */
            .pwrfip_msg_handler = tst_pwrfip_msg_send_spec_handler,
        },
        /* msg to receive [src=0x0C0100, dst=0x0C0000] */
        {
            .type = PWRFIP_MSG_TYPE_RECV,
            /* remote data link layer address: 0x0C0100 */
            .hdr.src.seg = 0,
            .hdr.src.lsap = 0x0C01, /* ssap */
            /* local data link layer address: 0x0C0000 */
            .hdr.dst.seg = 0,
            .hdr.dst.lsap = 0x0C00, /* dsap (=target) */
            .pwrfip_msg_handler = tst_pwrfip_msg_recv_spec_handler,
        },
    },
    /* station 1 */
    {
        /* msg to produce [src=0x0C0100, dst=0x0C0000] */
        {
            .type = PWRFIP_MSG_TYPE_SEND,
            .tx.channel = PWRFIP_MSG_TX_CH_APER,
            .tx.ack_mode = PWRFIP_MSG_TX_ACK_MODE_SDA,
            /* local data link layer address: 0x0C0100 */
            .hdr.src.seg = 0,
            .hdr.src.lsap = 0x0C01, /* ssap */
            /* remote data link layer address: 0x0C0000 */
            .hdr.dst.seg = 0,
            .hdr.dst.lsap = 0x0C00, /* dsap (=target) */
            .pwrfip_msg_handler = tst_pwrfip_msg_send_spec_handler,
        },
        /* msg to receive [src=0x0C0000, dst=0x0C0100] */
        {
            .type = PWRFIP_MSG_TYPE_RECV,
            /* remote data link layer address: 0x0C0000 */
            .hdr.src.seg = 0,
            .hdr.src.lsap = 0x0C00, /* ssap */
            /* local data link layer address: 0x0C0100 */
            .hdr.dst.seg = 0,
            .hdr.dst.lsap = 0x0C01, /* dsap (=target) */
            .pwrfip_msg_handler = tst_pwrfip_msg_recv_spec_handler,
        },
    },
};

/* ba periodic requests list [for periodic mcycle wind] */
#define TST_BA_PER_REQ_COUNT 3
static struct pwrfip_ba_request tst_ba_per_req[TST_BA_PER_REQ_COUNT] = {
    {
        .type = PWRFIP_BA_ID_DAT,
        .id = 0x3800,
    },
    {
        .type = PWRFIP_BA_ID_DAT,
        .id = 0x3801,
    },
    {
        .type = PWRFIP_BA_ID_DAT,
        .id = 0x9003,
    },
};

#define TST_MAX_BA_MCYCLE_WIND_COUNT 4
#define TST_BA_MCYCLE1_WIND_COUNT 4
#define TST_BA_MCYCLE2_WIND_COUNT 3
#define TST_BA_MCYCLE1_US 40000 /* 40ms*/
#define TST_BA_MCYCLE2_US 80000 /* 80ms */
static struct pwrfip_ba_wind_cfg tst_ba_wind_cfg[TST_MAX_BA_MCYCLE_COUNT][TST_MAX_BA_MCYCLE_WIND_COUNT] = {
    /* ba mcycle 1 */
    {
        /* 1 - periodic variable window */
        {
            .type = PWRFIP_BA_WIND_PER,
            .per.req_cnt = TST_BA_PER_REQ_COUNT,
            .per.req_list = &tst_ba_per_req[0],
        },
        /* 2 - aperiodic message window */
        {
            .type = PWRFIP_BA_WIND_APER_MSG,
            .aper_msg.end_ustime = 15000,
        },
        /* 3 - aperiodic variable window */
        {
            .type = PWRFIP_BA_WIND_APER_VAR,
            .aper_var.end_ustime = 35000,
            .aper_var.enable_testp = 1, /* enable presence test if no other
                                         * request to dispatch */
        },
        /* 4 - resync wait window */
        {
            .type = PWRFIP_BA_WIND_WAIT,
            .wait.end_ustime = TST_BA_MCYCLE1_US,
            .wait.is_silent = 0, /* fill window with padding frames */
            .wait.is_ext_resync = 0, /* internal resynchronization */
        },
    },
    /* ba mcycle 2 */
    {
        /* 1 - periodic variable window */
        {
            .type = PWRFIP_BA_WIND_PER,
            .per.req_cnt = TST_BA_PER_REQ_COUNT,
            .per.req_list = &tst_ba_per_req[0],
        },
        /* 2 - aperiodic message window */
        {
            .type = PWRFIP_BA_WIND_APER_MSG,
            .aper_msg.end_ustime = 75000,
        },
        /* 3 - resync wait window */
        {
            .type = PWRFIP_BA_WIND_WAIT,
            .wait.end_ustime = TST_BA_MCYCLE2_US,
            .wait.is_silent = 0, /* fill window with padding frames */
            .wait.is_ext_resync = 0, /* internal resynchronization */
        },
        /* no other window */
        {
            .type = 0,
        }
    },
};

static struct pwrfip_ba_mcycle_cfg tst_ba_mcycle_cfg[TST_MAX_BA_MCYCLE_COUNT] = {
    /* ba mcycle 1 */
    {
        .wind_cnt = TST_BA_MCYCLE1_WIND_COUNT,
        .wind_list = &tst_ba_wind_cfg[0][0],
    },
    /* ba mcycle 2 */
    {
        .wind_cnt = TST_BA_MCYCLE2_WIND_COUNT,
        .wind_list = &tst_ba_wind_cfg[1][0],
    },
};

static uint16_t tst_ids_tab1[2] = {
    0x7800, /* mps aper var */
    0x7801, /* mps aper var */
};

static uint16_t tst_ids_tab2[4] = {
    /* sm_mps: identification var (0x10XY where XY is node addr) */
    0x1000, /* node 0 */
    0x1001, /* node 1 */
    /* sm_mps: report var (0x11XY where XY is node addr) */
    0x1100, /* node 0 */
    0x1101, /* node 1 */
};

#define TST_VARIDS_LIST_SMMPS_INFO 1 /* list number for sm_mps infos */
static struct tst_varids tst_varids_list[TST_MAX_VARIDS_LIST_COUNT] = {
    /* variable ids list 1 */
    {
        .ids = tst_ids_tab1,
        .cnt = sizeof(tst_ids_tab1) / sizeof(uint16_t),
    },
    /* variable ids list 2 */
    {
        .ids = tst_ids_tab2,
        .cnt = sizeof(tst_ids_tab2) / sizeof(uint16_t),
    },
};

#define PWRFIP_BITRATE_RANGE (_PWRFIP_BITRATE_MAX - _PWRFIP_BITRATE_MIN)

/* turn around time (default) in us, according to the bitrate */
static const uint32_t tr_ustime[PWRFIP_BITRATE_RANGE] = {
    424, /* 424us@31.25Kbps */
    30, /* 30us@1Mbps */
    30, /* 30us@2.5Mbps */
    32, /* 32us@5Mbps */
    32, /* 32us@12.5Mbps */
    32, /* 32us@25Mbps */
};

/* silence time (default) in us, according to the bitrate */
static const uint32_t ts_ustime[PWRFIP_BITRATE_RANGE] = {
    4096, /* 4096us@31.25Kbps */
    150, /* 150us@1Mbps */
    96, /* 96us@2.5Mbps */
    92, /* 92us@5Mbps */
    92, /* 92us@12.5Mbps */
    92, /* 92us@25Mbps */
};

static const char *pwrfip_node_state_str[_PWRFIP_NODE_STATE_MAX] = {
    /* PWRFIP_NODE_STATE_INITIAL */
    "initial",
    /* PWRFIP_NODE_STATE_LOADED */
    "loaded",
    /* PWRFIP_NODE_STATE_READY */
    "ready",
    /* PWRFIP_NODE_STATE_RUNNING */
    "running",
};

const char *pwrfip_ba_state_str[_PWRFIP_BA_STATE_MAX] = {
    /* PWRFIP_BA_STATE_INITIAL */
    "initial",
    /* PWRFIP_BA_STATE_READY */
    "ready",
    /* PWRFIP_BA_STATE_STARTING */
    "starting",
    /* PWRFIP_BA_STATE_IDLE */
    "idle",
    /* PWRFIP_BA_STATE_RUNNING */
    "running",
};

static const char *pwrfip_node_op_str[_PWRFIP_NODE_OP_MAX] = {
    /* _PWRFIP_NODE_OP_UNKNOWN */
    "unknown",
    /* PWRFIP_NODE_OP_WAIT_RX_RP_FRM */
    "rx rp frame",
    /* PWRFIP_NODE_OP_WAIT_TX_RP_FRM */
    "tx rp frame",
    /* PWRFIP_NODE_OP_WAIT_RX_ID_FRM */
    "rx id frame",
    /* PWRFIP_NODE_OP_WAIT_TX_ID_FRM */
    "tx id frame",
};

static const char *pwrfip_ba_wind_str[_PWRFIP_BA_WIND_TYPE_MAX] = {
    /* _PWRFIP_BA_WIND_TYPE_NONE */
    "none",
    /* PWRFIP_BA_WIND_PER */
    "periodic",
    /* PWRFIP_BA_WIND_APER_VAR */
    "aper. var",
    /* PWRFIP_BA_WIND_APER_MSG */
    "aper. msg",
    /* PWRFIP_BA_WIND_WAIT */
    "wait",
};

static const char *pwrfip_var_err_str[_PWRFIP_VAR_ERR_MAX] = {
    /* _PWRFIP_VAR_OK */
    "no error",
    /* PWRFIP_VAR_ID_UNKNOWN */
    "unknown var id",
    /* PWRFIP_VAR_NOT_PRODUCING */
    "not a producing var",
    /* PWRFIP_VAR_NOT_CONSUMING */
    "not a consuming var",
    /* PWRFIP_VAR_TX_APER_CH_UNKNOWN */
    "unknown tx aper channel",
    /* PWRFIP_VAR_PDU_INCONSISTENT */
    "inconsistent var pdu",
    /* PWRFIP_VAR_LEN_TOO_LONG */
    "var length too long",
    /* PWRFIP_VAR_LEN_TOO_SHORT */
    "var length too short",
    /* PWRFIP_VAR_NEVER_RECEIVED */
    "var never received",
    /* PWRFIP_VAR_TX_APER_FIFO_EMPTY */
    "tx aper queue is empty",
    /* PWRFIP_VAR_TX_APER_FIFO_FULL */
    "tx aper queue is full",
    /* PWRFIP_VAR_NOT_MEANING */
    "payload not significant",
    /* PWRFIP_VAR_NOT_REFRESH */
    "payload not refreshed",
    /* PWRFIP_VAR_NOT_PROMPT */
    "payload not prompt",
    /* PWRFIP_VAR_BAD_PROMPT_PER */
    "bad reading frequency (promptness)",
    /* PWRFIP_VAR_BAD_REFRESH_PER */
    "bad writing frequency (refreshment)"
};

static const char *pwrfip_msg_err_str[_PWRFIP_MSG_ERR_MAX] = {
    /* _PWRFIP_MSG_OK */
    "no error",
    /* PWRFIP_MSG_TX_CH_UNKNOWN */
    "unknown message tx channel number",
    /* PWRFIP_MSG_TYPE_BAD */
    "bad message type",
    /* PWRFIP_MSG_LEN_BAD */
    "bad message length",
    /* PWRFIP_MSG_RX_FIFO_EMPTY */
    "rx message queue is empty",
    /* PWRFIP_MSG_TX_FIFO_EMPTY */
    "tx message queue is empty",
    /* PWRFIP_MSG_TX_FIFO_FULL */
    "tx message queue is full",
    /* PWRFIP_MSG_TX_TMO */
    "msg never sent and timeout expired",
    /* PWRFIP_MSG_TX_ACK_TMO */
    "msg sent but ack never received",
    /* PWRFIP_MSG_TX_ACK_NACK */
    "msg sent but ack is negative"
};

#endif
