Commit f7c33411 authored by Jean-Claude BAU's avatar Jean-Claude BAU Committed by Adam Wujek

[Issue:#196] WR time not set properly in GM mode

1/ wr_date script:
- Started before PPSi
- Set number of NTP retries to 10 if GM otherwise 1. GM info is
extracted from dot-config
- Clock source is controlled directly with wr_date tool
- Can be started any time without any risk to set a wrong date (see
point 2)
2/ wr_date
- 'set host' parameters take into account the time mode ( FR: set
sec+ns, BC: time cannot be set, GM: set seconds only+wait to be in a
middle of a second)
- function substrat_substrat() moved to time_lib.h. Also used by wr_mon
3/ wr_mon
- Print TAI-UTC
- Update Timing Mode & PLL locking state displayed values
parent c9664ba4
Subproject commit b66d61fe722246dbeb6b47cbeb629429fef69861
Subproject commit e9c7ba239fbc6dff66e8d1b50bfedacc7742d20d
#!/bin/sh
# First of all, run wr_date -n set, so to fix tai_offset in the kernel
# First of all, run 'wr_date -n set host', so to fix tai_offset in the kernel. Does not set the time
/wr/bin/wr_date -n set host > /dev/null
F=/etc/wr_date.conf
CCS=/sys/bus/clocksource/devices/clocksource0/current_clocksource
#CCS=/sys/bus/clocksource/devices/clocksource0/current_clocksource
#Each NTP attempts last around 10s
ntp_retries()
......@@ -25,47 +25,22 @@ ntp_retries()
return 1
}
gm_wait_lock()
{
gm_ntries=${1:-15}
#First check if we have configure softpll in GM mode <=> (1)
if /wr/bin/wrs_dump_shmem -S 2> logger | grep mode | grep -q \(1\); then
for i in `seq ${gm_ntries}` ; do
#Check if we have entered in locked state <=> (6)
al_state=$(/wr/bin/wrs_dump_shmem -S 2> /dev/null | grep align_state)
if echo ${al_state} | grep -q \(6\); then
return 0
else
echo "Retry $i/${gm_ntries}: GM mode but not locked! "${al_state}
fi
sleep 10
done
echo "Error: GM was not lock when setting ntp time to FPGA"
return 2
fi
return 1
}
ntp_to_hwclk()
{
S=$1
ntp_ntries=1
#Check if GM mode and wait for GM lock
if gm_wait_lock; then
# Get timing mode: Get it from dot-config ad wr_date is started before PPSi
TM=`grep -e '^CONFIG_TIME_' /wr/etc/dot-config | sed 's/^CONFIG_TIME_\(.*\)[=].*/\1/'`
if [ "$TM" == "GM" ] ; then
ntp_ntries=10
#Temporary disable white-rabbit as kernel clock source
echo "pit" > ${CCS}
else
ntp_ntries=1
fi
#Request NTP server and set time to FPGA is okay
if ntp_retries $S ${ntp_ntries}; then
/wr/bin/wr_date -v set host
date_set=1
#Enable back white rabbit as clock source
echo "white-rabbit" > ${CCS}
fi
}
......
......@@ -85,6 +85,9 @@ wrs_dump_shmem: wrs_dump_shmem.o wrs_dump_shmem_ppsi.o time_lib.o
wr_mon: wr_mon.o term.o time_lib.o
${CC} -o $@ $^ $(LDFLAGS)
wr_date: wr_date.o time_lib.o
${CC} -o $@ $^ $(LDFLAGS)
wr_management: wr_management.o term.o
${CC} -o $@ $^ $(LDFLAGS)
......
......@@ -79,3 +79,56 @@ char * relativeDifferenceToString(RelativeDifference time, char *buf ) {
sprintf(buf,"%c%"PRId32".%018"PRIu64, sign, nsecs, sub_yocto);
return buf;
}
/**
* Function to subtract timeval in a robust way
*
* In order to properly print the result on screen you can use:
*
* int neg=timeval_subtract(&diff, &a, &b);
* printf("%c%li.%06li\n",neg?'-':'+',labs(diff.tv_sec),labs(diff.tv_usec));
*
* @ref: https://stackoverflow.com/questions/15846762/timeval-subtract-explanation
* @note for safety reason a copy of x,y is used internally so x,y are never modified
* @param[inout] result A pointer on a timeval structure where the result will be stored.
* @param[in] x A pointer on x timeval struct
* @param[in] y A pointer on y timeval struct
* @return 1 if result is negative (seconds or useconds)
*
*
*/
int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y)
{
struct timeval xx = *x;
struct timeval yy = *y;
x = &xx; y = &yy;
if (x->tv_usec > 999999)
{
x->tv_sec += x->tv_usec / 1000000;
x->tv_usec %= 1000000;
}
if (y->tv_usec > 999999)
{
y->tv_sec += y->tv_usec / 1000000;
y->tv_usec %= 1000000;
}
result->tv_sec = x->tv_sec - y->tv_sec;
result->tv_usec = x->tv_usec - y->tv_usec;
if(result->tv_sec>0 && result->tv_usec < 0)
{
result->tv_usec += 1000000;
result->tv_sec--; // borrow
}
else if(result->tv_sec<0 && result->tv_usec > 0)
{
result->tv_usec -= 1000000;
result->tv_sec++; // borrow
}
return (result->tv_sec < 0) || (result->tv_usec<0);
}
......@@ -5,3 +5,4 @@ char * timeIntervalToString(TimeInterval time,char *buf);
char * timeToString(struct pp_time *time,char *buf);
char * timestampToString(struct Timestamp *time,char *buf);
char * relativeDifferenceToString(RelativeDifference time, char *buf );
int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y);
......@@ -18,7 +18,9 @@
#include <sys/time.h>
#include <sys/timex.h>
#include "../../kernel/wbgen-regs/ppsg-regs.h"
#include <libwr/softpll_export.h>
#include <libwr/util.h>
#include <time_lib.h>
#ifndef MOD_TAI
#define MOD_TAI 0x80
......@@ -46,7 +48,7 @@ void help(char *prgname)
" get print WR time to stdout\n"
" get tohost print WR time and set system time\n"
" set <value> set WR time to scalar seconds\n"
" set host set TAI from current host time\n"
" set host set TAI from current host time.\n"
" stat print statistics between TAI (WR time) and linux UTC\n"
" diff show the difference between WR FPGA time (HW) and linux time (SW)\n"
/* " set ntp set TAI from ntp and leap seconds" */
......@@ -182,80 +184,33 @@ int wrdate_get(volatile struct PPSG_WB *pps, int tohost)
}
/**
* Function to subtract timeval in a robust way
*
* In order to properly print the result on screen you can use:
*
* int neg=timeval_subtract(&diff, &a, &b);
* printf("%c%li.%06li\n",neg?'-':'+',labs(diff.tv_sec),labs(diff.tv_usec));
*
* @ref: https://stackoverflow.com/questions/15846762/timeval-subtract-explanation
* @note for safety reason a copy of x,y is used internally so x,y are never modified
* @param[inout] result A pointer on a timeval structure where the result will be stored.
* @param[in] x A pointer on x timeval struct
* @param[in] y A pointer on y timeval struct
* @return 1 if result is negative (seconds or useconds)
*
*
*/
int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y)
{
struct timeval xx = *x;
struct timeval yy = *y;
x = &xx; y = &yy;
int __wrdate_diff(volatile struct PPSG_WB *pps,struct timeval *ht, struct timeval *wt) {
struct timeval diff;
int neg=0;
if (x->tv_usec > 999999)
{
x->tv_sec += x->tv_usec / 1000000;
x->tv_usec %= 1000000;
}
neg=timeval_subtract(&diff, wt, ht);
if (y->tv_usec > 999999)
printf("%s%c%li.%06li\n",opt_verbose?("TAI(HW)-UTC(SW): "):(""),neg?'-':'+',labs(diff.tv_sec),labs(diff.tv_usec));
if(opt_verbose)
{
y->tv_sec += y->tv_usec / 1000000;
y->tv_usec %= 1000000;
}
result->tv_sec = x->tv_sec - y->tv_sec;
result->tv_usec = x->tv_usec - y->tv_usec;
wt->tv_sec-=get_kern_leaps(); //Convert HW clock from TAI to UTC
if(result->tv_sec>0 && result->tv_usec < 0)
{
result->tv_usec += 1000000;
result->tv_sec--; // borrow
}
else if(result->tv_sec<0 && result->tv_usec > 0)
{
result->tv_usec -= 1000000;
result->tv_sec++; // borrow
neg=timeval_subtract(&diff, wt, ht);
printf("UTC(HW)-UTC(SW): %c%li.%06li\n",neg?'-':'+',labs(diff.tv_sec),labs(diff.tv_usec));
}
return 0;
return (result->tv_sec < 0) || (result->tv_usec<0);
}
int wrdate_diff(volatile struct PPSG_WB *pps)
{
struct timeval sw, hw, diff;
int neg=0;
gettimeof_wr(&hw, pps);
gettimeofday(&sw, NULL);
struct timeval ht, wt;
neg=timeval_subtract(&diff, &hw, &sw);
gettimeof_wr(&wt, pps);
gettimeofday(&ht, NULL);
printf("%s%c%li.%06li\n",opt_verbose?("TAI(HW)-UTC(SW): "):(""),neg?'-':'+',labs(diff.tv_sec),labs(diff.tv_usec));
if(opt_verbose)
{
hw.tv_sec-=get_kern_leaps(); //Convert HW clock from TAI to UTC
neg=timeval_subtract(&diff, &hw, &sw);
printf("UTC(HW)-UTC(SW): %c%li.%06li\n",neg?'-':'+',labs(diff.tv_sec),labs(diff.tv_usec));
}
return 0;
return __wrdate_diff(pps,&ht, &wt);
}
/* Fix the TAI representation looking at the leap file */
......@@ -333,7 +288,7 @@ int fix_host_tai(void)
#define ADJ_SEC_ITER 10
static int wait_wr_adjustment(struct PPSG_WB *pps)
static int wait_wr_adjustment(volatile struct PPSG_WB *pps)
{
int count=0;
......@@ -407,6 +362,10 @@ int installClockSourceModule(void) {
}
ret=1;
if (opt_verbose) {
printf("Driver module "CLOCK_SOURCE_MODULE_NAME" installed.\n");
}
out:;
if ( fd >=0 )
close(fd);
......@@ -416,7 +375,7 @@ int installClockSourceModule(void) {
}
/* This sets WR time from host time */
int wrdate_internal_set(volatile struct PPSG_WB *pps, int deep)
int __wrdate_internal_set(volatile struct PPSG_WB *pps, int adjSecOnly, int deep)
{
struct timeval tvh, tvr; /* host, rabbit */
......@@ -465,7 +424,7 @@ int wrdate_internal_set(volatile struct PPSG_WB *pps, int deep)
(long)(tvh.tv_usec));
printf("WR time: %9li.%06li\n", (long)(tvr.tv_sec),
(long)(tvr.tv_usec));
printf("Fractional difference: %li usec\n", diff);
__wrdate_diff(pps,&tvh,&tvr);
}
if (diff64) {
......@@ -477,9 +436,9 @@ int wrdate_internal_set(volatile struct PPSG_WB *pps, int deep)
pps->ADJ_NSEC = 0;
asm("" : : : "memory"); /* barrier... */
pps->CR = pps->CR | PPSG_CR_CNT_ADJ;
if ( wait_wr_adjustment(pps) )
__wrdate_internal_set(pps,deep+1); /* adjust the usecs */
} else {
if ( wait_wr_adjustment(pps) && !adjSecOnly )
__wrdate_internal_set(pps,0,deep+1); /* adjust the usecs */
} else if ( !adjSecOnly ) {
if (opt_verbose)
printf("adjusting by %li usecs\n", diff);
pps->ADJ_UTCLO = 0;
......@@ -503,36 +462,106 @@ int wrdate_internal_set(volatile struct PPSG_WB *pps, int deep)
(long)(tvh.tv_usec));
printf("WR time: %9li.%06li\n", (long)(tvr.tv_sec),
(long)(tvr.tv_usec));
__wrdate_diff(pps,&tvh,&tvr);
}
return 0;
}
/* This sets WR time from host time */
int wrdate_internal_set(struct PPSG_WB *pps) {
return __wrdate_internal_set(pps,0);
int wrdate_internal_set(volatile struct PPSG_WB *pps, int adjSecOnly) {
return __wrdate_internal_set(pps,adjSecOnly,0);
}
/* This sets WR time from host time for grand master mode
* For a GM we adjust only the seconds part of the time.
*/
#define FULL_SEC (1000*1000) /* 1000 ms */
#define HALF_SEC (FULL_SEC/2) /* 500 ms */
#define LOW_LIMIT_HALF_SEC (300*1000) /* 300 ms */
#define HIGH_LIMIT_HALF_SEC (700*1000) /* 300 ms */
int wrdate_internal_set_gm(volatile struct PPSG_WB *pps) {
if (opt_verbose ) {
printf("Set WR time for grand master.\n");
}
/* We try to set the seconds between to PPS ticks */
while (1==1) {
struct timeval wt;
gettimeof_wr(&wt, pps);
if ( wt.tv_usec>LOW_LIMIT_HALF_SEC && wt.tv_usec<HIGH_LIMIT_HALF_SEC ) {
wrdate_internal_set(pps,1);
return 0;
} else {
useconds_t usec;
usec= ( wt.tv_usec>HALF_SEC ) ?
(FULL_SEC-wt.tv_usec)+HALF_SEC :
HALF_SEC-wt.tv_usec;
usleep(usec);
}
}
return 0;
}
#define SPLL_MAGIC 0x5b1157a7
#define FPGA_SPLL_STAT 0x10006800
int getTimingMode(void) {
static struct spll_stats *spll_stats_p;
if ( spll_stats_p==NULL ) {
spll_stats_p = create_map(FPGA_SPLL_STAT,sizeof(*spll_stats_p));
if ( spll_stats_p==NULL ) {
fprintf(stderr, "Cannot create map to Soft Pll stats\n");
return -1;
}
if (spll_stats_p->magic != SPLL_MAGIC) {
/* Wrong magic */
fprintf(stderr, "Soft PLL: unknown magic %x (known is %x)\n",
spll_stats_p->magic, SPLL_MAGIC);
return -1;
}
}
return spll_stats_p->mode;
}
/* Frontend to the set mechanism: parse the argument */
int wrdate_set(volatile struct PPSG_WB *pps, char *arg)
int wrdate_set(volatile struct PPSG_WB *pps, int argc, char **argv)
{
char *s;
unsigned long t; /* WARNING: 64 bit */
struct timeval tv;
if (!strcmp(argv[0], "host")) {
switch (getTimingMode()) {
case SPLL_MODE_GRAND_MASTER:
return wrdate_internal_set_gm(pps);
case SPLL_MODE_FREE_RUNNING_MASTER :
case SPLL_MODE_DISABLED :
return wrdate_internal_set(pps,0);
break;
case SPLL_MODE_SLAVE :
fprintf(stderr, "Slave timing mode: WR time cannot be set!!!\n");
return -1;
default:
fprintf(stderr, "Cannot read Soft PLL timing mode. WR time cannot be set.\n");
return -1;
}
}
if (!strcmp(arg, "host"))
return wrdate_internal_set(pps);
s = strdup(arg);
if (sscanf(arg, "%li%s", &t, s) == 1) {
s = strdup(argv[0]);
if (sscanf(argv[0], "%li%s", &t, s) == 1) {
tv.tv_sec = t;
tv.tv_usec = 0;
if (settimeofday(&tv, NULL) < 0) {
fprintf(stderr, "%s: settimeofday(%s): %s\n",
prgname, arg, strerror(errno));
prgname, argv[0], strerror(errno));
exit(1);
}
return wrdate_internal_set(pps);
return wrdate_internal_set(pps,0);
}
/* FIXME: other time formats */
......@@ -543,7 +572,7 @@ int wrdate_set(volatile struct PPSG_WB *pps, char *arg)
/* Print statistics between TAI and UTC dates */
#define STAT_SAMPLE_COUNT 20
int wrdate_stat(struct PPSG_WB *pps)
int wrdate_stat(volatile struct PPSG_WB *pps)
{
int udiff_ref=0,udiff_last;
......@@ -649,10 +678,10 @@ int main(int argc, char **argv)
return wrdate_stat(pps);
}
/* only other command is "set", with one argument */
if (strcmp(cmd, "set") || optind != argc - 1)
/* only other command is "set", with one on more arguments */
if (strcmp(cmd, "set") || optind > argc - 1)
help(argv[0]);
return wrdate_set(pps, argv[optind]);
return wrdate_set(pps, argc-optind,&argv[optind]);
}
......@@ -16,6 +16,8 @@
#include <fpga_io.h>
#include <minipc.h>
#include <signal.h>
#include <ppsi-wrs.h>
#include "term.h"
#include <time_lib.h>
......@@ -128,12 +130,13 @@ int mode = SHOW_GUI;
static struct minipc_ch *ptp_ch;
static struct wrs_shm_head *hal_head;
static struct hal_port_state *hal_ports;
struct hal_port_state *hal_ports;
/* local copy of port state */
static struct hal_port_state hal_ports_local_copy[HAL_MAX_PORTS];
static int hal_nports_local;
static struct wrs_shm_head *ppsi_head;
static struct pp_globals *ppg;
static void *ppg_arch;
static defaultDS_t *defaultDS;
static pid_t ptp_ch_pid; /* pid of ppsi connected via minipc */
static struct hal_temp_sensors *temp_sensors;
......@@ -182,19 +185,19 @@ static char * l1e_instance_extension_state[]={
#endif
static char * timind_mode_state[] = {
[TM_GRAND_MASTER]= "GM",
[TM_FREE_MASTER]= "FR",
[TM_BOUNDARY_CLOCK]= "BC",
[TM_DISABLED]= "--",
[WRH_TM_GRAND_MASTER]= "GM",
[WRH_TM_FREE_MASTER]= "FR",
[WRH_TM_BOUNDARY_CLOCK]= "BC",
[WRH_TM_DISABLED]= "--",
NULL
};
static char * pll_locking_state[] = {
[TM_LOCKING_STATE_NONE]= "NONE ",
[TM_LOCKING_STATE_LOCKING]= "LOCKING ",
[TM_LOCKING_STATE_LOCKED]= "LOCKED ",
[TM_LOCKING_STATE_HOLDOVER]= "HOLDOVER",
[TM_LOCKING_STATE_ERROR]= "ERROR ",
[WRH_TM_LOCKING_STATE_NONE]= "NONE ",
[WRH_TM_LOCKING_STATE_LOCKING]= "LOCKING ",
[WRH_TM_LOCKING_STATE_LOCKED]= "LOCKED ",
[WRH_TM_LOCKING_STATE_HOLDOVER]= "HOLDOVER",
[WRH_TM_LOCKING_STATE_ERROR]= "ERROR ",
NULL
};
......@@ -505,6 +508,10 @@ void init_shm(void)
}
ppg = (void *)ppsi_head + ppsi_head->data_off;
/* Access to ppg arch data */
if ( ppg->arch_data!=NULL)
ppg_arch=wrs_shm_follow(ppsi_head, ppg->arch_data);
/* Access to defaultDS data */
defaultDS = wrs_shm_follow(ppsi_head, ppg->defaultDS);
if (!defaultDS) {
......@@ -571,13 +578,8 @@ void show_ports(int hal_alive, int ppsi_alive)
tm = gmtime(&(hw.tv_sec));
strftime(datestr, sizeof(datestr), "%Y-%m-%d %H:%M:%S", tm);
term_cprintf(C_BLUE, "WR time (TAI): ");
term_cprintf(C_WHITE, "%s.%06li\n", datestr,hw.tv_usec);
tm = gmtime(&(sw.tv_sec));
strftime(datestr, sizeof(datestr), "%Y-%m-%d %H:%M:%S", tm);
term_cprintf(C_BLUE, "Switch time (UTC): ");
term_cprintf(C_WHITE, "%s.%06li", datestr,sw.tv_usec);
term_cprintf(C_BLUE, "WR time (TAI) : ");
term_cprintf(C_WHITE, "%s.%06li", datestr,hw.tv_usec);
term_cprintf(C_BLUE, " Leap seconds: ");
if (adjtimex(&timex_val) < 0) {
......@@ -587,11 +589,27 @@ void show_ports(int hal_alive, int ppsi_alive)
term_cprintf(C_WHITE, "%3d\n", *p);
}
term_cprintf(C_BLUE, "TimingMode: ");
term_cprintf(C_WHITE, "%s",getStateAsString(timind_mode_state,ppg->timingMode));
term_cprintf(C_BLUE, " PLL locking state: ");
term_cprintf(C_WHITE, "%s\n",getStateAsString(pll_locking_state,ppg->timingModeLockingState));
tm = gmtime(&(sw.tv_sec));
strftime(datestr, sizeof(datestr), "%Y-%m-%d %H:%M:%S", tm);
term_cprintf(C_BLUE, "Switch time (UTC): ");
term_cprintf(C_WHITE, "%s.%06li", datestr,sw.tv_usec);
term_cprintf(C_BLUE, " TAI-UTC : ");
{
struct timeval diff;
int neg=0;
neg=timeval_subtract(&diff, &hw, &sw);
term_cprintf(C_WHITE, "%c%li.%06li\n",neg?'-':'+',labs(diff.tv_sec),labs(diff.tv_usec));
}
if ( ppsi_alive && ppg_arch!=NULL) {
term_cprintf(C_BLUE, "TimingMode: ");
term_cprintf(C_WHITE, "%s",getStateAsString(timind_mode_state,((wrs_arch_data_t *)ppg_arch)->timingMode));
term_cprintf(C_BLUE, " PLL locking state: ");
term_cprintf(C_WHITE, "%s\n",getStateAsString(pll_locking_state,((wrs_arch_data_t *)ppg_arch)->timingModeLockingState));
}
term_cprintf(C_CYAN, "----- HAL ---|---------------------------------- PPSI --------------------------------------------------------\n");
term_cprintf(C_CYAN, " Iface| Freq |Inst| Name | Config | MAC of peer port | PTP/EXT/PLINK states | Pro | VLANs\n");
term_cprintf(C_CYAN, "------+------+----+--------------+------------+-------------------+------------------------------+-----+------\n");
......
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