Commit 4aa4b551 authored by Tomasz Wlostowski's avatar Tomasz Wlostowski Committed by Grzegorz Daniluk

[t24-fix]: rewritten RX timestamp linearization (phase + counter merging)…

[t24-fix]: rewritten RX timestamp linearization (phase + counter merging) algorithm to be easier to understand.

For more info, check the note in the Documents section of the wrpc-sw project on ohwr.org.
parent 4cd066de
...@@ -49,6 +49,7 @@ int ptpd_netif_init() ...@@ -49,6 +49,7 @@ int ptpd_netif_init()
return PTPD_NETIF_OK; return PTPD_NETIF_OK;
} }
//#define TRACE_WRAP mprintf
int ptpd_netif_get_hw_addr(wr_socket_t * sock, mac_addr_t * mac) int ptpd_netif_get_hw_addr(wr_socket_t * sock, mac_addr_t * mac)
{ {
get_mac_addr((uint8_t *) mac); get_mac_addr((uint8_t *) mac);
...@@ -65,6 +66,7 @@ void ptpd_netif_set_phase_transition(uint32_t phase) ...@@ -65,6 +66,7 @@ void ptpd_netif_set_phase_transition(uint32_t phase)
} }
} }
wr_socket_t *ptpd_netif_create_socket(int sock_type, int flags, wr_socket_t *ptpd_netif_create_socket(int sock_type, int flags,
wr_sockaddr_t * bind_addr) wr_sockaddr_t * bind_addr)
{ {
...@@ -116,62 +118,73 @@ int ptpd_netif_close_socket(wr_socket_t * sock) ...@@ -116,62 +118,73 @@ int ptpd_netif_close_socket(wr_socket_t * sock)
return 0; return 0;
} }
static inline int inside_range(int min, int max, int x) /*
{ * The new, fully verified linearization algorithm.
if (min < max) * Merges the phase, measured by the DDMTD with the number of clock ticks,
return (x >= min && x <= max); * and makes sure there are no jumps resulting from different moments of transitions in the
else * coarse counter and the phase values.
return (x <= max || x >= min); * As a result, we get the full, sub-ns RX timestamp.
} *
* Have a look at the note at http://ohwr.org/documents/xxx for details.
*/
void ptpd_netif_linearize_rx_timestamp(wr_timestamp_t * ts, int32_t dmtd_phase, void ptpd_netif_linearize_rx_timestamp(wr_timestamp_t * ts, int32_t dmtd_phase,
int cntr_ahead, int transition_point, int cntr_ahead, int transition_point,
int clock_period) int clock_period)
{ {
int trip_lo, trip_hi; int nsec_f, nsec_r;
int phase;
ts->raw_phase = dmtd_phase;
// "phase" transition: DMTD output value (in picoseconds)
// at which the transition of rising edge /* The idea is simple: the asynchronous RX timestamp trigger is tagged by two counters:
// TS counter will appear one counting at the rising clock edge, and the other on the falling. That means, the rising
ts->raw_phase = dmtd_phase; timestamp is 180 degree in advance wrs to the falling one. */
phase = dmtd_phase; /* Calculate the nanoseconds value for both timestamps. The rising edge one
is just the HW register */
// calculate the range within which falling edge timestamp is stable nsec_r = ts->nsec;
// (no possible transitions) /* The falling edge TS is the rising - 1 thick if the "rising counter ahead" bit is set. */
trip_lo = transition_point - clock_period / 4; nsec_f = cntr_ahead ? ts->nsec - (clock_period / 1000) : ts->nsec;
if (trip_lo < 0)
trip_lo += clock_period;
/* Adjust the rising edge timestamp phase so that it "jumps" roughly around the point
trip_hi = transition_point + clock_period / 4; where the counter value changes */
if (trip_hi >= clock_period) int phase_r = ts->raw_phase - transition_point;
trip_hi -= clock_period; if(phase_r < 0) /* unwrap negative value */
phase_r += clock_period;
// pp_printf("linearize: %d %d %d %d -- %d\n", trip_lo, transition_point, trip_hi, ep_get_bitslide(), phase);
/* Do the same with the phase for the falling edge, but additionally shift it by extra 180 degrees
if (inside_range(trip_lo, trip_hi, phase)) { (so that it matches the falling edge counter) */
// We are within +- 25% range of transition area of int phase_f = ts->raw_phase - transition_point + (clock_period / 2);
// rising counter. Take the falling edge counter value as the if(phase_f < 0)
// "reliable" one. cntr_ahead will be 1 when the rising edge phase_f += clock_period;
//counter is 1 tick ahead of the falling edge counter if(phase_f >= clock_period)
phase_f -= clock_period;
ts->nsec -= cntr_ahead ? (clock_period / 1000) : 0;
/* If we are within +- 25% from the transition in the rising edge counter, pick the falling one */
// check if the phase is before the counter transition value if( phase_r > 3 * clock_period / 4 || phase_r < clock_period / 4 )
// and eventually increase the counter by 1 to simulate a {
// timestamp transition exactly at s->phase_transition ts->nsec = nsec_f;
//DMTD phase value
if (inside_range(transition_point, trip_hi, phase)) /* The falling edge timestamp is half a cycle later with respect to the rising one. Add
ts->nsec += clock_period / 1000; the extra delay, as rising edge is our reference */
ts->phase = phase_f + clock_period / 2;
if(ts->phase >= clock_period) /* Handle overflow */
{
ts->phase -= clock_period;
ts->nsec += (clock_period / 1000);
}
} else { /* We are closer to the falling edge counter transition? Pick the opposite timestamp */
ts->nsec = nsec_r;
ts->phase = phase_r;
} }
ts->phase = phase - transition_point; /* In an unlikely case, after all the calculations, the ns counter may be overflown. */
if(ts->nsec >= 1000000000)
{
ts->nsec -= 1000000000;
ts->sec++;
}
/* normalize phase after subtraction */
if(ts->phase < 0)
ts->phase += clock_period;
} }
/* Slow, but we don't care much... */ /* Slow, but we don't care much... */
...@@ -259,7 +272,6 @@ int ptpd_netif_recvfrom(wr_socket_t * sock, wr_sockaddr_t * from, void *data, ...@@ -259,7 +272,6 @@ int ptpd_netif_recvfrom(wr_socket_t * sock, wr_sockaddr_t * from, void *data,
from->mac_dest[0],from->mac_dest[1],from->mac_dest[2],from->mac_dest[3], from->mac_dest[0],from->mac_dest[1],from->mac_dest[2],from->mac_dest[3],
from->mac_dest[4],from->mac_dest[5],from->mac_dest[6],from->mac_dest[7]);*/ from->mac_dest[4],from->mac_dest[5],from->mac_dest[6],from->mac_dest[7]);*/
return min(size - sizeof(struct ethhdr), data_length); return min(size - sizeof(struct ethhdr), data_length);
return 0;
} }
int ptpd_netif_select(wr_socket_t * wrSock) int ptpd_netif_select(wr_socket_t * wrSock)
...@@ -283,6 +295,7 @@ int ptpd_netif_sendto(wr_socket_t * sock, wr_sockaddr_t * to, void *data, ...@@ -283,6 +295,7 @@ int ptpd_netif_sendto(wr_socket_t * sock, wr_sockaddr_t * to, void *data,
minic_tx_frame((uint8_t *) & hdr, (uint8_t *) data, minic_tx_frame((uint8_t *) & hdr, (uint8_t *) data,
data_length + ETH_HEADER_SIZE, &hwts); data_length + ETH_HEADER_SIZE, &hwts);
if (tx_timestamp) { if (tx_timestamp) {
tx_timestamp->sec = hwts.sec; tx_timestamp->sec = hwts.sec;
tx_timestamp->nsec = hwts.nsec; tx_timestamp->nsec = hwts.nsec;
...@@ -292,6 +305,7 @@ int ptpd_netif_sendto(wr_socket_t * sock, wr_sockaddr_t * to, void *data, ...@@ -292,6 +305,7 @@ int ptpd_netif_sendto(wr_socket_t * sock, wr_sockaddr_t * to, void *data,
return rval; return rval;
} }
void update_rx_queues() void update_rx_queues()
{ {
struct my_socket *s = NULL; struct my_socket *s = NULL;
......
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