Commit c81db09e authored by baujc's avatar baujc

Big update ...

- New L1Sync and PTP servo calculation (delayAsym,...)
- Make function calls more uniforms between extensions
- refactoring
- Add a new state machine to enable/disable an extension and provide
only PTP support: New timer, new hooks, ...
- Fix bug in time format conversion
- Code removed when an extension is not required (#ifdef XXX )
- Align the PTP and L1Sync servo calculation (shared fct, same
calculation,...)
- Force only one servo running at a given time for a given instance
- New servo reset hook : called by main loop
- Add function to converte a time into a string
- Force to stay in FAULTY state during 60s
- Optimise function wrs_enable_timing_output()
parent d456d2fd
......@@ -69,7 +69,8 @@ static int run_all_state_machines(struct pp_globals *ppg)
ppi->frgn_rec_num = 0;
ppi->frgn_rec_best = -1;
if (ppg->ebest_idx == ppi->port_idx)
wr_servo_reset(ppi);
if( ppi->ext_hooks->servo_reset)
(*ppi->ext_hooks->servo_reset)(ppi);
}
}
......
......@@ -35,9 +35,13 @@ 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).
*/
#if CONFIG_PROFILE_WR == 1
port_fix_alpha = FIX_ALPHA_TWO_POW_FRACBITS *
((p->calib.sfp.alpha + 1.0) / (p->calib.sfp.alpha + 2.0)
- 0.5);
#else
port_fix_alpha =0;
#endif
if ( delta_tx || delta_rx) {
port_delta_tx = p->calib.delta_tx_phy
......@@ -64,15 +68,20 @@ int wrs_read_calibration_data(struct pp_instance *ppi,
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) {
#if CONFIG_PROFILE_WR == 1
double alpha;
alpha = ((double) ppi->asymmetryCorrectionPortDS.scaledDelayCoefficient)/REL_DIFF_TWO_POW_FRACBITS;
*fiber_fix_alpha = FIX_ALPHA_TWO_POW_FRACBITS * ((alpha + 1.0) / (alpha + 2.0) - 0.5);
#else
*fiber_fix_alpha=0;
#endif
}
if(clock_period_ps)
*clock_period_ps = port_cP; /* REF_CLOCK_PERIOD_PS */
return WRH_HW_CALIB_OK;
......
......@@ -102,15 +102,18 @@ static __inline__ double calculateDelayAsymCoefficient(double delayCoefficient
static void enable_asymmetryCorrection(struct pp_instance *ppi, Boolean enable ) {
if ( (ppi->asymmetryCorrectionPortDS.enable=enable)==TRUE ) {
/* Enabled: The delay asymmetry will be calculated */
ppi->asymmetryCorrectionPortDS.scaledDelayCoefficient=
ppi->cfg.scaledDelayCoefficient != 0 ?
ppi->cfg.scaledDelayCoefficient :
(RelativeDifference)(ppi->cfg.delayCoefficient * REL_DIFF_TWO_POW_FRACBITS);
ppi->portDS->delayAsymCoeff=(RelativeDifference)(calculateDelayAsymCoefficient(ppi->cfg.delayCoefficient) * REL_DIFF_TWO_POW_FRACBITS);
} else {
/* Disabled: The delay asymmetry will be provided by the config (constantAsymmetry) */
ppi->asymmetryCorrectionPortDS.constantAsymmetry=picos_to_interval(ppi->cfg.constantAsymmetry_ps);
double delayCoefficient;
if ( ppi->cfg.scaledDelayCoefficient != 0) {
ppi->asymmetryCorrectionPortDS.scaledDelayCoefficient=ppi->cfg.scaledDelayCoefficient;
delayCoefficient=ppi->cfg.scaledDelayCoefficient/REL_DIFF_TWO_POW_FRACBITS;
} else {
ppi->asymmetryCorrectionPortDS.scaledDelayCoefficient=(RelativeDifference)(ppi->cfg.delayCoefficient * REL_DIFF_TWO_POW_FRACBITS);
delayCoefficient=ppi->cfg.delayCoefficient;
}
ppi->portDS->delayAsymCoeff=(RelativeDifference)(calculateDelayAsymCoefficient(delayCoefficient) * REL_DIFF_TWO_POW_FRACBITS);
}
ppi->asymmetryCorrectionPortDS.constantAsymmetry=picos_to_interval(ppi->cfg.constantAsymmetry_ps);
}
int main(int argc, char **argv)
......@@ -266,9 +269,9 @@ int main(int argc, char **argv)
Boolean configured=FALSE;
#if CONFIG_PROFILE_HA == 1
sprintf(s, "port %i; iface wri%i; proto raw; profile ha", i + 1, i + 1);
configured=TRUE;
#endif
#if CONFIG_PROFILE_WR == 1
configured=TRUE;
if ( ! configured )
sprintf(s, "port %i; iface wri%i; proto raw; profile wr", i + 1, i + 1);
#endif
......@@ -288,6 +291,7 @@ int main(int argc, char **argv)
ppi->portDS = wrs_shm_alloc(ppsi_head, sizeof(*ppi->portDS));
ppi->servo = wrs_shm_alloc(ppsi_head, sizeof(*ppi->servo));
ppi->ext_hooks=&pp_hooks; /* Default value. Can be overwritten by an extension */
ppi->ptp_support=FALSE;
if (ppi->portDS) {
switch (ppi->cfg.profile) {
#if CONFIG_PROFILE_WR == 1
......@@ -324,9 +328,11 @@ int main(int argc, char **argv)
case PPSI_PROFILE_PTP :
/* Do not take care of L1SYNC */
enable_asymmetryCorrection(ppi,ppi->cfg.asymmetryCorrectionEnable);
ppi->protocol_extension=PPSI_EXT_NONE;
break;
#if CONFIG_PROFILE_CUSTOM == 1
case PPSI_PROFILE_CUSTOM :
ppi->protocol_extension=PPSI_EXT_NONE; /* can be changed ...*/
#if CONFIG_EXT_L1SYNC
if (ppi->cfg.l1SyncEnabled ) {
if ( !enable_l1Sync(ppi,TRUE) )
......
......@@ -276,7 +276,25 @@ int pp_state_machine(struct pp_instance *ppi, void *buf, int len)
if (ppi->state != ppi->next_state)
return pp_leave_current_state(ppi);
if (!len)
if (len) {
if ( ppi->link_state == PP_LSTATE_PROTOCOL_DETECTION ) {
if ( ppi->ptp_msg_received==FALSE ) {
/* First frame received since instance initialization */
int tmo;
ppi->ptp_msg_received=TRUE;
if ( ppi->ext_hooks->get_tmo_lstate_detection!=NULL)
tmo=(*ppi->ext_hooks->get_tmo_lstate_detection)(ppi);
else
tmo= ppi->timeouts[PP_TO_ANN_RECEIPT].initValueMs;
__pp_timeout_set(ppi,PP_TO_PROT_STATE, tmo);
}
}
if ( !ppi->ext_enabled && ppi->link_state==PP_LSTATE_PROTOCOL_DETECTION) {
/* Ptp protocol only */
ppi->link_state= PP_LSTATE_IN_PROGRESS;
}
} else
ppi->received_ptp_header.messageType = PPM_NO_MESSAGE;
err = ip->f1(ppi, buf, len);
......@@ -288,6 +306,19 @@ int pp_state_machine(struct pp_instance *ppi, void *buf, int len)
if (ppi->state != ppi->next_state)
return pp_leave_current_state(ppi);
/* Check protocol state */
if ( ppi->link_state==PP_LSTATE_PROTOCOL_DETECTION ) {
if ( ppi->ptp_msg_received && pp_timeout(ppi, PP_TO_PROT_STATE) ) {
if ( ppi->ptp_support && ppi->ext_enabled ) {
ppi->ext_enabled=FALSE;
ppi->ptp_msg_received=FALSE;
} else
ppi->link_state=PP_LSTATE_FAILURE;
}
}
if (ppi->link_state==PP_LSTATE_FAILURE ) {
}
/* run bmc independent of state, and since not message driven do this
* here 9.2.6.8 */
if (pp_timeout(ppi, PP_TO_BMC)) {
......@@ -307,6 +338,11 @@ int pp_state_machine(struct pp_instance *ppi, void *buf, int len)
/* 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);
if ( ppi->link_state==PP_LSTATE_FAILURE && ppi->ptp_support && ppi->ext_enabled ) {
ppi->ext_enabled=FALSE;
ppi->link_state=PP_LSTATE_PROTOCOL_DETECTION;
}
ppi->next_delay= (delay < ppi->next_delay) ? delay : ppi->next_delay;
}
......
......@@ -29,12 +29,6 @@
#define WRH_HW_CALIB_ERROR -1
#define WRH_HW_CALIB_NOT_FOUND -3
enum {
WRH_SERVO_ENTER, WRH_SERVO_LEAVE
};
#define FIX_ALPHA_FRACBITS 40
#define FIX_ALPHA_FRACBITS_AS_FLOAT 40.0
......@@ -70,7 +64,6 @@ struct wrh_operations {
unsigned int calibrationPatternLen);
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 *fixAlpha,
int32_t *clock_period, uint32_t *bit_slide_ps);
......
......@@ -11,6 +11,7 @@
/* general purpose constants */
#define PP_NSEC_PER_SEC (1000*1000*1000)
#define PP_PSEC_PER_SEC ((int64_t)1000*(int64_t)PP_NSEC_PER_SEC)
/* implementation specific constants */
#define PP_MAX_LINKS 64
......@@ -112,6 +113,7 @@ enum pp_timeouts {
PP_TO_ANN_SEND,
PP_TO_FAULT,
PP_TO_QUALIFICATION,
PP_TO_PROT_STATE,
/* Two timeouts for the protocol extension */
PP_TO_EXT_0,
PP_TO_EXT_1,
......
......@@ -52,7 +52,9 @@ typedef struct _UInteger64 { /*/* TODO : Should be replaced by UInteger64 */
/* Page 19 :the time interval is expressed in units of nanoseconds and multiplied by 2 +16 */
#define TIME_INTERVAL_FRACBITS 16
#define TIME_INTERVAL_FRACMASK 0xFFFF
#define TIME_INTERVAL_FRACBITS_AS_FLOAT 16.0
#define TIME_INTERVAL_ROUNDING_VALUE (1<<(TIME_INTERVAL_FRACBITS-1))
/* Min/max value expressed in picos (int64_t) which can be stored in a TimeInterval type */
#define TIME_INTERVAL_MIN_PICOS_VALUE_AS_INT64 ((int64_t) 0xFE0C000000000000)
......@@ -74,6 +76,7 @@ typedef struct Timestamp { /* page 13 (33) -- no typedef expected */
#define REL_DIFF_FRACBITS 62
#define REL_DIFF_FRACBITS_AS_FLOAT 62.0
#define REL_DIFF_TWO_POW_FRACBITS ((double)4.611686018427388E18) /* double value returned by pow(2.0,62.0) */
#define REL_DIFF_FRACMASK 0x3fffffffffffffff
/* Min/max values for RelativeDifference type */
#define RELATIVE_DIFFERENCE_MIN_VALUE INT64_MIN
......
......@@ -105,21 +105,38 @@ struct pp_avg_fltr {
#define PP_SERVO_FLAG_VALID (1<<0)
#define PP_SERVO_FLAG_WAIT_HW (1<<1)
struct pp_servo {
int state;
#define PP_SERVO_RESET_DATA_SIZE (sizeof(struct pp_servo)-offsetof(struct pp_servo,reset_address))
#define PP_SERVO_RESET_DATA(servo) memset(&servo->reset_address,0,PP_SERVO_RESET_DATA_SIZE);
struct pp_time delayMS;
struct pp_time delaySM;
struct pp_servo {
/* ptp servo specific data */
long long obs_drift;
struct pp_avg_fltr mpd_fltr;
struct pp_time meanDelay;
struct pp_time offsetFromMaster;
/* diagnostic data */
/* Data shared with extension servo */
struct pp_time delayMM; /* Shared with extension servo */
struct pp_time delayMS; /* Shared with extension servo */
struct pp_time meanDelay; /* Shared with extension servo */
struct pp_time offsetFromMaster; /* Shared with extension servo */
unsigned long flags; /* PP_SERVO_FLAG_INVALID, PP_SERVO_FLAG_VALID, ...*/
uint32_t update_count; /* incremented each time the servo is running */
/* Data used only by extensions */
int state;
char servo_state_name[32]; /* Updated by the servo itself */
/*
* ----- All data after this line will be cleared during by a servo initialization
*/
int reset_address;
/* Data shared with extension servo */
uint32_t update_count; /* incremented each time the servo is running */
struct pp_time update_time; /* Last updated time of the servo */
struct pp_time t1, t2, t3, t4, t5, t6;
/* ptp servo specific data */
int servo_locked; /* TRUE when servo is locked. This info can be used by HAL */
int got_sync; /* True when T1/T2 are available */
};
enum { /* The two sockets. They are called "net path" for historical reasons */
......@@ -177,6 +194,17 @@ typedef struct {
unsigned long tmo;
} t_timeOutConfig;
/*
* This enumeration correspond to the protocol state of a pp_instance.
* It is used to decide which instance must be active on a given port.
*/
typedef enum {
PP_LSTATE_PROTOCOL_DETECTION, /* Checking if the peer instance is using the same protocol */
PP_LSTATE_IN_PROGRESS, /* Right protocol detected. Try to establish the link with peer instance */
PP_LSTATE_LINKED, /* Link with peer well established */
PP_LSTATE_FAILURE /* Impossible to connect correctly to a peer instance */
} pp_link_state;
/*
* Structure for the individual ppsi link
*/
......@@ -258,7 +286,10 @@ struct pp_instance {
Boolean received_dresp; /* Count the number of delay response messages received for a given delay request */
Boolean received_dresp_fup; /* Count the number of delay response follow up messages received for a given delay request */
#endif
Boolean ptp_msg_received; /* Use to detect reception of a ptp message after an ppsi instance initialization */
Boolean ptp_support; /* True if allow pure PTP support */
Boolean ext_enabled; /* True if the extension is enabled */
pp_link_state link_state;
};
/* The following things used to be bit fields. Other flags are now enums */
......
#ifndef __PPSI_PP_TIME_H__
#define __PPSI_PP_TIME_H__
#define TIME_FRACBITS 16
#define TIME_FRACMASK 0xFFFF
#define TIME_FRACBITS_AS_FLOAT 16.0
#define TIME_ROUNDING_VALUE (1<<(TIME_FRACBITS-1))
/* Everything internally uses this time format, *signed* */
struct pp_time {
int64_t secs;
......
......@@ -213,8 +213,8 @@ struct pp_ext_hooks {
void (*s1)(struct pp_instance *ppi, struct pp_frgn_master *frgn_master);
int (*execute_slave)(struct pp_instance *ppi);
int (*handle_announce)(struct pp_instance *ppi);
int (*handle_sync)(struct pp_instance *ppi, struct pp_time *orig);
int (*handle_followup)(struct pp_instance *ppi, struct pp_time *orig);
int (*handle_sync)(struct pp_instance *ppi);
int (*handle_followup)(struct pp_instance *ppi);
int (*handle_preq) (struct pp_instance * ppi);
int (*handle_presp) (struct pp_instance * ppi);
int (*handle_signaling) (struct pp_instance * ppi, void *buf, int len);
......@@ -224,8 +224,14 @@ struct pp_ext_hooks {
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);
void (*servo_reset)(struct pp_instance *ppi);
/* If the extension requires hardware support for precise time stamp, returns 1 */
int (*require_precise_timestamp)(struct pp_instance *ppi);
int (*get_tmo_lstate_detection) (struct pp_instance *ppi);
};
#define is_ext_hook_available(p, c) ( /*p->ext_enabled && */ p->ext_hooks->c)
/*
* Network methods are encapsulated in a structure, so each arch only needs
* to provide that structure. This simplifies management overall.
......@@ -508,9 +514,12 @@ extern int f_simple_int(struct pp_argline *l, int lineno,
/* Servo */
extern void pp_servo_init(struct pp_instance *ppi);
extern void pp_servo_got_sync(struct pp_instance *ppi); /* got t1 and t2 */
extern void pp_servo_got_resp(struct pp_instance *ppi); /* got all t1..t4 */
extern int pp_servo_got_resp(struct pp_instance *ppi); /* got all t1..t4 */
extern void pp_servo_got_psync(struct pp_instance *ppi); /* got t1 and t2 */
extern void pp_servo_got_presp(struct pp_instance *ppi); /* got all t3..t6 */
extern int pp_servo_got_presp(struct pp_instance *ppi); /* got all t3..t6 */
extern int pp_servo_calculate_delays(struct pp_instance *ppi);
extern void pp_servo_apply_faulty_stamp(struct pp_servo *s, struct pp_time *faulty_stamps, int index);
/* bmc.c */
extern void bmc_m1(struct pp_instance *ppi);
......@@ -554,11 +563,13 @@ extern void msg_unpack_pdelay_resp(void *buf, MsgPDelayResp * presp);
extern void msg_unpack_pdelay_req(void *buf, MsgPDelayReq * pdelay_req);
/* each of them returns 0 if ok, -1 in case of error in send, 1 if stamp err */
#define PP_SEND_OK 0
#define PP_SEND_ERROR -1
#define PP_SEND_NO_STAMP 1
#define PP_SEND_DROP -2
#define PP_RECV_DROP PP_SEND_DROP
typedef enum {
PP_SEND_OK=0,
PP_SEND_ERROR=-1,
PP_SEND_NO_STAMP=1,
PP_SEND_DROP=-2,
PP_RECV_DROP=PP_SEND_DROP
}pp_send_status;
extern void *msg_copy_header(MsgHeader *dest, MsgHeader *src); /* REMOVE ME!! */
extern int msg_issue_announce(struct pp_instance *ppi);
......@@ -587,7 +598,9 @@ extern void picos_to_pp_time(int64_t picos, struct pp_time *ts);
extern void pp_time_hardwarize(struct pp_time *time, int clock_period_ps,int32_t *ticks, int32_t *picos);
extern int64_t interval_to_picos(TimeInterval interval);
extern int is_timestamps_incorrect(struct pp_instance *ppsi, int *err_count, int ts_mask);
extern char *time_to_string(struct pp_time *t);
extern char *interval_to_string(TimeInterval time);
extern char *relative_interval_to_string(TimeInterval time);
/*
* The state machine itself is an array of these structures.
......
......@@ -6,6 +6,9 @@
*/
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <ppsi/ppsi.h>
void normalize_pp_time(struct pp_time *t)
......@@ -38,17 +41,30 @@ void normalize_pp_time(struct pp_time *t)
/* 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);
struct pp_time t = {
.secs=0,
.scaled_nsecs=t2
};
normalize_pp_time(&t);
pp_time_add(t1,&t);
}
/* 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);
struct pp_time t = {
.secs=0,
.scaled_nsecs=t2
};
normalize_pp_time(&t);
pp_time_sub(t1,&t);
}
#define IS_ADD_WILL_OVERFLOW(a,b) \
( (((a > 0) && (b > INT64_MAX - a))) ||\
(((a < 0) && (b < INT64_MIN - a))) \
)
void pp_time_add(struct pp_time *t1, struct pp_time *t2)
{
t1->secs += t2->secs;
......@@ -56,6 +72,11 @@ void pp_time_add(struct pp_time *t1, struct pp_time *t2)
normalize_pp_time(t1);
}
#define IS_SUB_WILL_OVERFLOW(a,b) \
( ((b < 0) && (a > INT64_MAX + b)) ||\
((b > 0) && (a < INT64_MIN + b)) \
)
void pp_time_sub(struct pp_time *t1, struct pp_time *t2)
{
t1->secs -= t2->secs;
......@@ -76,28 +97,28 @@ void pp_time_div2(struct pp_time *t)
int64_t pp_time_to_picos(struct pp_time *ts)
{
return ts->secs * PP_NSEC_PER_SEC
+ ((ts->scaled_nsecs * 1000 + 0x8000) >> TIME_INTERVAL_FRACBITS);
return ts->secs * PP_PSEC_PER_SEC
+ ((ts->scaled_nsecs * 1000 + TIME_ROUNDING_VALUE) >> TIME_FRACBITS);
}
void picos_to_pp_time(int64_t picos, struct pp_time *ts)
{
uint64_t sec, nsec;
int phase;
int sign = (picos < 0 ? -1 : 1);
picos *= sign;
nsec = picos;
phase = __div64_32(&nsec, 1000);
sec = nsec;
sec=picos/PP_PSEC_PER_SEC;
picos-=sec*PP_PSEC_PER_SEC;
nsec = picos/1000;
picos-=nsec*1000;
ts->scaled_nsecs = ((int64_t)__div64_32(&sec, PP_NSEC_PER_SEC)) << TIME_INTERVAL_FRACBITS;
ts->scaled_nsecs += (phase << TIME_INTERVAL_FRACBITS) / 1000;
ts->scaled_nsecs = nsec << TIME_FRACBITS;
ts->scaled_nsecs += (picos << TIME_FRACBITS) / 1000;
ts->scaled_nsecs *= sign;
ts->secs = sec * sign;
}
#if 0
/* "Hardwarizes" the timestamp - e.g. makes the nanosecond field a multiple
* of 8/16ns cycles and puts the extra nanoseconds in the picos result */
void pp_time_hardwarize(struct pp_time *time, int clock_period_ps,
......@@ -105,6 +126,10 @@ void pp_time_hardwarize(struct pp_time *time, int clock_period_ps,
{
int32_t s, ns, ps, clock_ns;
if ( clock_period_ps <= 0 ) {
pp_error("%s : Invalid clock period %d\n",__func__, clock_period_ps);
exit(-1);
}
/* clock_period_ps *must* be a multiple of 1000 -- assert()? */
clock_ns = clock_period_ps / 1000;
......@@ -139,7 +164,26 @@ void pp_time_hardwarize(struct pp_time *time, int clock_period_ps,
*ticks = ns;
*picos = ps;
}
#else
/* "Hardwarizes" the timestamp - e.g. makes the nanosecond field a multiple
* of 8/16ns cycles and puts the extra nanoseconds in the picos result */
void pp_time_hardwarize(struct pp_time *time, int clock_period_ps,
int32_t *ticks, int32_t *picos)
{
int64_t ps, adj_ps;
int32_t sign=(time->scaled_nsecs<0) ? -1 : 1;
int64_t scaled_nsecs=time->scaled_nsecs*sign;
if ( clock_period_ps <= 0 ) {
pp_error("%s : Invalid clock period %d\n",__func__, clock_period_ps);
return;
}
ps = (scaled_nsecs * 1000L+TIME_INTERVAL_ROUNDING_VALUE) >> TIME_INTERVAL_FRACBITS; /* now picoseconds 0..999 -- positive*/
adj_ps=ps - ps%clock_period_ps;
*picos=(int32_t)(ps-adj_ps)*sign;
*ticks = (int32_t)(adj_ps/1000)*sign;
}
#endif
TimeInterval pp_time_to_interval(struct pp_time *ts)
{
......@@ -165,7 +209,7 @@ TimeInterval picos_to_interval(int64_t picos)
int sign = (picos < 0 ? -1 : 1);
picos *= sign;
scaled_ns=(picos/1000) << TIME_INTERVAL_FRACBITS; /* Calculate nanos */
scaled_ns|=((picos%1000) << TIME_INTERVAL_FRACBITS)/1000; /* Add picos */
scaled_ns+=((picos%1000) << TIME_INTERVAL_FRACBITS)/1000; /* Add picos */
return scaled_ns*sign;
}
......@@ -214,3 +258,65 @@ int is_timestamps_incorrect(struct pp_instance *ppsi, int *err_count, int ts_mas
}
return *err_count=0;
}
static char time_as_string[32];
/* Convert pp_time to string */
char *time_to_string(struct pp_time *t)
{
struct pp_time time=*t;
int picos;
char *sign;
if (t->secs < 0 || (t->secs == 0 && t->scaled_nsecs < 0) ) {
sign="-";
time.scaled_nsecs=-t->scaled_nsecs;
time.secs=-t->secs;
} else {
sign="";
time=*t;
}
picos=((int)(time.scaled_nsecs&TIME_FRACMASK)*1000+TIME_ROUNDING_VALUE)>>TIME_FRACBITS;
pp_sprintf(time_as_string, "%s%d.%09d%03d",
sign,
(int)time.secs,
(int)(time.scaled_nsecs >> TIME_FRACBITS),
picos);
return time_as_string;
}
/* Convert TimeInterval to string */
char *interval_to_string(TimeInterval time)
{
int64_t sign,nanos,picos;
if ( time<0 && time !=INT64_MIN) {
sign=-1;
time=-time;
} else {
sign=1;
}
nanos = time >> TIME_INTERVAL_FRACBITS;
picos = (((time & TIME_INTERVAL_FRACMASK) * 1000) + TIME_INTERVAL_ROUNDING_VALUE ) >> TIME_INTERVAL_FRACBITS;
sprintf(time_as_string,"%" PRId64 ".%03" PRId64, sign*nanos,picos);
return time_as_string;
}
/* Convert RelativeInterval to string */
char *relative_interval_to_string(TimeInterval time) {
int32_t nsecs=time >> REL_DIFF_FRACBITS;
uint64_t sub_yocto=0;
int64_t fraction;
uint64_t bitWeight=500000000000000000;
uint64_t mask;
fraction=time & REL_DIFF_FRACMASK;
for (mask=(uint64_t) 1<< (REL_DIFF_FRACBITS-1);mask!=0; mask>>=1 ) {
if ( mask & fraction )
sub_yocto+=bitWeight;
bitWeight/=2;
}
sprintf(time_as_string,"%"PRId32".%018"PRIu64, nsecs, sub_yocto);
return time_as_string;
}
......@@ -101,11 +101,8 @@ typedef struct { /*draft P1588_v_29: page 101 and 340-341 */
/* 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)
......@@ -127,13 +124,23 @@ static inline L1SyncOptParamsPortDS_t *L1E_DSPOR_OP(struct pp_instance *ppi)
/****************************************************************************************/
/* l1e_servo interface */
#define L1E_SERVO_RESET_DATA_SIZE (sizeof(struct l1e_servo_state)-offsetof(struct l1e_servo_state,reset_address))
#define L1E_SERVO_RESET_DATA(servo) memset(&servo->reset_address,0,L1E_SERVO_RESET_DATA_SIZE);
struct l1e_servo_state {
/* 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;
/* ----- All data after this line will cleared during a servo reset */
int reset_address;
/* These fields are used by servo code, after setting at init time */
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;
......@@ -141,15 +148,7 @@ struct l1e_servo_state {
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;
};
......@@ -158,9 +157,9 @@ struct l1e_servo_state {
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_got_sync(struct pp_instance *ppi);
int l1e_servo_got_resp(struct pp_instance *ppi);
int l1e_servo_got_presp(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,
......@@ -180,6 +179,9 @@ static inline struct l1e_servo_state *L1E_SRV(struct pp_instance *ppi)
}
static inline int l1e_get_rx_tmo_ms(L1SyncBasicPortDS_t * bds) {
return (4 << (bds->logL1SyncInterval + 8)) * bds->L1SyncReceiptTimeout;
}
extern struct pp_ext_hooks l1e_ext_hooks;
......
......@@ -19,7 +19,6 @@ char *l1e_state_name[] = {
[L1SYNC_UP] = "L1SYNC_UP",
};
void l1e_print_L1Sync_basic_bitmaps(struct pp_instance *ppi, uint8_t configed,
uint8_t active, char* text)
{
......@@ -100,6 +99,7 @@ static int l1e_init(struct pp_instance *ppi, void *buf, int len)
/* Init configuration members of L1SyncOptParamsPortDS */
L1E_DSPOR_OP(ppi)->timestampsCorrectedTx=TRUE;
ppi->ext_enabled=TRUE;
return 0;
}
......@@ -112,13 +112,16 @@ static int l1e_handle_signaling(struct pp_instance * ppi, void *buf, int len)
if ( l1e_unpack_signal(ppi, buf, len)==0 ) {
/* Valid Sync message */
int timeout_tx_sync;
/* Reset reception timeout */
timeout_tx_sync = (4 << (bds->logL1SyncInterval + 8)) * bds->L1SyncReceiptTimeout;
__pp_timeout_set(ppi, L1E_TIMEOUT_RX_SYNC, timeout_tx_sync);
__pp_timeout_set(ppi, L1E_TIMEOUT_RX_SYNC, l1e_get_rx_tmo_ms(bds));
bds->L1SyncLinkAlive = TRUE;
if ( ppi->link_state==PP_LSTATE_PROTOCOL_DETECTION ||
ppi->link_state==PP_LSTATE_FAILURE) {
ppi->link_state=PP_LSTATE_IN_PROGRESS;
ppi->ext_enabled=TRUE; // Force L1SYNC extension as L1SYNC messages are received
}
}
return 0;
}
......@@ -135,102 +138,64 @@ uint8_t l1e_creat_L1Sync_bitmask(int tx_coh, int rx_coh, int congru)
static int l1e_handle_resp(struct pp_instance *ppi)
{
struct pp_time *ofm = &SRV(ppi)->offsetFromMaster;
l1e_ext_portDS_t *l1epds = L1E_DSPOR(ppi);
pp_diag(ppi, ext, 2, "hook: %s\n", __func__);
if ( l1epds->basic.L1SyncState != L1SYNC_UP )
return 0;
/* This correction_field we received is already part of t4 */
/*
* If no WR mode is on, run normal code, if T2/T3 are valid.
* After we adjusted the pps counter, stamps are invalid, so
* we'll have the Unix time instead, marked by "correct"
*/
if (!l1epds->head.extModeOn) {
if ( is_timestamps_incorrect(ppi, NULL, 0x6 /* mask=t2&t3 */) ) {
pp_diag(ppi, servo, 1,"T2 or T3 incorrect, discarding tuple\n");
return 0;
}
if ( ppi->ext_enabled ) {
l1e_servo_got_resp(ppi);
}
else {
pp_servo_got_resp(ppi);
/*
* pps always on if offset less than 1 second,
* until we have a configurable threshold */
WRH_OPER()->enable_timing_output(ppi, ofm->secs==0);
WRH_OPER()->enable_timing_output(ppi,
ppi->state==PPS_SLAVE &&
SRV(ppi)->offsetFromMaster.secs==0 &&
SRV(ppi)->offsetFromMaster.scaled_nsecs!=0);
}
l1e_servo_got_delay(ppi);
l1e_servo_update(ppi);
return 0;
}
static int l1e_sync_followup(struct pp_instance *ppi, struct pp_time *t1) {
l1e_ext_portDS_t *pds=L1E_DSPOR(ppi);
if ((pds->basic.L1SyncState != L1SYNC_UP) || !pds->head.extModeOn )
return 0;
l1e_servo_got_sync(ppi, t1, &ppi->t2);
if (CONFIG_HAS_P2P && ppi->delayMechanism == P2P)
l1e_servo_update(ppi);
static int l1e_sync_followup(struct pp_instance *ppi) {
if ( ppi->ext_enabled ) {
l1e_servo_got_sync(ppi);
}
else {
pp_servo_got_sync(ppi);
if (CONFIG_HAS_P2P && ppi->delayMechanism == P2P ) {
/* pps always on if offset less than 1 second,
* until ve have a configurable threshold
*/
WRH_OPER()->enable_timing_output(ppi,
ppi->state==PPS_SLAVE &&
SRV(ppi)->offsetFromMaster.secs==0 &&
SRV(ppi)->offsetFromMaster.scaled_nsecs!=0);
}
}
return 1; /* the caller returns too */
}
/* Hmm... "execute_slave" should look for errors; but it's off in WR too */
static int l1e_handle_followup(struct pp_instance *ppi,
struct pp_time *t1)
static int l1e_handle_followup(struct pp_instance *ppi)
{
/* This handle is called in case of two step clock */
pp_diag(ppi, ext, 2, "hook: %s\n", __func__);
return l1e_sync_followup(ppi,t1);
return l1e_sync_followup(ppi);
}
static int l1e_handle_sync(struct pp_instance *ppi,
struct pp_time *t1)
static int l1e_handle_sync(struct pp_instance *ppi)
{
/* This handle is called in case of one step clock */
pp_diag(ppi, ext, 2, "hook: %s\n", __func__);
return l1e_sync_followup(ppi,t1);
return l1e_sync_followup(ppi);
}
static __attribute__((used)) int l1e_handle_presp(struct pp_instance *ppi)
{
struct pp_time *ofm = &SRV(ppi)->offsetFromMaster;
l1e_ext_portDS_t *pds=L1E_DSPOR(ppi);
/* Servo is active only when the state is UP */
if ( pds->basic.L1SyncState != L1SYNC_UP )
return 0;
/*
* If no WR mode is on, run normal code, if T2/T3 are valid.
* After we adjusted the pps counter, stamps are invalid, so
* we'll have the Unix time instead, marked by "correct"
*/
if (!WRH_DSPOR_HEAD(ppi)->extModeOn) {
if ( is_timestamps_incorrect(ppi, NULL, 0x24 /* mask=t3&t6 */) ) {
pp_diag(ppi, servo, 1,
"T3 or T6 incorrect, discarding tuple\n");
return 0;
}
pp_servo_got_presp(ppi);
/*
* pps always on if offset less than 1 second,
* until ve have a configurable threshold */
WRH_OPER()->enable_timing_output(ppi, ofm->secs==0);
return 0;
}
/* FIXME: verify that last-received cField is already accounted for */
l1e_servo_got_delay(ppi);
if ( ppi->ext_enabled )
l1e_servo_got_presp(ppi);
else
pp_servo_got_presp(ppi);
return 0;
}
......@@ -244,8 +209,9 @@ static int l1e_ready_for_slave(struct pp_instance *ppi)
return 1; /* Ready for slave */
}
static void l1e_state_change(struct pp_instance *ppi) {
if ( !ppi->ext_enabled)
return;
switch (ppi->next_state) {
case PPS_DISABLED :
/* In PPSI we go to DISABLE state when the link is down */
......@@ -259,6 +225,20 @@ static void l1e_state_change(struct pp_instance *ppi) {
}
}
static int l1e_new_slave (struct pp_instance *ppi, void *buf, int len) {
if ( ppi->ext_enabled )
l1e_servo_init(ppi);
return 0;
}
static int l1e_require_precise_timestamp(struct pp_instance *ppi) {
return ppi->ext_enabled ? L1E_DSPOR_BS(ppi)->L1SyncState==L1SYNC_UP : 0;
}
static int l1e_get_tmo_lstate_detection(struct pp_instance *ppi) {
return l1e_get_rx_tmo_ms(L1E_DSPOR_BS(ppi));
}
/* The global structure used by ppsi */
struct pp_ext_hooks l1e_ext_hooks = {
.open = l1e_open,
......@@ -269,9 +249,13 @@ struct pp_ext_hooks l1e_ext_hooks = {
.handle_resp = l1e_handle_resp,
.handle_sync = l1e_handle_sync,
.handle_followup = l1e_handle_followup,
.new_slave = l1e_new_slave,
#if CONFIG_HAS_P2P
.handle_presp = l1e_handle_presp,
#endif
.state_change = l1e_state_change,
.servo_reset= l1e_servo_reset,
.require_precise_timestamp=l1e_require_precise_timestamp,
.get_tmo_lstate_detection=l1e_get_tmo_lstate_detection
};
......@@ -4,7 +4,8 @@
*
* Released according to the GNU LGPL, version 2.1 or any later version.
*/
#include <stdint.h>
#include <inttypes.h>
#include <ppsi/ppsi.h>
#include "l1e-constants.h"
#include <libwr/shmem.h>
......@@ -22,34 +23,14 @@ static const char *l1e_servo_state_name[] = {
/* Enable tracking by default. Disabling the tracking is used for demos. */
static int l1e_tracking_enabled = 1;
static struct pp_time l1e_faulty_stamps[6]; /* if unused, dropped at link time */
static int l1e_got_sync = 0;
/* prototypes */
static int l1e_p2p_delay(struct pp_instance *ppi, struct l1e_servo_state *s);
static void l1e_apply_faulty_stamp(struct l1e_servo_state *s, int index);
static void l1e_dump_timestamp(struct pp_instance *ppi, char *what, struct pp_time ts);
static int __l1e_servo_update(struct pp_instance *ppi);
/* External data */
extern struct wrs_shm_head *ppsi_head;
static void l1e_apply_faulty_stamp(struct l1e_servo_state *s, int index)
{
if (PROTO_EXT_HAS_FAULTS) {
assert(index >= 1 && index <= 6, "Wrong T index %i\n", index);
pp_time_add(&s->t1 + index - 1, l1e_faulty_stamps + index - 1);
}
}
static void l1e_dump_timestamp(struct pp_instance *ppi, char *what,struct pp_time ts)
{
pp_diag(ppi, servo, 2, "%s = %ld.%09ld%03ld\n", what, (long)ts.secs,
(long)(ts.scaled_nsecs >> 16),
/* unlikely what we had earlier, third field is not phase */
((long)(ts.scaled_nsecs & 0xffff) * 1000 + 0x8000) >> 16);
}
void l1e_servo_enable_tracking(int enable)
{
l1e_tracking_enabled = enable;
......@@ -58,6 +39,9 @@ void l1e_servo_enable_tracking(int enable)
int l1e_servo_init(struct pp_instance *ppi)
{
struct l1e_servo_state *s=L1E_SRV(ppi);
struct pp_servo *gs=SRV(ppi);
pp_servo_init(ppi); // Initialize the standard servo data
/* shmem lock */
wrs_shm_write(ppsi_head, WRS_SHM_WRITE_BEGIN);
......@@ -80,17 +64,15 @@ int l1e_servo_init(struct pp_instance *ppi)
WRH_OPER()->adjust_phase(s->cur_setpoint_ps);
s->missed_iters = 0;
SRV(ppi)->state = L1E_SYNC_TAI;
gs->state = L1E_SYNC_TAI;
strcpy(SRV(ppi)->servo_state_name, l1e_servo_state_name[SRV(ppi)->state]);
SRV(ppi)->flags |= PP_SERVO_FLAG_VALID;
SRV(ppi)->update_count = 0;
ppi->t_ops->get(ppi, &s->update_time);
gs->flags |= PP_SERVO_FLAG_VALID;
gs->update_count = 0;
ppi->t_ops->get(ppi, &SRV(ppi)->update_time);
s->tracking_enabled = l1e_tracking_enabled;
l1e_got_sync = 0;
/* shmem unlock */
wrs_shm_write(ppsi_head, WRS_SHM_WRITE_END);
return 0;
......@@ -99,292 +81,103 @@ int l1e_servo_init(struct pp_instance *ppi)
void l1e_servo_reset(struct pp_instance *ppi)
{
/* values from servo_state to be preserved */
uint32_t n_err_state;
uint32_t n_err_offset;
uint32_t n_err_delta_rtt;
if ( ppi->ext_enabled ) {
struct l1e_servo_state *s=L1E_SRV(ppi);
struct l1e_servo_state *s=L1E_SRV(ppi);
/* shmem lock */
wrs_shm_write(ppsi_head, WRS_SHM_WRITE_BEGIN);
ppi->flags = 0;
/* shmem lock */
wrs_shm_write(ppsi_head, WRS_SHM_WRITE_BEGIN);
ppi->flags = 0;
/* preserve some values from servo_state */
n_err_state = s->n_err_state;
n_err_offset = s->n_err_offset;
n_err_delta_rtt = s->n_err_delta_rtt;
/* clear servo_state to display empty fields in wr_mon and SNMP */
memset(s, 0, sizeof(struct l1e_servo_state));
/* restore values from servo_state */
s->n_err_state = n_err_state;
s->n_err_offset = n_err_offset;
s->n_err_delta_rtt = n_err_delta_rtt;
L1E_SERVO_RESET_DATA(s);
/* shmem unlock */
wrs_shm_write(ppsi_head, WRS_SHM_WRITE_END);
/* shmem unlock */
wrs_shm_write(ppsi_head, WRS_SHM_WRITE_END);
}
}
/**
* SYNC/FOLLOW_UP messages have been received: t1/t2 are available
*/
int l1e_servo_got_sync(struct pp_instance *ppi, struct pp_time *t1,
struct pp_time *t2)
int l1e_servo_got_sync(struct pp_instance *ppi)
{
struct l1e_servo_state *s=L1E_SRV(ppi);
s->t1 = *t1; l1e_apply_faulty_stamp(s, 1);
s->t2 = *t2; l1e_apply_faulty_stamp(s, 2);
l1e_got_sync = 1;
return 0;
}
/**
* DELAY_RESPONSE message has been received: t3/t4 are available
*/
int l1e_servo_got_delay(struct pp_instance *ppi)
{
struct l1e_servo_state *s=L1E_SRV(ppi);
struct pp_servo *gs=SRV(ppi);
/* shmem lock */
wrs_shm_write(ppsi_head, WRS_SHM_WRITE_BEGIN);
s->t3 = ppi->t3; l1e_apply_faulty_stamp(s, 3);
s->t4 = ppi->t4; l1e_apply_faulty_stamp(s, 4);
gs->t1=ppi->t1;pp_servo_apply_faulty_stamp(gs, l1e_faulty_stamps,1);
gs->t2=ppi->t2;pp_servo_apply_faulty_stamp(gs, l1e_faulty_stamps, 2);
if (CONFIG_HAS_P2P && ppi->delayMechanism == P2P) {
s->t5 = ppi->t5; l1e_apply_faulty_stamp(s, 5);
s->t6 = ppi->t6; l1e_apply_faulty_stamp(s, 6);
l1e_p2p_delay(ppi, s);
if (CONFIG_HAS_P2P && ppi->delayMechanism == P2P && gs->got_sync) {
gs->got_sync=0;
__l1e_servo_update(ppi);
}else {
gs->got_sync=1;
}
/* shmem unlock */
wrs_shm_write(ppsi_head, WRS_SHM_WRITE_END);
return 0;
}
#define BITS_IN_INT64 (sizeof(int64_t)*8)
/* Get the position of the first bit set on the left of a 64 bits integer */
static int getMsbSet(int64_t value) {
if ( value==0 )
return 0; /* value=0 so return bit 0 */
if ( value<0 )
value=-value; /* Negative value: change it to its positive value for the calculation */
return BITS_IN_INT64 - __builtin_clzll(value); /* using gcc built-in function */
}
#define DELAY_ASYM_BASE_FRACTION 50 /* Maxim value that can be used for the calculation */
/**
* Calculate the delayAsymmetry : delayAsymCoeff * meanDelay
*
* This calculation is made in order to use the maximum of bits in the fraction part. It will depend
* on the value of delayAsymCoeff and meanDelay. The smaller these values will be, bigger
* the fraction part will be.
*/
static TimeInterval calculateDelayAsymmetry(RelativeDifference scaledDelayAsymCoeff, TimeInterval scaledMeanDelay) {
TimeInterval delayAsym;
int64_t rescaledAsymDelayCoeff,rescaledMeanDelay;
int lostBits,fracBitsUsed;
lostBits=getMsbSet(scaledDelayAsymCoeff)-(REL_DIFF_FRACBITS-DELAY_ASYM_BASE_FRACTION)+
getMsbSet(scaledMeanDelay)+(DELAY_ASYM_BASE_FRACTION-TIME_INTERVAL_FRACBITS)-BITS_IN_INT64;
if ( lostBits<0 )
lostBits=0;
fracBitsUsed=DELAY_ASYM_BASE_FRACTION-(lostBits>>1)-1;
rescaledMeanDelay = scaledMeanDelay<<(fracBitsUsed-TIME_INTERVAL_FRACBITS);
rescaledAsymDelayCoeff=scaledDelayAsymCoeff>>(REL_DIFF_FRACBITS-fracBitsUsed);
delayAsym= rescaledAsymDelayCoeff*rescaledMeanDelay;
delayAsym+=(1<<(fracBitsUsed-1));
delayAsym>>=fracBitsUsed;
delayAsym>>=(fracBitsUsed-TIME_INTERVAL_FRACBITS);
return delayAsym;
return 0;
}
/**
* PDELAY_RESPONSE/PDELAY_RESPONSE_FOLLOW_UP messages have been received: t3/t4/t5/t6 are available
* DELAY_RESPONSE message has been received: t3/t4 are available
*/
static int l1e_p2p_delay(struct pp_instance *ppi, struct l1e_servo_state *s)
int l1e_servo_got_resp(struct pp_instance *ppi)
{
static int errcount;
int64_t meanLinkDelay_ps;
struct pp_servo *gs=SRV(ppi);
int ret;
static int errcount=0;
if ( is_timestamps_incorrect(ppi,&errcount, 0x3C /* mask=t3&t4&t5&t6*/))
return 0;
SRV(ppi)->update_count++;
ppi->t_ops->get(ppi, &s->update_time);
if ( !gs->got_sync )
return 0; /* t1 & t2 not available yet */
gs->got_sync=0;
/*
* Calculate of the round trip delay (delayMM)
* delayMM = (t6-t3)-(t5-t4)
*/
{ /* avoid modifying stamps in place */
struct pp_time mtime, stime;
stime = s->t6; pp_time_sub(&stime, &s->t3);
mtime = s->t5; pp_time_sub(&mtime, &s->t4);
s->delayMM = stime; pp_time_sub(&s->delayMM, &mtime);
}
s->delayMM_ps = pp_time_to_picos(&s->delayMM);
/*
* Calculate the meanLinkDelay
* meanLinkDelay=delayMM/2)
*/
if (s->delayMM_ps < 0) {
s->delayMM_ps =meanLinkDelay_ps=0;
picos_to_pp_time(s->delayMM_ps, &s->delayMM);
} else {
meanLinkDelay_ps=s->delayMM_ps>>1; /* meanLinkDelay=delayMM/2 */
}
if (__PP_DIAG_ALLOW(ppi, pp_dt_servo, 1)) {
l1e_dump_timestamp(ppi, "servo:t1", s->t1);
l1e_dump_timestamp(ppi, "servo:t2", s->t2);
l1e_dump_timestamp(ppi, "servo:t3", s->t3);
l1e_dump_timestamp(ppi, "servo:t4", s->t4);
l1e_dump_timestamp(ppi, "servo:t5", s->t5);
l1e_dump_timestamp(ppi, "servo:t6", s->t6);
l1e_dump_timestamp(ppi, "->delayMM", s->delayMM);
}
if ( ppi->asymmetryCorrectionPortDS.enable ) {
/* Enabled: The delay asymmetry must be calculated
* delayAsymmetry=delayAsymCoefficient * meanPathDelay
*/
ppi->portDS->delayAsymmetry=calculateDelayAsymmetry(ppi->portDS->delayAsymCoeff,picos_to_interval(meanLinkDelay_ps));
} else {
/* Disabled: The delay asymmetry is provided by configuration */
ppi->portDS->delayAsymmetry=ppi->asymmetryCorrectionPortDS.constantAsymmetry;
}
if ( is_timestamps_incorrect(ppi,&errcount,0xC /* mask=t3&t4 */) )
return 0;
/* delayMS = meanLinkDelay + delayAsym */
s->delayMS_ps = meanLinkDelay_ps + interval_to_picos(ppi->portDS->delayAsymmetry);
picos_to_pp_time(s->delayMS_ps, &SRV(ppi)->delayMS);
wrs_shm_write(ppsi_head, WRS_SHM_WRITE_BEGIN);
update_meanDelay(ppi,picos_to_interval(meanLinkDelay_ps)); /* update currentDS.meanDelay and portDS.meanLinkDelay (idf needed) */
picos_to_pp_time(meanLinkDelay_ps,&SRV(ppi)->meanDelay); /* update servo.meanDelay */
gs->t3 = ppi->t3; pp_servo_apply_faulty_stamp(gs, l1e_faulty_stamps,3);
gs->t4 = ppi->t4; pp_servo_apply_faulty_stamp(gs, l1e_faulty_stamps,4);
return 1;
ret=__l1e_servo_update(ppi);
wrs_shm_write(ppsi_head, WRS_SHM_WRITE_END);
return ret;
}
static int l1e_p2p_offset(struct pp_instance *ppi,
struct l1e_servo_state *s, struct pp_time *offsetMS)
/**
* PDELAY_RESPONSE_FUP message has been received: t3/t4/t5/t6 are available
*/
int l1e_servo_got_presp(struct pp_instance *ppi)
{
static int errcount;
if ( is_timestamps_incorrect(ppi,&errcount, 0x3 /* mask=t1&t2 */))
return 0;
l1e_got_sync = 0;
SRV(ppi)->update_count++;
ppi->t_ops->get(ppi, &s->update_time);
/* Calculate offsetFromMaster : t1-t2+meanLinkDelay+delayAsym=t1-t2+delayMS */
*offsetMS = s->t1;
pp_time_sub(offsetMS, &s->t2);
pp_time_add(offsetMS, &SRV(ppi)->delayMS); /* Add delayMS */
/* is it possible to calculate it in client,
* but then t1 and t2 require shmem locks */
s->tracking_enabled = l1e_tracking_enabled;
SRV(ppi)->offsetFromMaster=*offsetMS; /* Update servo.offsetFromMaster */
DSCUR(ppi)->offsetFromMaster = pp_time_to_interval(offsetMS); /* Update currentDS.offsetFromMaster */
return 1;
}
static int l1e_e2e_offset(struct pp_instance *ppi, struct l1e_servo_state *s,
struct pp_time *offsetMS) {
static int errcount;
int64_t meanPathDelay_ps;
struct pp_servo *gs=SRV(ppi);
static int errcount=0;
if (is_timestamps_incorrect(ppi, &errcount, 0xF /* mask=t1&t2&t3&t4 */))
if ( is_timestamps_incorrect(ppi,&errcount,0x3C /* mask=&t3&t4&t5&t6 */) )
return 0;
if (WRH_OPER()->servo_hook)
WRH_OPER()->servo_hook(ppi, WRH_SERVO_ENTER);
SRV(ppi)->update_count++;
ppi->t_ops->get(ppi, &s->update_time);
l1e_got_sync = 0;
/*
* Calculate of the round trip delay (delayMM)
* delayMM = t4-t1-(t3-t2)
*/
{
/* Avoid modifying stamps in place*/
struct pp_time mtime, stime;
mtime = s->t4;
pp_time_sub(&mtime, &s->t1);
stime = s->t3;
pp_time_sub(&stime, &s->t2);
s->delayMM = mtime;
pp_time_sub(&s->delayMM, &stime);
}
s->delayMM_ps = pp_time_to_picos(&s->delayMM);
/*
* Calculate the meanPathDelay
* meanPathDelay=delayMM/2)
*/
if (s->delayMM_ps < 0) {
s->delayMM_ps =meanPathDelay_ps=0;
picos_to_pp_time(s->delayMM_ps, &s->delayMM);
} else {
meanPathDelay_ps=s->delayMM_ps>>1; /* meanPathDelay=delayMM/2 */
}
if (__PP_DIAG_ALLOW(ppi, pp_dt_servo, 1)) {
l1e_dump_timestamp(ppi, "t1", s->t1);
l1e_dump_timestamp(ppi, "t2", s->t2);
l1e_dump_timestamp(ppi, "t3", s->t3);
l1e_dump_timestamp(ppi, "t4", s->t4);
l1e_dump_timestamp(ppi, "delayMM", s->delayMM);
}
if ( ppi->asymmetryCorrectionPortDS.enable ) {
/* Enabled: The delay asymmetry must be calculated
* delayAsymmetry=delayAsymCoefficient * meanPathDelay
*/
ppi->portDS->delayAsymmetry=calculateDelayAsymmetry(ppi->portDS->delayAsymCoeff,picos_to_interval(meanPathDelay_ps));
} else {
/* Disabled: The delay asymmetry is provided by configuration */
ppi->portDS->delayAsymmetry=ppi->asymmetryCorrectionPortDS.constantAsymmetry;
}
/* delayMS = meanPathDelay + delayAsym */
s->delayMS_ps = meanPathDelay_ps + interval_to_picos(ppi->portDS->delayAsymmetry);
picos_to_pp_time(s->delayMS_ps, &SRV(ppi)->delayMS);
wrs_shm_write(ppsi_head, WRS_SHM_WRITE_BEGIN);
/* Calculate offsetFromMaster : t1-t2+meanPathDelay+delayAsym=t1-t2+delayMS */
*offsetMS = s->t1;
pp_time_sub(offsetMS, &s->t2);
pp_time_add(offsetMS, &SRV(ppi)->delayMS); /* Add delayMS */
gs->t3 = ppi->t3; pp_servo_apply_faulty_stamp(gs, l1e_faulty_stamps,3);
gs->t4 = ppi->t4; pp_servo_apply_faulty_stamp(gs, l1e_faulty_stamps,4);
gs->t5 = ppi->t5; pp_servo_apply_faulty_stamp(gs, l1e_faulty_stamps,5);
gs->t6 = ppi->t6; pp_servo_apply_faulty_stamp(gs, l1e_faulty_stamps,6);
s->tracking_enabled = l1e_tracking_enabled;
gs->got_sync=1;
SRV(ppi)->offsetFromMaster=*offsetMS; /* Update servo.offsetFromMaster */
DSCUR(ppi)->offsetFromMaster = pp_time_to_interval(offsetMS); /* Update currentDS.offsetFromMaster */
wrs_shm_write(ppsi_head, WRS_SHM_WRITE_END);
picos_to_pp_time(meanPathDelay_ps,&SRV(ppi)->meanDelay); /* update servo.meanDelay */
update_meanDelay(ppi,picos_to_interval(meanPathDelay_ps)); /* update currentDS.meanDelay and portDS.meanLinkDelay (idf needed) */
return 1;
}
int l1e_servo_update(struct pp_instance *ppi)
static int __l1e_servo_update(struct pp_instance *ppi)
{
l1e_ext_portDS_t *pds=L1E_DSPOR(ppi);
struct pp_servo *gs=SRV(ppi);
struct l1e_servo_state *s=L1E_SRV(ppi);
int remaining_offset;
int32_t offset_ticks;
......@@ -394,38 +187,34 @@ int l1e_servo_update(struct pp_instance *ppi)
struct pp_time offsetMS ;
int32_t offset_ps;
if (!l1e_got_sync)
if ( gs->state==L1E_UNINITIALIZED )
return 0;
/* shmem lock */
wrs_shm_write(ppsi_head, WRS_SHM_WRITE_BEGIN);
if ( SRV(ppi)->state==L1E_UNINITIALIZED )
goto out;
prev_delayMM_ps = s->delayMM_ps;
if (CONFIG_HAS_P2P && ppi->delayMechanism == P2P) {
if (!l1e_p2p_offset(ppi, s, &offsetMS))
goto out;
} else {
if (!l1e_e2e_offset(ppi, s, &offsetMS))
goto out;
}
if ( !pp_servo_calculate_delays(ppi) )
return 0;
s->delayMM_ps=pp_time_to_picos(&gs->delayMM);
offsetMS=gs->offsetFromMaster;
s->offsetMS_ps=pp_time_to_picos(&offsetMS);
pp_diag(ppi, servo, 2,
"ML: scaledDelayCoeff = %lld, delayMS = %lld, offsetMS = %lld [ps]\n",
(long long )ppi->asymmetryCorrectionPortDS.scaledDelayCoefficient,
(long long )s->delayMS_ps,
(long long )s->offsetMS_ps);
l1e_dump_timestamp(ppi,"ML: offsetMS",offsetMS);
s->tracking_enabled = l1e_tracking_enabled;
// Servo updated
gs->update_count++;
ppi->t_ops->get(ppi, &gs->update_time);
pp_time_hardwarize(&offsetMS, s->clock_period_ps,
&offset_ticks, &offset_ps);
pp_diag(ppi, servo, 2, "offsetMS: %li sec %09li ticks (%li ps)\n",
(long)offsetMS.secs, (long)offset_ticks,
(long)offset_ps);
// if (CONFIG_HAS_P2P && ppi->delayMechanism == P2P) {
// if (!l1e_p2p_offset(ppi, s, &offsetMS))
// goto out;
// } else {
// if (!l1e_e2e_offset(ppi, s, &offsetMS))
// goto out;
// }
if (pds->basic.L1SyncState != L1SYNC_UP)
return 1; /* State is not UP. We have to wait before to start the synchronisation */
locking_poll_ret = WRH_OPER()->locking_poll(ppi, 0);
if (locking_poll_ret != WRH_SPLL_READY
......@@ -438,46 +227,52 @@ int l1e_servo_update(struct pp_instance *ppi)
/* After each action on the hardware, we must verify if it is over. */
if (!WRH_OPER()->adjust_in_progress()) {
SRV(ppi)->flags &= ~PP_SERVO_FLAG_WAIT_HW;
gs->flags &= ~PP_SERVO_FLAG_WAIT_HW;
} else {
pp_diag(ppi, servo, 1, "servo:busy\n");
goto out;
return 1;
}
/* So, we didn't return. Choose the right state */
if (offsetMS.secs) /* so bad... */
SRV(ppi)->state = L1E_SYNC_TAI;
else if (offset_ticks) /* not that bad */
SRV(ppi)->state = L1E_SYNC_NSEC;
if (offsetMS.secs) {/* so bad... */
gs->state = L1E_SYNC_TAI;
pp_diag(ppi, servo, 2, "offsetMS: %li sec ...\n",
(long)offsetMS.secs);
} else {
pp_time_hardwarize(&offsetMS, s->clock_period_ps,
&offset_ticks, &offset_ps);
pp_diag(ppi, servo, 2, "offsetMS: %li sec %09li ticks (%li ps)\n",
(long)offsetMS.secs, (long)offset_ticks,
(long)offset_ps);
if (offset_ticks) /* not that bad */
gs->state = L1E_SYNC_NSEC;
/* else, let the states below choose the sequence */
}
pp_diag(ppi, servo, 2, "offsetMS: %li.%09li (+%li)\n",
(long)offsetMS.secs, (long)offset_ticks,
(long)offset_ps);
/* update string state name */
strcpy(gs->servo_state_name, l1e_servo_state_name[gs->state]);
pp_diag(ppi, servo, 1, "l1e_servo state: %s%s\n",
l1e_servo_state_name[SRV(ppi)->state],
SRV(ppi)->flags & PP_SERVO_FLAG_WAIT_HW ? " (wait for hw)" : "");
/* update string state name */
strcpy(SRV(ppi)->servo_state_name, l1e_servo_state_name[SRV(ppi)->state]);
l1e_servo_state_name[gs->state],
gs->flags & PP_SERVO_FLAG_WAIT_HW ? " (wait for hw)" : "");
switch (SRV(ppi)->state) {
switch (gs->state) {
case L1E_SYNC_TAI:
WRH_OPER()->adjust_counters(offsetMS.secs, 0);
SRV(ppi)->flags |= PP_SERVO_FLAG_WAIT_HW;
gs->flags |= PP_SERVO_FLAG_WAIT_HW;
/*
* If nsec wrong, code above forces SYNC_NSEC,
* Else, we must ensure we leave this status towards
* fine tuning
*/
SRV(ppi)->state = L1E_SYNC_PHASE;
gs->state = L1E_SYNC_PHASE;
break;
case L1E_SYNC_NSEC:
WRH_OPER()->adjust_counters(0, offset_ticks);
SRV(ppi)->flags |= PP_SERVO_FLAG_WAIT_HW;
SRV(ppi)->state = L1E_SYNC_PHASE;
gs->flags |= PP_SERVO_FLAG_WAIT_HW;
gs->state = L1E_SYNC_PHASE;
break;
case L1E_SYNC_PHASE:
......@@ -488,8 +283,8 @@ int l1e_servo_update(struct pp_instance *ppi)
pp_diag(ppi, servo, 3, "%s.%d: Adjust_phase: %d\n",__func__,__LINE__,s->cur_setpoint_ps);
WRH_OPER()->adjust_phase(s->cur_setpoint_ps);
SRV(ppi)->flags |= PP_SERVO_FLAG_WAIT_HW;
SRV(ppi)->state = L1E_WAIT_OFFSET_STABLE;
gs->flags |= PP_SERVO_FLAG_WAIT_HW;
gs->state = L1E_WAIT_OFFSET_STABLE;
if (ARCH_IS_WRS) {
/*
......@@ -500,8 +295,8 @@ int l1e_servo_update(struct pp_instance *ppi)
struct pp_time t;
ppi->t_ops->get(ppi,&t);
unix_time_ops.set(ppi, &t);
pp_diag(ppi, time, 1, "system time set to %li TAI\n",
(long)ppi->t4.secs);
pp_diag(ppi, time, 1, "system time set to %s TAI\n",
time_to_string(&t));
}
break;
......@@ -512,13 +307,13 @@ int l1e_servo_update(struct pp_instance *ppi)
if(remaining_offset < WRH_SERVO_OFFSET_STABILITY_THRESHOLD) {
WRH_OPER()->enable_timing_output(ppi, 1);
s->prev_delayMS_ps = s->delayMS_ps;
SRV(ppi)->state = L1E_TRACK_PHASE;
gs->state = L1E_TRACK_PHASE;
} else {
s->missed_iters++;
}
if (s->missed_iters >= 10) {
s->missed_iters = 0;
SRV(ppi)->state = L1E_SYNC_PHASE;
gs->state = L1E_SYNC_PHASE;
}
break;
......@@ -529,7 +324,7 @@ int l1e_servo_update(struct pp_instance *ppi)
if(l1e_tracking_enabled) {
if (abs(offset_ps) >
2 * WRH_SERVO_OFFSET_STABILITY_THRESHOLD) {
SRV(ppi)->state = WR_SYNC_PHASE;
gs->state = L1E_SYNC_PHASE;
break;
}
......@@ -547,11 +342,11 @@ int l1e_servo_update(struct pp_instance *ppi)
}
SRV(ppi)->servo_locked=SRV(ppi)->state==L1E_TRACK_PHASE;
gs->servo_locked=gs->state==L1E_TRACK_PHASE;
/* Increase number of servo updates with state different than
* L1E_TRACK_PHASE. (Used by SNMP) */
if (SRV(ppi)->state != L1E_TRACK_PHASE)
if (gs->state != L1E_TRACK_PHASE)
s->n_err_state++;
/* Increase number of servo updates with offset exceeded
......@@ -563,13 +358,5 @@ int l1e_servo_update(struct pp_instance *ppi)
* SNMP_MAX_DELTA_RTT_PS (Used by SNMP) */
if (abs(prev_delayMM_ps - s->delayMM_ps) > SNMP_MAX_DELTA_RTT_PS)
s->n_err_delta_rtt++;
out:
/* shmem unlock */
wrs_shm_write(ppsi_head, WRS_SHM_WRITE_END);
if (WRH_OPER()->servo_hook)
WRH_OPER()->servo_hook(ppi, WRH_SERVO_LEAVE);
return 0;
return 1;
}
......@@ -47,7 +47,6 @@ static l1e_state_machine_t le1_state_actions[] ={
},
};
/*
* This hook is called by fsm to run the extension state machine.
* It is used to send signaling messages.
......@@ -60,6 +59,9 @@ int l1e_run_state_machine(struct pp_instance *ppi) {
Boolean newState=nextState!=basicDS->L1SyncState;
int delay;
if ( !ppi->ext_enabled )
return INT_MAX; /* Return a big delay. fsm will then not use it */
if ( nextState>=MAX_STATE_ACTIONS)
return pp_next_delay_2(ppi,L1E_TIMEOUT_TX_SYNC, L1E_TIMEOUT_RX_SYNC);
......@@ -74,8 +76,7 @@ int l1e_run_state_machine(struct pp_instance *ppi) {
/* Check L1SYNC reception Time-out */
if ( pp_timeout(ppi, L1E_TIMEOUT_RX_SYNC) ) {
/* Time-out detected */
int timeout_tx_sync = (4 << (basicDS->logL1SyncInterval + 8)) * basicDS->L1SyncReceiptTimeout;
__pp_timeout_set(ppi, L1E_TIMEOUT_RX_SYNC, timeout_tx_sync);
__pp_timeout_set(ppi, L1E_TIMEOUT_RX_SYNC, l1e_get_rx_tmo_ms(basicDS));
basicDS->L1SyncLinkAlive = FALSE;
execute_state_machine=TRUE;
}
......@@ -248,8 +249,6 @@ static int l1e_handle_state_disabled(struct pp_instance *ppi, Boolean new_state)
l1e_portDS->basic.peerIsRxCoherent =
l1e_portDS->basic.peerIsCongruent =
FALSE;
/* Set extension mode disabled */
l1e_portDS->head.extModeOn = l1e_portDS->parentExtModeOn = 0;
}
/* Check if state transition needed */
if ( le1_evt_L1_SYNC_ENABLED(ppi) && !le1_evt_L1_SYNC_RESET(ppi) ) {
......@@ -276,8 +275,6 @@ static int l1e_handle_state_idle(struct pp_instance *ppi, Boolean new_state){
l1e_portDS->basic.peerIsTxCoherent =
l1e_portDS->basic.peerIsRxCoherent=
l1e_portDS->basic.peerIsCongruent = FALSE;
/* Set extension mode disabled */
l1e_portDS->head.extModeOn = l1e_portDS->parentExtModeOn = 0;
l1e_send_sync_msg(ppi,1); /* Send immediately a message */
}
......@@ -285,6 +282,7 @@ static int l1e_handle_state_idle(struct pp_instance *ppi, Boolean new_state){
if ( !le1_evt_L1_SYNC_ENABLED(ppi) || le1_evt_L1_SYNC_RESET(ppi) ) {
/* Go to DISABLE state */
l1e_portDS->basic.next_state=L1SYNC_DISABLED;
ppi->link_state=PP_LSTATE_FAILURE;
return 0; /* Treatment required asap */
}
if ( le1_evt_LINK_OK(ppi) ) {
......@@ -303,8 +301,7 @@ static int l1e_handle_state_link_alive(struct pp_instance *ppi, Boolean new_stat
/* State initialization */
if ( new_state ) {
/* Initialize time-out peer L1SYNC reception */
int timeout_tx_sync = (4 << (basic->logL1SyncInterval + 8)) * basic->L1SyncReceiptTimeout;
__pp_timeout_set(ppi, L1E_TIMEOUT_RX_SYNC, timeout_tx_sync);
__pp_timeout_set(ppi, L1E_TIMEOUT_RX_SYNC, l1e_get_rx_tmo_ms(basic));
}
/* Check if state transition needed */
......@@ -374,9 +371,9 @@ static int l1e_handle_state_up(struct pp_instance *ppi, Boolean new_state){
/* State initialization */
if ( new_state ) {
l1e_servo_init(ppi); /* The servo can be initialized because the PPL is locked */
l1e_portDS->head.extModeOn =
l1e_portDS->parentExtModeOn = 1;
// JCB - test one servo
// l1e_servo_init(ppi); /* The servo can be initialized because the PPL is locked */
WRH_OPER()->enable_ptracker(ppi);
}
......@@ -384,6 +381,7 @@ static int l1e_handle_state_up(struct pp_instance *ppi, Boolean new_state){
if ( !le1_evt_LINK_OK(ppi) ) {
/* Go to IDLE state */
next_state=L1SYNC_IDLE;
ppi->link_state=PP_LSTATE_FAILURE;
}
if ( !le1_evt_CONFIG_OK(ppi) ) {
/* Return to LINK_ALIVE state */
......@@ -395,14 +393,13 @@ static int l1e_handle_state_up(struct pp_instance *ppi, Boolean new_state){
}
if (next_state!=0 ) {
l1e_portDS->basic.next_state=next_state;
l1e_portDS->head.extModeOn =
l1e_portDS->parentExtModeOn = 0;
WRH_OPER()->locking_disable(ppi); /* Unlock the PLL */
l1e_servo_reset(ppi);
return 0; /* Treat the next state asap */
}
/* Iterative treatment */
ppi->link_state=PP_LSTATE_LINKED;
l1e_update_correction_values(ppi);
l1e_send_sync_msg(ppi,0);
return pp_next_delay_2(ppi,L1E_TIMEOUT_TX_SYNC, L1E_TIMEOUT_RX_SYNC); /* Return the shorter timeout */
......
......@@ -187,12 +187,12 @@ static int wr_handle_announce(struct pp_instance *ppi)
return 0;
}
static int wr_sync_followup(struct pp_instance *ppi, struct pp_time *t1) {
static int wr_sync_followup(struct pp_instance *ppi) {
if (!WR_DSPOR(ppi)->wrModeOn)
return 0;
wr_servo_got_sync(ppi, t1, &ppi->t2);
wr_servo_got_sync(ppi);
if (CONFIG_HAS_P2P && ppi->delayMechanism == P2P)
wr_servo_update(ppi);
......@@ -200,18 +200,18 @@ static int wr_sync_followup(struct pp_instance *ppi, struct pp_time *t1) {
return 1; /* the caller returns too */
}
static int wr_handle_sync(struct pp_instance *ppi, struct pp_time *t1)
static int wr_handle_sync(struct pp_instance *ppi)
{
/* This handle is called in case of one step clock */
pp_diag(ppi, ext, 2, "hook: %s\n", __func__);
return wr_sync_followup(ppi,t1);
return wr_sync_followup(ppi);
}
static int wr_handle_followup(struct pp_instance *ppi, struct pp_time *t1)
static int wr_handle_followup(struct pp_instance *ppi)
{
/* This handle is called in case of two step clock */
pp_diag(ppi, ext, 2, "hook: %s\n", __func__);
return wr_sync_followup(ppi,t1);
return wr_sync_followup(ppi);
}
static __attribute__((used)) int wr_handle_presp(struct pp_instance *ppi)
......@@ -328,6 +328,10 @@ static void wr_state_change(struct pp_instance *ppi)
}
}
static int wr_require_precise_timestamp(struct pp_instance *ppi) {
return WR_DSPOR(ppi)->wrModeOn;
}
struct pp_ext_hooks wr_ext_hooks = {
.init = wr_init,
.open = wr_open,
......@@ -347,4 +351,6 @@ struct pp_ext_hooks wr_ext_hooks = {
.unpack_announce = wr_unpack_announce,
.state_decision = wr_state_decision,
.state_change = wr_state_change,
.servo_reset= wr_servo_reset,
.require_precise_timestamp=wr_require_precise_timestamp,
};
......@@ -110,8 +110,7 @@ int wr_execute_slave(struct pp_instance *ppi);
int wr_servo_init(struct pp_instance *ppi);
void wr_servo_reset(struct pp_instance *ppi);
void wr_servo_enable_tracking(int enable);
int wr_servo_got_sync(struct pp_instance *ppi, struct pp_time *t1,
struct pp_time *t2);
int wr_servo_got_sync(struct pp_instance *ppi);
int wr_servo_got_delay(struct pp_instance *ppi);
int wr_servo_update(struct pp_instance *ppi);
......
......@@ -181,7 +181,7 @@ int msg_pack_wrsig(struct pp_instance *ppi, Enumeration16 wr_msg_id)
put_be32(buf+68, wrp->deltaRx.scaledPicoseconds.lsb);
len = 24;
/*JCB: Hack. serrvo_init() called too early. PTP state machine must be modify. */
/*JCB: Hack. servo_init() called too early. PTP state machine must be modify. */
/* We should stay in UNCALIBRATED state during WR protocol */
s->delta_txm_ps = delta_to_ps(wrp->otherNodeDeltaTx);
s->delta_rxm_ps = delta_to_ps(wrp->otherNodeDeltaRx);
......
......@@ -150,14 +150,13 @@ int wr_servo_init(struct pp_instance *ppi)
return 0;
}
int wr_servo_got_sync(struct pp_instance *ppi, struct pp_time *t1,
struct pp_time *t2)
int wr_servo_got_sync(struct pp_instance *ppi)
{
struct wr_servo_state *s =
&((struct wr_data *)ppi->ext_data)->servo_state;
s->t1 = *t1; apply_faulty_stamp(s, 1);
s->t2 = *t2; apply_faulty_stamp(s, 2);
s->t1 = ppi->t1; apply_faulty_stamp(s, 1);
s->t2 = ppi->t2; apply_faulty_stamp(s, 2);
got_sync = 1;
return 0;
}
......@@ -222,8 +221,6 @@ static int wr_p2p_delay(struct pp_instance *ppi, struct wr_servo_state *s)
}
if (__PP_DIAG_ALLOW(ppi, pp_dt_servo, 1)) {
dump_timestamp(ppi, "servo:t1", s->t1);
dump_timestamp(ppi, "servo:t2", s->t2);
dump_timestamp(ppi, "servo:t3", s->t3);
dump_timestamp(ppi, "servo:t4", s->t4);
dump_timestamp(ppi, "servo:t5", s->t5);
......@@ -285,9 +282,6 @@ static int wr_e2e_offset(struct pp_instance *ppi,
if ( is_timestamps_incorrect(ppi,&errcount, 0xF /* mask=t1&t2&t3&t4 */))
return 0;
if (WRH_OPER()->servo_hook) /* FIXME: check this, missing in p2p */
WRH_OPER()->servo_hook(ppi, WRH_SERVO_ENTER);
SRV(ppi)->update_count++;
ppi->t_ops->get(ppi, &s->update_time);
......@@ -523,8 +517,5 @@ out:
/* shmem unlock */
wrs_shm_write(ppsi_head, WRS_SHM_WRITE_END);
if (WRH_OPER()->servo_hook)
WRH_OPER()->servo_hook(ppi, WRH_SERVO_LEAVE);
return 0;
}
......@@ -284,7 +284,7 @@ void bmc_s1(struct pp_instance *ppi,
prop->ptpTimescale = ((frgn_master->flagField[1] & FFB_PTP) != 0);
prop->timeSource = frgn_master->timeSource;
if (ppi->ext_hooks->s1)
if (is_ext_hook_available(ppi,s1))
ppi->ext_hooks->s1(ppi, frgn_master);
}
......@@ -1509,7 +1509,7 @@ int bmc(struct pp_instance *ppi)
}
/* Extra states handled here */
if (ppi->ext_hooks->state_decision)
if (is_ext_hook_available(ppi,state_decision))
next_state = ppi->ext_hooks->state_decision(ppi, next_state);
return next_state;
......
......@@ -21,11 +21,20 @@ static int presp_call_servo(struct pp_instance *ppi)
return 0; /* not an error, just no data */
pp_timeout_set(ppi, PP_TO_FAULT);
if (ppi->ext_hooks->handle_presp)
if (is_ext_hook_available(ppi,handle_presp))
ret = ppi->ext_hooks->handle_presp(ppi);
else
pp_servo_got_presp(ppi);
else {
if ( pp_servo_got_presp(ppi) && !ppi->ext_enabled ) {
ppi->link_state=PP_LSTATE_LINKED;
}
}
if ( ppi->state==PPS_MASTER) {
/* Called to update meanLinkDelay
* No risk of interaction with the slave servo.
* Each instance has its own servo structure
*/
pp_servo_calculate_delays(ppi);
}
return ret;
}
......@@ -146,13 +155,17 @@ int st_com_peer_handle_preq(struct pp_instance *ppi, void *buf,
if (ppi->delayMechanism != P2P)
return 0;
if (ppi->ext_hooks->handle_preq)
if (is_ext_hook_available(ppi,handle_preq))
e = ppi->ext_hooks->handle_preq(ppi);
if (e)
return e;
msg_issue_pdelay_resp(ppi, &ppi->last_rcv_time);
msg_issue_pdelay_resp_followup(ppi, &ppi->last_snt_time);
if ( !ppi->ext_enabled ) {
ppi->link_state=PP_LSTATE_LINKED;
}
return 0;
}
......
......@@ -122,14 +122,14 @@ int st_com_handle_announce(struct pp_instance *ppi, void *buf, int len)
if ( ! DSPOR(ppi)->masterOnly ) {
bmc_add_frgn_master(ppi, buf, len);
}
if (ppi->ext_hooks->handle_announce)
if (is_ext_hook_available(ppi,handle_announce))
return ppi->ext_hooks->handle_announce(ppi);
return 0;
}
int st_com_handle_signaling(struct pp_instance *ppi, void *buf, int len)
{
if (ppi->ext_hooks->handle_signaling)
if (is_ext_hook_available(ppi,handle_signaling))
return ppi->ext_hooks->handle_signaling(ppi,buf,len);
return 0;
}
......@@ -173,5 +173,3 @@ int __send_and_log(struct pp_instance *ppi, int msglen, int chtype,enum pp_msg_f
void __attribute__((weak)) update_meanDelay(struct pp_instance *ppi, TimeInterval meanDelay) {
DSCUR(ppi)->meanDelay=meanDelay;
}
......@@ -237,7 +237,7 @@ static int msg_pack_announce(struct pp_instance *ppi)
*(UInteger8 *) (buf + 62) = (UInteger8)DSCUR(ppi)->stepsRemoved;
*(Enumeration8 *) (buf + 63) = DSPRO(ppi)->timeSource;
if (ppi->ext_hooks->pack_announce)
if (is_ext_hook_available(ppi,pack_announce))
len = ppi->ext_hooks->pack_announce(ppi);
return len;
}
......@@ -263,7 +263,7 @@ void msg_unpack_announce(struct pp_instance *ppi, void *buf, MsgAnnounce *ann)
ann->timeSource = *(Enumeration8 *) (buf + 63);
/* this can fill in extention specific flags otherwise just zero them*/
if (ppi->ext_hooks->unpack_announce)
if (is_ext_hook_available(ppi,unpack_announce))
ppi->ext_hooks->unpack_announce(buf, ann);
else
ann->ext_specific = 0;
......
......@@ -158,7 +158,7 @@ int pp_init_globals(struct pp_globals *ppg, struct pp_runtime_opts *pp_rt_opts)
struct pp_instance *ppi = INST(ppg, i);
int r;
if (ppi->ext_hooks->open) {
if (is_ext_hook_available(ppi,open)) {
ret=(r=ppi->ext_hooks->open(ppi, rt_opts))==0 ? ret : r;
}
}
......@@ -174,7 +174,7 @@ int pp_close_globals(struct pp_globals *ppg)
struct pp_instance *ppi = INST(ppg, i);
int r;
if (ppi->ext_hooks->close) {
if (is_ext_hook_available(ppi,close) ){
ret=(r=ppi->ext_hooks->close(ppi))==0 ? ret : r;
}
}
......
......@@ -22,11 +22,18 @@ extern struct wrs_shm_head *ppsi_head;
static void pp_servo_mpd_fltr(struct pp_instance *, struct pp_avg_fltr *,
struct pp_time *);
static int pp_servo_offset_master(struct pp_instance *, struct pp_time *,
struct pp_time *, struct pp_time *);
static int pp_servo_offset_master(struct pp_instance *, struct pp_time *);
static int64_t pp_servo_pi_controller(struct pp_instance *, struct pp_time *);
static void _pp_servo_init(struct pp_instance *ppi);
static void __pp_servo_update(struct pp_instance *ppi);
void pp_servo_apply_faulty_stamp(struct pp_servo *s, struct pp_time *faulty_stamps, int index)
{
if (PROTO_EXT_HAS_FAULTS) {
assert(index >= 1 && index <= 6, "Wrong T index %i\n", index);
pp_time_add(&s->t1 + index - 1, faulty_stamps + index - 1);
}
}
void pp_servo_init(struct pp_instance *ppi)
{
......@@ -38,10 +45,10 @@ void pp_servo_init(struct pp_instance *ppi)
static void _pp_servo_init(struct pp_instance *ppi)
{
int d;
SRV(ppi)->state=0;
SRV(ppi)->servo_state_name[0]=0;
SRV(ppi)->mpd_fltr.s_exp = 0; /* clears meanDelay filter */
struct pp_servo * servo=SRV(ppi);
PP_SERVO_RESET_DATA(servo);
servo->mpd_fltr.s_exp = 0; /* clears meanDelay filter */
if (ppi->t_ops->init_servo) {
/* The system may pre-set us to keep current frequency */
d = ppi->t_ops->init_servo(ppi);
......@@ -49,239 +56,305 @@ static void _pp_servo_init(struct pp_instance *ppi)
pp_diag(ppi, servo, 1, "error in t_ops->servo_init");
d = 0;
}
SRV(ppi)->obs_drift = -d << 10; /* note "-" */
servo->obs_drift = -d << 10; /* note "-" */
} else {
/* level clock */
if (pp_can_adjust(ppi))
ppi->t_ops->adjust(ppi, 0, 0);
SRV(ppi)->obs_drift = 0;
servo->obs_drift = 0;
}
SRV(ppi)->flags |= PP_SERVO_FLAG_VALID;
SRV(ppi)->update_count = 0;
servo->flags |= PP_SERVO_FLAG_VALID;
pp_timeout_set(ppi, PP_TO_FAULT);
pp_diag(ppi, servo, 1, "Initialized: obs_drift %lli\n",
SRV(ppi)->obs_drift);
servo->obs_drift);
}
/* internal helper, returning static storage to be used immediately */
static char *fmt_ppt(struct pp_time *t)
{
static char s[24];
pp_sprintf(s, "%s%d.%09d",
(t->secs < 0 || (t->secs == 0 && t->scaled_nsecs < 0))
? "-" : " ",
/* FIXME: this is wrong for some of the negatives */
(int)abs(t->secs), (int)abs(t->scaled_nsecs >> 16));
return s;
#define BITS_IN_INT64 (sizeof(int64_t)*8)
/* Get the position of the first bit set on the left of a 64 bits integer */
static int getMsbSet(int64_t value) {
if ( value==0 )
return 0; /* value=0 so return bit 0 */
if ( value<0 )
value=-value; /* Negative value: change it to its positive value for the calculation */
return BITS_IN_INT64 - __builtin_clzll(value); /* using gcc built-in function */
}
/* Called by slave and uncalib when we have t1 and t2 */
void pp_servo_got_sync(struct pp_instance *ppi)
{
struct pp_time *delayMS = &SRV(ppi)->delayMS;
static int errcount=0;
#define DELAY_ASYM_BASE_FRACTION 50 /* Maxim value that can be used for the calculation */
if ( is_timestamps_incorrect(ppi,&errcount,3 /* mask=t1&t2 */) )
return;
/**
* Calculate the delayAsymmetry : delayAsymCoeff * meanDelay
*
* This calculation is made in order to use the maximum of bits in the fraction part. It will depend
* on the value of delayAsymCoeff and meanDelay. The smaller these values will be, bigger
* the fraction part will be.
*/
static TimeInterval calculateDelayAsymmetry(RelativeDifference scaledDelayAsymCoeff, TimeInterval scaledMeanDelay, TimeInterval constantAsymmetry) {
TimeInterval delayAsym;
int64_t rescaledAsymDelayCoeff,rescaledMeanDelay;
int lostBits,fracBitsUsed;
lostBits=getMsbSet(scaledDelayAsymCoeff)-(REL_DIFF_FRACBITS-DELAY_ASYM_BASE_FRACTION)+
getMsbSet(scaledMeanDelay)+(DELAY_ASYM_BASE_FRACTION-TIME_INTERVAL_FRACBITS)-BITS_IN_INT64;
if ( lostBits<0 )
lostBits=0;
fracBitsUsed=DELAY_ASYM_BASE_FRACTION-(lostBits>>1)-1;
rescaledMeanDelay = scaledMeanDelay<<(fracBitsUsed-TIME_INTERVAL_FRACBITS);
rescaledAsymDelayCoeff=scaledDelayAsymCoeff>>(REL_DIFF_FRACBITS-fracBitsUsed);
delayAsym= rescaledAsymDelayCoeff*rescaledMeanDelay;
delayAsym+=(1<<(fracBitsUsed-1));
delayAsym>>=fracBitsUsed;
delayAsym>>=(fracBitsUsed-TIME_INTERVAL_FRACBITS);
delayAsym+=constantAsymmetry;
return delayAsym;
}
static int calculate_p2p_delayMM(struct pp_instance *ppi) {
struct pp_servo *servo=SRV(ppi);
struct pp_time mtime, stime; /* Avoid modifying stamps in place*/
static int errcount;
if ( is_timestamps_incorrect(ppi,&errcount, 0x3C /* mask=t3&t4&t5&t6*/))
return 0; /* Error. Invalid timestamps */
if (__PP_DIAG_ALLOW(ppi, pp_dt_servo, 2)) {
pp_diag(ppi, servo, 2, "T3: %s s\n", time_to_string(&ppi->t3));
pp_diag(ppi, servo, 2, "T4: %s s\n", time_to_string(&ppi->t4));
pp_diag(ppi, servo, 2, "T5: %s s\n", time_to_string(&ppi->t5));
pp_diag(ppi, servo, 2, "T6: %s s\n", time_to_string(&ppi->t6));
}
/*
* calc 'master_to_slave_delay'; no correction field
* appears in the formulas because it's already merged with t1
* Calculate of the round trip delay (delayMM)
* delayMM = (t6-t3)-(t5-t4)
*/
*delayMS = ppi->t2;
pp_time_sub(delayMS, &ppi->t1);
SRV(ppi)->update_count++;
stime = servo->t6; pp_time_sub(&stime, &servo->t3);
mtime = servo->t5; pp_time_sub(&mtime, &servo->t4);
servo->delayMM = stime;
pp_time_sub(&servo->delayMM, &mtime);
return 1;
}
/* Called by slave and uncalib when we have t1 and t2 */
void pp_servo_got_psync(struct pp_instance *ppi)
{
struct pp_time *m_to_s_dly = &SRV(ppi)->delayMS;
struct pp_time *mpd = &SRV(ppi)->meanDelay;
struct pp_time *ofm = &SRV(ppi)->offsetFromMaster;
int adj32;
static int errcount=0;
if ( is_timestamps_incorrect(ppi,&errcount,3 /* mask=t1&t2 */) )
return;
static int calculate_e2e_delayMM(struct pp_instance *ppi) {
struct pp_servo *servo=SRV(ppi);
struct pp_time mtime, stime; /* Avoid modifying stamps in place*/
static int errcount;
pp_diag(ppi, servo, 2, "T1: %s\n", fmt_ppt(&ppi->t1));
pp_diag(ppi, servo, 2, "T2: %s\n", fmt_ppt(&ppi->t2));
if ( is_timestamps_incorrect(ppi,&errcount, 0xF /* mask=t1&t2&t3&t4*/))
return 0; /* Error. Invalid timestamps */
shmem_lock(); /* Share memory locked */
if (__PP_DIAG_ALLOW(ppi, pp_dt_servo, 2)) {
pp_diag(ppi, servo, 2, "T1: %s s\n", time_to_string(&servo->t1));
pp_diag(ppi, servo, 2, "T2: %s s\n", time_to_string(&servo->t2));
pp_diag(ppi, servo, 2, "T3: %s s\n", time_to_string(&servo->t3));
pp_diag(ppi, servo, 2, "T4: %s s\n", time_to_string(&servo->t4));
}
/*
* calc 'master_to_slave_delay'; no correction field
* appears in the formulas because it's already merged with t1
* Calculate the round trip delay (delayMM)
* delayMM = t4-t1-(t3-t2)
*/
*m_to_s_dly = ppi->t2;
pp_time_sub(m_to_s_dly, &ppi->t1);
mtime = servo->t4;
pp_time_sub(&mtime, &servo->t1);
stime = servo->t3;
pp_time_sub(&stime, &servo->t2);
servo->delayMM = mtime;
pp_time_sub(&servo->delayMM, &stime);
return 1;
}
/* update 'offsetFromMaster' and possibly jump in time */
if (!pp_servo_offset_master(ppi, mpd, ofm, m_to_s_dly)) {
int pp_servo_calculate_delays(struct pp_instance *ppi) {
int64_t meanDelay_ps,delayMM_ps,delayMS_ps;
static int errcount;
struct pp_servo *servo=SRV(ppi);
int ret;
/* PI controller returns a scaled_nsecs adjustment, so shift back */
adj32 = (int)(pp_servo_pi_controller(ppi, ofm) >> 16);
/* t1/t2 needed by both P2P and E2E calculation */
if ( is_timestamps_incorrect(ppi,&errcount, 0x3 /* mask=t1&t2 */))
return 0; /* Error. Invalid timestamps */
/* apply controller output as a clock tick rate adjustment, if
* provided by arch, or as a raw offset otherwise */
if (pp_can_adjust(ppi)) {
if (ppi->t_ops->adjust_freq)
ppi->t_ops->adjust_freq(ppi, -adj32);
else
ppi->t_ops->adjust_offset(ppi, -adj32);
}
if (CONFIG_HAS_P2P && ppi->delayMechanism == P2P)
ret=calculate_p2p_delayMM(ppi);
else
ret=calculate_e2e_delayMM(ppi);
if ( !ret)
return 0; /* delays cannot be calculated */
pp_diag(ppi, servo, 2, "Observed drift: %9i\n",
(int)SRV(ppi)->obs_drift >> 10);
delayMM_ps = pp_time_to_picos(&servo->delayMM);
/*
* Calculate the meanDelay
* meanDelay=delayMM/2)
*/
meanDelay_ps=delayMM_ps>>1; /* meanDelay=delayMM/2 */
if ( ppi->asymmetryCorrectionPortDS.enable ) {
/* Enabled: The delay asymmetry must be calculated
* delayAsymmetry=delayAsymCoefficient * meanPathDelay
*/
ppi->portDS->delayAsymmetry=calculateDelayAsymmetry(ppi->portDS->delayAsymCoeff,
picos_to_interval(meanDelay_ps),
ppi->asymmetryCorrectionPortDS.constantAsymmetry);
} else {
/* Disabled: The delay asymmetry is provided by configuration */
ppi->portDS->delayAsymmetry=ppi->asymmetryCorrectionPortDS.constantAsymmetry;
}
SRV(ppi)->update_count++;
shmem_unlock(); /* Share memory unlocked */
/* delayMS = meanDelay + delayAsym */
delayMS_ps = meanDelay_ps + interval_to_picos(ppi->portDS->delayAsymmetry);
picos_to_pp_time(delayMS_ps, &SRV(ppi)->delayMS);
/* Calculate offsetFromMaster : t1-t2+meanDelay+delayAsym=t1-t2+delayMS */
servo->offsetFromMaster = servo->t1;
pp_time_sub(&servo->offsetFromMaster, &servo->t2);
pp_time_add(&servo->offsetFromMaster, &servo->delayMS); /* Add delayMS */
DSCUR(ppi)->offsetFromMaster = pp_time_to_interval(&servo->offsetFromMaster); /* Update currentDS.offsetFromMaster */
picos_to_pp_time(meanDelay_ps,&servo->meanDelay); /* update servo.meanDelay */
update_meanDelay(ppi,picos_to_interval(meanDelay_ps)); /* update currentDS.meanDelay and portDS.meanLinkDelay (if needed) */
if (__PP_DIAG_ALLOW(ppi, pp_dt_servo, 2)) {
pp_diag(ppi, servo, 2,"delayMM : %s s\n", time_to_string(&servo->delayMM));
pp_diag(ppi, servo, 2,"delayMS : %s s\n", time_to_string(&servo->delayMS));
pp_diag(ppi, servo, 2,"delayAsym : %s ns\n", relative_interval_to_string(ppi->portDS->delayAsymCoeff));
pp_diag(ppi, servo, 2,"delayAsymCoeff : %s ns\n", interval_to_string(ppi->portDS->delayAsymmetry));
pp_diag(ppi, servo, 2,"meanDelay : %s s\n", time_to_string(&servo->meanDelay));
pp_diag(ppi, servo, 2,"offsetFromMaster: %s s\n", time_to_string(&servo->offsetFromMaster));
}
return 1;
}
/* Called by slave and uncalib when we have t1 and t2 */
/* t1 & t2 are already checked and they are correct */
void pp_servo_got_sync(struct pp_instance *ppi)
{
struct pp_servo *servo=SRV(ppi);
shmem_lock(); /* Share memory locked */
servo->t1=ppi->t1;
servo->t2=ppi->t2;
if (CONFIG_HAS_P2P && ppi->delayMechanism == P2P && servo->got_sync) {
/* P2P mechanism */
servo->got_sync=0;
__pp_servo_update(ppi);
} else
servo->got_sync=1;
shmem_unlock(); /* Share memory locked */
}
/* called by slave states when delay_resp is received (all t1..t4 are valid) */
void pp_servo_got_resp(struct pp_instance *ppi)
int pp_servo_got_resp(struct pp_instance *ppi)
{
struct pp_time *delayMS = &SRV(ppi)->delayMS;
struct pp_time *delaySM = &SRV(ppi)->delaySM;
struct pp_time *mpd = &SRV(ppi)->meanDelay;
struct pp_time *ofm = &SRV(ppi)->offsetFromMaster;
struct pp_avg_fltr *mpd_fltr = &SRV(ppi)->mpd_fltr;
int adj32;
struct pp_servo *servo=SRV(ppi);
static int errcount=0;
if ( !servo->got_sync )
return 0; /* t1 & t2 not available yet */
servo->got_sync=0; /* reseted for next time */
/* We sometimes enter here before we got sync/f-up */
if (ppi->t1.secs == 0 && ppi->t1.scaled_nsecs == 0) {
pp_diag(ppi, servo, 2, "discard T3/T4: we miss T1/T2\n");
return;
}
if ( is_timestamps_incorrect(ppi,&errcount,0xF /* mask=t1&t2&t3&t4 */) )
return;
shmem_lock(); /* Share memory locked */
/*
* calc 'slave_to_master_delay', removing delay_resp correction field
* added by transparent clocks in the path.
*/
*delaySM = ppi->t4;
pp_time_sub(delaySM, &ppi->t3);
pp_diag(ppi, servo, 2, "T1: %s\n", fmt_ppt(&ppi->t1));
pp_diag(ppi, servo, 2, "T2: %s\n", fmt_ppt(&ppi->t2));
pp_diag(ppi, servo, 2, "T3: %s\n", fmt_ppt(&ppi->t3));
pp_diag(ppi, servo, 2, "T4: %s\n", fmt_ppt(&ppi->t4));
pp_diag(ppi, servo, 1, "delayMS: %s\n", fmt_ppt(delayMS));
pp_diag(ppi, servo, 1, "delaySM: %s\n", fmt_ppt(delaySM));
/* Calc mean path delay, used later to calc "offset from master" */
*mpd = SRV(ppi)->delayMS;
pp_time_add(mpd, &SRV(ppi)->delaySM);
pp_time_div2(mpd);
update_meanDelay(ppi,pp_time_to_interval(mpd)); /* update currentDS.meanDelay and portDS.meanLinkDelay (idf needed) */
pp_diag(ppi, servo, 1, "meanDelay: %s\n", fmt_ppt(mpd));
if (mpd->secs) {/* Hmm.... we called this "bad event" */
shmem_unlock(); /* Share memory unlocked */
return;
if ( is_timestamps_incorrect(ppi,&errcount,0xC /* mask=t3&t4 */) ) {
return 0;
}
/* mean path delay filtering */
pp_servo_mpd_fltr(ppi, mpd_fltr, mpd);
/* update 'offsetFromMaster' and possibly jump in time */
if (!pp_servo_offset_master(ppi, mpd, ofm, delayMS)) {
shmem_lock(); /* Share memory locked */
/* PI controller */
adj32 = (int)(pp_servo_pi_controller(ppi, ofm) >> 16);
/* Save t3 and t4 */
servo->t3=ppi->t3;
servo->t4=ppi->t4;
/* apply controller output as a clock tick rate adjustment, if
* provided by arch, or as a raw offset otherwise */
if (pp_can_adjust(ppi)) {
if (ppi->t_ops->adjust_freq) {
ppi->t_ops->adjust_freq(ppi, -adj32);
}
else {
ppi->t_ops->adjust_offset(ppi, -adj32);
}
}
}
SRV(ppi)->update_count++;
shmem_unlock(); /* Share memory unlocked */
__pp_servo_update(ppi);
pp_diag(ppi, servo, 2, "Observed drift: %9i\n",
(int)SRV(ppi)->obs_drift >> 10);
shmem_unlock(); /* Share memory locked */
return 1;
}
/* called by slave states when delay_resp is received (all t1..t4 are valid) */
void pp_servo_got_presp(struct pp_instance *ppi)
int pp_servo_got_presp(struct pp_instance *ppi)
{
struct pp_time *delayMS = &SRV(ppi)->delayMS;
struct pp_time *delaySM = &SRV(ppi)->delaySM;
struct pp_time *mpd = &SRV(ppi)->meanDelay;
struct pp_avg_fltr *mpd_fltr = &SRV(ppi)->mpd_fltr;
struct pp_servo * servo = SRV(ppi);
static int errcount=0;
if ( is_timestamps_incorrect(ppi,&errcount,0x3C /* mask=&t3&t4&t5&t6 */) )
return;
return 0;
shmem_lock(); /* Share memory locked */
/*
* calc 'slave_to_master_delay', removing the correction field
* added by transparent clocks in the path.
*/
*delaySM = ppi->t6;
pp_time_sub(delaySM, &ppi->t5);
*delayMS = ppi->t4;
pp_time_sub(delayMS, &ppi->t3);
servo->t3=ppi->t3;
servo->t4=ppi->t4;
servo->t5=ppi->t5;
servo->t6=ppi->t6;
servo->got_sync=1;
pp_diag(ppi, servo, 2, "T3: %s\n", fmt_ppt(&ppi->t3));
pp_diag(ppi, servo, 2, "T4: %s\n", fmt_ppt(&ppi->t4));
pp_diag(ppi, servo, 2, "T5: %s\n", fmt_ppt(&ppi->t5));
pp_diag(ppi, servo, 2, "T6: %s\n", fmt_ppt(&ppi->t6));
pp_diag(ppi, servo, 1, "delayMS: %s\n", fmt_ppt(delayMS));
pp_diag(ppi, servo, 1, "delaySM: %s\n", fmt_ppt(delaySM));
shmem_unlock(); /* Share memory unlocked */
return 1;
}
/* Calc mean path delay, used later to calc "offset from master" */
*mpd = SRV(ppi)->delayMS;
pp_time_add(mpd, &SRV(ppi)->delaySM);
pp_time_div2(mpd);
update_meanDelay(ppi,pp_time_to_interval(mpd)); /* update currentDS.meanDelay and portDS.meanLinkDelay (idf needed) */
pp_diag(ppi, servo, 1, "meanDelay: %s\n", fmt_ppt(mpd));
if (!mpd->secs) /* =0 Hmm.... we called this "bad event" */
pp_servo_mpd_fltr(ppi, mpd_fltr, mpd);
static void __pp_servo_update(struct pp_instance *ppi) {
struct pp_servo *servo=SRV(ppi);
struct pp_time *meanDelay =&servo->meanDelay;
struct pp_avg_fltr *meanDelayFilter = &servo->mpd_fltr;
struct pp_time *offsetFromMaster = &servo->offsetFromMaster;
int adj32;
SRV(ppi)->update_count++;
if ( !pp_servo_calculate_delays(ppi) )
return;
if (meanDelay->secs) /* Hmm.... we called this "bad event" */
return;
pp_servo_mpd_fltr(ppi, meanDelayFilter, meanDelay);
/* update 'offsetFromMaster' and possibly jump in time */
if (!pp_servo_offset_master(ppi,offsetFromMaster)) {
/* PI controller returns a scaled_nsecs adjustment, so shift back */
adj32 = (int)(pp_servo_pi_controller(ppi, offsetFromMaster) >> 16);
/* apply controller output as a clock tick rate adjustment, if
* provided by arch, or as a raw offset otherwise */
if (pp_can_adjust(ppi)) {
if (ppi->t_ops->adjust_freq)
ppi->t_ops->adjust_freq(ppi, adj32);
else
ppi->t_ops->adjust_offset(ppi, adj32);
}
pp_diag(ppi, servo, 2, "Observed drift: %9i\n",
(int)SRV(ppi)->obs_drift >> 10);
}
servo->update_count++;
ppi->t_ops->get(ppi, &servo->update_time);
shmem_unlock(); /* Share memory unlocked */
}
static void pp_servo_mpd_fltr(struct pp_instance *ppi, struct pp_avg_fltr *mpd_fltr,
struct pp_time *mpd)
static void pp_servo_mpd_fltr(struct pp_instance *ppi, struct pp_avg_fltr *meanDelayFilter,
struct pp_time *meanDelay)
{
int s;
uint64_t y;
if (mpd_fltr->s_exp < 1) {
if (meanDelayFilter->s_exp < 1) {
/* First time, keep what we have */
mpd_fltr->y = mpd->scaled_nsecs;
if (mpd->scaled_nsecs < 0)
mpd_fltr->y = 0;
meanDelayFilter->y = meanDelay->scaled_nsecs;
if (meanDelay->scaled_nsecs < 0)
meanDelayFilter->y = 0;
}
/* avoid overflowing filter: calculate number of bits */
s = OPTS(ppi)->s;
while (mpd_fltr->y >> (63 - s))
while (meanDelayFilter->y >> (63 - s))
--s;
if (mpd_fltr->s_exp > 1LL << s)
mpd_fltr->s_exp = 1LL << s;
if (meanDelayFilter->s_exp > 1LL << s)
meanDelayFilter->s_exp = 1LL << s;
/* crank down filter cutoff by increasing 's_exp' */
if (mpd_fltr->s_exp < 1LL << s)
++mpd_fltr->s_exp;
if (meanDelayFilter->s_exp < 1LL << s)
++meanDelayFilter->s_exp;
/*
* It may happen that mpd appears as negative. This happens when
......@@ -290,10 +363,10 @@ static void pp_servo_mpd_fltr(struct pp_instance *ppi, struct pp_avg_fltr *mpd_f
* measured in the master. Ignore such values, by keeping the
* current average instead.
*/
if (mpd->scaled_nsecs < 0)
mpd->scaled_nsecs = mpd_fltr->y;
if (mpd->scaled_nsecs < 0)
mpd->scaled_nsecs = 0;
if (meanDelay->scaled_nsecs < 0)
meanDelay->scaled_nsecs = meanDelayFilter->y;
if (meanDelay->scaled_nsecs < 0)
meanDelay->scaled_nsecs = 0;
/*
* It may happen that mpd appears to be very big. This happens
......@@ -305,19 +378,19 @@ static void pp_servo_mpd_fltr(struct pp_instance *ppi, struct pp_avg_fltr *mpd_f
* The constant multipliers have been chosed arbitrarily, but
* they work well in testing environment.
*/
if (mpd->scaled_nsecs > 3 * mpd_fltr->y) {
if (meanDelay->scaled_nsecs > 3 * meanDelayFilter->y) {
pp_diag(ppi, servo, 1, "Trim too-long mpd: %i\n",
(int)(mpd->scaled_nsecs >> 16));
(int)(meanDelay->scaled_nsecs >> 16));
/* add fltr->s_exp to ensure we are not trapped into 0 */
mpd->scaled_nsecs = mpd_fltr->y * 2 + mpd_fltr->s_exp + 1;
meanDelay->scaled_nsecs = meanDelayFilter->y * 2 + meanDelayFilter->s_exp + 1;
}
/* filter 'meanDelay' (running average) -- use an unsigned "y" */
y = (mpd_fltr->y * (mpd_fltr->s_exp - 1) + mpd->scaled_nsecs);
__div64_32(&y, mpd_fltr->s_exp);
mpd->scaled_nsecs = mpd_fltr->y = y;
update_meanDelay(ppi,picos_to_interval(pp_time_to_interval(mpd))); /* update currentDS.meanDelay and portDS.meanLinkDelay (idf needed) */
pp_diag(ppi, servo, 1, "After avg(%i), meanDelay: %i\n",
(int)mpd_fltr->s_exp, (int)(mpd->scaled_nsecs >> 16));
y = (meanDelayFilter->y * (meanDelayFilter->s_exp - 1) + meanDelay->scaled_nsecs);
__div64_32(&y, meanDelayFilter->s_exp);
meanDelay->scaled_nsecs = meanDelayFilter->y = y;
update_meanDelay(ppi,pp_time_to_interval(meanDelay)); /* update currentDS.meanDelay and portDS.meanLinkDelay (idf needed) */
pp_diag(ppi, servo, 1, "After avg(%i), meanDelay: %s \n",
(int)meanDelayFilter->s_exp, time_to_string(meanDelay));
}
/* Thresholds are used to decide if we must use time or frequency adjustment
......@@ -325,14 +398,9 @@ static void pp_servo_mpd_fltr(struct pp_instance *ppi, struct pp_avg_fltr *mpd_f
#define TIME_ADJUST_THRESHOLD_SCALED_NS (((int64_t)20000000)<<TIME_INTERVAL_FRACBITS) /* 20ms */
#define TIME_ADJUST_THRESHOLD_SEC 0
static int pp_servo_offset_master(struct pp_instance *ppi, struct pp_time *mpd,
struct pp_time *ofm, struct pp_time *delayMS)
static int pp_servo_offset_master(struct pp_instance *ppi, struct pp_time *ofm)
{
struct pp_time time_tmp;
*ofm = *delayMS;
pp_time_sub(ofm, mpd);
DSCUR(ppi)->offsetFromMaster=pp_time_to_interval(ofm);
pp_diag(ppi, servo, 1, "Offset from master: %s\n", fmt_ppt(ofm));
if ( !( ofm->secs ||
(ofm->scaled_nsecs>TIME_ADJUST_THRESHOLD_SCALED_NS ) ||
......@@ -345,14 +413,20 @@ static int pp_servo_offset_master(struct pp_instance *ppi, struct pp_time *mpd,
return 0; /* e.g., a loopback test run... "-t" on cmdline */
ppi->t_ops->get(ppi, &time_tmp);
pp_time_sub(&time_tmp, ofm);
pp_time_add(&time_tmp, ofm);
ppi->t_ops->set(ppi, &time_tmp);
_pp_servo_init(ppi);
if (ARCH_IS_WRS) {
/* Enable PPS output */
WRH_OPER()->enable_timing_output(ppi, 1);
}
return 1; /* done */
}
static
int64_t pp_servo_pi_controller(struct pp_instance * ppi, struct pp_time *ofm)
static int64_t pp_servo_pi_controller(struct pp_instance * ppi, struct pp_time *ofm)
{
long long I_term;
long long P_term;
......
......@@ -103,7 +103,11 @@ int pp_initializing(struct pp_instance *ppi, void *buf, int len)
pp_timeout_setall(ppi);/* PP_TO_BMC is not set by default */
pp_timeout_set(ppi, PP_TO_BMC);
if (ppi->ext_hooks->init)
ppi->link_state=PP_LSTATE_PROTOCOL_DETECTION;
ppi->ptp_msg_received=FALSE;
ppi->ext_enabled=(ppi->protocol_extension!=PPSI_EXT_NONE);
if (is_ext_hook_available(ppi,init))
ret = ppi->ext_hooks->init(ppi, buf, len);
if (ret) {
pp_diag(ppi, ext, 1, "%s: can't init extension\n", __func__);
......
......@@ -29,7 +29,7 @@ int pp_listening(struct pp_instance *ppi, void *buf, int len)
MsgHeader *hdr = &ppi->received_ptp_header;
pp_timeout_set(ppi, PP_TO_FAULT); /* no fault as long as we listen */
if (ppi->ext_hooks->listening)
if (is_ext_hook_available(ppi,listening))
e = ppi->ext_hooks->listening(ppi, buf, len);
if (e)
goto out;
......
......@@ -31,7 +31,9 @@ static int master_handle_delay_request(struct pp_instance *ppi,
void *buf, int len)
{
if (ppi->state == PPS_MASTER) /* not pre-master */
msg_issue_delay_resp(ppi, &ppi->last_rcv_time);
if ( msg_issue_delay_resp(ppi, &ppi->last_rcv_time)==0 && !ppi->ext_enabled ) {
ppi->link_state=PP_LSTATE_LINKED;
}
return 0;
}
......@@ -79,7 +81,7 @@ int pp_master(struct pp_instance *ppi, void *buf, int len)
* PPM_NO_MESSAGE
*/
msgtype = ppi->received_ptp_header.messageType;
if (ppi->ext_hooks->master_msg)
if (is_ext_hook_available(ppi,master_msg))
msgtype = ppi->ext_hooks->master_msg(ppi, buf, len, msgtype);
if (msgtype < 0) {
e = msgtype;
......
......@@ -36,6 +36,7 @@ static pp_action *actions[] = {
static int slave_handle_sync(struct pp_instance *ppi, void *buf,
int len)
{
static int errcount=0;
MsgHeader *hdr = &ppi->received_ptp_header;
MsgSync sync;
......@@ -64,18 +65,19 @@ static int slave_handle_sync(struct pp_instance *ppi, void *buf,
ppi->t1 = sync.originTimestamp;
pp_time_add(&ppi->t1, &hdr->cField);
ppi->syncCF = 0;
/* t1 & t2 are saved in the instance. Check if they are correct */
if ( is_timestamps_incorrect(ppi,&errcount,3 /* mask=t1&t2 */) )
return 0;
/* Call the extension; it may do it all and ask to return */
if (ppi->ext_hooks->handle_sync) {
int ret = ppi->ext_hooks->handle_sync(ppi, &ppi->t1);
if ( is_ext_hook_available(ppi,handle_sync) ) {
int ret = ppi->ext_hooks->handle_sync(ppi);
if (ret == 1)
return 0;
if (ret < 0)
return ret;
}
if (CONFIG_HAS_P2P && ppi->delayMechanism == P2P)
pp_servo_got_psync(ppi);
else
pp_servo_got_sync(ppi);
pp_servo_got_sync(ppi);
}
return 0;
}
......@@ -83,8 +85,8 @@ static int slave_handle_sync(struct pp_instance *ppi, void *buf,
static int slave_handle_followup(struct pp_instance *ppi, void *buf,
int len)
{
static int errcount=0;
MsgFollowUp follow;
int ret = 0;
MsgHeader *hdr = &ppi->received_ptp_header;
......@@ -113,19 +115,19 @@ static int slave_handle_followup(struct pp_instance *ppi, void *buf,
pp_time_add(&ppi->t1, &follow.preciseOriginTimestamp);
pp_time_add(&ppi->t1, &hdr->cField);
ppi->syncCF = hdr->cField.scaled_nsecs; /* for diag about TC */
/* Call the extension; it may do it all and ask to return */
if (ppi->ext_hooks->handle_followup)
ret = ppi->ext_hooks->handle_followup(ppi, &ppi->t1);
if (ret == 1)
/* t1 & t2 are saved in the instance. Check if they are correct */
if ( is_timestamps_incorrect(ppi,&errcount,3 /* mask=t1&t2 */) )
return 0;
if (ret < 0)
return ret;
if (CONFIG_HAS_P2P && ppi->delayMechanism == P2P)
pp_servo_got_psync(ppi);
else
pp_servo_got_sync(ppi);
/* Call the extension; it may do it all and ask to return */
if (is_ext_hook_available(ppi,handle_followup) ){
int ret = ppi->ext_hooks->handle_followup(ppi);
if (ret == 1)
return 0;
if (ret < 0)
return ret;
}
/* default servo action */
pp_servo_got_sync(ppi);
return 0;
}
......@@ -133,9 +135,9 @@ static int slave_handle_followup(struct pp_instance *ppi, void *buf,
static int slave_handle_response(struct pp_instance *ppi, void *buf,
int len)
{
int e = 0;
MsgHeader *hdr = &ppi->received_ptp_header;
MsgDelayResp resp;
int ret;
msg_unpack_delay_resp(buf, &resp);
......@@ -155,15 +157,17 @@ static int slave_handle_response(struct pp_instance *ppi, void *buf,
/* WARNING: should be "sub" (see README-cfield::BUG) */
pp_timeout_set(ppi, PP_TO_FAULT);
if (ppi->ext_hooks->handle_resp)
e = ppi->ext_hooks->handle_resp(ppi);
else
pp_servo_got_resp(ppi);
if (e)
return e;
if (DSPOR(ppi)->logMinDelayReqInterval !=
hdr->logMessageInterval) {
if (is_ext_hook_available(ppi,handle_resp)) {
ret=ppi->ext_hooks->handle_resp(ppi);
}
else {
if ( (ret=pp_servo_got_resp(ppi)) && !ppi->ext_enabled ) {
ppi->link_state=PP_LSTATE_LINKED;
}
}
if ( ret &&
DSPOR(ppi)->logMinDelayReqInterval !=hdr->logMessageInterval) {
DSPOR(ppi)->logMinDelayReqInterval =
hdr->logMessageInterval;
/* new value for logMin */
......@@ -200,7 +204,7 @@ static int slave_execute(struct pp_instance *ppi)
{
int ret = 0;
if (ppi->ext_hooks->execute_slave)
if (is_ext_hook_available(ppi,execute_slave))
ret = ppi->ext_hooks->execute_slave(ppi);
if (ret == 1) /* done: just return */
return 0;
......@@ -216,13 +220,13 @@ static int slave_execute(struct pp_instance *ppi)
*/
int pp_slave(struct pp_instance *ppi, void *buf, int len)
{
int e = 0; /* error var, to check errors in msg handling */
int ret = PP_SEND_OK; /* error var, to check errors in msg handling */
int uncalibrated = (ppi->state == PPS_UNCALIBRATED);
MsgHeader *hdr = &ppi->received_ptp_header;
/* upgrade from uncalibrated to slave or back*/
if (uncalibrated) {
if ( ppi->ext_hooks->ready_for_slave != NULL ) {
if ( is_ext_hook_available(ppi,ready_for_slave) ) {
if ( (*ppi->ext_hooks->ready_for_slave)(ppi) ) {
ppi->next_state = PPS_SLAVE;
}
......@@ -244,9 +248,9 @@ int pp_slave(struct pp_instance *ppi, void *buf, int len)
pp_diag(ppi, bmc, 2, "Entered to uncalibrated, reset servo\n");
pp_servo_init(ppi);
if (ppi->ext_hooks->new_slave)
e = ppi->ext_hooks->new_slave(ppi, buf, len);
if (e)
if (is_ext_hook_available(ppi,new_slave))
ret = ppi->ext_hooks->new_slave(ppi, buf, len);
if (ret!=PP_SEND_OK)
goto out;
}
......@@ -258,7 +262,7 @@ int pp_slave(struct pp_instance *ppi, void *buf, int len)
*/
if (hdr->messageType < ARRAY_SIZE(actions)
&& actions[hdr->messageType]) {
e = actions[hdr->messageType](ppi, buf, len);
ret = actions[hdr->messageType](ppi, buf, len);
} else {
if (len)
pp_diag(ppi, frames, 1, "Ignored frame %i\n",
......@@ -269,25 +273,17 @@ int pp_slave(struct pp_instance *ppi, void *buf, int len)
* This function, common to uncalibrated and slave,
* is the core of the slave: hook
*/
e = slave_execute(ppi);
ret = slave_execute(ppi);
st_com_check_announce_receive_timeout(ppi);
out:
switch(e) {
case PP_SEND_OK: /* 0 */
break;
case PP_SEND_ERROR:
/* ignore: a lost frame is not the end of the world */
break;
case PP_SEND_NO_STAMP:
/* nothing, just keep the ball rolling */
e = 0;
break;
if ( ret==PP_SEND_NO_STAMP ) {
ret = PP_SEND_OK;/* nothing, just keep the ball rolling */
}
ppi->next_delay = pp_next_delay_2(ppi,
PP_TO_ANN_RECEIPT, PP_TO_REQUEST);
return e;
return ret;
}
......@@ -193,28 +193,28 @@ static int unix_time_set(struct pp_instance *ppi, const struct pp_time *t)
struct timespec tp;
if (!t) { /* Change the network notion of the utc/tai offset */
struct timex t;
struct timex tmx;
t.modes = MOD_TAI;
t.constant = DSPRO(ppi)->currentUtcOffset;
if (adjtimex(&t) < 0)
tmx.modes = MOD_TAI;
tmx.constant = DSPRO(ppi)->currentUtcOffset;
if (adjtimex(&tmx) < 0)
clock_fatal_error("change TAI offset");
pp_diag(ppi, time, 1, "New TAI offset: %i\n",
DSPRO(ppi)->currentUtcOffset);
return 0;
}
/* UTC = TAI - 35 */
tp.tv_sec = t->secs - DSPRO(ppi)->currentUtcOffset;
tp.tv_nsec = t->scaled_nsecs >> 16;
if ( tp.tv_sec < 0 || tp.tv_nsec<0) {
pp_error("%s: Cannot set clock time with negative values: %lisec %lins\n", __func__,(long int) tp.tv_sec,tp.tv_nsec );
} else {
if (clock_settime(CLOCK_REALTIME, &tp) < 0) {
clock_fatal_error("clock_settime");
/* UTC = TAI - 35 */
tp.tv_sec = t->secs - DSPRO(ppi)->currentUtcOffset;
tp.tv_nsec = t->scaled_nsecs >> 16;
if ( tp.tv_sec < 0 || tp.tv_nsec<0) {
pp_error("%s: Cannot set clock time with negative values: %lisec %lins\n", __func__,(long int) tp.tv_sec,tp.tv_nsec );
} else {
if (clock_settime(CLOCK_REALTIME, &tp) < 0) {
clock_fatal_error("clock_settime");
}
pp_diag(ppi, time, 1, "%s: %9li.%09li\n", __func__,
tp.tv_sec, tp.tv_nsec);
}
pp_diag(ppi, time, 1, "%s: %9li.%09li\n", __func__,
tp.tv_sec, tp.tv_nsec);
}
return 0;
}
......
......@@ -239,27 +239,28 @@ static int wrs_recv_msg(struct pp_instance *ppi, int fd, void *pkt, int len,
aux = (struct tpacket_auxdata *)dp;
}
if(sts && t)
{
int cntr_ahead = sts->hwtimeraw.tv_sec & 0x80000000 ? 1: 0;
t->scaled_nsecs = (long long)sts->hwtimeraw.tv_nsec << 16;
t->secs = sts->hwtimeraw.tv_sec & 0x7fffffff;
if ( t ) {
if (sts) {
int cntr_ahead = sts->hwtimeraw.tv_sec & 0x80000000 ? 1: 0;
t->scaled_nsecs = (long long)sts->hwtimeraw.tv_nsec << 16;
t->secs = sts->hwtimeraw.tv_sec & 0x7fffffff;
update_dmtd(s, ppi);
if ( WRH_DSPOR_HEAD(ppi)==NULL || !WRH_DSPOR_HEAD(ppi)->extModeOn) {
goto drop;
}
if (s->dmtd_phase_valid) {
wrs_linearize_rx_timestamp(t, s->dmtd_phase,
cntr_ahead, s->phase_transition, s->clock_period);
update_dmtd(s, ppi);
if ( ppi->ext_hooks->require_precise_timestamp!=NULL &&
(*ppi->ext_hooks->require_precise_timestamp)(ppi)) {
/* Precise time stamp required */
if (s->dmtd_phase_valid) {
wrs_linearize_rx_timestamp(t, s->dmtd_phase,
cntr_ahead, s->phase_transition, s->clock_period);
} else {
mark_incorrect(t);
}
}
} else {
mark_incorrect(t);
}
} else {
mark_incorrect(t);
}
drop:
/* For UDP, avoid all of the following, as we don't have vlans */
if (ppi->proto == PPSI_PROTO_UDP)
goto out;
......
......@@ -101,10 +101,10 @@ int wrs_enable_timing_output(struct pp_instance *ppi, int enable)
{
int ret, rval;
hexp_pps_params_t p;
static int ppsOutputOn=-1; /* -1 means we don't know the state */
if (enable == WRH_DSPOR_HEAD(ppi)->ppsOutputOn)
if (enable == ppsOutputOn)
return WRH_SPLL_OK;
WRH_DSPOR_HEAD(ppi)->ppsOutputOn = enable;
p.pps_valid = enable;
......@@ -113,6 +113,7 @@ int wrs_enable_timing_output(struct pp_instance *ppi, int enable)
if ((ret < 0) || (rval < 0))
return WRH_SPLL_ERROR;
ppsOutputOn = enable;
return WRH_SPLL_OK;
}
......
......@@ -15,10 +15,11 @@ static const char *timeOutNames[__PP_TO_ARRAY_SIZE]={
"ANN_SEND",
"FAULT",
"QUAL",
"PROT_STATE",
"EXT_0",
"EXT_1"
};
#define TIMEOUT_FAULTY_STATE_MS (60*1000) /* define the time to stay on faulty state before to go to initializing state */
#define TIMEOUT_MAX_LOG_VALUE 21 /* 2^21 * 1000 =2097152000ms is the maximum value that can be stored in an integer */
#define TIMEOUT_MIN_LOG_VALUE -9 /* 2^-9 = 1ms is the minimum value that can be stored in an integer */
#define TIMEOUT_MAX_VALUE_MS ((1<< TIMEOUT_MAX_LOG_VALUE)*1000)
......@@ -59,14 +60,17 @@ void pp_timeout_init(struct pp_instance *ppi)
timeouts[PP_TO_QUALIFICATION].which_rand =
timeouts[PP_TO_ANN_RECEIPT].which_rand =
timeouts[PP_TO_FAULT].which_rand =
timeouts[PP_TO_PROT_STATE].which_rand =
timeouts[PP_TO_EXT_0].which_rand =
timeouts[PP_TO_EXT_1].which_rand = TO_RAND_NONE;
timeouts[PP_TO_REQUEST].initValueMs= pp_timeout_log_to_ms(logDelayRequest);
/* fault timeout is 4 avg request intervals, not randomized */
timeouts[PP_TO_FAULT].initValueMs = pp_timeout_log_to_ms(logDelayRequest);
if ( timeouts[PP_TO_FAULT].initValueMs < (TIMEOUT_MAX_VALUE_MS>>2))
timeouts[PP_TO_FAULT].initValueMs<<=2; /* We can multiply by 4. No risk of overload */
timeouts[PP_TO_SYNC_SEND].initValueMs = pp_timeout_log_to_ms(port->logSyncInterval);
timeouts[PP_TO_BMC].initValueMs = pp_timeout_log_to_ms(port->logAnnounceInterval);
timeouts[PP_TO_ANN_RECEIPT].initValueMs = 1000 * (
......@@ -145,9 +149,13 @@ void pp_timeout_setall(struct pp_instance *ppi)
{
int i;
for (i = 0; i < __PP_TO_ARRAY_SIZE; i++) {
/* keep BMC timeout */
if (i!=PP_TO_BMC) {
pp_timeout_set(ppi, i);
if ( i==PP_TO_FAULT && ppi->next_state==PPS_FAULTY ){
__pp_timeout_set(ppi,PP_TO_FAULT,TIMEOUT_FAULTY_STATE_MS);
} else {
/* keep BMC timeout */
if (i!=PP_TO_BMC) {
pp_timeout_set(ppi, i);
}
}
}
/* but announce_send must be send soon */
......
......@@ -14,6 +14,7 @@
#define CALIBRATED_MASK 0x4
#define WR_CONFIG_MASK 0x3
#if CONFIG_PROFILE_WR == 1
static char *wr_message_name[] = {
"SLAVE_PRESENT",
"LOCK",
......@@ -22,6 +23,7 @@ static char *wr_message_name[] = {
"CALIBRATED",
"WR_MODE_ON",
};
#endif
static int dump_vlan(char *prefix, int vlan);
......@@ -165,6 +167,8 @@ static void dump_msg_resp_etc(char *prefix, char *s, struct ptp_sync_etc *p)
dump_1port(prefix, s, p->port);
}
#if CONFIG_PROFILE_WR == 1
/* TLV dumper, now white-rabbit aware */
static int wr_dump_tlv(char *prefix, struct ptp_tlv *tlv, int totallen)
{
......@@ -275,6 +279,9 @@ static int wr_dump_tlv(char *prefix, struct ptp_tlv *tlv, int totallen)
return explen;
}
#endif
#if CONFIG_EXT_L1SYNC == 1
static int l1sync_dump_tlv(char *prefix, struct l1sync_tlv *tlv, int totallen)
{
......@@ -299,6 +306,7 @@ static int l1sync_dump_tlv(char *prefix, struct l1sync_tlv *tlv, int totallen)
explen - sizeof(*tlv));
return explen;
}
#endif
/* A big function to dump the ptp information */
static void dump_payload(char *prefix, void *pl, int len)
......@@ -396,12 +404,16 @@ static void dump_payload(char *prefix, void *pl, int len)
break;
}
switch ( messageType) {
#if CONFIG_PROFILE_WR == 1
case PPM_ANNOUNCE :
donelen += wr_dump_tlv(prefix, pl + donelen, n);
break;
#endif
#if CONFIG_EXT_L1SYNC == 1
case PPM_SIGNALING :
donelen += l1sync_dump_tlv(prefix, pl + donelen, n);
break;
#endif
default :
goto out;
}
......
......@@ -82,8 +82,8 @@ struct dump_info dstp_info [] = {
#define DUMP_STRUCT struct pp_servo
struct dump_info servo_state_info [] = {
DUMP_FIELD(int , state),
DUMP_FIELD(time, delayMM),
DUMP_FIELD(time, delayMS),
DUMP_FIELD(time, delaySM),
DUMP_FIELD(long_long, obs_drift),
DUMP_FIELD(Integer64, mpd_fltr.m),
DUMP_FIELD(Integer64, mpd_fltr.y),
......@@ -91,7 +91,14 @@ struct dump_info servo_state_info [] = {
DUMP_FIELD(time, meanDelay),
DUMP_FIELD(time, offsetFromMaster),
DUMP_FIELD(unsigned_long, flags),
DUMP_FIELD(time, update_time),
DUMP_FIELD(UInteger32, update_count),
DUMP_FIELD(time, t1),
DUMP_FIELD(time, t2),
DUMP_FIELD(time, t3),
DUMP_FIELD(time, t4),
DUMP_FIELD(time, t5),
DUMP_FIELD(time, t6),
DUMP_FIELD_SIZE(char, servo_state_name,32),
DUMP_FIELD(int, servo_locked),
};
......@@ -101,7 +108,6 @@ struct dump_info servo_state_info [] = {
#define DUMP_STRUCT struct l1e_servo_state
struct dump_info l1e_servo_state_info [] = {
DUMP_FIELD(Integer32, clock_period_ps),
DUMP_FIELD(time, delayMM),
DUMP_FIELD(Integer64, delayMM_ps),
DUMP_FIELD(Integer32, cur_setpoint_ps),
DUMP_FIELD(Integer64, delayMS_ps),
......@@ -111,13 +117,6 @@ struct dump_info l1e_servo_state_info [] = {
DUMP_FIELD(UInteger32, n_err_state),
DUMP_FIELD(UInteger32, n_err_offset),
DUMP_FIELD(UInteger32, n_err_delta_rtt),
DUMP_FIELD(time, update_time),
DUMP_FIELD(time, t1),
DUMP_FIELD(time, t2),
DUMP_FIELD(time, t3),
DUMP_FIELD(time, t4),
DUMP_FIELD(time, t5),
DUMP_FIELD(time, t6),
DUMP_FIELD(Integer64, prev_delayMS_ps),
DUMP_FIELD(int, missed_iters),
};
......@@ -125,7 +124,6 @@ struct dump_info l1e_servo_state_info [] = {
#undef DUMP_STRUCT
#define DUMP_STRUCT l1e_ext_portDS_t
struct dump_info l1e_ext_portDS_info [] = {
DUMP_FIELD(Boolean, parentExtModeOn),
DUMP_FIELD(Boolean, basic.L1SyncEnabled),
DUMP_FIELD(Boolean, basic.txCoherentIsRequired),
DUMP_FIELD(Boolean, basic.rxCoherentIsRequired),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment