Commit 51fc7cc4 authored by Sven Meier's avatar Sven Meier

ptp timescale: leap flag and utc offset handling at midnight using system leap second handling

The UTC leap flags are propagated to the system (unix) so the leap second is correctly handled at midnight
so the UTC time is always correct.
parent 20c0c0c4
......@@ -198,7 +198,9 @@ extern struct pp_network_operations unix_net_ops;
* If "set" receives a NULL time value, it should update the TAI offset.
*/
struct pp_time_operations {
int (*get_utc_time)(struct pp_instance *ppi, int *hours, int *minutes, int *seconds);
int (*get_utc_offset)(struct pp_instance *ppi, int *offset, int *leap59, int *leap61);
int (*set_utc_offset)(struct pp_instance *ppi, int offset, int leap59, int leap61);
int (*get)(struct pp_instance *ppi, struct pp_time *t);
int (*set)(struct pp_instance *ppi, const struct pp_time *t);
/* freq_ppb is parts per billion */
......
......@@ -41,35 +41,7 @@ void bmc_m1(struct pp_instance *ppi)
parent->grandmasterPriority1 = defds->priority1;
parent->grandmasterPriority2 = defds->priority2;
ret = ppi->t_ops->get_utc_offset(ppi, &offset, &leap59, &leap61);
if (ret) {
offset = PP_DEFAULT_UTC_OFFSET;
pp_diag(ppi, bmc, 1,
"Could not get UTC offset from system, taking default: %i\n",
offset);
}
/* Time Properties data set */
if (prop->currentUtcOffset != offset) {
pp_diag(ppi, bmc, 1, "New UTC offset: %i\n",
offset);
prop->currentUtcOffset = offset;
ppi->t_ops->set(ppi, NULL);
}
if (ret)
{
prop->timeTraceable = FALSE;
prop->currentUtcOffsetValid = FALSE;
prop->leap59 = FALSE;
prop->leap61 = FALSE;
}
else
{
prop->timeTraceable = TRUE;
prop->currentUtcOffsetValid = TRUE;
prop->leap59 = (leap59 != 0);
prop->leap61 = (leap61 != 0);
}
/* based on the clock class we set the frequency traceable flags */
if ((defds->clockQuality.clockClass < PP_PTP_CLASS_GM_UNLOCKED) ||
(defds->clockQuality.clockClass < PP_ARB_CLASS_GM_UNLOCKED))
......@@ -93,6 +65,7 @@ void bmc_m1(struct pp_instance *ppi)
prop->timeSource = GPS;
break;
case PP_ARB_CLASS_GM_UNLOCKED:
prop->ptpTimescale = FALSE;
prop->timeSource = INTERNAL_OSCILLATOR;
break;
......@@ -102,94 +75,54 @@ void bmc_m1(struct pp_instance *ppi)
prop->timeSource = INTERNAL_OSCILLATOR;
break;
}
}
/* ppi->port_idx port is becoming Master. Table 13 (9.3.5) of the spec. */
void bmc_m2(struct pp_instance *ppi)
{
struct DSParent *parent = DSPAR(ppi);
struct DSDefault *defds = DSDEF(ppi);
struct DSTimeProperties *prop = DSPRO(ppi);
int ret = 0;
int offset, leap59, leap61;
/* Current data set update */
DSCUR(ppi)->stepsRemoved = 0;
clear_time(&DSCUR(ppi)->offsetFromMaster);
clear_time(&DSCUR(ppi)->meanPathDelay);
/* Parent data set: we are the parent */
memset(parent, 0, sizeof(*parent));
parent->parentPortIdentity.clockIdentity = defds->clockIdentity;
parent->parentPortIdentity.portNumber = 0;
/* Copy grandmaster params from our defds (FIXME: is ir right?) */
parent->grandmasterIdentity = defds->clockIdentity;
parent->grandmasterClockQuality = defds->clockQuality;
parent->grandmasterPriority1 = defds->priority1;
parent->grandmasterPriority2 = defds->priority2;
ret = ppi->t_ops->get_utc_offset(ppi, &offset, &leap59, &leap61);
if (ret) {
offset = PP_DEFAULT_UTC_OFFSET;
pp_diag(ppi, bmc, 1,
"Could not get UTC offset from system, taking default: %i\n",
offset);
}
/* Time Properties data set */
if (prop->currentUtcOffset != offset) {
pp_diag(ppi, bmc, 1, "New UTC offset: %i\n",
offset);
prop->currentUtcOffset = offset;
ppi->t_ops->set(ppi, NULL);
}
if (ret)
{
if (prop->ptpTimescale) {
ret = ppi->t_ops->get_utc_offset(ppi, &offset, &leap59, &leap61);
if (ret) {
offset = PP_DEFAULT_UTC_OFFSET;
pp_diag(ppi, bmc, 1,
"Could not get UTC offset from system, taking default: %i\n",
offset);
}
if (prop->currentUtcOffset != offset) {
pp_diag(ppi, bmc, 1, "New UTC offset: %i\n",
offset);
prop->currentUtcOffset = offset;
ppi->t_ops->set(ppi, NULL);
}
if (ret)
{
prop->timeTraceable = FALSE;
prop->currentUtcOffsetValid = FALSE;
prop->leap59 = FALSE;
prop->leap61 = FALSE;
}
else
{
prop->timeTraceable = TRUE;
prop->currentUtcOffsetValid = TRUE;
prop->leap59 = (leap59 != 0);
prop->leap61 = (leap61 != 0);
}
} else {
/* 9.4 for ARB just take the value when built */
prop->currentUtcOffset = PP_DEFAULT_UTC_OFFSET;
/* always false */
prop->timeTraceable = FALSE;
prop->currentUtcOffsetValid = FALSE;
prop->leap59 = FALSE;
prop->leap61 = FALSE;
}
else
{
prop->timeTraceable = TRUE;
prop->currentUtcOffsetValid = TRUE;
prop->leap59 = (leap59 != 0);
prop->leap61 = (leap61 != 0);
}
/* based on the clock class we set the frequency traceable flags */
if ((defds->clockQuality.clockClass < PP_PTP_CLASS_GM_UNLOCKED) ||
(defds->clockQuality.clockClass < PP_ARB_CLASS_GM_UNLOCKED))
prop->frequencyTraceable = TRUE;
else
prop->frequencyTraceable = FALSE;
}
switch (defds->clockQuality.clockClass) {
case PP_PTP_CLASS_GM_LOCKED:
case PP_PTP_CLASS_GM_HOLDOVER:
prop->ptpTimescale = TRUE;
prop->timeSource = GPS;
break;
case PP_PTP_CLASS_GM_UNLOCKED:
prop->ptpTimescale = TRUE;
prop->timeSource = INTERNAL_OSCILLATOR;
break;
case PP_ARB_CLASS_GM_LOCKED:
case PP_ARB_CLASS_GM_HOLDOVER:
prop->ptpTimescale = FALSE;
prop->timeSource = GPS;
break;
case PP_ARB_CLASS_GM_UNLOCKED:
prop->ptpTimescale = FALSE;
prop->timeSource = INTERNAL_OSCILLATOR;
break;
default:
/* FIXME: if we don't know better we stay with this */
prop->ptpTimescale = TRUE;
prop->timeSource = INTERNAL_OSCILLATOR;
break;
}
/* ppi->port_idx port is becoming Master. Table 13 (9.3.5) of the spec. */
void bmc_m2(struct pp_instance *ppi)
{
/* same as m1, just call this then */
bmc_m1(ppi);
}
/* ppi->port_idx port is becoming Master. Table 14 (9.3.5) of the spec. */
......@@ -206,6 +139,9 @@ void bmc_s1(struct pp_instance *ppi,
{
struct DSParent *parent = DSPAR(ppi);
struct DSTimeProperties *prop = DSPRO(ppi);
int ret = 0;
int offset, leap59, leap61;
int hours, minutes, seconds;
/* Current DS */
DSCUR(ppi)->stepsRemoved = frgn_master->stepsRemoved + 1;
......@@ -218,15 +154,103 @@ void bmc_s1(struct pp_instance *ppi,
parent->grandmasterPriority2 = frgn_master->grandmasterPriority2;
/* Timeproperties DS */
if (prop->currentUtcOffset != frgn_master->currentUtcOffset) {
pp_diag(ppi, bmc, 1, "New UTC offset: %i\n",
frgn_master->currentUtcOffset);
prop->ptpTimescale = ((frgn_master->flagField[1] & FFB_PTP) != 0);
if (prop->ptpTimescale) {
ret = ppi->t_ops->get_utc_time(ppi, &hours, &minutes, &seconds);
if (ret) {
pp_diag(ppi, bmc, 1,
"Could not get UTC time from system, taking received flags\n");
prop->leap59 = ((frgn_master->flagField[1] & FFB_LI59) != 0);
prop->leap61 = ((frgn_master->flagField[1] & FFB_LI61) != 0);
prop->currentUtcOffset = frgn_master->currentUtcOffset;
} else {
if (hours >= 12) {
/* stop 2 announce intervals before midnight */
if ((hours == 23) && (minutes == 59) &&
(seconds >= (60 - (2 * (1 << ppi->portDS->logAnnounceInterval))))) {
pp_diag(ppi, bmc, 2,
"Approaching midnight, not updating leap flags\n");
} else {
ret = ppi->t_ops->get_utc_offset(ppi, &offset, &leap59, &leap61);
if (ret) {
pp_diag(ppi, bmc, 1,
"Could not get UTC flags from system, taking received flags\n");
prop->leap59 = ((frgn_master->flagField[1] & FFB_LI59) != 0);
prop->leap61 = ((frgn_master->flagField[1] & FFB_LI61) != 0);
prop->currentUtcOffset = frgn_master->currentUtcOffset;
} else {
if (((leap59 != 0) != ((frgn_master->flagField[1] & FFB_LI59) != 0)) ||
((leap61 != 0) != ((frgn_master->flagField[1] & FFB_LI59) != 0)) ||
(offset != frgn_master->currentUtcOffset)) {
prop->leap59 = ((frgn_master->flagField[1] & FFB_LI59) != 0);
prop->leap61 = ((frgn_master->flagField[1] & FFB_LI61) != 0);
prop->currentUtcOffset = frgn_master->currentUtcOffset;
if (prop->leap59)
leap59 = 1;
else
leap59 = 0;
if (prop->leap61)
leap61 = 1;
else
leap61 = 0;
offset = prop->currentUtcOffset;
pp_diag(ppi, bmc, 1,
"UTC flags changed,"
"offset: %i, "
"leap59: %i, "
"leap61: %i\n",
offset, leap59, leap61);
ret = ppi->t_ops->set_utc_offset(ppi, offset, leap59, leap61);
if (ret) {
pp_diag(ppi, bmc, 1,
"Could not set UTC offset on system\n");
}
}
}
}
} else {
/* stop for 2 announce intervals after midnight */
if ((hours == 00) && (minutes == 00) &&
(seconds <= (0 + (2 * (1 << ppi->portDS->logAnnounceInterval))))) {
pp_diag(ppi, bmc, 2,
"short after midnight, taking local offset\n");
ret = ppi->t_ops->get_utc_offset(ppi, &offset, &leap59, &leap61);
if (ret) {
pp_diag(ppi, bmc, 1,
"Could not get UTC offset from system\n");
} else {
prop->currentUtcOffset = offset;
}
prop->leap59 = FALSE;
prop->leap61 = FALSE;
} else {
if (prop->currentUtcOffset != frgn_master->currentUtcOffset) {
pp_diag(ppi, bmc, 1, "New UTC offset in the middle of the day: %i\n",
frgn_master->currentUtcOffset);
prop->currentUtcOffset = frgn_master->currentUtcOffset;
ppi->t_ops->set(ppi, NULL);
}
prop->leap59 = ((frgn_master->flagField[1] & FFB_LI59) != 0);
prop->leap61 = ((frgn_master->flagField[1] & FFB_LI61) != 0);
}
}
}
} else {
/* just take what we get */
prop->leap59 = ((frgn_master->flagField[1] & FFB_LI59) != 0);
prop->leap61 = ((frgn_master->flagField[1] & FFB_LI61) != 0);
prop->currentUtcOffset = frgn_master->currentUtcOffset;
ppi->t_ops->set(ppi, NULL);
}
prop->currentUtcOffsetValid = ((frgn_master->flagField[1] & FFB_UTCV) != 0);
prop->leap59 = ((frgn_master->flagField[1] & FFB_LI59) != 0);
prop->leap61 = ((frgn_master->flagField[1] & FFB_LI61) != 0);
prop->timeTraceable = ((frgn_master->flagField[1] & FFB_TTRA) != 0);
prop->frequencyTraceable = ((frgn_master->flagField[1] & FFB_FTRA) != 0);
prop->ptpTimescale = ((frgn_master->flagField[1] & FFB_PTP) != 0);
......
......@@ -79,12 +79,44 @@ int pp_lib_may_issue_sync(struct pp_instance *ppi)
int pp_lib_may_issue_announce(struct pp_instance *ppi)
{
struct DSTimeProperties *prop = DSPRO(ppi);
int ret = 0;
int offset, leap59, leap61;
int hours, minutes, seconds;
int e;
if (!pp_timeout(ppi, PP_TO_ANN_SEND))
return 0;
pp_timeout_set(ppi, PP_TO_ANN_SEND);
/* this check has to be done here since the
* update of the properties might have not
* happened before sending
*/
if (prop->ptpTimescale) {
ret = ppi->t_ops->get_utc_time(ppi, &hours, &minutes, &seconds);
if (ret) {
pp_diag(ppi, frames, 1,
"Could not get UTC time from system, taking received flags\n");
} else {
/* for 2 announce intervals after midnight, get the offset from the system */
if ((hours == 00) && (minutes == 00) &&
(seconds <= (0 + (2 * (1 << ppi->portDS->logAnnounceInterval))))) {
pp_diag(ppi, frames, 2,
"short after midnight, taking local offset\n");
ret = ppi->t_ops->get_utc_offset(ppi, &offset, &leap59, &leap61);
if (ret) {
pp_diag(ppi, frames, 1,
"Could not get UTC offset from system\n");
} else {
prop->currentUtcOffset = offset;
}
prop->leap59 = FALSE;
prop->leap61 = FALSE;
}
}
}
e = pp_vlan_issue_announce(ppi);
if (e)
pp_diag(ppi, frames, 1, "could not send announce\n");
......
......@@ -8,6 +8,12 @@
#include <ppsi/ppsi.h>
#include "bare-linux.h"
static int bare_time_get_utc_time(struct pp_instance *ppi, int *hours, int *minutes, int *seconds)
{
/* TODO */
return -1;
}
static int bare_time_get_utc_offset(struct pp_instance *ppi, int *offset, int *leap59, int *leap61)
{
int ret;
......@@ -31,11 +37,19 @@ static int bare_time_get_utc_offset(struct pp_instance *ppi, int *offset, int *l
*offset = (int)t.tai;
return 0;
} else {
*leap59 = 0;
*leap61 = 0;
*offset = 0;
return -1;
}
}
static int bare_time_set_utc_offset(struct pp_instance *ppi, int offset, int leap59, int leap61)
{
/* TODO */
return -1;
}
static int bare_time_get_servo_state(struct pp_instance *ppi, int *state)
{
*state = PP_SERVO_UNKNOWN;
......@@ -134,7 +148,9 @@ static unsigned long bare_calc_timeout(struct pp_instance *ppi, int millisec)
}
struct pp_time_operations bare_time_ops = {
.get_utc_time = bare_time_get_utc_time,
.get_utc_offset = bare_time_get_utc_offset,
.set_utc_offset = bare_time_set_utc_offset,
.get_servo_state = bare_time_get_servo_state,
.get = bare_time_get,
.set = bare_time_set,
......
......@@ -46,6 +46,15 @@ int sim_fast_forward_ns(struct pp_globals *ppg, int64_t ff_ns)
return 0;
}
static int sim_time_get_utc_time(struct pp_instance *ppi, int *hours, int *minutes, int *seconds)
{
/* no UTC time */
*hours = 0;
*minutes = 0;
*seconds = 0;
return -1;
}
static int sim_time_get_utc_offset(struct pp_instance *ppi, int *offset, int *leap59, int *leap61)
{
/* no UTC offset */
......@@ -55,6 +64,12 @@ static int sim_time_get_utc_offset(struct pp_instance *ppi, int *offset, int *le
return -1;
}
static int sim_time_set_utc_offset(struct pp_instance *ppi, int offset, int leap59, int leap61)
{
/* no UTC offset */
return -1;
}
static int sim_time_get_servo_state(struct pp_instance *ppi, int *state)
{
*state = PP_SERVO_UNKNOWN;
......@@ -128,8 +143,10 @@ static unsigned long sim_calc_timeout(struct pp_instance *ppi, int millisec)
}
struct pp_time_operations sim_time_ops = {
.get_servo_state = sim_time_get_servo_state,
.get_utc_time = sim_time_get_utc_time,
.get_utc_offset = sim_time_get_utc_offset,
.set_utc_offset = sim_time_set_utc_offset,
.get_servo_state = sim_time_get_servo_state,
.get = sim_time_get,
.set = sim_time_set,
.adjust = sim_time_adjust,
......
......@@ -23,6 +23,34 @@ static void clock_fatal_error(char *context)
exit(1);
}
static int unix_time_get_utc_time(struct pp_instance *ppi, int *hours, int *minutes, int *seconds)
{
int ret;
struct timex t;
time_t now;
struct tm *date;
/* Get the UTC time */
memset(&t, 0, sizeof(t));
ret = adjtimex(&t);
if (ret >= 0) {
now = t.time.tv_sec;
/* use localtime for correct leap handling */
date = localtime(&now);
*hours = date->tm_hour;
*minutes = date->tm_min;
*seconds = date->tm_sec;
return 0;
} else {
*hours = 0;
*minutes = 0;
*seconds = 0;
return -1;
}
return -1;
}
static int unix_time_get_utc_offset(struct pp_instance *ppi, int *offset, int *leap59, int *leap61)
{
int ret;
......@@ -51,11 +79,46 @@ static int unix_time_get_utc_offset(struct pp_instance *ppi, int *offset, int *l
*offset = *((int *)(&t.stbcnt) + 1);
return 0;
} else {
*leap59 = 0;
*leap61 = 0;
*offset = 0;
return -1;
}
}
static int unix_time_set_utc_offset(struct pp_instance *ppi, int offset, int leap59, int leap61)
{
struct timex t;
if (leap59) {
memset(&t, 0, sizeof(t));
t.modes = MOD_STATUS;
t.status = STA_DEL;
if (adjtimex(&t) < 0) {
pp_diag(ppi, time, 1, "set leap second failed");
return -1;
}
} else if (leap61) {
memset(&t, 0, sizeof(t));
t.modes = MOD_STATUS;
t.status = STA_INS;
if (adjtimex(&t) < 0) {
pp_diag(ppi, time, 1, "set leap second failed");
return -1;
}
}
memset(&t, 0, sizeof(t));
t.modes = MOD_TAI;
t.constant = offset;
if (adjtimex(&t) < 0) {
pp_diag(ppi, time, 1, "set UTC offset failed");
return -1;
}
return 0;
}
static int unix_time_get_servo_state(struct pp_instance *ppi, int *state)
{
*state = PP_SERVO_UNKNOWN;
......@@ -163,8 +226,10 @@ static unsigned long unix_calc_timeout(struct pp_instance *ppi, int millisec)
}
struct pp_time_operations unix_time_ops = {
.get_servo_state = unix_time_get_servo_state,
.get_utc_time = unix_time_get_utc_time,
.get_utc_offset = unix_time_get_utc_offset,
.set_utc_offset = unix_time_set_utc_offset,
.get_servo_state = unix_time_get_servo_state,
.get = unix_time_get,
.set = unix_time_set,
.adjust = unix_time_adjust,
......
......@@ -9,6 +9,15 @@
#include "pps_gen.h" /* in wrpc-sw */
#include "syscon.h" /* in wrpc-sw */
static int wrpc_time_get_utc_time(struct pp_instance *ppi, int *hours, int *minutes, int *seconds)
{
/* no UTC time */
*hours = 0;
*minutes = 0;
*seconds = 0;
return -1;
}
static int wrpc_time_get_utc_offset(struct pp_instance *ppi, int *offset, int *leap59, int *leap61)
{
/* no UTC offset */
......@@ -18,6 +27,12 @@ static int wrpc_time_get_utc_offset(struct pp_instance *ppi, int *offset, int *l
return -1;
}
static int wrpc_time_set_utc_offset(struct pp_instance *ppi, int offset, int leap59, int leap61)
{
/* no UTC offset */
return -1;
}
static int wrpc_time_get_servo_state(struct pp_instance *ppi, int *state)
{
struct wr_dsport *wrp = WR_DSPOR(ppi);
......@@ -87,8 +102,10 @@ static unsigned long wrpc_calc_timeout(struct pp_instance *ppi, int millisec)
}
struct pp_time_operations wrpc_time_ops = {
.get_servo_state = wrpc_time_get_servo_state,
.get_utc_time = wrpc_time_get_utc_time,
.get_utc_offset = wrpc_time_get_utc_offset,
.set_utc_offset = wrpc_time_set_utc_offset,
.get_servo_state = wrpc_time_get_servo_state,
.get = wrpc_time_get,
.set = wrpc_time_set,
.adjust = wrpc_time_adjust,
......
......@@ -202,37 +202,19 @@ static int wrdate_get(struct pp_time *t)
return 0;
}
static int wrs_time_get_utc_time(struct pp_instance *ppi, int *hours, int *minutes, int *seconds)
{
return unix_time_ops.get_utc_time(ppi, hours, minutes, seconds);
}
static int wrs_time_get_utc_offset(struct pp_instance *ppi, int *offset, int *leap59, int *leap61)
{
int ret;
struct timex t;
/*
* Get the UTC/TAI difference
*/
memset(&t, 0, sizeof(t));
ret = adjtimex(&t);
if (ret >= 0) {
if (ret == TIME_INS) {
*leap59 = 0;
*leap61 = 1;
} else if (ret == TIME_DEL) {
*leap59 = 1;
*leap61 = 0;
} else {
*leap59 = 0;
*leap61 = 0;
}
/*
* Our WRS kernel has tai support, but our compiler does not.
* We are 32-bit only, and we know for sure that tai is
* exactly after stbcnt. It's a bad hack, but it works
*/
*offset = *((int *)(&t.stbcnt) + 1);
return 0;
} else {
*offset = 0;
return -1;
}
return unix_time_ops.get_utc_offset(ppi, offset, leap59, leap61);
}
static int wrs_time_set_utc_offset(struct pp_instance *ppi, int offset, int leap59, int leap61)
{
return unix_time_ops.set_utc_offset(ppi, offset, leap59, leap61);
}
static int wrs_time_get_servo_state(struct pp_instance *ppi, int *state)
......@@ -432,8 +414,10 @@ static unsigned long wrs_calc_timeout(struct pp_instance *ppi,
}
struct pp_time_operations wrs_time_ops = {
.get_servo_state = wrs_time_get_servo_state,
.get_utc_time = wrs_time_get_utc_time,
.get_utc_offset = wrs_time_get_utc_offset,
.set_utc_offset = wrs_time_set_utc_offset,
.get_servo_state = wrs_time_get_servo_state,
.get = wrs_time_get,
.set = wrs_time_set,
.adjust = wrs_time_adjust,
......
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