#ifndef LIP_PHY_STAT_DEFS_H
#define LIP_PHY_STAT_DEFS_H

#include <stdint.h>
#include <string.h>
#include "ltimer.h"
#include "lip_phy_cfg_defs.h"

#define LIP_PHY_STATS_AVG_BITS              LIP_PHY_STATS_AVG_SIZE_POW2
#define LIP_PHY_STATS_AVG_CNT               (1 << LIP_PHY_STATS_AVG_BITS)
#define LIP_PHY_STATS_PAR_VALUE_MAX         0xFFFFUL

#define LIP_PHY_STATS_PAR_FLAG_VALID        (0x0001UL << 0)
#define LIP_PHY_STATS_PAR_FLAG_STALE        (0x0001UL << 1)
#define LIP_PHY_STATS_PAR_FLAG_SKIP_NEXT    (0x0001UL << 2)



#define LIP_PHY_STATS_PUT_MSE_STD_SHIFT     0
#define LIP_PHY_STATS_PUT_SQI_STD_SHIFT     (LIP_PHY_STATS_PUT_MSE_STD_SHIFT + 6)
#define LIP_PHY_STATS_PUT_PMSE_STD_SHIFT    (LIP_PHY_STATS_PUT_MSE_STD_SHIFT + 3)

#define LIP_PHY_STATS_RES_SQI_SHIFT         (LIP_PHY_STATS_AVG_BITS + LIP_PHY_STATS_PUT_SQI_STD_SHIFT)
#define LIP_PHY_STATS_RES_SQI_FRACT_MSK     ((1UL << LIP_PHY_STATS_RES_SQI_SHIFT) - 1)

#define LIP_PHY_STATS_RES_MSE_MAX_VAL       ((1 << (9 + LIP_PHY_STATS_PUT_MSE_STD_SHIFT + LIP_PHY_STATS_AVG_BITS)) - 1)

/* структура для подсчета среднего значения одного параметра статистики */
typedef struct {
    uint16_t arr[LIP_PHY_STATS_AVG_CNT]; /* массив сохраненных значений */
    uint8_t pos; /* позиция в arr, в которую будет сохранен следующий элемент */
    uint8_t cnt; /* количество действительных элементов в arr */
    uint32_t sum; /* текущий результат вычисления суммы по arr */
} t_lip_phy_par_avg_buf;

/* стурктура для сохранения результирующего значения одного параметра */
typedef struct {
    uint16_t value;
    uint16_t flags;
} t_lip_phy_par_value;

/* структура для сохранения всех результирующих значений одного параметра */
typedef struct {
    t_lip_phy_par_value cur; /* текущее значение */
    t_lip_phy_par_value wc;  /* худшее значение за интервал */
} t_lip_phy_stats_par_result;


/* контекст для расчета одного значения */
typedef struct {
    t_lip_phy_par_avg_buf avg; /* структура для подсчета среденего */
} t_lip_phy_stats_par_ctx;

/* результаты вычисления всех параметров на одну диф. пару */
typedef struct {
    /* параметры по OPEN Alliance TC1 - Advanced diagnostics features for 100BASE-T1 automotive Ethernet PHYs  */
    t_lip_phy_stats_par_result sqi; /* Signal Quality Indicator (SQI) */
    t_lip_phy_stats_par_result mse; /* Mean Square Error (MSE) */
    t_lip_phy_stats_par_result pmse; /* peak Mean Square Error (pMSE)  */
} t_lip_phy_stats_pair_results;


/* общий контекст для всех параметров на одну диф. пару */
typedef struct {
    t_lip_phy_stats_par_ctx sqi;
    t_lip_phy_stats_par_ctx mse;
    t_lip_phy_stats_par_ctx pmse;
} t_lip_phy_stats_pair_ctx;


/* все результаты расчета параметров статистики по PHY */
typedef struct {
    struct {
        /* результаты вычисления параметров, расчитываемых отдельно для каждой диф. пары */
        t_lip_phy_stats_pair_results pairs[LIP_PHY_MAX_PAIR_CNT];
        t_lip_phy_par_value rx_errs_cntr;   /* счетчик ошибок приема */
        t_lip_phy_par_value idle_errs_cntr; /* счетчик ошибок в IDLE символах */
    } link;
    uint32_t link_drop_cnt; /* счетчик событий link-down */
} t_lip_phy_stats_results;

/* общий контекст вычисления статистических параметров по PHY */
typedef struct {
    struct  {
        uint8_t fsm;  /* Текущее состояние автомата получения статистки по PHY. Значения зависят от модели PHY.
                         Значение 0 всегда должно соответветствовать IDLE - опрос статистики завершен.
                         Значение отличное от 0 означает, что процесс опроса статистики в работе,
                         и необходимо повторно вызвать update_states для продвижения автомата до перехода
                         fms в 0 */
        uint8_t pair_num; /* номер диф. пары, по которой собирается статистика */
        uint16_t save_val; /* дополнительная переменная для сохранения значения регистра. использование зависит от PHY */
    } physpec; /* значения, используемые специфической для конкретного PHY логикой */


    /* контекст вычисления параметров по отдельным парам */
    struct {
        t_lip_phy_stats_pair_ctx pairs[LIP_PHY_MAX_PAIR_CNT];
    } link;
#if LIP_PHY_STATS_WC_INTERVAL_MS > 0
    t_ltimer wc_stale_tmr; /* таймер для сброса Worst Case параметров  (если задан таймаут) */
#endif
    t_ltimer stats_check_tmr; /* таймер для интервала запуска проверки параметров */
} t_lip_phy_stats_ctx;

/* общая структура с контекстом расчетов и результатами для статистики по одному PHY */
typedef struct {
    t_lip_phy_stats_results results;
    t_lip_phy_stats_ctx ctx;
} t_lip_phy_stats;

#endif // LIP_PHY_STAT_DEFS_H
