Commit 0f688012 authored by Alessandro Rubini's avatar Alessandro Rubini

wr/wrpc: implement absolute calibration support

This is a port of previous work by Peter Jansweijer from nikhef.

To perform absolute calibration, we need a grand-master look-alike
mode that sends sync once a second (and hopefully slightly after the
pps signal).

Using a special gateware that sends a pulse whenever a frame is
transmitted and received, users can correlate collected timestamps
(T1 and T4), this special pulse and the pps pulse of the node.

The procedure for absolute calibration is described in

http://www.ohwr.org/attachments/4542/WhiteRabbitAbsoluteCalibrationProcedure.pdf

Another commit, in wrpc-sw, adds "mode abscal" for this feature to be used.
Signed-off-by: Alessandro Rubini's avatarAlessandro Rubini <rubini@gnudd.com>
parent 9b178a77
......@@ -131,6 +131,7 @@ int wrc_ptp_set_mode(int mode)
switch (mode) {
case WRC_MODE_GM:
case WRC_MODE_ABSCAL: /* absolute calibration, gm-lookalike */
wrp->wrConfig = WR_M_ONLY;
ppi->role = PPSI_ROLE_MASTER;
*class_ptr = PP_CLASS_WR_GM_LOCKED;
......
......@@ -18,7 +18,7 @@
#define WRC_MODE_GM 1
#define WRC_MODE_MASTER 2
#define WRC_MODE_SLAVE 3
#define WRC_MODE_ABSCAL 4
extern int ptp_mode;
int wrc_ptp_init(void);
......
......@@ -15,3 +15,5 @@ OBJ-y += $D/fsm-table.o \
$D/state-wr-link-on.o \
$D/wr-msg.o \
$D/wr-servo.o
OBJ-$(CONFIG_ABSCAL) += $D/state-wr-abscal.o
......@@ -30,5 +30,8 @@ struct pp_state_table_item pp_state_table[] = {
{ WRS_CALIBRATED, "wr-calibrated", wr_calibrated,},
{ WRS_RESP_CALIB_REQ, "wr-resp-calib-req", wr_resp_calib_req,},
{ WRS_WR_LINK_ON, "wr-link-on", wr_link_on,},
#ifdef CONFIG_ABSCAL
{ WRS_ABSCAL, "absolute-calibration", wr_abscal,},
#endif
{ PPS_END_OF_TABLE,}
};
#include <ppsi/ppsi.h>
#include "common-fun.h"
#include "wr-api.h"
/*
* This is similar to master state, but it only sends sync, that
* is going to be timestampedboth internally and externally (on a scope).
* We should send it as close as possible to the pps signal.
*/
/* Calculate when is the next pps going to happen */
static int next_pps_ms(struct pp_instance *ppi, struct pp_time *t)
{
int nsec;
ppi->t_ops->get(ppi, t);
nsec = t->scaled_nsecs >> 16;
return 1000 - (nsec / 1000 / 1000);
}
/*
* This is using a software loop during the last 10ms in order to get
* right after the pps event
*/
int wr_abscal(struct pp_instance *ppi, uint8_t *pkt, int plen)
{
struct pp_time t;
int len, i;
if (ppi->is_new_state) {
/* add 1s to be enough in the future, the first time */
__pp_timeout_set(ppi, PP_TO_EXT_0, 990 + next_pps_ms(ppi, &t));
return 0;
}
i = next_pps_ms(ppi, &t) - 10;
if (pp_timeout(ppi, PP_TO_EXT_0)) {
uint64_t secs = t.secs;
/* Wait for the second to tick */
while( ppi->t_ops->get(ppi, &t), t.secs == secs)
;
/* Send sync, no f-up -- actually we could send any frame */
ppi->t_ops->get(ppi, &t);
len = msg_pack_sync(ppi, &t);
__send_and_log(ppi, len, PP_NP_EVT);
/* And again next second */
__pp_timeout_set(ppi, PP_TO_EXT_0, next_pps_ms(ppi, &t) - 10);
ppi->next_delay = next_pps_ms(ppi, &t) - 10;
return 0;
}
/* no timeout: wait according to next_pps_ms calculated earlier */
ppi->next_delay = i > 0 ? i : 0;
return 0;
}
......@@ -33,5 +33,24 @@ int wr_link_on(struct pp_instance *ppi, unsigned char *pkt, int plen)
ppi->next_state = PPS_SLAVE;
else
ppi->next_state = PPS_MASTER;
#ifdef CONFIG_ABSCAL
/*
* absolute calibration only exists in arch-wrpc, so far, but
* we can't include wrpc headers, not available in wrs builds
*/
extern int ptp_mode;
extern int ep_get_bitslide(void);
if (ptp_mode == 4 /* WRC_MODE_ABSCAL */) {
ppi->next_state = WRS_ABSCAL;
/* print header for the serial port stream of stamps */
pp_printf("### t4.phase is already corrected for bitslide\n");
pp_printf("t1: t4: "
"bitslide: %d\n",ep_get_bitslide());
pp_printf(" sec. ns.pha sec. ns.pha\n");
}
#endif
return 0;
}
......@@ -94,6 +94,7 @@ int wr_calibration(struct pp_instance *ppi, unsigned char *pkt, int plen);
int wr_calibrated(struct pp_instance *ppi, unsigned char *pkt, int plen);
int wr_resp_calib_req(struct pp_instance *ppi, unsigned char *pkt, int plen);
int wr_link_on(struct pp_instance *ppi, unsigned char *pkt, int plen);
int wr_abscal(struct pp_instance *ppi, unsigned char *pkt, int plen);
/* Common functions, used by various states and hooks */
void wr_handshake_init(struct pp_instance *ppi, int mode);
......
......@@ -123,6 +123,8 @@ enum {
WR_PORT_CALIBRATION_6,
WR_PORT_CALIBRATION_7,
WR_PORT_CALIBRATION_8,
/* A special send-sync-only state for absolute calibration */
WRS_ABSCAL,
};
/* White Rabbit commands (for new implementation, single FSM), see table 38 */
......
......@@ -97,6 +97,14 @@ int pp_initializing(struct pp_instance *ppi, unsigned char *pkt, int plen)
ppi->next_state = PPS_LISTENING;
else
ppi->next_state = PPS_MASTER;
#ifdef CONFIG_ABSCAL
/* absolute calibration only exists in arch-wrpc, so far */
extern int ptp_mode;
if (ptp_mode == 4 /* WRC_MODE_ABSCAL */)
ppi->next_state = WRS_WR_LINK_ON;
#endif
return 0;
failure:
......
......@@ -7,11 +7,17 @@
#include <ppsi/ppsi.h>
#include "ptpdump.h"
#include "../arch-wrpc/wrpc.h"
#include <syscon.h> /* wrpc-sw */
#include <endpoint.h> /* wrpc-sw */
#include <ptpd_netif.h> /* wrpc-sw */
int frame_rx_delay_us; /* set by faults.c */
#define HAS_ABSCAL 0
#ifdef CONFIG_ABSCAL
#define HAS_ABSCAL 1
#endif
/*
* we know we create one socket only in wrpc. The buffer size used to be
* 512. Let's keep it unchanged, because we might enqueue a few frames.
......@@ -67,7 +73,8 @@ static int wrpc_net_recv(struct pp_instance *ppi, void *pkt, int len,
t->secs = wr_ts.sec;
t->scaled_nsecs = (int64_t)wr_ts.nsec << 16;
t->scaled_nsecs += wr_ts.phase * (1 << 16) / 1000;
if (!wr_ts.correct)
/* avoid "incorrect" stamps when abscal is running */
if (!wr_ts.correct && ptp_mode != WRC_MODE_ABSCAL)
mark_incorrect(t);
}
......@@ -77,6 +84,24 @@ static int wrpc_net_recv(struct pp_instance *ppi, void *pkt, int len,
if (pp_diag_allow(ppi, frames, 2))
dump_payloadpkt("recv: ", pkt, got, t);
#endif
if (HAS_ABSCAL && ptp_mode == WRC_MODE_ABSCAL) {
struct pp_time t4, t_bts;
int bitslide;
/* WR counts bitslide later, in fixed-delta, so subtract it */
t4 = *t;
bitslide = ep_get_bitslide();
t_bts.secs = 0;
t_bts.scaled_nsecs = (bitslide << 16) / 1000;
pp_time_sub(&t4, &t_bts);
pp_printf("%09d %09d %03d",
(int)t4.secs, (int)(t4.scaled_nsecs >> 16),
((int)(t4.scaled_nsecs & 0xffff) * 1000) >> 16);
/* Print the difference from T1, too */
pp_time_sub(&t4, &ppi->last_snt_time);
pp_printf(" %9d.%3d\n", (int)(t4.scaled_nsecs >> 16),
((int)(t4.scaled_nsecs & 0xffff) * 1000) >> 16);
}
if (CONFIG_HAS_WRPC_FAULTS && ppsi_drop_rx()) {
pp_diag(ppi, frames, 1, "Drop received frame\n");
......@@ -131,6 +156,11 @@ static int wrpc_net_send(struct pp_instance *ppi, void *pkt, int len,
__func__, snt, (long)t->secs,
(long)(t->scaled_nsecs >> 16));
}
if (HAS_ABSCAL && ptp_mode == WRC_MODE_ABSCAL)
pp_printf("%09d %09d %03d ", /* first half of a line */
(int)t->secs, (int)(t->scaled_nsecs >> 16),
((int)(t->scaled_nsecs & 0xffff) * 1000) >> 16);
if (CONFIG_HAS_WRPC_FAULTS && drop) {
pp_diag(ppi, frames, 1, "Drop sent frame\n");
return PP_SEND_DROP;
......
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