/*
 * All Rights Reserved (C) 2021-2025
 * Exoligent SARL (Colombes, France)
 * Website: www.exoligent.com
 */

#ifndef __POWERFIP_COMMON_H
#define __POWERFIP_COMMON_H

#define PWRFIP_SRAM_BSZ (1u << 22) // 4MB
#define PWRFIP_SRAM_WSZ (1u << 19)

/**
 * ENUMERATION
 */
enum pwrfip_node_state { /**< node finite-state machine */
    /* no config loaded (initial state) */
    PWRFIP_NODE_STATE_INITIAL,
    /* general node config loaded () */
    PWRFIP_NODE_STATE_LOADED,
    /* user context loaded (aele) (stopped state: ready to start) */
    PWRFIP_NODE_STATE_READY,
    /* running state (active on network) */
    PWRFIP_NODE_STATE_RUNNING,
    _PWRFIP_NODE_STATE_MAX,
};

enum pwrfip_ba_state { /**< ba finite-state machine */
    /* no ba config loaded (initial state) */
    PWRFIP_BA_STATE_INITIAL,
    /* user context loaded (mcycle(s)) (stopped state: ready to start) */
    PWRFIP_BA_STATE_READY,
    /* starting-up state (not yet active) */
    PWRFIP_BA_STATE_STARTING,
    /* idle state (maybe another ba is active on network) */
    PWRFIP_BA_STATE_IDLE,
    /* running state (ba active on network) */
    PWRFIP_BA_STATE_RUNNING,
    _PWRFIP_BA_STATE_MAX,
};

enum pwrfip_node_operation { /**< node operation in progress */
    /* unknown operation */
    _PWRFIP_NODE_OP_UNKNOWN,
    /* wait for rp_xx frame reception */
    PWRFIP_NODE_OP_WAIT_RX_RP_FRM,
    /* rp_xx frame transmission */
    PWRFIP_NODE_OP_WAIT_TX_RP_FRM,
    /* wait for id_xx frame reception */
    PWRFIP_NODE_OP_WAIT_RX_ID_FRM,
    /* id_xx frame transmission */
    PWRFIP_NODE_OP_WAIT_TX_ID_FRM,
    _PWRFIP_NODE_OP_MAX,
};

enum pwrfip_ba_wind_type { /**< macrocycle window in progress */
    /* no ba window in progress */
    _PWRFIP_BA_WIND_TYPE_NONE,
    _PWRFIP_BA_WIND_TYPE_MIN,
    /* periodic window */
    PWRFIP_BA_WIND_PER = _PWRFIP_BA_WIND_TYPE_MIN,
    /* aperiodic variable window */
    PWRFIP_BA_WIND_APER_VAR,
    /* aperiodic message window */
    PWRFIP_BA_WIND_APER_MSG,
    /* ext/int resync waiting window */
    PWRFIP_BA_WIND_WAIT,
    _PWRFIP_BA_WIND_TYPE_MAX,
};

enum pwrfip_medium_state {
    PWRFIP_MEDIUM_STATE_CH1_VALID = (1 << 0),
    PWRFIP_MEDIUM_STATE_CH2_VALID = (1 << 1),
    PWRFIP_MEDIUM_STATE_CH1_TX_ERROR = (1 << 2),
    PWRFIP_MEDIUM_STATE_CH2_TX_ERROR = (1 << 3),
    /* watchdog on channel 1 (MAU has to be reset) */
    PWRFIP_MEDIUM_STATE_CH1_WATCHDOG = (1 << 4),
    /* watchdog on channel 2 (MAU has to be reset) */
    PWRFIP_MEDIUM_STATE_CH2_WATCHDOG = (1 << 5),
};

enum pwrfip_var_flags {
    /**
     * PROD/CONS
     */
    /* enable refreshment status (mps status) */
    PWRFIP_VAR_FLAGS_REFRESH = (1 << 0),
    /* enable dynamic refreshment status (var_time) */
    PWRFIP_VAR_FLAGS_DYN_REFRESH = (1 << 1),
    /**
     * PROD only
     */
    /* enable aper. var request capability */
    PWRFIP_VAR_FLAGS_APER_VAR_REQ = (1 << 8),
    /* enable aper. msg request capability */
    PWRFIP_VAR_FLAGS_APER_MSG_REQ = (1 << 9),
    /**
     * CONS only
     */
    /* enable promptness status */
    PWRFIP_VAR_FLAGS_PROMPT = (1 << 12),
    /* enable pdu+len frame check */
    PWRFIP_VAR_FLAGS_CHK_PDU_LEN = (1 << 13),
    PWRFIP_VAR_FLAGS_MAX_VAL = (1 << 15),
};

/* var_state err_code */
enum pwrfip_var_err_code {
    _PWRFIP_VAR_OK,
    _PWRFIP_VAR_ERR_MIN,
    /* configuration errors */
    PWRFIP_VAR_ID_UNKNOWN = _PWRFIP_VAR_ERR_MIN,
    PWRFIP_VAR_NOT_PRODUCING,
    PWRFIP_VAR_NOT_CONSUMING,
    PWRFIP_VAR_TX_APER_CH_UNKNOWN,
    /* context error */
    PWRFIP_VAR_PDU_INCONSISTENT,
    PWRFIP_VAR_LEN_TOO_LONG,
    PWRFIP_VAR_LEN_TOO_SHORT,
    PWRFIP_VAR_NEVER_RECEIVED,
    PWRFIP_VAR_TX_APER_FIFO_EMPTY,
    PWRFIP_VAR_TX_APER_FIFO_FULL,
    /* payload error */
    /* -> cons var */
    PWRFIP_VAR_NOT_MEANING,
    PWRFIP_VAR_NOT_REFRESH,
    PWRFIP_VAR_NOT_PROMPT,
    /* bad time between 2 user app readings */
    PWRFIP_VAR_BAD_PROMPT_PER,
    /* -> prod var */
    /* bad time between 2 user app writings */
    PWRFIP_VAR_BAD_REFRESH_PER,
    _PWRFIP_VAR_ERR_MAX,
};

/* msg_state err_code */
enum pwrfip_msg_err_code {
    _PWRFIP_MSG_OK,
    _PWRFIP_MSG_ERR_MIN,
    /* configuration errors */
    PWRFIP_MSG_TX_CH_UNKNOWN = _PWRFIP_MSG_ERR_MIN,
    /* context error */
    PWRFIP_MSG_TYPE_BAD,
    PWRFIP_MSG_LEN_BAD,
    /* -> rx msg */
    PWRFIP_MSG_RX_FIFO_EMPTY,
    /* -> tx msg */
    PWRFIP_MSG_TX_FIFO_EMPTY,
    PWRFIP_MSG_TX_FIFO_FULL,
    PWRFIP_MSG_TX_TMO,
    PWRFIP_MSG_TX_ACK_TMO,
    PWRFIP_MSG_TX_ACK_NACK,
    _PWRFIP_MSG_ERR_MAX,
};

/*
 * Message reception capability
 * It defines the sensitivity of the node to receive messages
 * according to the destination segment of the message headers
 * received.
 */
enum pwrfip_msg_rx_seg_cap {
    _PWRFIP_MSG_SEG_CAP_MIN = 0,
    /* ignore all messages intended for the segment */
    PWRFIP_MSG_SEG_IGNORE = _PWRFIP_MSG_SEG_CAP_MIN,
    /* accept all messages intended for the segment
     * (regardless of the destination lsap [msg_hdr])
     * note: used for bridge applications
     */
    PWRFIP_MSG_SEG_ACCEPT_ALL,
    /* limited acceptance:
     * accept the message intented for the segment
     * only if the destination lsap [msg_hdr] is configured
     * for the node.
     * (i.e. attached identifier accept message reception)
     */
    PWRFIP_MSG_SEG_ACCEPT_LTD,
    _PWRFIP_MSG_SEG_CAP_MAX,
};

/* Transmission channels for messages */
#define PWRFIP_MSG_TX_CH_PER_CNT 8 /* count of periodic message tx channels */
enum pwrfip_msg_tx_channel {
    _PWRFIP_MSG_TX_CH_MIN = 0,
    PWRFIP_MSG_TX_CH_APER = _PWRFIP_MSG_TX_CH_MIN,
    PWRFIP_MSG_TX_CH_PER_1,
    PWRFIP_MSG_TX_CH_PER_2,
    PWRFIP_MSG_TX_CH_PER_3,
    PWRFIP_MSG_TX_CH_PER_4,
    PWRFIP_MSG_TX_CH_PER_5,
    PWRFIP_MSG_TX_CH_PER_6,
    PWRFIP_MSG_TX_CH_PER_7,
    PWRFIP_MSG_TX_CH_PER_8,
    _PWRFIP_MSG_TX_CH_MAX,
};

/* Acknowledgement mode for a FIP message */
enum pwrfip_msg_tx_ack_mode {
    _PWRFIP_MSG_TX_ACK_MODE_MIN = 0,
    /* send data without acknowledgment */
    PWRFIP_MSG_TX_ACK_MODE_SDN = _PWRFIP_MSG_TX_ACK_MODE_MIN,
    /* send data with acknowledgment */
    PWRFIP_MSG_TX_ACK_MODE_SDA,
    _PWRFIP_MSG_TX_ACK_MODE_MAX,
};

/* FIP message type */
enum pwrfip_msg_type {
    _PWRFIP_MSG_TYPE_MIN = 0,
    /* message to receive */
    PWRFIP_MSG_TYPE_RECV = _PWRFIP_MSG_TYPE_MIN,
    /* message to send */
    PWRFIP_MSG_TYPE_SEND,
    _PWRFIP_MSG_TYPE_MAX,
};

/* note: keep compatibility with fipcode (alstom) */
enum pwrfip_event_code {
    PWRFIP_EVT_SEND_VAR_P = 0x8100,
    PWRFIP_EVT_SEND_VAR_T = 0x0100,
    PWRFIP_EVT_RECV_VAR_P = 0x8200,
    PWRFIP_EVT_RECV_VAR_T = 0x0200,
    PWRFIP_EVT_RECV_MSG = 0x0240,
    PWRFIP_EVT_SEND_MSG = 0x0140,
    PWRFIP_EVT_SEND_APU = 0x0130,
    PWRFIP_EVT_SEND_APN = 0x0131,
    PWRFIP_EVT_BA_ACTIVITY = 0x0400,
    /* ba has stopped on timeout (after wait sync) */
    PWRFIP_EVT_BA_STOP_TMO = 0x0401,
    /* ba has stopped on network fault */
    PWRFIP_EVT_BA_STOP_ERR = 0x0402,
    /* ba has stopped after user request */
    PWRFIP_EVT_BA_STOP_USR = 0x0404,
    PWRFIP_EVT_BA_IDLE = 0x0408,
};

/**
 * STRUCTURES
 */
#pragma pack(1) // 1 byte alignment

struct pwrfip_date {
    union {
        uint32_t raw;
        struct {
            uint8_t day;
            uint8_t month;
            uint8_t year;
            uint8_t reserved;
        } info;
    };
};

struct pwrfip_version {
    union {
        uint32_t raw;
        struct {
            uint8_t patch;
            uint8_t minor;
            uint8_t major;
            uint8_t reserved;
        } info;
    };
    /* build date */
    struct pwrfip_date date;
};

/* struct: status/report */
struct pwrfip_node_status {
    uint16_t state; /* enum pwrfip_node_state */
    uint16_t op; /* enum pwrfip_node_operation */
    /* sensors */
    int16_t temperature; /* 2's complement (16-bit signed) */
    uint16_t reserved;
};
#define PWRFIP_NODE_STATUS_BSZ (sizeof(struct pwrfip_node_status))

struct pwrfip_ba_status {
    uint16_t state; /* enum pwrfip_ba_state */
    uint16_t window; /* enum pwrfip_ba_wind_type */
    uint32_t index; /* current macrocycle index */
};
#define PWRFIP_BA_STATUS_BSZ (sizeof(struct pwrfip_ba_status))

struct pwrfip_medium_status {
    uint16_t state; /* enum pwrfip_medium_state */
    uint16_t reserved;
};
#define PWRFIP_MEDIUM_STATUS_BSZ (sizeof(struct pwrfip_medium_status))

struct pwrfip_tx_err {
    /**
     * Medium Attachment Unit (MAU) errors
     */
    /* no mau tx error occurs */
    uint64_t ok;
    /* collision: other frame present on network */
    uint64_t collision;
    /* problem of consistency between send and read-back data */
    uint64_t consistency;
    uint64_t reserved[5];
    /**
     * Application layer errors
     */
    /* tx var is not correctly refreshed inside local database.
      (refreshment period has expired) */
    uint64_t not_fresh;
};

#define PWRFIP_TX_ERR_WSZ (sizeof(struct pwrfip_tx_err) / 4)

struct pwrfip_rx_err {
    /**
     * MAU frame errors
     */
    /* no mau rx error occurs */
    uint64_t ok;
    /* -> Physical Layer errors */
    /* missing preamble (glitches on line) */
    uint64_t pre_mis;
    /* missing Frame Start Delimiter (FSD) */
    uint64_t fsd_mis;
    /* unknown Frame Start Delimiter (FSD) */
    uint64_t fsd_unk;
    /* missing Frame End Delimiter (FED) */
    uint64_t fed_mis;
    /* -> Data-Link Layer errors */
    /* wrong Cyclic Redundancy Check (CRC) */
    uint64_t crc_bad;
    uint64_t reserved[10];
    /**
     * Application layer errors
     */
    /* unknown FIP Protocol Data Unit (PDU) */
    uint64_t pdu_bad;
    /* bad FIP frame length (LEN) */
    uint64_t len_bad;
    /* rx var has not been correctly refreshed
     * by a remote fip node (agent) */
    uint64_t not_fresh;
    /* var is not prompt.
     * local database hasn't been read (by the user)
     * during promptness period */
    uint64_t not_prompt;
};
#define PWRFIP_RX_ERR_WSZ (sizeof(struct pwrfip_rx_err) / 4)

struct pwrfip_node_report {
    struct pwrfip_node_status node_status;
    struct pwrfip_ba_status ba_status;
    struct pwrfip_medium_status medium_status;
    /* stats */
    struct pwrfip_tx_err tx_err;
    struct pwrfip_rx_err rx_err;
};
#define PWRFIP_NODE_REPORT_BSZ (sizeof(struct pwrfip_node_report))

struct pwrfip_event {
    uint64_t epoch;
    uint16_t code; /* enum pwrfip_event_code */
    uint16_t param;
    uint32_t reserved[2];
};
#define PWRFIP_EVENT_BSZ (sizeof(struct pwrfip_event))
#define PWRFIP_EVENT_WSZ (PWRFIP_EVENT_BSZ / 4)
#define PWRFIP_EVENT_MAX 32

struct pwrfip_irq {
    uint32_t src; /**< irq source event (see enum pwrfip_irq_flags) */
    uint64_t cnt;
    /* extras: used for synchronous events */
    struct pwrfip_event evt;
};
#define PWRFIP_IRQ_BSZ (sizeof(struct pwrfip_irq))

#pragma pack()

#endif /* __POWERFIP_COMMON_H */
