#include "lip/app/ptp/lip_ptp_cfg_defs.h"
#if LIP_PTP_ENABLE
#include "lip_ptp_nb_rate_ratio.h"
#include "lip/app/ptp/lip_ptp_internal.h"
#include "lip/app/ptp/misc/lip_ptp_tstmp_ops.h"
#include <math.h>


/* обновление вычисления соотношения частот локального клока соседа и своего */
void lip_ptp_nb_rate_ratio_calc(t_lip_ptp_port_ctx *p, const t_ptp_nb_rate_ratio_tsmp *tstmp) {
    t_lip_ptp_nb_rate_ratio_calc_ctx *ctx = &p->nb_rate_ratio;
    /* вычисляем отноншение частот, если накопили минимально достаточное количество отсчетов */
    if (ctx->tstms_cnt >= LIP_PTP_RATE_RATIO_INTERVAL_MIN_CNT) {
        /* Вычисление соотношения частот, как отношение интервалов времени в измерении разных клоков.
         * В качестве начала интервала берем самое старое соотношение времен из очереди.
         * Если очередь полная, то самый старый элемент соответствует тому, который
         * будет перезаписан на текущей итерации новыми данными (tstmps[ctx->tstms_pos]),
         * иначе это элемент в самом начале буфера (tstmps[0]).
         * В качестве конца интервала используем новые отметки времени */
        t_ptp_nb_rate_ratio_tsmp *prev_tstmp = (ctx->tstms_cnt == LIP_PTP_RATE_RATIO_INTERVAL_CNT) ? &ctx->tstmps[ctx->tstms_pos] : &ctx->tstmps[0];
        t_lip_fns t_loc = lip_ptp_tstmp_delta_fns(&tstmp->t_loc, &prev_tstmp->t_loc); /* время интервала по своему локальному клоку */
        t_lip_fns t_rem = lip_ptp_tstmp_delta_fns(&tstmp->t_rem, &prev_tstmp->t_rem); /* время интервала по локальному клоку удаленного узла */
        t_rem += tstmp->t_rem_cor - prev_tstmp->t_rem_cor; /* дополнительная коррекция времен удаленного узла полем коррекции */
        double rate = (double)t_rem/t_loc;
        double drate = (1. - rate) * 1000000;
        /* проверка аномальных отклонений, возможно связанных с перезагрузкой соседнего узла.
         * если обнаружили, то начинаем подсчет rateRatio заново */
        if (fabs(drate) < LIP_PTP_NB_RATE_RATIO_MAX_PPM) {
            p->stats.nbRateRatio = rate;
            p->stats.flags |= LIP_PTP_PORT_STATS_FLAG_NB_RATE_RATIO_VALID;
        } else {
            p->stats.nbRateRatio = 1.;
            p->stats.flags &= ~LIP_PTP_PORT_STATS_FLAG_NB_RATE_RATIO_VALID;
            ctx->tstms_pos = 0;
            ctx->tstms_cnt = 0;
        }

    }

    /* сохраняем новый отсчет времени в конец очереди (с учетом возможного
     * изменения tstms_pos в логике выше) */
    ctx->tstmps[ctx->tstms_pos] = *tstmp;
    /* переход к следующему элементу очереди */
    if (++ctx->tstms_pos == LIP_PTP_RATE_RATIO_INTERVAL_CNT)
        ctx->tstms_pos = 0;

    /* Увеличиваем счетчик действительных меток времени, если уже не накопили макс. кол-во */
    if (ctx->tstms_cnt < LIP_PTP_RATE_RATIO_INTERVAL_CNT) {
        ++ctx->tstms_cnt;
    }
}

void lip_ptp_nb_rate_ratio_init(t_lip_ptp_port_ctx *p) {
    t_lip_ptp_nb_rate_ratio_calc_ctx *ctx = &p->nb_rate_ratio;
    p->stats.nbRateRatio = 1.;
    p->stats.flags &= ~LIP_PTP_PORT_STATS_FLAG_NB_RATE_RATIO_VALID;
    ctx->tstms_pos = 0;
    ctx->tstms_cnt = 0;
    ctx->src = LIP_PTP_RATE_RATIO_SRC_PDELAY;
}
#endif

