#ifndef LIP_PHY_STATS_H
#define LIP_PHY_STATS_H

#include "lip_config.h"
#include "lip_phy.h"

#if LIP_PHY_USE_STATS
void lip_phy_stats_par_add_avg_val(t_lip_phy_par_avg_buf *par, uint16_t val, t_lip_phy_par_value *res);
void lip_phy_stats_par_add_wc(uint16_t val, t_lip_phy_par_value *res, bool pos);
void lip_phy_stats_par_add_cntr(uint16_t val, t_lip_phy_par_value *res);

static inline void lip_phy_stats_sqi_upd(t_lip_phy_stats *stats, uint8_t pair_num, uint16_t val, uint16_t wc) {
    t_lip_phy_stats_pair_ctx     *pair_ctx = &stats->ctx.link.pairs[pair_num];
    t_lip_phy_stats_pair_results *pair_res = &stats->results.link.pairs[pair_num];
    lip_phy_stats_par_add_avg_val(&pair_ctx->sqi.avg, val, &pair_res->sqi.cur);
    lip_phy_stats_par_add_wc(wc, &pair_res->sqi.wc, true);
}

static inline void lip_phy_stats_mse_upd(t_lip_phy_stats *stats, uint8_t pair_num, uint16_t val, uint16_t wc) {
    t_lip_phy_stats_pair_ctx     *pair_ctx = &stats->ctx.link.pairs[pair_num];
    t_lip_phy_stats_pair_results *pair_res = &stats->results.link.pairs[pair_num];
    lip_phy_stats_par_add_avg_val(&pair_ctx->mse.avg, val, &pair_res->mse.cur);
    lip_phy_stats_par_add_wc(wc, &pair_res->mse.wc, false);
}

static inline void lip_phy_stats_pmse_upd(t_lip_phy_stats *stats, uint8_t pair_num, uint16_t val, uint16_t wc) {
    t_lip_phy_stats_pair_ctx     *pair_ctx = &stats->ctx.link.pairs[pair_num];
    t_lip_phy_stats_pair_results *pair_res = &stats->results.link.pairs[pair_num];
    lip_phy_stats_par_add_avg_val(&pair_ctx->pmse.avg, val, &pair_res->pmse.cur);
    lip_phy_stats_par_add_wc(wc, &pair_res->pmse.wc, false);
}

static inline void lip_phy_link_wc_stale(t_lip_phy_stats *stats, bool skip_next) {
    const uint16_t flags = LIP_PHY_STATS_PAR_FLAG_STALE | (skip_next ? LIP_PHY_STATS_PAR_FLAG_SKIP_NEXT : 0);
    for (uint8_t pair_num = 0; pair_num < LIP_PHY_MAX_PAIR_CNT; ++pair_num) {
        t_lip_phy_stats_pair_results *pair_res = &stats->results.link.pairs[pair_num];
        pair_res->sqi.wc.flags  |= flags;
        pair_res->mse.wc.flags  |= flags;
        pair_res->pmse.wc.flags |= flags;
    }
#if LIP_PHY_STATS_WC_INTERVAL_MS > 0
    ltimer_restart(&stats->ctx.wc_stale_tmr);
#endif
}


static inline void lip_phy_link_stats_clear(t_lip_phy_stats *stats) {
    memset(&stats->results.link, 0, sizeof(stats->results.link));
    memset(&stats->ctx.link, 0, sizeof(stats->ctx.link));
    lip_phy_link_wc_stale(stats, true);
    stats->results.link.rx_errs_cntr.flags = LIP_PHY_STATS_PAR_FLAG_SKIP_NEXT;
#if LIP_PHY_STATS_WC_INTERVAL_MS > 0
    ltimer_set_ms(&stats->ctx.wc_stale_tmr, LIP_PHY_STATS_WC_INTERVAL_MS);
#endif
    ltimer_set_ms(&stats->ctx.stats_check_tmr, LIP_PHY_STATS_CHECK_INTERVAL_MS);
    stats->ctx.physpec.fsm = 0;
}

void lip_phy_stats_poll(t_lip_phy_ctx *ctx);

#endif


#endif // LIP_PHY_STATS_H

