Commit 4bfaea77 authored by Jean-Claude BAU's avatar Jean-Claude BAU Committed by Adam Wujek

High Accuracy - first implementation

This implementation works on a WR Switch but does not yet integrate all
required functionalities. List of current modifications :
- Implementation of the L1SYNC protocol
- Modifications of the standard protocol: new hook, TS calculation
- Change WRS to integrate HA
- HAL adaptations
- ...
parent 41bedca5
......@@ -116,7 +116,7 @@ config PROFILE_WR
config PROFILE_HA
bool
default n if ARCH_WRS || ARCH_WRPC
default y if ARCH_WRS || ARCH_WRPC
config PROFILE_PTP
bool
......
......@@ -80,7 +80,6 @@ typedef struct {
#define HEXP_PORT_MODE_WR_SLAVE 2
#define HEXP_PORT_MODE_NON_WR 3
#define FIX_ALPHA_FRACBITS 40
/*
#define HEXP_PORT_TSC_RISING 1
#define HEXP_PORT_TSC_FALLING 2
......
......@@ -39,6 +39,9 @@ typedef struct hal_port_calibration {
uint32_t delta_tx_phy;
uint32_t delta_rx_phy;
/* bit slide expresse in picos */
uint32_t bitslide_ps;
/* Current board routing delays (between the DDMTD inputs to
the PHY clock inputs/outputs), in picoseconds */
uint32_t delta_tx_board;
......
......@@ -40,17 +40,19 @@ extern void wrs_main_loop(struct pp_globals *ppg);
extern void wrs_init_ipcserver(struct minipc_ch *ppsi_ch);
/* wrs-calibration.c */
int wrs_read_calibration_data(struct pp_instance *ppi,
uint32_t *delta_tx, uint32_t *delta_rx,
int32_t *fix_alpha, int32_t *clock_period);
int wrs_read_calibration_data(struct pp_instance *ppi, uint32_t *delta_tx,
uint32_t *delta_rx, int32_t *fix_alpha, int32_t *clock_period,
uint32_t *bit_slide_ps);
int wrs_calibrating_disable(struct pp_instance *ppi, int txrx);
int wrs_calibrating_enable(struct pp_instance *ppi, int txrx);
int wrs_calibrating_poll(struct pp_instance *ppi, int txrx, uint32_t *delta);
int wrs_calibration_pattern_enable(struct pp_instance *ppi,
unsigned int calib_period,
unsigned int calib_pattern,
unsigned int calib_pattern_len);
unsigned int calib_period, unsigned int calib_pattern,
unsigned int calib_pattern_len);
int wrs_calibration_pattern_disable(struct pp_instance *ppi);
int wrs_read_correction_data(struct pp_instance *ppi, int64_t *fixAlpha,
int32_t *clock_period_ps, uint32_t *bit_slide_ps);
/* wrs-time.c (some should moce to wrs-spll.c) */
int wrs_locking_enable(struct pp_instance *ppi);
......
......@@ -50,7 +50,15 @@ static int run_all_state_machines(struct pp_globals *ppg)
ppi->iface_name, ppi->link_up ? "up":"down");
if (ppi->link_up) {
uint32_t bit_slide_ps;
ppi->state = PPS_INITIALIZING;
if ( wrs_read_correction_data(ppi,NULL,NULL,&bit_slide_ps)!= WRH_HW_CALIB_OK ) {
pp_diag(ppi, fsm, 1, "Cannot read bit_slide value values\n");
bit_slide_ps=0;
}
pp_diag(ppi, fsm, 1, "semistaticLatency(bit-slide)=%u [ps]\n",bit_slide_ps);
ppi->timestampCorrectionPortDS.semistaticLatency= picos_to_interval(bit_slide_ps);
}
else {
ppi->next_state = PPS_DISABLED;
......
......@@ -15,7 +15,7 @@
int wrs_read_calibration_data(struct pp_instance *ppi,
uint32_t *delta_tx, uint32_t *delta_rx, int32_t *fix_alpha,
int32_t *clock_period)
int32_t *clock_period, uint32_t *bit_slide_ps)
{
struct hal_port_state *p;
/* The following fields come from struct hexp_port_state */
......@@ -35,17 +35,21 @@ int wrs_read_calibration_data(struct pp_instance *ppi,
* way as the HAL itself was doing to fill the RPC structure.
* Formulas copied from libwr/hal_shmem.c (get_exported_state).
*/
port_delta_tx = p->calib.delta_tx_phy
+ p->calib.sfp.delta_tx_ps + p->calib.delta_tx_board;
port_delta_rx = p->calib.delta_rx_phy
+ p->calib.sfp.delta_rx_ps + p->calib.delta_rx_board;
port_fix_alpha = (double)pow(2.0, 40.0) *
((p->calib.sfp.alpha + 1.0) / (p->calib.sfp.alpha + 2.0)
- 0.5);
pp_diag(ppi, servo, 1, "deltas: tx=%d, rx=%d\n",
port_delta_tx, port_delta_rx);
if ( delta_tx || delta_rx) {
port_delta_tx = p->calib.delta_tx_phy
+ p->calib.sfp.delta_tx_ps + p->calib.delta_tx_board;
port_delta_rx = p->calib.delta_rx_phy
+ p->calib.sfp.delta_rx_ps + p->calib.delta_rx_board;
pp_diag(ppi, servo, 1, "deltas: tx=%d, rx=%d\n",
port_delta_tx, port_delta_rx);
}
if ( bit_slide_ps )
*bit_slide_ps=p->calib.bitslide_ps;
if(delta_tx)
*delta_tx = port_delta_tx;
if(delta_rx)
......@@ -57,6 +61,24 @@ int wrs_read_calibration_data(struct pp_instance *ppi,
return WRH_HW_CALIB_OK;
}
int wrs_read_correction_data(struct pp_instance *ppi, int64_t *fiber_fix_alpha,
int32_t *clock_period_ps, uint32_t *bit_slide_ps) {
double alpha;
int32_t port_cP;
wrs_read_calibration_data(ppi, NULL, NULL,NULL, &port_cP, bit_slide_ps);
if(fiber_fix_alpha) {
alpha = ((double) ppi->asymmetryCorrectionPortDS.scaledDelayCoefficient)/(double)pow(2.0, REL_DIFF_FRACBITS_AS_FLOAT);
*fiber_fix_alpha = (double)pow(2.0, FIX_ALPHA_FRACBITS_AS_FLOAT) * ((alpha + 1.0) / (alpha + 2.0) - 0.5);
}
if(clock_period_ps)
*clock_period_ps = port_cP; /* REF_CLOCK_PERIOD_PS */
return WRH_HW_CALIB_OK;
}
int wrs_calibrating_disable(struct pp_instance *ppi, int txrx)
{
return 0;
......@@ -71,7 +93,7 @@ int wrs_calibrating_poll(struct pp_instance *ppi, int txrx, uint32_t *delta)
{
uint32_t delta_tx, delta_rx;
wrs_read_calibration_data(ppi, &delta_tx, &delta_rx, NULL, NULL);
wrs_read_calibration_data(ppi, &delta_tx, &delta_rx, NULL, NULL, NULL);
*delta = (txrx == WRH_HW_CALIB_TX) ? delta_tx : delta_rx;
......
......@@ -45,7 +45,7 @@ struct wrh_operations wrh_oper = {
.adjust_in_progress = wrs_adjust_in_progress,
.adjust_counters = wrs_adjust_counters,
.adjust_phase = wrs_adjust_phase,
.read_corr_data = wrs_read_correction_data,
.read_calib_data = wrs_read_calibration_data,
.calib_disable = wrs_calibrating_disable,
.calib_enable = wrs_calibrating_enable,
......@@ -210,13 +210,22 @@ int main(int argc, char **argv)
if (ppg->cfg.cfg_items == 0)
pp_config_file(ppg, 0, PP_DEFAULT_CONFIGFILE);
if (ppg->cfg.cfg_items == 0) {
/* Default configuration for WR switch is all ports */
/* Default configuration for switch is all ports - Priority given to HA */
char s[128];
int i;
for (i = 0; i < 18; i++) {
Boolean configured=FALSE;
#if CONFIG_EXT_L1SYNC == 1
sprintf(s, "port %i; iface wri%i; proto raw;"
"extension whiterabbit; role auto", i + 1, i + 1);
"profile ha; role auto", i + 1, i + 1);
configured=TRUE;
#endif
#if CONFIG_EXT_WR == 1
if ( ! configured )
sprintf(s, "port %i; iface wri%i; proto raw;"
"profile wr; role auto", i + 1, i + 1);
#endif
pp_config_string(ppg, s);
}
}
......@@ -254,7 +263,7 @@ int main(int argc, char **argv)
if ( ppi->cfg.profile==PPSI_PROFILE_HA ) {
ppi->protocol_extension=PPSI_EXT_L1S;
/* Add L1E extension portDS */
if ( !(ppi->portDS->ext_dsport =alloc_fn(ppsi_head, sizeof(struct l1e_ext_portDS))) ) {
if ( !(ppi->portDS->ext_dsport =alloc_fn(ppsi_head, sizeof(l1e_ext_portDS_t))) ) {
goto exit_out_of_memory;
}
......@@ -262,7 +271,13 @@ int main(int argc, char **argv)
if (! (ppi->ext_data = alloc_fn(ppsi_head,sizeof(struct l1e_data))) ) {
goto exit_out_of_memory;
}
/* Set ingress/egress latencies */
ppi->timestampCorrectionPortDS.egressLatency=picos_to_interval(ppi->cfg.egressLatency_ps);
ppi->timestampCorrectionPortDS.ingressLatency=picos_to_interval(ppi->cfg.ingressLatency_ps);
ppi->timestampCorrectionPortDS.messageTimestampPointLatency=0;
ppi->asymmetryCorrectionPortDS.constantAsymmetry=picos_to_interval(ppi->cfg.constantAsymmetry_ps);
ppi->asymmetryCorrectionPortDS.scaledDelayCoefficient=
(RelativeDifference)(ppi->cfg.delayCoefficient * (double)pow(2.0, REL_DIFF_FRACBITS_AS_FLOAT));
/* Set L1SYNC extension hooks */
ppi->ext_hooks=&l1e_ext_hooks;
/* Set default profile parameters */
......
......@@ -32,7 +32,17 @@ void __pp_diag(struct pp_instance *ppi, enum pp_diag_things th,
return;
/* Use the normal output channel for diagnostics */
pp_printf("%s-%i-%s: ", thing_name[th], level, name);
if (PP_DIAG_EXTRA_PRINT_TIME) {
int hours, minutes, seconds;
if (ppi && ppi->t_ops && ppi->t_ops->get_utc_time )
ppi->t_ops->get_utc_time(ppi, &hours, &minutes, &seconds);
else
hours=minutes=seconds=0;
pp_printf("%02d:%02d:%02d %s-%i-%s: ", hours, minutes,seconds,thing_name[th], level, name);
} else {
pp_printf("%s-%i-%s: ", thing_name[th], level, name);
}
va_start(args, fmt);
pp_vprintf(fmt, args);
va_end(args);
......
......@@ -65,7 +65,7 @@ static void pp_diag_fsm(struct pp_instance *ppi, char *name, int sequence,
static struct pp_state_table_item *
get_current_state_table_item(struct pp_instance *ppi)
{
struct pp_state_table_item *ip = ppi->current_state_item;;
struct pp_state_table_item *ip = ppi->current_state_item;
/* Avoid searching if we already know where we are */
ppi->is_new_state = 0;
......@@ -82,6 +82,17 @@ get_current_state_table_item(struct pp_instance *ppi)
return NULL;
}
char *get_state_as_string(struct pp_instance *ppi, int state) {
static char *def="INVALID";
struct pp_state_table_item *ip = ppi->current_state_item;
for (ip = pp_state_table; ip->state != PPS_END_OF_TABLE; ip++)
if (ip->state == state) {
return ip->name;
}
return def;
}
/*
* Returns delay to next state, which is always zero.
*/
......@@ -293,5 +304,11 @@ int pp_state_machine(struct pp_instance *ppi, void *buf, int len)
if (pp_next_delay_1(ppi, PP_TO_BMC) < ppi->next_delay)
ppi->next_delay = pp_next_delay_1(ppi, PP_TO_BMC);
/* Run the extension state machine. The extension can provide its own time-out */
if ( ppi->ext_hooks->run_ext_state_machine) {
int delay = ppi->ext_hooks->run_ext_state_machine(ppi);
ppi->next_delay= (delay < ppi->next_delay) ? delay : ppi->next_delay;
}
return ppi->next_delay;
}
......@@ -74,7 +74,7 @@ struct wrh_operations {
int (*read_calib_data)(struct pp_instance *ppi,
uint32_t *deltaTx, uint32_t *deltaRx,
int32_t *fix_alpha, int32_t *clock_period);
int32_t *fix_alpha, int32_t *clock_period, uint32_t *bit_slide_ps);
int (*calib_disable)(struct pp_instance *ppi, int txrx);
int (*calib_enable)(struct pp_instance *ppi, int txrx);
int (*calib_poll)(struct pp_instance *ppi, int txrx, uint32_t *delta);
......@@ -85,10 +85,8 @@ struct wrh_operations {
int (*calib_pattern_disable)(struct pp_instance *ppi);
int (*enable_timing_output)(struct pp_instance *ppi, int enable);
int (*servo_hook)(struct pp_instance *ppi, int action);
int (*read_corr_data)(struct pp_instance *ppi, int64_t *delayCoeff,
int64_t *ingressLatency, int64_t *egressLatency,
int64_t *msgTPointLatency, int64_t *delayAsymmetry,
int64_t *fixAlpha, int32_t *clock_period );
int (*read_corr_data)(struct pp_instance *ppi, int64_t *fixAlpha,
int32_t *clock_period, uint32_t *bit_slide_ps);
};
......
......@@ -69,6 +69,9 @@ extern void __pp_diag(struct pp_instance *ppi, enum pp_diag_things th,
# define PP_HAS_DIAG 1
#endif
/* Constant used to enable extra diagnostic information - Inserted at compilation time */
#define PP_DIAG_EXTRA_PRINT_TIME (1 && PP_HAS_DIAG) /* Print time on each pp_diag calls */
/* So, this is the function that is to be used by real ppsi code */
#define pp_diag(ppi_, th_, level_, ...) \
({ \
......
......@@ -134,6 +134,10 @@ struct pp_instance_cfg {
char iface_name[16];
int profile; /* PPSI_PROFILE_PTP, PPSI_PROFILE_WR, PPSI_PROFILE_HA */
int delayMechanism; /* Should be enum ENDelayMechanism but forced to int for configuration parsing */
int64_t egressLatency_ps;
int64_t ingressLatency_ps;
int64_t constantAsymmetry_ps;
double delayCoefficient;
};
/*
......
......@@ -190,6 +190,7 @@ struct pp_ext_hooks {
int (*handle_signaling) (struct pp_instance * ppi, void *buf, int len);
int (*pack_announce)(struct pp_instance *ppi);
void (*unpack_announce)(void *buf, MsgAnnounce *ann);
int (*ready_for_slave)(struct pp_instance *ppi); /* returns: 0=Not ready 1=ready */
int (*state_decision)(struct pp_instance *ppi, int next_state);
void (*state_change)(struct pp_instance *ppi);
int (*run_ext_state_machine) (struct pp_instance *ppi);
......@@ -286,6 +287,8 @@ struct pp_cfg_time {
union pp_cfg_arg {
int i;
int i2[2];
int64_t i64;
double d;
char *s;
struct pp_cfg_time ts;
};
......@@ -309,6 +312,8 @@ enum pp_argtype {
ARG_STR,
ARG_NAMES,
ARG_TIME,
ARG_DOUBLE,
ARG_INT64
};
struct pp_argline {
cfg_handler f;
......@@ -458,6 +463,8 @@ extern void pp_time_sub(struct pp_time *t1, struct pp_time *t2);
extern void pp_time_div2(struct pp_time *t);
extern TimeInterval pp_time_to_interval(struct pp_time *ts);
extern TimeInterval picos_to_interval(int64_t picos);
extern void pp_time_add_interval(struct pp_time *t1, TimeInterval t2);
extern void pp_time_sub_interval(struct pp_time *t1, TimeInterval t2);
/* Function for time conversion */
extern int64_t pp_time_to_picos(struct pp_time *ts);
......
......@@ -82,6 +82,42 @@ int f_simple_int(struct pp_argline *l, int lineno,
return 0;
}
static inline void ASSIGN_INT64_FIELD(struct pp_argline *l,
struct pp_globals *ppg,
int64_t v)
{
if (l->needs_port)
*(int64_t *)(((void *)CUR_PPI(ppg)) + l->field_offset) = v;
else
*(int64_t *)(((void *)GOPTS(ppg)) + l->field_offset) = v;
}
static int f_simple_int64(struct pp_argline *l, int lineno,
struct pp_globals *ppg, union pp_cfg_arg *arg)
{
CHECK_PPI(l->needs_port);
ASSIGN_INT64_FIELD(l, ppg, arg->i64);
return 0;
}
static inline void ASSIGN_DOUBLE_FIELD(struct pp_argline *l,
struct pp_globals *ppg,
double v)
{
if (l->needs_port)
*(double *)(((void *)CUR_PPI(ppg)) + l->field_offset) = v;
else
*(double *)(((void *)GOPTS(ppg)) + l->field_offset) = v;
}
static int f_simple_double( struct pp_argline *l, int lineno,
struct pp_globals *ppg, union pp_cfg_arg *arg)
{
CHECK_PPI(l->needs_port);
ASSIGN_DOUBLE_FIELD(l, ppg, arg->d);
return 0;
}
static int f_if(struct pp_argline *l, int lineno, struct pp_globals *ppg,
union pp_cfg_arg *arg)
{
......@@ -195,7 +231,7 @@ static int f_announce_intvl(struct pp_argline *l, int lineno,
pp_printf("config line %i: announce interval out of range: %i, "
"forced to %i\n", lineno, arg->i, i);
}
GOPTS(ppg)->announce_intvl = i;
GOPTS(ppg)->logAnnounceInterval = i;
return 0;
}
......@@ -246,6 +282,10 @@ static struct pp_argline pp_global_arglines[] = {
INST_OPTION_INT("extension", ARG_NAMES, arg_profile, cfg.profile), /* TODO: stay for backward compatibility. Should be removed in the future */
INST_OPTION_INT("profile", ARG_NAMES, arg_profile, cfg.profile),
INST_OPTION_INT("mechanism", ARG_NAMES, arg_delayMechanism, cfg.delayMechanism),
INST_OPTION_INT64("egressLatency", ARG_INT64, NULL,cfg.egressLatency_ps),
INST_OPTION_INT64("ingressLatency", ARG_INT64, NULL,cfg.ingressLatency_ps),
INST_OPTION_DOUBLE("delayCoefficient", ARG_DOUBLE, NULL,cfg.delayCoefficient),
INST_OPTION_INT64("constantAsymmetry", ARG_INT64, NULL,cfg.constantAsymmetry_ps),
LEGACY_OPTION(f_vlan, "vlan", ARG_STR),
LEGACY_OPTION(f_diag, "diagnostic", ARG_STR),
RT_OPTION_INT("clock-class", ARG_INT, NULL, clock_quality.clockClass),
......@@ -254,11 +294,11 @@ static struct pp_argline pp_global_arglines[] = {
RT_OPTION_INT("clock-allan-variance", ARG_INT, NULL,
clock_quality.offsetScaledLogVariance),
LEGACY_OPTION(f_servo_pi, "servo-pi", ARG_INT2),
RT_OPTION_INT("domain-number", ARG_INT, NULL, domain_number),
RT_OPTION_INT("domain-number", ARG_INT, NULL, domainNumber),
LEGACY_OPTION(f_announce_intvl, "announce-interval", ARG_INT),
RT_OPTION_INT("sync-interval", ARG_INT, NULL, sync_intvl),
RT_OPTION_INT("priority1", ARG_INT, NULL, prio1),
RT_OPTION_INT("priority2", ARG_INT, NULL, prio2),
RT_OPTION_INT("sync-interval", ARG_INT, NULL, logSyncInterval),
RT_OPTION_INT("priority1", ARG_INT, NULL, priority1),
RT_OPTION_INT("priority2", ARG_INT, NULL, priority2),
{}
};
......@@ -425,6 +465,13 @@ static int pp_config_line(struct pp_globals *ppg, char *line, int lineno)
}
break;
case ARG_INT64:
if (sscanf(line, "%lli", &(cfg_arg.i64)) != 1) {
pp_error("line %i: \"%s\"[%s]: not int64\n", lineno, word,line);
return -1;
}
break;
case ARG_INT2:
if (sscanf(line, "%i,%i", cfg_arg.i2, &cfg_arg.i2[1]) < 0) {
pp_error("line %i: wrong arg \"%s\" for \"%s\"\n",
......@@ -433,6 +480,13 @@ static int pp_config_line(struct pp_globals *ppg, char *line, int lineno)
}
break;
case ARG_DOUBLE:
if (sscanf(line, "%lf", &cfg_arg.d) < 0) {
pp_error("line %i: wrong arg \"%s\" for \"%s\"\n",
lineno, line, word);
return -1;
}
break;
case ARG_STR:
while (*line && blank(*line))
line++;
......
......@@ -35,6 +35,20 @@ void normalize_pp_time(struct pp_time *t)
t->scaled_nsecs *= sign;
}
/* Add a TimeInterval to a pp_time */
void pp_time_add_interval(struct pp_time *t1, TimeInterval t2)
{
t1->scaled_nsecs += t2;
normalize_pp_time(t1);
}
/* Substract a TimeInterval to a pp_time */
void pp_time_sub_interval(struct pp_time *t1, TimeInterval t2)
{
t1->scaled_nsecs -= t2;
normalize_pp_time(t1);
}
void pp_time_add(struct pp_time *t1, struct pp_time *t2)
{
t1->secs += t2->secs;
......
# All files are under directory D: I'm lazy
D := proto-ext-l1sync
OBJ-y += $D/l1e-hooks.o \
$D/l1e-servo.o\
$D/l1e-msg.o\
$D/l1e-state-machine.o
\ No newline at end of file
/*
* Copyright (C) 2018 CERN (www.cern.ch)
* Author: Jean-Claude BAU & Maciej Lipinski
*
* Released according to the GNU LGPL, version 2.1 or any later version.
*/
#ifndef __L1SYNC_EXT_API_H__
#define __L1SYNC_EXT_API_H__
#if CONFIG_EXT_L1SYNC == 1
#define PROTO_EXT_L1SYNC (1)
#else
#define PROTO_EXT_L1SYNC (0)
#endif
#if CONFIG_EXT_L1SYNC == 1
#include <ppsi/lib.h>
#include "../include/hw-specific/wrh.h"
#include "l1e-constants.h"
#include <math.h>
/* Rename the timeouts, for readability */
#define L1E_TIMEOUT_TX_SYNC PP_TO_EXT_0
#define L1E_TIMEOUT_RX_SYNC PP_TO_EXT_1
#define L1E_DEFAULT_L1SYNCRECEIPTTIMEOUT 5 /* was 3: need more for pll lock */
/*
* We don't have ha_dsport, but rather rely on wr_dsport with our fields added.
*
*
* Fortunately (and strangely (thanks Maciej), here the spec *is* consistent.
* These 3 bits are valid 4 times, in 4 different bytes (conf/active, me/peer)
*/
#define L1E_TX_COHERENT 0x01
#define L1E_RX_COHERENT 0x02
#define L1E_CONGRUENT 0x04
#define L1E_OPT_PARAMS 0x08
enum l1_sync_states { /*draft P1588_v_29: page 334 */
__L1SYNC_MISSING = 0, /* my addition... */ //TODO: std-error->report in ballout
L1SYNC_DISABLED = 1,
L1SYNC_IDLE,
L1SYNC_LINK_ALIVE,
L1SYNC_CONFIG_MATCH,
L1SYNC_UP,
};
/* Pack/Unkpack L1SYNC messages (all of them are signalling messages) */
int l1e_pack_signal(struct pp_instance *ppi);
int l1e_unpack_signal(struct pp_instance *ppi, void *pkt, int plen);
/*
* These structures are used as extension-specific data in the DSPort
* ()
*/
typedef struct { /*draft P1588_v_29: page 100 and 333-335 */
/* configurable members */
Boolean L1SyncEnabled;
Boolean txCoherentIsRequired;
Boolean rxCoherentIsRequired;
Boolean congruentIsRequired;
Boolean optParamsEnabled;
Integer8 logL1SyncInterval;
Integer8 L1SyncReceiptTimeout;
/* dynamic members */
Boolean L1SyncLinkAlive;
Boolean isTxCoherent;
Boolean isRxCoherent;
Boolean isCongruent;
Enumeration8 L1SyncState;
Boolean peerTxCoherentIsRequired;
Boolean peerRxCoherentIsRequired;
Boolean peerCongruentIsRequired;
Boolean peerIsTxCoherent;
Boolean peerIsRxCoherent;
Boolean peerIsCongruent;
/* None compliant members with IEEE1558-2018 */
Enumeration8 next_state;
} L1SyncBasicPortDS_t;
typedef struct { /*draft P1588_v_29: page 101 and 340-341 */
/* configurable members */
Boolean timestampsCorrectedTx;
/* dynamic members */
Boolean phaseOffsetTxValid;
Boolean frequencyOffsetTxValid;
struct pp_time phaseOffsetTx;
Timestamp phaseOffsetTxTimesatmp;
struct pp_time frequencyOffsetTx;
Timestamp frequencyOffsetTxTimesatmp;
} L1SyncOptParamsPortDS_t;
/* Add all extension port DS related structure must be store here */
typedef struct {
wrh_portds_head_t head; /* Must be always at the first place */
L1SyncBasicPortDS_t basic;
L1SyncOptParamsPortDS_t opt_params;
Boolean parentExtModeOn;
}l1e_ext_portDS_t;
static inline l1e_ext_portDS_t *L1E_DSPOR(struct pp_instance *ppi)
{
return (l1e_ext_portDS_t *) ppi->portDS->ext_dsport;
}
static inline L1SyncBasicPortDS_t *L1E_DSPOR_BS(struct pp_instance *ppi)
{
return &L1E_DSPOR(ppi)->basic;
}
static inline L1SyncOptParamsPortDS_t *L1E_DSPOR_OP(struct pp_instance *ppi)
{
return &L1E_DSPOR(ppi)->opt_params;
}
/****************************************************************************************/
/* l1e_servo interface */
struct l1e_servo_state {
int state;
/* These fields are used by servo code, after setting at init time */
int64_t fiber_fix_alpha;
int32_t clock_period_ps;
/* Following fields are for monitoring/diagnostics (use w/ shmem) */
struct pp_time delayMM;
int64_t delayMM_ps;
int32_t cur_setpoint_ps;
int64_t delayMS_ps;
int tracking_enabled;
int64_t skew_ps;
int64_t offsetMS_ps;
/* Values used by snmp. Values are increased at servo update when
* erroneous condition occurs. */
uint32_t n_err_state;
uint32_t n_err_offset;
uint32_t n_err_delta_rtt;
struct pp_time update_time;
/* These fields are used by servo code, across iterations */
struct pp_time t1, t2, t3, t4, t5, t6;
int64_t prev_delayMS_ps;
int missed_iters;
};
/* Prototypes */
int l1e_servo_init(struct pp_instance *ppi);
void l1e_servo_reset(struct pp_instance *ppi);
void l1e_servo_enable_tracking(int enable);
int l1e_servo_got_sync(struct pp_instance *ppi, struct pp_time *t1,
struct pp_time *t2);
int l1e_servo_got_delay(struct pp_instance *ppi);
int l1e_servo_update(struct pp_instance *ppi);
uint8_t l1e_creat_L1Sync_bitmask(int tx_coh, int rx_coh, int congru);
void l1e_print_L1Sync_basic_bitmaps(struct pp_instance *ppi,
uint8_t configed, uint8_t active, char* text);
void l1e_servo_enable_tracking(int enable);
int l1e_update_correction_values(struct pp_instance *ppi);
int l1e_run_state_machine(struct pp_instance *ppi);
/* All data used as extension ppsi l1sync must be put here */
struct l1e_data {
struct l1e_servo_state servo_state;
};
static inline struct l1e_servo_state *L1E_SRV(struct pp_instance *ppi)
{
return &((struct l1e_data *)ppi->ext_data)->servo_state;
}
extern struct pp_ext_hooks l1e_ext_hooks;
#endif /* CONFIG_EXT_L1SYNC == 1 */
#endif /* __L1SYNC_EXT_API_H__ */
/*
* Copyright (C) 2018 CERN (www.cern.ch)
* Author: Jean-Claude BAU & Maciej Lipinski
*
* Released according to the GNU LGPL, version 2.1 or any later version.
*/
#ifndef __L1SYNC_EXT_CONSTANTS_H__
#define __L1SYNC_EXT_CONSTANTS_H__
/* Define threshold values for SNMP */
#define SNMP_MAX_OFFSET_PS 500
#define SNMP_MAX_DELTA_RTT_PS 1000
/* L1SYNC Servo */
enum {
L1E_UNINITIALIZED = 0,
L1E_SYNC_NSEC,
L1E_SYNC_TAI,
L1E_SYNC_PHASE,
L1E_TRACK_PHASE,
L1E_WAIT_OFFSET_STABLE,
};
#endif /* __L1SYNC_EXT_CONSTANTS_H__ */
/*
* Copyright (C) 2018 CERN (www.cern.ch)
* Author: Jean-Claude BAU & Maciej Lipinski
*
* Released according to the GNU LGPL, version 2.1 or any later version.
*/
#include <inttypes.h>
#include <ppsi/ppsi.h>
#include <common-fun.h>
#include "l1e-api.h"
#include "l1e-constants.h"
#include <math.h>
char *l1e_state_name[] = {
[L1SYNC_DISABLED] = "L1SYNC_DISABLED",
[L1SYNC_IDLE] = "L1SYNC_IDLE",
[L1SYNC_LINK_ALIVE] = "L1SYNC_LINK_ALIVE",
[L1SYNC_CONFIG_MATCH] = "L1SYNC_CONFIG_MATCH",
[L1SYNC_UP] = "L1SYNC_UP",
};
void l1e_print_L1Sync_basic_bitmaps(struct pp_instance *ppi, uint8_t configed,
uint8_t active, char* text)
{
pp_diag(ppi, ext, 2, "ML: L1Sync %s\n", text);
pp_diag(ppi, ext, 2, "ML: \tConfig: TxC=%d RxC=%d Cong=%d Param=%d\n",
((configed & L1E_TX_COHERENT) == L1E_TX_COHERENT),
((configed & L1E_RX_COHERENT) == L1E_RX_COHERENT),