Commit 71e13609 authored by Aurelio Colosimo's avatar Aurelio Colosimo

proto-ext-whiterabbit development starting point

This commit simply copies everything from proto-standard to
proto-ext-whiterabbit. Actually, this is not an extension yet, since it is
quite hard to separate what is "modified" from what is "extended". So we
will have a separate directory for white rabbit, develop it as a separate
and independent plugin, and, a the end, split what is an extension of
proto-standard.

Notice that, with the current commit, whiterabbit is set as default in the
Makefile, so that you do not need to make PROTO_EXT=whiterabbit, but simply
make. In order to compile proto-standard, just set empty PROTO_EXT:
make PROTO_EXT=
parent b2cdf162
......@@ -28,12 +28,18 @@ OBJ-y := fsm.o
# include diagnostic objects
include diag/Makefile
# proto-standard is always included
include proto-standard/Makefile
# Update 2012-07-10
# proto-standard should always be included, but in this current devel step
# each proto is intended as a separate plugin (not properly an "extension").
# See below (ifdef PROTO_EXT/else)
#include proto-standard/Makefile
# including the extension Makefile, if an extension is there
PROTO_EXT ?= whiterabbit
ifdef PROTO_EXT
include proto-ext-$(PROTO_EXT)/Makefile
else
include proto-standard/Makefile
endif
WRMODE = slave
......
......@@ -33,7 +33,7 @@ all: $(TARGET) $(TARGET).bin
# were not selected yet (e.g., pp_open_instance() ).
$(TARGET): $(TARGET).o $A/crt0.o $(LIBARCH)
$(CC) -Wl,-Map,$(TARGET).map2 $(ARCH_LDFLAGS) -o $@ $A/crt0.o \
$(TARGET).o -L$A -larch -L$D -lstd
$(TARGET).o -L$A -larch -L$D -lstd -L$W -lwr
$(TARGET).bin: $(TARGET)
$(OBJCOPY) -O binary $^ $@
# Makefile for an extended protocol.
# Alessandro Rubini for CERN, 2011 -- public domain
#
# We add to obj-y, and further undefined symbols are taken from libstd
# (i.e., code and data from the standard protocol)
# Hosted environment: build the final exectuable
P := proto-ext-$(PROTO_EXT)
# All files are under D: I'm lazy
W := proto-ext-whiterabbit
OBJ-y += $P/ext-wr.o
LIBWR := $W/libwr.a
LIBS += -L$W -lwr
OBJ-libwr := $W/fsm-table.o \
$W/state-initializing.o \
$W/state-faulty.o \
$W/state-disabled.o \
$W/state-listening.o \
$W/state-pre-master.o \
$W/state-master.o \
$W/state-passive.o \
$W/state-uncalibrated.o \
$W/state-slave.o \
$W/common-fun.o \
$W/bmc.o \
$W/msg.o \
$W/arith.o \
$W/servo.o \
$W/open-close.o
$(TARGET).o: $(LIBWR)
$(LIBWR): $(OBJ-libwr)
$(AR) r $@ $^
/*
* Aurelio Colosimo for CERN, 2011 -- GNU LGPL v2.1 or later
* Based on PTPd project v. 2.1.0 (see AUTHORS for details)
*/
#include <limits.h>
#include <ppsi/ppsi.h>
#include <ppsi/diag.h>
void int64_to_TimeInternal(Integer64 bigint, TimeInternal *internal)
{
uint64_t bigint_val;
if (bigint.msb < 0)
pp_printf("BUG: %s doesn't support negatives\n", __func__);
bigint_val = bigint.lsb;
bigint_val += ((int64_t)bigint.msb) << 32;
/* Use __div64_32 from library, to avoid libgcc on small targets */
internal->nanoseconds = __div64_32(&bigint_val, PP_NSEC_PER_SEC);
internal->seconds = bigint_val;
}
int from_TimeInternal(TimeInternal *internal, Timestamp *external)
{
/*
* fromInternalTime is only used to convert time given by the system
* to a timestamp As a consequence, no negative value can normally
* be found in (internal)
*
* Note that offsets are also represented with TimeInternal structure,
* and can be negative, but offset are never convert into Timestamp
* so there is no problem here.
*/
if ((internal->seconds & ~INT_MAX) ||
(internal->nanoseconds & ~INT_MAX)) {
PP_PRINTF("Error: Negative value cannot be converted into "
"timestamp\n");
return -1;
} else {
external->secondsField.lsb = internal->seconds;
external->nanosecondsField = internal->nanoseconds;
external->secondsField.msb = 0;
}
return 0;
}
int to_TimeInternal(TimeInternal *internal, Timestamp *external)
{
/* Program will not run after 2038... */
if (external->secondsField.lsb < INT_MAX) {
internal->seconds = external->secondsField.lsb;
internal->nanoseconds = external->nanosecondsField;
return 0;
} else {
PP_PRINTF("to_TimeInternal: "
"seconds field is higher than signed integer (32bits)\n");
return -1;
}
}
static void normalize_TimeInternal(TimeInternal *r)
{
r->seconds += r->nanoseconds / PP_NSEC_PER_SEC;
r->nanoseconds -= r->nanoseconds / PP_NSEC_PER_SEC * PP_NSEC_PER_SEC;
if (r->seconds > 0 && r->nanoseconds < 0) {
r->seconds -= 1;
r->nanoseconds += PP_NSEC_PER_SEC;
} else if (r->seconds < 0 && r->nanoseconds > 0) {
r->seconds += 1;
r->nanoseconds -= PP_NSEC_PER_SEC;
}
}
void add_TimeInternal(TimeInternal *r, TimeInternal *x, TimeInternal *y)
{
r->seconds = x->seconds + y->seconds;
r->nanoseconds = x->nanoseconds + y->nanoseconds;
normalize_TimeInternal(r);
}
void sub_TimeInternal(TimeInternal *r, TimeInternal *x, TimeInternal *y)
{
r->seconds = x->seconds - y->seconds;
r->nanoseconds = x->nanoseconds - y->nanoseconds;
normalize_TimeInternal(r);
}
void div2_TimeInternal(TimeInternal *r)
{
r->nanoseconds += r->seconds % 2 * 1000000000;
r->seconds /= 2;
r->nanoseconds /= 2;
normalize_TimeInternal(r);
}
void set_TimeInternal(TimeInternal *t, Integer32 s, Integer32 ns)
{
t->seconds = s;
t->nanoseconds = ns;
}
void display_TimeInternal(const char *label, TimeInternal *t)
{
PP_VPRINTF("%s: %s%d.%09d \n", label,
(t->seconds < 0 || (t->seconds == 0 && t->nanoseconds < 0)) ? "-" : " ",
abs(t->seconds), abs(t->nanoseconds));
}
/*
* Aurelio Colosimo for CERN, 2011 -- GNU LGPL v2.1 or later
* Based on PTPd project v. 2.1.0 (see AUTHORS for details)
*/
#include <ppsi/ppsi.h>
#include <ppsi/diag.h>
/* Flag Field bits symbolic names (table 57, pag. 151) */
#define FFB_LI61 0x01
#define FFB_LI59 0x02
#define FFB_UTCV 0x04
#define FFB_PTP 0x08
#define FFB_TTRA 0x10
#define FFB_FTRA 0x20
/* Local clock is becoming Master. Table 13 (9.3.5) of the spec. */
void m1(struct pp_instance *ppi)
{
/* Current data set update */
DSCUR(ppi)->stepsRemoved = 0;
DSCUR(ppi)->offsetFromMaster.nanoseconds = 0;
DSCUR(ppi)->offsetFromMaster.seconds = 0;
DSCUR(ppi)->meanPathDelay.nanoseconds = 0;
DSCUR(ppi)->meanPathDelay.seconds = 0;
/* Parent data set */
pp_memcpy(DSPAR(ppi)->parentPortIdentity.clockIdentity,
DSDEF(ppi)->clockIdentity, PP_CLOCK_IDENTITY_LENGTH);
DSPAR(ppi)->parentPortIdentity.portNumber = 0;
DSPAR(ppi)->parentStats = PP_DEFAULT_PARENTS_STATS;
DSPAR(ppi)->observedParentClockPhaseChangeRate = 0;
DSPAR(ppi)->observedParentOffsetScaledLogVariance = 0;
pp_memcpy(DSPAR(ppi)->grandmasterIdentity, DSDEF(ppi)->clockIdentity,
PP_CLOCK_IDENTITY_LENGTH);
DSPAR(ppi)->grandmasterClockQuality.clockAccuracy =
DSDEF(ppi)->clockQuality.clockAccuracy;
DSPAR(ppi)->grandmasterClockQuality.clockClass =
DSDEF(ppi)->clockQuality.clockClass;
DSPAR(ppi)->grandmasterClockQuality.offsetScaledLogVariance =
DSDEF(ppi)->clockQuality.offsetScaledLogVariance;
DSPAR(ppi)->grandmasterPriority1 = DSDEF(ppi)->priority1;
DSPAR(ppi)->grandmasterPriority2 = DSDEF(ppi)->priority2;
/* Time Properties data set */
DSPRO(ppi)->timeSource = INTERNAL_OSCILLATOR;
}
/* Local clock is synchronized to Ebest Table 16 (9.3.5) of the spec. */
void s1(struct pp_instance *ppi, MsgHeader *hdr, MsgAnnounce *ann)
{
/* Current DS */
DSCUR(ppi)->stepsRemoved = ann->stepsRemoved + 1;
/* Parent DS */
pp_memcpy(DSPAR(ppi)->parentPortIdentity.clockIdentity,
hdr->sourcePortIdentity.clockIdentity,
PP_CLOCK_IDENTITY_LENGTH);
DSPAR(ppi)->parentPortIdentity.portNumber =
hdr->sourcePortIdentity.portNumber;
pp_memcpy(DSPAR(ppi)->grandmasterIdentity,
ann->grandmasterIdentity, PP_CLOCK_IDENTITY_LENGTH);
DSPAR(ppi)->grandmasterClockQuality.clockAccuracy =
ann->grandmasterClockQuality.clockAccuracy;
DSPAR(ppi)->grandmasterClockQuality.clockClass =
ann->grandmasterClockQuality.clockClass;
DSPAR(ppi)->grandmasterClockQuality.offsetScaledLogVariance =
ann->grandmasterClockQuality.offsetScaledLogVariance;
DSPAR(ppi)->grandmasterPriority1 = ann->grandmasterPriority1;
DSPAR(ppi)->grandmasterPriority2 = ann->grandmasterPriority2;
/* Timeproperties DS */
DSPRO(ppi)->currentUtcOffset = ann->currentUtcOffset;
/* "Valid" is bit 2 in second octet of flagfield */
DSPRO(ppi)->currentUtcOffsetValid = ((hdr->flagField[1] & FFB_UTCV)
!= 0);
DSPRO(ppi)->leap59 = ((hdr->flagField[1] & FFB_LI59) != 0);
DSPRO(ppi)->leap61 = ((hdr->flagField[1] & FFB_LI61) != 0);
DSPRO(ppi)->timeTraceable = ((hdr->flagField[1] & FFB_TTRA) != 0);
DSPRO(ppi)->frequencyTraceable = ((hdr->flagField[1] & FFB_FTRA) != 0);
DSPRO(ppi)->ptpTimescale = ((hdr->flagField[1] & FFB_PTP) != 0);
DSPRO(ppi)->timeSource = ann->timeSource;
}
/* Copy local data set into header and ann message. 9.3.4 table 12. */
void copy_d0( struct pp_instance *ppi, MsgHeader *hdr, MsgAnnounce *ann)
{
ann->grandmasterPriority1 = DSDEF(ppi)->priority1;
pp_memcpy(ann->grandmasterIdentity, DSDEF(ppi)->clockIdentity,
PP_CLOCK_IDENTITY_LENGTH);
ann->grandmasterClockQuality.clockClass =
DSDEF(ppi)->clockQuality.clockClass;
ann->grandmasterClockQuality.clockAccuracy =
DSDEF(ppi)->clockQuality.clockAccuracy;
ann->grandmasterClockQuality.offsetScaledLogVariance =
DSDEF(ppi)->clockQuality.offsetScaledLogVariance;
ann->grandmasterPriority2 = DSDEF(ppi)->priority2;
ann->stepsRemoved = 0;
pp_memcpy(hdr->sourcePortIdentity.clockIdentity,
DSDEF(ppi)->clockIdentity, PP_CLOCK_IDENTITY_LENGTH);
}
/*
* Data set comparison bewteen two foreign masters (9.3.4 fig 27)
* return similar to memcmp()
*/
Integer8 bmc_dataset_cmp(struct pp_instance *ppi,
MsgHeader *hdr_a, MsgAnnounce *ann_a,
MsgHeader *hdr_b, MsgAnnounce *ann_b)
{
short comp = 0;
Octet *ppci;
PP_VPRINTF("BMC: in bmc_dataset_cmp\n");
/* Identity comparison */
if (!pp_memcmp(ann_a->grandmasterIdentity,
ann_b->grandmasterIdentity, PP_CLOCK_IDENTITY_LENGTH)) {
/* Algorithm part2 Fig 28 */
if (ann_a->stepsRemoved > ann_b->stepsRemoved + 1)
return 1;
else if (ann_b->stepsRemoved > ann_a->stepsRemoved + 1)
return -1;
else { /* A within 1 of B */
ppci = DSPAR(ppi)->parentPortIdentity.clockIdentity;
if (ann_a->stepsRemoved > ann_b->stepsRemoved) {
if (!pp_memcmp(
hdr_a->sourcePortIdentity.clockIdentity,
ppci,
PP_CLOCK_IDENTITY_LENGTH)) {
PP_PRINTF("Sender=Receiver: Error -1");
return 0;
} else
return 1;
} else if (ann_b->stepsRemoved > ann_a->stepsRemoved) {
if (!pp_memcmp(
hdr_b->sourcePortIdentity.clockIdentity,
ppci,
PP_CLOCK_IDENTITY_LENGTH)) {
PP_PRINTF("Sender=Receiver: Error -3");
return 0;
} else {
return -1;
}
} else { /* steps removed A == steps removed B */
if (!pp_memcmp(
hdr_a->sourcePortIdentity.clockIdentity,
hdr_b->sourcePortIdentity.clockIdentity,
PP_CLOCK_IDENTITY_LENGTH)) {
PP_PRINTF("Sender=Receiver: Error -2");
return 0;
} else if ((pp_memcmp(
hdr_a->sourcePortIdentity.clockIdentity,
hdr_b->sourcePortIdentity.clockIdentity,
PP_CLOCK_IDENTITY_LENGTH)) < 0)
return -1;
else
return 1;
}
}
} else { /* GrandMaster are not identical */
/* FIXME: rewrite in a more readable way */
if (ann_a->grandmasterPriority1 == ann_b->grandmasterPriority1) {
if (ann_a->grandmasterClockQuality.clockClass ==
ann_b->grandmasterClockQuality.clockClass) {
if (ann_a->grandmasterClockQuality.clockAccuracy == ann_b->grandmasterClockQuality.clockAccuracy) {
if (ann_a->grandmasterClockQuality.offsetScaledLogVariance == ann_b->grandmasterClockQuality.offsetScaledLogVariance) {
if (ann_a->grandmasterPriority2 == ann_b->grandmasterPriority2) {
comp = pp_memcmp(ann_a->grandmasterIdentity, ann_b->grandmasterIdentity, PP_CLOCK_IDENTITY_LENGTH);
if (comp < 0)
return -1;
else if (comp > 0)
return 1;
else
return 0;
} else {
/* Priority2 are not identical */
comp = pp_memcmp(&ann_a->grandmasterPriority2, &ann_b->grandmasterPriority2, 1);
if (comp < 0)
return -1;
else if (comp > 0)
return 1;
else
return 0;
}
} else {
/* offsetScaledLogVariance are not identical */
comp = pp_memcmp(&ann_a->grandmasterClockQuality.clockClass, &ann_b->grandmasterClockQuality.clockClass, 1);
if (comp < 0)
return -1;
else if (comp > 0)
return 1;
else
return 0;
}
} else { /* Accuracy are not identitcal */
comp = pp_memcmp(&ann_a->grandmasterClockQuality.clockAccuracy, &ann_b->grandmasterClockQuality.clockAccuracy, 1);
if (comp < 0)
return -1;
else if (comp > 0)
return 1;
else
return 0;
}
} else { /* ClockClass are not identical */
comp = pp_memcmp(&ann_a->grandmasterClockQuality.clockClass, &ann_b->grandmasterClockQuality.clockClass, 1);
if (comp < 0)
return -1;
else if (comp > 0)
return 1;
else
return 0;
}
} else { /* Priority1 are not identical */
comp = pp_memcmp(&ann_a->grandmasterPriority1, &ann_b->grandmasterPriority1, 1);
if (comp < 0)
return -1;
else if (comp > 0)
return 1;
else
return 0;
}
}
}
/* State decision algorithm 9.3.3 Fig 26 */
UInteger8 bmc_state_decision( struct pp_instance *ppi,
MsgHeader *hdr, MsgAnnounce *ann)
{
int cmpres;
if (OPTS(ppi)->slave_only) {
s1(ppi, hdr, ann);
return PPS_SLAVE;
}
if ((!ppi->number_foreign_records) && (ppi->state == PPS_LISTENING))
return PPS_LISTENING;
copy_d0(ppi, &ppi->msg_tmp_header, &ppi->msg_tmp.announce);
cmpres = bmc_dataset_cmp(ppi,
&ppi->msg_tmp_header,
&ppi->msg_tmp.announce,
hdr, ann);
if (DSDEF(ppi)->clockQuality.clockClass < 128) {
if (cmpres < 0) {
m1(ppi);
return PPS_MASTER;
} else if (cmpres > 0) {
s1(ppi, hdr, ann);
return PPS_PASSIVE;
}
} else {
if (cmpres < 0) {
m1(ppi);
return PPS_MASTER;
} else if (cmpres > 0) {
s1(ppi, hdr, ann);
return PPS_SLAVE;
}
}
if (cmpres == 0) {
PP_PRINTF("Error in bmc_state_decision, cmpres=0.\n");
}
/* MB: Is this the return code below correct? */
/* Anyway, it's a valid return code. */
return PPS_FAULTY;
}
UInteger8 bmc(struct pp_instance *ppi, struct pp_frgn_master *frgn_master)
{
Integer16 i, best;
if (!ppi->number_foreign_records)
if (ppi->state == PPS_MASTER) {
m1(ppi);
return ppi->state;
}
for (i = 1, best = 0; i < ppi->number_foreign_records; i++)
if (bmc_dataset_cmp(ppi,
&frgn_master[i].hdr,
&frgn_master[i].ann,
&frgn_master[best].hdr,
&frgn_master[best].ann) < 0)
best = i;
PP_VPRINTF("bmc, best record : %d\n", best);
ppi->foreign_record_best = best;
return bmc_state_decision(ppi, &frgn_master[best].hdr,
&frgn_master[best].ann);
}
/*
* Aurelio Colosimo for CERN, 2011 -- GNU LGPL v2.1 or later
* Based on PTPd project v. 2.1.0 (see AUTHORS for details)
*/
#include <ppsi/ppsi.h>
#include <ppsi/diag.h>
#include "common-fun.h"
int st_com_execute_slave(struct pp_instance *ppi, int check_delayreq)
{
int ret = 0;
if (pp_timer_expired(ppi->timers[PP_TIMER_ANN_RECEIPT])) {
PP_VPRINTF("event ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES\n");
ppi->number_foreign_records = 0;
ppi->foreign_record_i = 0;
if (!DSDEF(ppi)->slaveOnly &&
DSDEF(ppi)->clockQuality.clockClass != 255) {
m1(ppi);
ppi->next_state = PPS_MASTER;
} else {
ppi->next_state = PPS_LISTENING;
st_com_restart_annrec_timer(ppi);
}
}
if (!check_delayreq)
return 0;
if (OPTS(ppi)->e2e_mode) {
if (pp_timer_expired(ppi->timers[PP_TIMER_DELAYREQ])) {
PP_VPRINTF("event DELAYREQ_INTERVAL_TIMEOUT_EXPIRES\n");
ret = msg_issue_delay_req(ppi);
set_TimeInternal(&ppi->delay_req_send_time,
ppi->last_snt_time.seconds, ppi->last_snt_time.nanoseconds);
/* Add latency */
add_TimeInternal(&ppi->delay_req_send_time,
&ppi->delay_req_send_time,
&OPTS(ppi)->outbound_latency);
}
} else {
if (pp_timer_expired(ppi->timers[PP_TIMER_PDELAYREQ]))
{
PP_VPRINTF("event PDELAYREQ_INTERVAL_TOUT_EXPIRES\n");
ret = msg_issue_pdelay_req(ppi);
}
}
return ret;
}
void st_com_restart_annrec_timer(struct pp_instance *ppi)
{
/* 0 <= logAnnounceInterval <= 4, see pag. 237 of spec */
if (DSPOR(ppi)->logAnnounceInterval < 0)
PP_PRINTF("Error: logAnnounceInterval < 0");
pp_timer_start((DSPOR(ppi)->announceReceiptTimeout) <<
DSPOR(ppi)->logAnnounceInterval,
ppi->timers[PP_TIMER_ANN_RECEIPT]);
}
int st_com_check_record_update(struct pp_instance *ppi)
{
if (ppi->record_update) {
PP_VPRINTF("event STATE_DECISION_EVENT\n");
ppi->record_update = FALSE;
ppi->next_state = bmc(ppi, ppi->frgn_master);
if (ppi->next_state != ppi->state)
return 1;
}
return 0;
}
void st_com_add_foreign(struct pp_instance *ppi, unsigned char *buf)
{
int i, j;
int found = 0;
MsgHeader *hdr = &ppi->msg_tmp_header;
j = ppi->foreign_record_best;
/* Check if foreign master is already known */
for (i = 0; i < ppi->number_foreign_records; i++) {
if (!pp_memcmp(hdr->sourcePortIdentity.clockIdentity,
ppi->frgn_master[j].port_identity.
clockIdentity,
PP_CLOCK_IDENTITY_LENGTH) &&
(hdr->sourcePortIdentity.portNumber ==
ppi->frgn_master[j].port_identity.portNumber))
{
/* Foreign Master is already in Foreign master data set
*/
ppi->frgn_master[j].ann_messages++;
found = 1;
PP_VPRINTF("st_com_add_foreign: ann_messages: %d\n",
ppi->frgn_master[j].ann_messages);
msg_copy_header(&ppi->frgn_master[j].hdr, hdr);
msg_unpack_announce(buf, &ppi->frgn_master[j].ann);
break;
}
j = (j + 1) % ppi->number_foreign_records;
}
/* Old foreign master */
if (found)
return;
/* New foreign master */
if (ppi->number_foreign_records <
OPTS(ppi)->max_foreign_records) {
ppi->number_foreign_records++;
}
j = ppi->foreign_record_i;
/* Copy new foreign master data set from announce message */
pp_memcpy(ppi->frgn_master[j].port_identity.clockIdentity,
hdr->sourcePortIdentity.clockIdentity,
PP_CLOCK_IDENTITY_LENGTH);
ppi->frgn_master[j].port_identity.portNumber =
hdr->sourcePortIdentity.portNumber;
ppi->frgn_master[j].ann_messages = 0;
/*
* header and announce field of each Foreign Master are
* usefull to run Best Master Clock Algorithm
*/
msg_copy_header(&ppi->frgn_master[j].hdr, hdr);
msg_unpack_announce(buf, &ppi->frgn_master[j].ann);
PP_VPRINTF("New foreign Master added \n");
ppi->foreign_record_i = (ppi->foreign_record_i+1) %
OPTS(ppi)->max_foreign_records;
}
int st_com_slave_handle_announce(struct pp_instance *ppi, unsigned char *buf,
int len)
{
MsgHeader *hdr = &ppi->msg_tmp_header;
if (len < PP_ANNOUNCE_LENGTH)
return -1;
if (ppi->is_from_self)
return 0;
/*
* Valid announce message is received : BMC algorithm
* will be executed
*/
ppi->record_update = TRUE;
if (!ppi->is_from_cur_par) {
msg_unpack_announce(buf, &ppi->msg_tmp.announce);
s1(ppi, hdr, &ppi->msg_tmp.announce);
} else {
/* st_com_add_foreign takes care of announce unpacking */
st_com_add_foreign(ppi, buf);
}
/*Reset Timer handling Announce receipt timeout*/
st_com_restart_annrec_timer(ppi);
return 0;
}
int st_com_slave_handle_sync(struct pp_instance *ppi, unsigned char *buf,
int len)
{
TimeInternal *time;
TimeInternal origin_tstamp;
TimeInternal correction_field;
MsgHeader *hdr = &ppi->msg_tmp_header;
if (len < PP_SYNC_LENGTH)
return -1;
if (ppi->is_from_self)
return 0;
time = &ppi->last_rcv_time;
if (ppi->is_from_cur_par) {
ppi->sync_receive_time.seconds = time->seconds;
ppi->sync_receive_time.nanoseconds = time->nanoseconds;
/* FIXME diag to file? will we ever handle it?
if (OPTS(ppi)->recordFP)
fprintf(rtOpts->recordFP, "%d %llu\n",
header->sequenceId,
((time->seconds * 1000000000ULL) +
time->nanoseconds));
*/
if ((hdr->flagField[0] & PP_TWO_STEP_FLAG) != 0) {
ppi->waiting_for_follow = TRUE;
ppi->recv_sync_sequence_id = hdr->sequenceId;
/* Save correctionField of Sync message */
int64_to_TimeInternal(
hdr->correctionfield,
&correction_field);
ppi->last_sync_corr_field.seconds =
correction_field.seconds;
ppi->last_sync_corr_field.nanoseconds =
correction_field.nanoseconds;
} else {
msg_unpack_sync(buf, &ppi->msg_tmp.sync);
int64_to_TimeInternal(
ppi->msg_tmp_header.correctionfield,
&correction_field);
display_TimeInternal("Correction field",
&correction_field);
ppi->waiting_for_follow = FALSE;
to_TimeInternal(&origin_tstamp,
&ppi->msg_tmp.sync.originTimestamp);
pp_update_offset(ppi, &origin_tstamp,
&ppi->sync_receive_time,
&correction_field);
pp_update_clock(ppi);
}
}
return 0;
}
int st_com_slave_handle_followup(struct pp_instance *ppi, unsigned char *buf,
int len)
{
TimeInternal precise_orig_timestamp;
TimeInternal correction_field;
MsgHeader *hdr = &ppi->msg_tmp_header;
if (len < PP_FOLLOW_UP_LENGTH)
return -1;
if (!ppi->is_from_cur_par) {
PP_VPRINTF("SequenceID doesn't match last Sync message\n");
return 0;
}
if (!ppi->waiting_for_follow) {
PP_VPRINTF("Slave was not waiting a follow up message\n");
return 0;
}
if (ppi->recv_sync_sequence_id != hdr->sequenceId) {
PP_VPRINTF("Follow up message is not from current parent\n");
return 0;
}
msg_unpack_follow_up(buf, &ppi->msg_tmp.follow);
ppi->waiting_for_follow = FALSE;
to_TimeInternal(&precise_orig_timestamp,
&ppi->msg_tmp.follow.preciseOriginTimestamp);
int64_to_TimeInternal(ppi->msg_tmp_header.correctionfield,
&correction_field);
add_TimeInternal(&correction_field, &correction_field,
&ppi->last_sync_corr_field);
pp_update_offset(ppi, &precise_orig_timestamp,
&ppi->sync_receive_time,
&correction_field);
pp_update_clock(ppi);
return 0;
}
int st_com_handle_pdelay_req(struct pp_instance *ppi, unsigned char *buf,
int len)
{
TimeInternal *time;
MsgHeader *hdr = &ppi->msg_tmp_header;
if (len < PP_PDELAY_REQ_LENGTH)
return -1;
if (OPTS(ppi)->e2e_mode)
return 0;
time = &ppi->last_rcv_time;
if (ppi->is_from_self) {
/* Get sending timestamp from IP stack
* with So_TIMESTAMP */
ppi->pdelay_req_send_time.seconds =
time->seconds;
ppi->pdelay_req_send_time.nanoseconds =
time->nanoseconds;
/*Add latency*/
add_TimeInternal(&ppi->pdelay_req_send_time,
&ppi->pdelay_req_send_time,
&OPTS(ppi)->outbound_latency);
} else {
msg_copy_header(&ppi->pdelay_req_hdr, hdr);
return msg_issue_pdelay_resp(ppi, time, hdr);
}
return 0;
}
int st_com_master_handle_announce(struct pp_instance *ppi, unsigned char *buf,
int len)
{
if (len < PP_ANNOUNCE_LENGTH)
return -1;
if (ppi->is_from_self) {
PP_VPRINTF("master handle_announce: ignore msg from self\n");
return 0;
}
PP_VPRINTF("Announce message from another foreign master\n");
st_com_add_foreign(ppi, buf);
ppi->record_update = TRUE;
return 0;
}
int st_com_master_handle_sync(struct pp_instance *ppi, unsigned char *buf,
int len)
{
/* No more used: follow up is sent right after the corresponding sync */
return 0;
}
/*
* Aurelio Colosimo for CERN, 2011 -- GNU LGPL v2.1 or later
* Based on PTPd project v. 2.1.0 (see AUTHORS for details)
*/
#include <ppsi/ppsi.h>
/* Contains all functions common to more than one state */
/* returns -1 in case of error, see below */
int st_com_execute_slave(struct pp_instance *ppi, int check_delayreq);
void st_com_restart_annrec_timer(struct pp_instance *ppi);
int st_com_check_record_update(struct pp_instance *ppi);
/* Each of the following "handle" functions" return 0 in case of correct
* message, -1 in case the message contained in buf is not proper (e.g. size
* is not the expected one
*/
int st_com_slave_handle_announce(struct pp_instance *ppi, unsigned char *buf,
int len);
int st_com_master_handle_announce(struct pp_instance *ppi, unsigned char *buf,
int len);
int st_com_slave_handle_sync(struct pp_instance *ppi, unsigned char *buf,
int len);
int st_com_master_handle_sync(struct pp_instance *ppi, unsigned char *buf,
int len);
int st_com_slave_handle_followup(struct pp_instance *ppi, unsigned char *buf,
int len);
int st_com_handle_pdelay_req(struct pp_instance *ppi, unsigned char *buf,
int len);
/*
* Aurelio Colosimo for CERN, 2011 -- GNU LGPL v2.1 or later
*/
#include <ppsi/ppsi.h>
/*
* This is the default state machine table. It is weak so an extension
* protocol can define its own stuff. It is in its own source file, so
* the linker can avoid pulling this data space if another table is there.
*/
struct pp_state_table_item pp_state_table[] __weak = {
{ PPS_INITIALIZING, "initializing", pp_initializing,},
{ PPS_FAULTY, "faulty", pp_faulty,},
{ PPS_DISABLED, "disabled", pp_disabled,},
{ PPS_LISTENING, "listening", pp_listening,},
{ PPS_PRE_MASTER, "pre-master", pp_pre_master,},
{ PPS_MASTER, "master", pp_master,},
{ PPS_PASSIVE, "passive", pp_passive,},
{ PPS_UNCALIBRATED, "uncalibrated", pp_uncalibrated,},
{ PPS_SLAVE, "slave", pp_slave,},
{ PPS_END_OF_TABLE,}
};
This diff is collapsed.
/*
* Aurelio Colosimo for CERN, 2011 -- GNU LGPL v2.1 or later
*/
#include <ppsi/ppsi.h>
#include <ppsi/diag.h>
/*
* This file deals with opening and closing an instance. The channel
* must already have been created. In practices, this initializes the
* state machine to the first state.
*
* A protocol extension can override none or both of these functions.
*/
struct pp_runtime_opts default_rt_opts = {
.clock_quality = {
.clockClass = PP_DEFAULT_CLOCK_CLASS,
.clockAccuracy = PP_DEFAULT_CLOCK_ACCURACY,
.offsetScaledLogVariance = PP_DEFAULT_CLOCK_VARIANCE,
},
.inbound_latency = PP_DEFAULT_INBOUND_LATENCY,
.outbound_latency = PP_DEFAULT_OUTBOUND_LATENCY,
.max_rst = PP_DEFAULT_MAX_RESET,
.max_dly = PP_DEFAULT_MAX_DELAY,
.no_adjust = PP_DEFAULT_NO_ADJUST,
.no_rst_clk = PP_DEFAULT_NO_RESET_CLOCK,
.ap = PP_DEFAULT_AP,
.ai = PP_DEFAULT_AI,
.s = PP_DEFAULT_DELAY_S,
.ethernet_mode = PP_DEFAULT_ETHERNET_MODE,
.e2e_mode = PP_DEFAULT_E2E_MODE,
.gptp_mode = PP_DEFAULT_GPTP_MODE,
.ofst_first_updated = 0, /* FIXME: is it a option or a state var? */
.max_foreign_records = PP_DEFAULT_MAX_FOREIGN_RECORDS,
.cur_utc_ofst = PP_DEFAULT_UTC_OFFSET,
.announce_intvl = PP_DEFAULT_ANNOUNCE_INTERVAL,
.sync_intvl = PP_DEFAULT_SYNC_INTERVAL,
.prio1 = PP_DEFAULT_PRIORITY1,
.prio2 = PP_DEFAULT_PRIORITY2,
.domain_number = PP_DEFAULT_DOMAIN_NUMBER,
.ttl = PP_DEFAULT_TTL,
};
int pp_open_instance(struct pp_instance *ppi, struct pp_runtime_opts *rt_opts)
{
if (rt_opts)
OPTS(ppi) = rt_opts;
else
OPTS(ppi) = &default_rt_opts;
ppi->state = PPS_INITIALIZING;
return 0;
}
int pp_close_instance(struct pp_instance *ppi)
{
/* Nothing to do by now */
return 0;
}
This diff is collapsed.
/*
* Aurelio Colosimo for CERN, 2011 -- GNU LGPL v2.1 or later
* Based on PTPd project v. 2.1.0 (see AUTHORS for details)
*/
#include <ppsi/ppsi.h>
/* This is a placeholder for white rabbit extension. */
/* TODO extension white rabbit*/
int pp_disabled(struct pp_instance *ppi, unsigned char *pkt, int plen)
{
/* nothing to do */
ppi->next_delay = PP_DEFAULT_NEXT_DELAY_MS;
return 0;
}
/*
* Aurelio Colosimo for CERN, 2011 -- GNU LGPL v2.1 or later
* Based on PTPd project v. 2.1.0 (see AUTHORS for details)
*/
#include <ppsi/ppsi.h>
#include <ppsi/diag.h>
/*
* Fault troubleshooting. Now only prints an error messages and comes back to
* PTP_INITIALIZING state
*/
int pp_faulty(struct pp_instance *ppi, unsigned char *pkt, int plen)
{
pp_printf("event FAULT_CLEARED\n");
ppi->next_state = PPS_INITIALIZING;
ppi->next_delay = PP_DEFAULT_NEXT_DELAY_MS * 4;
return 0;
}
/*
* Aurelio Colosimo for CERN, 2011 -- GNU LGPL v2.1 or later
* Based on PTPd project v. 2.1.0 (see AUTHORS for details)
*/
#include <ppsi/ppsi.h>
#include <ppsi/diag.h>
/*
* Initializes network and other stuff
*/
static int pp_did_init;
int pp_initializing(struct pp_instance *ppi, unsigned char *pkt, int plen)
{
unsigned char *id, *mac;
if (pp_did_init)
pp_net_shutdown(ppi);
if (pp_net_init(ppi) < 0)
goto failure;
pp_did_init = 1;
/* Initialize default data set */
DSDEF(ppi)->twoStepFlag = PP_TWO_STEP_FLAG;
/* Clock identity comes from mac address with 0xff:0xfe intermixed */
id = DSDEF(ppi)->clockIdentity;
mac = NP(ppi)->ch[PP_NP_GEN].addr;
id[0] = mac[0];
id[1] = mac[1];
id[2] = mac[2];
id[3] = 0xff;
id[4] = 0xfe;
id[5] = mac[3];
id[6] = mac[4];
id[7] = mac[5];
DSDEF(ppi)->numberPorts = 1;
pp_memcpy(&DSDEF(ppi)->clockQuality, &OPTS(ppi)->clock_quality,
sizeof(ClockQuality));
DSDEF(ppi)->priority1 = OPTS(ppi)->prio1;
DSDEF(ppi)->priority2 = OPTS(ppi)->prio2;
DSDEF(ppi)->domainNumber = OPTS(ppi)->domain_number;
DSDEF(ppi)->slaveOnly = OPTS(ppi)->slave_only;
if (OPTS(ppi)->slave_only)
ppi->defaultDS->clockQuality.clockClass = 255;
/* Initialize port data set */
pp_memcpy(ppi->portDS->portIdentity.clockIdentity,
ppi->defaultDS->clockIdentity, PP_CLOCK_IDENTITY_LENGTH);
DSPOR(ppi)->portIdentity.portNumber = 1;
DSPOR(ppi)->logMinDelayReqInterval = PP_DEFAULT_DELAYREQ_INTERVAL;
DSPOR(ppi)->peerMeanPathDelay.seconds = 0;
DSPOR(ppi)->peerMeanPathDelay.nanoseconds = 0;
DSPOR(ppi)->logAnnounceInterval = OPTS(ppi)->announce_intvl;
DSPOR(ppi)->announceReceiptTimeout =
PP_DEFAULT_ANNOUNCE_RECEIPT_TIMEOUT;
DSPOR(ppi)->logSyncInterval = OPTS(ppi)->sync_intvl;
DSPOR(ppi)->delayMechanism = PP_DEFAULT_DELAY_MECHANISM;
DSPOR(ppi)->logMinPdelayReqInterval = PP_DEFAULT_PDELAYREQ_INTERVAL;
DSPOR(ppi)->versionNumber = PP_VERSION_PTP;
if (pp_timer_init(ppi))
goto failure;
pp_init_clock(ppi);
m1(ppi);
msg_pack_header(ppi, ppi->buf_out);
ppi->next_state = PPS_LISTENING;
ppi->next_delay = PP_DEFAULT_NEXT_DELAY_MS;
return 0;
failure:
pp_printf("Failed to initialize network\n");
ppi->next_state = PPS_FAULTY;
ppi->next_delay = PP_DEFAULT_NEXT_DELAY_MS;
return 0;
}
/*
* Aurelio Colosimo for CERN, 2011 -- GNU LGPL v2.1 or later
* Based on PTPd project v. 2.1.0 (see AUTHORS for details)
*/
#include <ppsi/ppsi.h>
#include <ppsi/diag.h>
#include "common-fun.h"
int pp_listening(struct pp_instance *ppi, unsigned char *pkt, int plen)
{
int e = 0; /* error var, to check errors in msg handling */
if (ppi->is_new_state)
st_com_restart_annrec_timer(ppi);
if (st_com_check_record_update(ppi))
goto state_updated;
if (plen == 0)
goto no_incoming_msg;
switch (ppi->msg_tmp_header.messageType) {
case PPM_ANNOUNCE:
e = st_com_master_handle_announce(ppi, pkt, plen);
break;
case PPM_SYNC:
e = st_com_master_handle_sync(ppi, pkt, plen);
break;
default:
/* disreguard, nothing to do */
break;
}
no_incoming_msg:
if (e == 0)
e = st_com_execute_slave(ppi, 0);
if (e != 0)
ppi->next_state = PPS_FAULTY;
state_updated:
/* Leaving this state */
if (ppi->next_state != ppi->state)
pp_timer_stop(ppi->timers[PP_TIMER_ANN_RECEIPT]);
ppi->next_delay = PP_DEFAULT_NEXT_DELAY_MS;
return 0;
}
/*
* Aurelio Colosimo for CERN, 2011 -- GNU LGPL v2.1 or later
* Based on PTPd project v. 2.1.0 (see AUTHORS for details)
*/
#include <ppsi/ppsi.h>
#include <ppsi/diag.h>
#include "common-fun.h"
int pp_master(struct pp_instance *ppi, unsigned char *pkt, int plen)
{
TimeInternal *time;
TimeInternal *time_snt;
TimeInternal req_rec_tstamp;
TimeInternal correction_field;
TimeInternal resp_orig_tstamp;
int e = 0; /* error var, to check errors in msg handling */
MsgHeader *hdr = &ppi->msg_tmp_header;
time = &ppi->last_rcv_time;
if (ppi->is_new_state) {
pp_timer_start(1 << DSPOR(ppi)->logSyncInterval,
ppi->timers[PP_TIMER_SYNC]);
pp_timer_start(1 << DSPOR(ppi)->logAnnounceInterval,
ppi->timers[PP_TIMER_ANN_INTERVAL]);
pp_timer_start(1 << DSPOR(ppi)->logMinPdelayReqInterval,
ppi->timers[PP_TIMER_PDELAYREQ]);
}
if (st_com_check_record_update(ppi))
goto state_updated;
if (pp_timer_expired(ppi->timers[PP_TIMER_SYNC])) {
PP_VPRINTF("event SYNC_INTERVAL_TIMEOUT_EXPIRES\n");
if (msg_issue_sync(ppi) < 0)
goto failure;
time_snt = &ppi->last_snt_time;
add_TimeInternal(time_snt, time_snt, &OPTS(ppi)->outbound_latency);
if (msg_issue_followup(ppi, time_snt))
goto failure;
}
if (pp_timer_expired(ppi->timers[PP_TIMER_ANN_INTERVAL])) {
PP_VPRINTF("event ANNOUNCE_INTERVAL_TIMEOUT_EXPIRES\n");
if (msg_issue_announce(ppi) < 0)
goto failure;
}
if (!OPTS(ppi)->e2e_mode) {
if (pp_timer_expired(ppi->timers[PP_TIMER_PDELAYREQ])) {
PP_VPRINTF("event PDELAYREQ_INTERVAL_TOUT_EXPIRES\n");
if (msg_issue_pdelay_req(ppi) < 0)
goto failure;
}
}
if (plen == 0)
goto no_incoming_msg;
switch (ppi->msg_tmp_header.messageType) {
case PPM_ANNOUNCE:
e = st_com_master_handle_announce(ppi, pkt, plen);
break;
case PPM_SYNC:
e = st_com_master_handle_sync(ppi, pkt, plen);
break;
case PPM_DELAY_REQ:
msg_copy_header(&ppi->delay_req_hdr, hdr);
msg_issue_delay_resp(ppi, time);
break;
case PPM_PDELAY_REQ:
e = st_com_handle_pdelay_req(ppi, pkt, plen);
break;
case PPM_PDELAY_RESP:
/* Loopback Timestamp */
if (OPTS(ppi)->e2e_mode)
break;
if (ppi->is_from_self) {
/*Add latency*/
add_TimeInternal(time, time,
&OPTS(ppi)->outbound_latency);
e = msg_issue_pdelay_resp_follow_up(ppi, time);
break;
}
msg_unpack_pdelay_resp(pkt, &ppi->msg_tmp.presp);
if (!((ppi->sent_seq_id[PPM_PDELAY_REQ] ==
hdr->sequenceId)
&& (!pp_memcmp(DSPOR(ppi)->portIdentity.clockIdentity,
ppi->msg_tmp.presp.requestingPortIdentity.
clockIdentity,
PP_CLOCK_IDENTITY_LENGTH))
&& (DSPOR(ppi)->portIdentity.portNumber ==
ppi->msg_tmp.presp.requestingPortIdentity.portNumber))
) {
if ((hdr->flagField[0] & PP_TWO_STEP_FLAG) != 0) {
/* Two Step Clock */
/* Store t4 (Fig 35) */
ppi->pdelay_resp_receive_time.seconds =
time->seconds;
ppi->pdelay_resp_receive_time.nanoseconds =
time->nanoseconds;
/* Store t2 (Fig 35) */
to_TimeInternal(&req_rec_tstamp,
&ppi->msg_tmp.presp.
requestReceiptTimestamp);
ppi->pdelay_req_receive_time.seconds =
req_rec_tstamp.seconds;
ppi->pdelay_req_receive_time.nanoseconds =
req_rec_tstamp.nanoseconds;
int64_to_TimeInternal(
hdr->correctionfield,
&correction_field);
ppi->last_pdelay_resp_corr_field.seconds =
correction_field.seconds;
ppi->last_pdelay_resp_corr_field.nanoseconds =
correction_field.nanoseconds;
break;
} else {
/* One step Clock */
/* Store t4 (Fig 35)*/
ppi->pdelay_resp_receive_time.seconds =
time->seconds;
ppi->pdelay_resp_receive_time.nanoseconds =
time->nanoseconds;
int64_to_TimeInternal(
hdr->correctionfield,
&correction_field);
pp_update_peer_delay(ppi, &correction_field, 0);
break;
}
}
break; /* XXX added by gnn for safety */
case PPM_PDELAY_RESP_FOLLOW_UP:
if (hdr->sequenceId == ppi->sent_seq_id[PPM_PDELAY_REQ] - 1) {
msg_unpack_pdelay_resp_followup(pkt,
&ppi->msg_tmp.prespfollow);
to_TimeInternal(&resp_orig_tstamp,
&ppi->msg_tmp.prespfollow.
responseOriginTimestamp);
ppi->pdelay_resp_send_time.seconds =
resp_orig_tstamp.seconds;
ppi->pdelay_resp_send_time.nanoseconds =
resp_orig_tstamp.nanoseconds;
int64_to_TimeInternal(
ppi->msg_tmp_header.correctionfield,
&correction_field);
add_TimeInternal(&correction_field,
&correction_field,
&ppi->last_pdelay_resp_corr_field);
pp_update_peer_delay(ppi, &correction_field, 1);
break;
}
break;
default:
/* disreguard, nothing to do */
break;
}
no_incoming_msg:
failure:
if (e == 0) {
if (DSDEF(ppi)->slaveOnly ||
DSDEF(ppi)->clockQuality.clockClass == 255)
ppi->next_state = PPS_LISTENING;
} else {
ppi->next_state = PPS_FAULTY;
}
state_updated:
/* Leaving this state */
if (ppi->next_state != ppi->state) {
pp_timer_stop(ppi->timers[PP_TIMER_SYNC]);
pp_timer_stop(ppi->timers[PP_TIMER_ANN_INTERVAL]);
pp_timer_stop(ppi->timers[PP_TIMER_PDELAYREQ]);
}
ppi->next_delay = PP_DEFAULT_NEXT_DELAY_MS;
return 0;
}
/*
* Aurelio Colosimo for CERN, 2011 -- GNU LGPL v2.1 or later
* Based on PTPd project v. 2.1.0 (see AUTHORS for details)
*/
#include <ppsi/ppsi.h>
#include "common-fun.h"
int pp_passive(struct pp_instance *ppi, unsigned char *pkt, int plen)
{
int e = 0; /* error var, to check errors in msg handling */
if (ppi->is_new_state) {
pp_timer_start(1 << DSPOR(ppi)->logMinPdelayReqInterval,
ppi->timers[PP_TIMER_PDELAYREQ]);
st_com_restart_annrec_timer(ppi);
}
if (st_com_check_record_update(ppi))
goto state_updated;
if (plen == 0)
goto no_incoming_msg;
switch (ppi->msg_tmp_header.messageType) {
case PPM_ANNOUNCE:
e = st_com_master_handle_announce(ppi, pkt, plen);
break;
case PPM_PDELAY_REQ:
e = st_com_handle_pdelay_req(ppi, pkt, plen);
break;
case PPM_SYNC:
e = st_com_master_handle_sync(ppi, pkt, plen);
break;
default:
/* disreguard, nothing to do */
break;
}
no_incoming_msg:
if (e == 0)
e = st_com_execute_slave(ppi, 0);
if (e != 0)
ppi->next_state = PPS_FAULTY;
state_updated:
/* Leaving this state */
if (ppi->next_state != ppi->state) {
pp_timer_stop(ppi->timers[PP_TIMER_ANN_RECEIPT]);
pp_timer_stop(ppi->timers[PP_TIMER_PDELAYREQ]);
}
ppi->next_delay = PP_DEFAULT_NEXT_DELAY_MS;
return 0;
}
/*
* Aurelio Colosimo for CERN, 2011 -- GNU LGPL v2.1 or later
* Based on PTPd project v. 2.1.0 (see AUTHORS for details)
*/
#include <ppsi/ppsi.h>
int pp_pre_master(struct pp_instance *ppi, unsigned char *pkt, int plen)
{
/*
* No need of PRE_MASTER state because of only ordinary clock
* implementation.
*/
return 0;
}
/*
* Aurelio Colosimo for CERN, 2011 -- GNU LGPL v2.1 or later
* Based on PTPd project v. 2.1.0 (see AUTHORS for details)
*/
#include <ppsi/ppsi.h>
#include <ppsi/diag.h>
#include "common-fun.h"
int pp_slave(struct pp_instance *ppi, unsigned char *pkt, int plen)
{
int e = 0; /* error var, to check errors in msg handling */
TimeInternal *time;
TimeInternal req_rec_tstamp;
TimeInternal correction_field;
TimeInternal resp_orig_tstamp;
MsgHeader *hdr = &ppi->msg_tmp_header;
time = &ppi->last_rcv_time;
if (ppi->is_new_state) {
pp_init_clock(ppi);
ppi->waiting_for_follow = FALSE;
ppi->pdelay_req_send_time.seconds = 0;
ppi->pdelay_req_send_time.nanoseconds = 0;
ppi->pdelay_req_receive_time.seconds = 0;
ppi->pdelay_req_receive_time.nanoseconds = 0;
ppi->pdelay_resp_send_time.seconds = 0;
ppi->pdelay_resp_send_time.nanoseconds = 0;
ppi->pdelay_resp_receive_time.seconds = 0;
ppi->pdelay_resp_receive_time.nanoseconds = 0;
st_com_restart_annrec_timer(ppi);
if (OPTS(ppi)->e2e_mode)
pp_timer_start(1 << DSPOR(ppi)->logMinDelayReqInterval,
ppi->timers[PP_TIMER_DELAYREQ]);
else
pp_timer_start(1 << DSPOR(ppi)->logMinPdelayReqInterval,
ppi->timers[PP_TIMER_PDELAYREQ]);
}
if (st_com_check_record_update(ppi))
goto state_updated;
if (plen == 0)
goto no_incoming_msg;
switch (ppi->msg_tmp_header.messageType) {
case PPM_ANNOUNCE:
e = st_com_slave_handle_announce(ppi, pkt, plen);
break;
case PPM_SYNC:
e = st_com_slave_handle_sync(ppi, pkt, plen);
break;
case PPM_FOLLOW_UP:
e = st_com_slave_handle_followup(ppi, pkt, plen);
break;
case PPM_DELAY_REQ:
e = (plen < PP_DELAY_REQ_LENGTH);
if (!e && ppi->is_from_self) {
/* No more used: delay_req_send_time was taken
* when sending it */
}
break;
case PPM_DELAY_RESP:
e = (plen < PP_DELAY_RESP_LENGTH);
if (e)
break;
if (!OPTS(ppi)->e2e_mode)
break;
msg_unpack_delay_resp(pkt, &ppi->msg_tmp.resp);
if ((pp_memcmp(DSPOR(ppi)->portIdentity.clockIdentity,
ppi->msg_tmp.resp.requestingPortIdentity.clockIdentity,
PP_CLOCK_IDENTITY_LENGTH) == 0) &&
((ppi->sent_seq_id[PPM_DELAY_REQ] - 1) ==
hdr->sequenceId) &&
(DSPOR(ppi)->portIdentity.portNumber ==
ppi->msg_tmp.resp.requestingPortIdentity.portNumber)
&& ppi->is_from_cur_par) {
to_TimeInternal(&req_rec_tstamp,
&ppi->msg_tmp.resp.receiveTimestamp);
ppi->delay_req_receive_time.seconds =
req_rec_tstamp.seconds;
ppi->delay_req_receive_time.nanoseconds =
req_rec_tstamp.nanoseconds;
int64_to_TimeInternal(
hdr->correctionfield,
&correction_field);
pp_update_delay(ppi, &correction_field);
ppi->log_min_delay_req_interval =
hdr->logMessageInterval;
} else {
PP_VPRINTF("pp_slave : "
"Delay Resp doesn't match Delay Req\n");
}
break;
case PPM_PDELAY_REQ:
e = st_com_handle_pdelay_req(ppi, pkt, plen);
break;
case PPM_PDELAY_RESP:
if (OPTS(ppi)->e2e_mode)
break;
e = (plen < PP_PDELAY_RESP_LENGTH);
if (e)
break;
if (ppi->is_from_self) {
add_TimeInternal(time, time,
&OPTS(ppi)->outbound_latency);
msg_issue_pdelay_resp_follow_up(ppi, time);
break;
}
msg_unpack_pdelay_resp(pkt,
&ppi->msg_tmp.presp);
if (!((ppi->sent_seq_id[PPM_PDELAY_REQ] ==
hdr->sequenceId)
&& (!pp_memcmp(DSPOR(ppi)->portIdentity.clockIdentity,
ppi->msg_tmp.presp.requestingPortIdentity.
clockIdentity, PP_CLOCK_IDENTITY_LENGTH))
&& (DSPOR(ppi)->portIdentity.portNumber ==
ppi->msg_tmp.presp.
requestingPortIdentity.portNumber))) {
if ((hdr->flagField[0] & 0x02) ==
PP_TWO_STEP_FLAG) {
/* Two Step Clock */
/* Store t4 (Fig 35) */
ppi->pdelay_resp_receive_time.seconds =
time->seconds;
ppi->pdelay_resp_receive_time.nanoseconds =
time->nanoseconds;
/* Store t2 (Fig 35) */
to_TimeInternal(&req_rec_tstamp,
&ppi->msg_tmp.presp.
requestReceiptTimestamp);
ppi->pdelay_req_receive_time.seconds =
req_rec_tstamp.seconds;
ppi->pdelay_req_receive_time.nanoseconds =
req_rec_tstamp.nanoseconds;
int64_to_TimeInternal(hdr->correctionfield,
&correction_field);
ppi->last_pdelay_resp_corr_field.seconds =
correction_field.seconds;
ppi->last_pdelay_resp_corr_field.nanoseconds =
correction_field.nanoseconds;
} else {
/* One step Clock */
/* Store t4 (Fig 35) */
ppi->pdelay_resp_receive_time.seconds =
time->seconds;
ppi->pdelay_resp_receive_time.nanoseconds =
time->nanoseconds;
int64_to_TimeInternal(hdr->correctionfield,
&correction_field);
pp_update_peer_delay(ppi,& correction_field, 0);
}
} else {
PP_VPRINTF("pp_slave : PDelay Resp doesn't "
"match PDelay Req.\n");
}
break;
case PPM_PDELAY_RESP_FOLLOW_UP:
if (OPTS(ppi)->e2e_mode)
break;
e = (plen < PP_PDELAY_RESP_FOLLOW_UP_LENGTH);
if (e)
break;
if (hdr->sequenceId ==
ppi->sent_seq_id[PPM_PDELAY_REQ]) {
msg_unpack_pdelay_resp_followup(
pkt,
&ppi->msg_tmp.prespfollow);
to_TimeInternal(
&resp_orig_tstamp,
&ppi->msg_tmp.prespfollow.
responseOriginTimestamp);
ppi->pdelay_resp_send_time.seconds =
resp_orig_tstamp.seconds;
ppi->pdelay_resp_send_time.nanoseconds =
resp_orig_tstamp.nanoseconds;
int64_to_TimeInternal(
hdr->correctionfield,
&correction_field);
add_TimeInternal(&correction_field, &correction_field,
&ppi->last_pdelay_req_corr_field);
pp_update_peer_delay(ppi, &correction_field, 1);
}
break;
default:
/* disreguard, nothing to do */
break;
}
no_incoming_msg:
if (e == 0)
e = st_com_execute_slave(ppi, 1);
if (e != 0)
ppi->next_state = PPS_FAULTY;
state_updated:
/* Leaving this state */
if (ppi->next_state != ppi->state) {
pp_timer_stop(ppi->timers[PP_TIMER_ANN_RECEIPT]);
if (OPTS(ppi)->e2e_mode)
pp_timer_stop(ppi->timers[PP_TIMER_DELAYREQ]);
else
pp_timer_stop(ppi->timers[PP_TIMER_PDELAYREQ]);
pp_init_clock(ppi);
}
ppi->next_delay = PP_DEFAULT_NEXT_DELAY_MS;
return 0;
}
/*
* Aurelio Colosimo for CERN, 2011 -- GNU LGPL v2.1 or later
* Based on PTPd project v. 2.1.0 (see AUTHORS for details)
*/
#include <ppsi/ppsi.h>
#include "common-fun.h"
int pp_uncalibrated(struct pp_instance *ppi, unsigned char *pkt, int plen)
{
int e = 0; /* error var, to check errors in msg handling */
if (plen == 0)
goto no_incoming_msg;
switch (ppi->msg_tmp_header.messageType) {
case PPM_ANNOUNCE:
e = st_com_slave_handle_announce(ppi, pkt, plen);
break;
case PPM_SYNC:
e = st_com_slave_handle_sync(ppi, pkt, plen);
break;
case PPM_FOLLOW_UP:
e = st_com_slave_handle_followup(ppi, pkt, plen);
break;
default:
/* disreguard, nothing to do */
break;
}
no_incoming_msg:
if (e == 0)
e = st_com_execute_slave(ppi, 0);
if (e != 0)
ppi->next_state = PPS_FAULTY;
ppi->next_delay = PP_DEFAULT_NEXT_DELAY_MS;
return 0;
}
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