linuxptp/SOURCES/linuxptp-nmeadelay.patch

366 lines
13 KiB
Diff

commit 0c406008b530140ed6d992915a6c8a1e5abf15d5
Author: Miroslav Lichvar <mlichvar@redhat.com>
Date: Thu Jan 25 11:26:15 2024 +0100
ts2phc: Don't switch system clock to nanosecond mode.
ts2phc is not synchronizing the system clock and should not switch the
clock to the nanosecond mode with adjtimex(modes=ADJ_NANO) or make any
other modifications to it. The process that is controlling the clock
(e.g. an NTP client) might not be using the nanosecond mode.
There are two instances of the adjtimex() call in the code. One is used
only to read the clock and can be replaced with faster clock_gettime().
The other instance is also reading the TAI offset. Instead of switching
to the nanosecond mode, change the timestamp conversion to handle both
microsecond and nanosecond modes according to the current clock status.
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
Signed-off-by: Miroslav Lichvar <mlichvar@redhat.com>
diff --git a/ts2phc_generic_pps_source.c b/ts2phc_generic_pps_source.c
index d503aac..e6b8145 100644
--- a/ts2phc_generic_pps_source.c
+++ b/ts2phc_generic_pps_source.c
@@ -38,7 +38,6 @@ static int get_ntx(struct timex *ntx)
return -1;
memset(ntx, 0, sizeof(*ntx));
- ntx->modes = ADJ_NANO;
code = adjtimex(ntx);
if (code == -1) {
pr_err("adjtimex failed: %m");
@@ -93,7 +92,10 @@ static int ts2phc_generic_pps_source_getppstime(struct ts2phc_pps_source *src,
}
ts->tv_sec = ntx.time.tv_sec + tai_offset;
- ts->tv_nsec = ntx.time.tv_usec;
+ if (ntx.status & STA_NANO)
+ ts->tv_nsec = ntx.time.tv_usec;
+ else
+ ts->tv_nsec = ntx.time.tv_usec * 1000;
return 0;
}
diff --git a/ts2phc_nmea_pps_source.c b/ts2phc_nmea_pps_source.c
index 3a4267d..5b2e06b 100644
--- a/ts2phc_nmea_pps_source.c
+++ b/ts2phc_nmea_pps_source.c
@@ -62,14 +62,13 @@ static int open_nmea_connection(const char *host, const char *port,
static void *monitor_nmea_status(void *arg)
{
+ struct timespec rxtime, rxtime_rt, tmo = { 2, 0 };
struct nmea_parser *np = nmea_parser_create();
struct pollfd pfd = { -1, POLLIN | POLLPRI };
char *host, input[256], *port, *ptr, *uart;
struct ts2phc_nmea_pps_source *s = arg;
- struct timespec rxtime, tmo = { 2, 0 };
int cnt, num, parsed, baud;
struct nmea_rmc rmc;
- struct timex ntx;
if (!np) {
pr_err("failed to create NMEA parser");
@@ -79,8 +78,6 @@ static void *monitor_nmea_status(void *arg)
port = config_get_string(s->config, NULL, "ts2phc.nmea_remote_port");
uart = config_get_string(s->config, NULL, "ts2phc.nmea_serialport");
baud = config_get_int(s->config, NULL, "ts2phc.nmea_baudrate");
- memset(&ntx, 0, sizeof(ntx));
- ntx.modes = ADJ_NANO;
while (is_running()) {
if (pfd.fd == -1) {
@@ -92,7 +89,7 @@ static void *monitor_nmea_status(void *arg)
}
num = poll(&pfd, 1, NMEA_TMO);
clock_gettime(CLOCK_MONOTONIC, &rxtime);
- adjtimex(&ntx);
+ clock_gettime(CLOCK_REALTIME, &rxtime_rt);
if (num < 0) {
pr_err("poll failed");
break;
@@ -124,8 +121,7 @@ static void *monitor_nmea_status(void *arg)
if (!nmea_parse(np, ptr, cnt, &rmc, &parsed)) {
pthread_mutex_lock(&s->mutex);
s->local_monotime = rxtime;
- s->local_utctime.tv_sec = ntx.time.tv_sec;
- s->local_utctime.tv_nsec = ntx.time.tv_usec;
+ s->local_utctime = rxtime_rt;
s->rmc_utctime = rmc.ts;
s->rmc_fix_valid = rmc.fix_valid;
pthread_mutex_unlock(&s->mutex);
commit 72b44bc885e519667a12c89d5b640484807e4946
Author: Miroslav Lichvar <mlichvar@redhat.com>
Date: Tue Jun 4 08:57:15 2024 +0200
ts2phc: Use CLOCK_MONOTONIC_RAW for NMEA PPS timestamp.
In the calculation of the NMEA PPS timestamp is used an interval
measured by the CLOCK_MONOTONIC system clock. This clock may have a
large frequency error when another process (e.g. phc2sys or an NTP
client) is correcting a large time error by slewing.
This frequency error may cause the timestamp to overflow into the next
second and cause a one-second error in the measured offset, or the wrong
edge of the pulse to be rejected.
Switch from CLOCK_MONOTONIC to CLOCK_MONOTONIC_RAW to avoid the
impact of the system clock adjustments.
Signed-off-by: Miroslav Lichvar <mlichvar@redhat.com>
diff --git a/ts2phc_nmea_pps_source.c b/ts2phc_nmea_pps_source.c
index 5b2e06b..7a28433 100644
--- a/ts2phc_nmea_pps_source.c
+++ b/ts2phc_nmea_pps_source.c
@@ -88,7 +88,7 @@ static void *monitor_nmea_status(void *arg)
}
}
num = poll(&pfd, 1, NMEA_TMO);
- clock_gettime(CLOCK_MONOTONIC, &rxtime);
+ clock_gettime(CLOCK_MONOTONIC_RAW, &rxtime);
clock_gettime(CLOCK_REALTIME, &rxtime_rt);
if (num < 0) {
pr_err("poll failed");
@@ -160,7 +160,7 @@ static int ts2phc_nmea_pps_source_getppstime(struct ts2phc_pps_source *src,
int64_t utc_time;
bool fix_valid;
- clock_gettime(CLOCK_MONOTONIC, &now);
+ clock_gettime(CLOCK_MONOTONIC_RAW, &now);
local_t2 = timespec_to_tmv(now);
pthread_mutex_lock(&m->mutex);
commit 30e6c4dba892236d8cfe08dc6c55238e11504c71
Author: Miroslav Lichvar <mlichvar@redhat.com>
Date: Mon Jun 3 10:32:05 2024 +0200
ts2phc: Provide source type.
Save the PPS source type in the instance and add a function to retrieve
it. This will be needed for NMEA-specific rounding of timestamps.
Signed-off-by: Miroslav Lichvar <mlichvar@redhat.com>
diff --git a/ts2phc_pps_source.c b/ts2phc_pps_source.c
index c333f65..ae2ad46 100644
--- a/ts2phc_pps_source.c
+++ b/ts2phc_pps_source.c
@@ -26,6 +26,8 @@ struct ts2phc_pps_source *ts2phc_pps_source_create(struct ts2phc_private *priv,
src = ts2phc_phc_pps_source_create(priv, dev);
break;
}
+ if (src)
+ src->type = type;
return src;
}
@@ -46,3 +48,8 @@ struct ts2phc_clock *ts2phc_pps_source_get_clock(struct ts2phc_pps_source *src)
return NULL;
}
+
+enum ts2phc_pps_source_type ts2phc_pps_source_get_type(struct ts2phc_pps_source *src)
+{
+ return src->type;
+}
diff --git a/ts2phc_pps_source.h b/ts2phc_pps_source.h
index 293c693..c87e3af 100644
--- a/ts2phc_pps_source.h
+++ b/ts2phc_pps_source.h
@@ -53,4 +53,11 @@ int ts2phc_pps_source_getppstime(struct ts2phc_pps_source *src, struct timespec
struct ts2phc_clock *ts2phc_pps_source_get_clock(struct ts2phc_pps_source *src);
+/**
+ * Returns the type of the PPS source
+ * @param src Pointer to a source obtained via @ref ts2phc_pps_source_create().
+ * @return The type of the clock.
+ */
+enum ts2phc_pps_source_type ts2phc_pps_source_get_type(struct ts2phc_pps_source *src);
+
#endif
diff --git a/ts2phc_pps_source_private.h b/ts2phc_pps_source_private.h
index 99e6a78..ea6a8ad 100644
--- a/ts2phc_pps_source_private.h
+++ b/ts2phc_pps_source_private.h
@@ -13,6 +13,7 @@
#include "ts2phc_pps_source.h"
struct ts2phc_pps_source {
+ enum ts2phc_pps_source_type type;
void (*destroy)(struct ts2phc_pps_source *src);
int (*getppstime)(struct ts2phc_pps_source *src, struct timespec *ts);
struct ts2phc_clock *(*get_clock)(struct ts2phc_pps_source *src);
commit bebd15ae90dbfcb74a33e5b428f24c733abf1134
Author: Miroslav Lichvar <mlichvar@redhat.com>
Date: Mon Jun 3 11:06:16 2024 +0200
ts2phc: Fix edge rejection for pulse widths over 0.5s.
If the configured pulse width is longer than 0.5 seconds, the calculated
range of ignored offsets is too small to cover the wrong edge. Fix the
calculation of the limits to use the minimum of pulsewidth and
(1.0s - pulsewidth). A pulsewidth of 0.5s should give the shortest interval.
Signed-off-by: Miroslav Lichvar <mlichvar@redhat.com>
diff --git a/ts2phc_pps_sink.c b/ts2phc_pps_sink.c
index 05ac225..ca9f721 100644
--- a/ts2phc_pps_sink.c
+++ b/ts2phc_pps_sink.c
@@ -175,6 +175,8 @@ static struct ts2phc_pps_sink *ts2phc_pps_sink_create(struct ts2phc_private *pri
sink->correction = nanoseconds_to_tmv(correction);
pulsewidth = config_get_int(cfg, device, "ts2phc.pulsewidth");
+ if (pulsewidth > 500000000)
+ pulsewidth = 1000000000 - pulsewidth;
pulsewidth /= 2;
sink->ignore_upper = 1000000000 - pulsewidth;
sink->ignore_lower = pulsewidth;
commit 435e9fc6ebec8daa8ab9f88c2d590e35ace9b2f6
Author: Miroslav Lichvar <mlichvar@redhat.com>
Date: Mon Jun 3 13:57:23 2024 +0200
ts2phc: Move upper/lower rejection limit calculation.
The ignore_upper and ignore_lower fields of the ts2phc_pps_sink struct
are calculated when the PPS source is not known yet. Replace the fields
with the configured pulsewidth and calculate the limits locally later
when needed in ts2phc_pps_sink_ignore(). This will allow an
NMEA-specific calculation of the limits.
Signed-off-by: Miroslav Lichvar <mlichvar@redhat.com>
diff --git a/ts2phc_pps_sink.c b/ts2phc_pps_sink.c
index ca9f721..8121afb 100644
--- a/ts2phc_pps_sink.c
+++ b/ts2phc_pps_sink.c
@@ -30,8 +30,7 @@ struct ts2phc_pps_sink {
struct ptp_pin_desc pin_desc;
unsigned int polarity;
tmv_t correction;
- uint32_t ignore_lower;
- uint32_t ignore_upper;
+ uint32_t pulsewidth;
struct ts2phc_clock *clock;
};
@@ -153,8 +152,8 @@ static struct ts2phc_pps_sink *ts2phc_pps_sink_create(struct ts2phc_private *pri
struct config *cfg = priv->cfg;
struct ptp_extts_request extts;
struct ts2phc_pps_sink *sink;
- int err, pulsewidth;
int32_t correction;
+ int err;
sink = calloc(1, sizeof(*sink));
if (!sink) {
@@ -174,12 +173,9 @@ static struct ts2phc_pps_sink *ts2phc_pps_sink_create(struct ts2phc_private *pri
correction = config_get_int(cfg, device, "ts2phc.extts_correction");
sink->correction = nanoseconds_to_tmv(correction);
- pulsewidth = config_get_int(cfg, device, "ts2phc.pulsewidth");
- if (pulsewidth > 500000000)
- pulsewidth = 1000000000 - pulsewidth;
- pulsewidth /= 2;
- sink->ignore_upper = 1000000000 - pulsewidth;
- sink->ignore_lower = pulsewidth;
+ sink->pulsewidth = config_get_int(cfg, device, "ts2phc.pulsewidth");
+ if (sink->pulsewidth > 500000000)
+ sink->pulsewidth = 1000000000 - sink->pulsewidth;
sink->clock = ts2phc_clock_add(priv, device);
if (!sink->clock) {
@@ -243,12 +239,16 @@ static bool ts2phc_pps_sink_ignore(struct ts2phc_private *priv,
struct timespec source_ts)
{
tmv_t source_tmv = timespec_to_tmv(source_ts);
+ uint32_t ignore_lower, ignore_upper;
source_tmv = tmv_sub(source_tmv, priv->perout_phase);
source_ts = tmv_to_timespec(source_tmv);
- return source_ts.tv_nsec > sink->ignore_lower &&
- source_ts.tv_nsec < sink->ignore_upper;
+ ignore_upper = 1000000000 - sink->pulsewidth / 2;
+ ignore_lower = sink->pulsewidth / 2;
+
+ return source_ts.tv_nsec > ignore_lower &&
+ source_ts.tv_nsec < ignore_upper;
}
static enum extts_result ts2phc_pps_sink_event(struct ts2phc_private *priv,
commit 0257b245df1a32869f356c0cfbeacfe5f0a522f5
Author: Miroslav Lichvar <mlichvar@redhat.com>
Date: Mon Jun 3 11:31:45 2024 +0200
ts2phc: Allow longer NMEA delays.
Timestamps from PPS sources are rounded to the nearest pulse, i.e. for
correct synchronization the offset between the source timestamp and
external PPS event timestamp needs to be between -0.5 and +0.5 seconds.
For the pulse edge rejection to work correctly it needs to be even
smaller, between -pulsewidth/2 and +pulsewidth/2.
With the NMEA PPS source the offset is the delay in the reception of the
RMC message. This message is not expected to come exactly on time with
the corresponding pulse. A positive delay is expected, typically at
least few tens of milliseconds, but some receivers have delays longer
than 0.5 seconds.
Add NMEA-specific rounding of the offset to not expect negative delays
and allow positive delays of up to 1 second, or whole pulsewidth if the
edge rejection is enabled.
Signed-off-by: Miroslav Lichvar <mlichvar@redhat.com>
diff --git a/ts2phc.c b/ts2phc.c
index 03c88b1..4817c85 100644
--- a/ts2phc.c
+++ b/ts2phc.c
@@ -418,9 +418,16 @@ static int ts2phc_pps_source_implicit_tstamp(struct ts2phc_private *priv,
* deduce the timestamp (actually only seconds part, nanoseconds are by
* construction zero) of this edge at the emitter based on the
* emitter's current time.
+ *
+ * With an NMEA source assume its messages always follow the pulse, i.e.
+ * assign the timestamp to the previous pulse instead of nearest pulse.
*/
- if (source_ts.tv_nsec > NS_PER_SEC / 2)
+ if (ts2phc_pps_source_get_type(priv->src) == TS2PHC_PPS_SOURCE_NMEA) {
source_ts.tv_sec++;
+ } else {
+ if (source_ts.tv_nsec > NS_PER_SEC / 2)
+ source_ts.tv_sec++;
+ }
source_ts.tv_nsec = 0;
tmv = timespec_to_tmv(source_ts);
diff --git a/ts2phc_pps_sink.c b/ts2phc_pps_sink.c
index 8121afb..0d399b8 100644
--- a/ts2phc_pps_sink.c
+++ b/ts2phc_pps_sink.c
@@ -244,8 +244,13 @@ static bool ts2phc_pps_sink_ignore(struct ts2phc_private *priv,
source_tmv = tmv_sub(source_tmv, priv->perout_phase);
source_ts = tmv_to_timespec(source_tmv);
- ignore_upper = 1000000000 - sink->pulsewidth / 2;
- ignore_lower = sink->pulsewidth / 2;
+ if (ts2phc_pps_source_get_type(priv->src) == TS2PHC_PPS_SOURCE_NMEA) {
+ ignore_upper = sink->pulsewidth;
+ ignore_lower = 0;
+ } else {
+ ignore_upper = 1000000000 - sink->pulsewidth / 2;
+ ignore_lower = sink->pulsewidth / 2;
+ }
return source_ts.tv_nsec > ignore_lower &&
source_ts.tv_nsec < ignore_upper;