summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Burnicki <martin.burnicki@meinberg.de>2018-03-09 12:00:00 +0100
committerMartin Burnicki <martin.burnicki@meinberg.de>2018-03-09 12:00:00 +0100
commit8af775dc00e14dc74e7cd74dc202cec636efbddd (patch)
tree4b849e9646d65ab21b25de736a4c1179e989f473
parentc839fb5b430388eff87487e9a1ce58b38921c807 (diff)
downloadntptest-8af775dc00e14dc74e7cd74dc202cec636efbddd.tar.gz
ntptest-8af775dc00e14dc74e7cd74dc202cec636efbddd.zip
Improve printing of refid using functions from new module mbgntp.c1.8
-rwxr-xr-xmbglib/common/mbg_ntp_test_util.c121
-rwxr-xr-xmbglib/common/mbg_ntp_test_util.h7
-rwxr-xr-xmbglib/common/mbgntp.c170
-rwxr-xr-xmbglib/common/mbgntp.h98
-rwxr-xr-xmbglib/common/mbgtime.h24
-rwxr-xr-xmbglib/common/timeutil.c216
-rwxr-xr-xmbglib/common/timeutil.h35
-rwxr-xr-xmbglib/common/words.h12
-rwxr-xr-xntptest.c8
-rwxr-xr-xunix/Makefile5
10 files changed, 568 insertions, 128 deletions
diff --git a/mbglib/common/mbg_ntp_test_util.c b/mbglib/common/mbg_ntp_test_util.c
index ba19d77..52c04ee 100755
--- a/mbglib/common/mbg_ntp_test_util.c
+++ b/mbglib/common/mbg_ntp_test_util.c
@@ -1,7 +1,7 @@
/**************************************************************************
*
- * $Id: mbg_ntp_test_util.c 1.8 2017/09/06 14:04:26 martin REL_M $
+ * $Id: mbg_ntp_test_util.c 1.9 2018/03/09 09:55:16 martin REL_M $
*
* Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany
*
@@ -10,6 +10,9 @@
*
* -----------------------------------------------------------------------
* $Log: mbg_ntp_test_util.c $
+ * Revision 1.9 2018/03/09 09:55:16 martin
+ * Improved printing of refid using functions from new module mbgntp.c.
+ * Moved snprint_ntp_prec() to mbgntp.c.
* Revision 1.8 2017/09/06 14:04:26 martin
* Root delay and root dispersion are now printed
* with 6 instead of only 4 fractional digits.
@@ -192,61 +195,6 @@ void print_ntp_time( const char *msg, const NTP_TSTAMP *t, const char *tail, int
/*HDR*/
-int snprint_ntp_prec( char *s, size_t max_len, int8_t prec_exp )
-{
- typedef struct
- {
- double limit;
- double scale;
- int frac_digits;
- const char *units;
- } SC_INFO;
-
- const SC_INFO *p;
-
- int shift_cnt = abs( prec_exp );
- double d = (double) ( (uint64_t) 1UL << shift_cnt );
-
- if ( prec_exp < 0 )
- {
- int i;
-
- #define N_SC_INFO_NEG 7
-
- static const SC_INFO sc_info_neg[N_SC_INFO_NEG] =
- {
- { 1., 1e3, 0, "ms" }, // 2^^0
- { 8., 1e3, 2, "ms" }, // 2^^3
- { 1024., 1e6, 0, "us" }, // 2^^10
- { 8192., 1e6, 2, "us" }, // 2^^12
- { 524288., 1e9, 0, "ns" }, // 2^^19
- { 8388608., 1e9, 2, "ns" }, // 2^^23
- { 134217728., 1e9, 3, "ns" } // 2^^27
- };
-
- for ( i = N_SC_INFO_NEG; i > 0; )
- {
- i--;
- p = &sc_info_neg[i];
- if ( d > p->limit )
- break;
- }
-
- d = p->scale / d;
- }
- else
- {
- static const SC_INFO sc_info_pos = { 0, 0, 0, "s" };
- p = &sc_info_pos;
- }
-
- return snprintf_safe( s, max_len, "%.*f %s", p->frac_digits, d, p->units );
-
-} // snprint_ntp_prec
-
-
-
-/*HDR*/
/**
* @brief Print contents of an NTP packet on several lines
*
@@ -254,21 +202,22 @@ int snprint_ntp_prec( char *s, size_t max_len, int8_t prec_exp )
* @param[in] p An ::NTP_PACKET_INFO structure containing the NTP packet plus some additional information.
* @param[in] print_date_time If not 0, print also the date and time derived from the NTP time stamps.
*/
-void print_ntp_packet( const char *msg, const NTP_PACKET_INFO *p, int print_date_time )
+void print_ntp_packet( const char *msg, const NTP_PACKET_INFO *p, int print_date_time, int verbose )
{
const NTP_BASE_PACKET *pbp = &p->packet.base;
size_t i;
- char ref_id_str[80];
- char *cp = ref_id_str;
+ char ref_id_str_txt[5];
+ char ref_id_str_bin[16];
int8_t pkt_precision = pbp->flags.precision;
char prec_str[40];
+ bool refid_should_be_text = ntp_refid_should_be_text( pbp->flags.stratum, &pbp->refid );
snprint_ntp_prec( prec_str, sizeof( prec_str ), pkt_precision );
printf( "%s\n", msg );
printf( INDENT
- "mode %u, version %u, leap_ind %u, "
+ "mode %u, version %u, leap %u, "
"stratum %u, poll %u, prec %i (%s)\n"
,
pbp->flags.mode,
@@ -280,42 +229,36 @@ void print_ntp_packet( const char *msg, const NTP_PACKET_INFO *p, int print_date
prec_str
);
-
- for ( i = 0; ; )
- {
- unsigned char uc = BYTE_OF( pbp->refid.as_u32, i );
-
- if ( !isdigit( uc ) )
- {
- sprintf( ref_id_str, "%.*s", // TODO FIXME
- (int) sizeof( pbp->refid ),
- pbp->refid.as_chars
- );
- break;
- }
-
- cp += sprintf( cp, "%u", uc );
-
- if ( ++i >= sizeof( pbp->refid ) )
- {
- *cp = 0;
- break;
- }
-
- *cp++ = '.';
- }
+ snprintf_ntp_refid_as_text( ref_id_str_txt, sizeof( ref_id_str_txt ), &pbp->refid );
+ snprintf_ntp_refid_as_dotted_quad( ref_id_str_bin, sizeof( ref_id_str_bin ), &pbp->refid );
printf(
INDENT "root delay: %08lX (%.6f s)\n"
INDENT "root dispersion: %08lX (%.6f s/s)\n"
- INDENT "reference id: %08lX (%s)\n"
+ INDENT "reference id: %08lX "
,
(long) pbp->root_delay, _u_fp_to_d( pbp->root_delay ),
(long) pbp->root_dispersion, _u_fp_to_d( pbp->root_dispersion ),
- (long) pbp->refid.as_u32,
- ref_id_str
+ (long) pbp->refid.as_u32
);
+ if ( refid_should_be_text )
+ {
+ printf( "(\"%s\"", ref_id_str_txt );
+
+ if ( verbose )
+ printf( ", %s", ref_id_str_bin );
+ }
+ else // refid is an IPv4 address or IPv6 address hash
+ {
+ printf( "(%s", ref_id_str_bin );
+
+ if ( verbose )
+ printf( ", \"%s\"", ref_id_str_txt );
+ }
+ printf( ")\n" );
+
+
print_ntp_time( INDENT "Ref time: ", &pbp->reference_time, newline, print_date_time );
print_ntp_time( INDENT "Org time (T1): ", &pbp->originate_time, newline, print_date_time );
print_ntp_time( INDENT "Rcv time (T2): ", &pbp->receive_time, newline, print_date_time );
@@ -546,13 +489,13 @@ void print_ntp_results( const NTP_RESULTS *p_rslt, const NTP_PACKET_INFO *p_req,
int print_date_time, int verbose )
{
if ( p_req )
- print_ntp_packet( "Request packet:", p_req, print_date_time );
+ print_ntp_packet( "Request packet:", p_req, print_date_time, verbose );
if ( p_rcv )
{
double d;
bool smearing_active;
- print_ntp_packet( "Response packet:", p_rcv, print_date_time );
+ print_ntp_packet( "Response packet:", p_rcv, print_date_time, verbose );
smearing_active = leap_smearing_active( &p_rcv->packet.base.refid, &d );
if ( verbose || smearing_active )
{
diff --git a/mbglib/common/mbg_ntp_test_util.h b/mbglib/common/mbg_ntp_test_util.h
index fb2a5d4..5f303d1 100755
--- a/mbglib/common/mbg_ntp_test_util.h
+++ b/mbglib/common/mbg_ntp_test_util.h
@@ -1,7 +1,7 @@
/**************************************************************************
*
- * $Id: mbg_ntp_test_util.h 1.5 2016/11/21 17:22:50 martin REL_M $
+ * $Id: mbg_ntp_test_util.h 1.6 2018/03/09 09:55:33 martin REL_M $
*
* Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany
*
@@ -10,6 +10,8 @@
*
* -----------------------------------------------------------------------
* $Log: mbg_ntp_test_util.h $
+ * Revision 1.6 2018/03/09 09:55:33 martin
+ * Updated function prototypes.
* Revision 1.5 2016/11/21 17:22:50 martin
* Adjustable client poll value sent to server, defaults to 6.
* Revision 1.4 2016/08/05 12:37:31 martin
@@ -313,7 +315,6 @@ int check_bounds( int opt_val, int min_val, int max_val, int default_val )
*/
void print_ntp_time( const char *msg, const NTP_TSTAMP *t, const char *tail, int print_date_time ) ;
- int snprint_ntp_prec( char *s, size_t max_len, int8_t prec_exp ) ;
/**
* @brief Print contents of an NTP packet on several lines
*
@@ -321,7 +322,7 @@ int check_bounds( int opt_val, int min_val, int max_val, int default_val )
* @param[in] p An ::NTP_PACKET_INFO structure containing the NTP packet plus some additional information.
* @param[in] print_date_time If not 0, print also the date and time derived from the NTP time stamps.
*/
- void print_ntp_packet( const char *msg, const NTP_PACKET_INFO *p, int print_date_time ) ;
+ void print_ntp_packet( const char *msg, const NTP_PACKET_INFO *p, int print_date_time, int verbose ) ;
/**
* @brief Initialize a basic NTP packet
diff --git a/mbglib/common/mbgntp.c b/mbglib/common/mbgntp.c
new file mode 100755
index 0000000..007a048
--- /dev/null
+++ b/mbglib/common/mbgntp.c
@@ -0,0 +1,170 @@
+
+/**************************************************************************
+ *
+ * $Id: mbgntp.c 1.1 2018/03/09 09:56:35 martin REL_M $
+ *
+ * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany
+ *
+ * Description:
+ * Functions useful for NTP implementations.
+ *
+ * -----------------------------------------------------------------------
+ * $Log: mbgntp.c $
+ * Revision 1.1 2018/03/09 09:56:35 martin
+ * Initial revision.
+ *
+ **************************************************************************/
+
+#define _MBGNTP
+ #include <mbgntp.h>
+#undef _MBGNTP
+
+#include <str_util.h>
+
+
+
+/*HDR*/
+/**
+ * @brief Print the value of the 'precision' field from an NTP packet to a string buffer
+ *
+ * @param[out] s Address of a string buffer to be filled.
+ * @param[in] max_len Size of the string buffer.
+ * @param[in] prec_exp The precision value from the NTP packet.
+ */
+int snprint_ntp_prec( char *s, size_t max_len, int8_t prec_exp )
+{
+ typedef struct
+ {
+ double limit;
+ double scale;
+ int frac_digits;
+ const char *units;
+ } SC_INFO;
+
+ const SC_INFO *p;
+
+ int shift_cnt = abs( prec_exp );
+ double d = (double) ( (uint64_t) 1UL << shift_cnt );
+
+ if ( prec_exp < 0 )
+ {
+ int i;
+
+ #define N_SC_INFO_NEG 7
+
+ static const SC_INFO sc_info_neg[N_SC_INFO_NEG] =
+ {
+ { 1., 1e3, 0, "ms" }, // 2^^0
+ { 8., 1e3, 2, "ms" }, // 2^^3
+ { 1024., 1e6, 0, "us" }, // 2^^10
+ { 8192., 1e6, 2, "us" }, // 2^^12
+ { 524288., 1e9, 0, "ns" }, // 2^^19
+ { 8388608., 1e9, 2, "ns" }, // 2^^23
+ { 134217728., 1e9, 3, "ns" } // 2^^27
+ };
+
+ for ( i = N_SC_INFO_NEG; i > 0; )
+ {
+ i--;
+ p = &sc_info_neg[i];
+ if ( d > p->limit )
+ break;
+ }
+
+ d = p->scale / d;
+ }
+ else
+ {
+ static const SC_INFO sc_info_pos = { 0, 0, 0, "s" };
+ p = &sc_info_pos;
+ }
+
+ return snprintf_safe( s, max_len, "%.*f %s", p->frac_digits, d, p->units );
+
+} // snprint_ntp_prec
+
+
+
+/*HDR*/
+/**
+ * @brief Print an NTP refid as text to a string buffer
+ *
+ * The function ::ntp_refid_should_be_text can be called to determine
+ * if the refid is to be interpreted as printable text, so this function
+ * can be used to print it into a string buffer.
+ *
+ * Please note the 4 char refid may not be 0-terminated, so you can't
+ * simply cast the original refid to a string, and then print it.
+ *
+ * @param[out] s Address of a string buffer to be filled.
+ * @param[in] max_len Size of the string buffer.
+ * @param[in] p Pointer to a ::NTP_REFID.
+ *
+ * @return Number of characters copied to the destination buffer, without the terminating 0
+ *
+ * @see ::ntp_refid_should_be_text
+ * @see ::snprintf_ntp_refid_as_dotted_quad
+ */
+int snprintf_ntp_refid_as_text( char *s, size_t max_len, const NTP_REFID *p )
+{
+ char *cp = s;
+ int i;
+
+ for ( i = 0; i < sizeof( *p ) && i < max_len; i++ )
+ {
+ char c = p->as_chars[i];
+ *cp++ = ( c > 0x1f && c < 0x7F ) ? c : '.';
+ }
+
+ *cp = 0; // force terminating 0
+
+ return cp - s;
+
+} // snprintf_ntp_refid_as_text
+
+
+
+/*HDR*/
+/**
+ * @brief Print an NTP refid as dotted quad to a string buffer
+ *
+ * The function ::ntp_refid_should_be_text can be called to determine
+ * if the refid is to be interpreted as printable text, in which case
+ * ::snprintf_ntp_refid_as_text should be used to print it, or as binary
+ * number, in which case this function should be called to print it.
+ *
+ * Historically, a binary refid was always the IPv4 address of the upstream
+ * time source, so it is usually displayed as dotted quad string.
+ * Actually the upstream IP address can also be an IPv6 address which
+ * doesn't fit into the 4 byte refid field, so in case of an IPv6 address
+ * the binary refid are the 4 LSBs of the MD5 hash of the IPv6 address.
+ *
+ * @param[out] s Address of a string buffer to be filled.
+ * @param[in] max_len Size of the string buffer.
+ * @param[in] p Pointer to a ::NTP_REFID.
+ *
+ * @return Number of characters copied to the destination buffer, without the terminating 0
+ *
+ * @see ::ntp_refid_should_be_text
+ * @see ::snprintf_ntp_refid_as_dotted_quad
+ */
+int snprintf_ntp_refid_as_dotted_quad( char *s, size_t max_len, const NTP_REFID *p )
+{
+ int n = 0;
+ int i;
+
+ for ( i = 0; ; )
+ {
+ n += snprintf_safe( &s[n], max_len - n, "%u", p->as_u8s[i] );
+
+ if ( ++i >= sizeof( *p ) )
+ break;
+
+ n += sn_cpy_str_safe( &s[n], max_len - n, "." );
+ }
+
+ return n;
+
+} // snprintf_ntp_refid_as_dotted_quad
+
+
diff --git a/mbglib/common/mbgntp.h b/mbglib/common/mbgntp.h
index 1b00f7f..d01b90d 100755
--- a/mbglib/common/mbgntp.h
+++ b/mbglib/common/mbgntp.h
@@ -1,7 +1,7 @@
/**************************************************************************
*
- * $Id: mbgntp.h 1.10 2017/08/15 15:45:02 martin REL_M $
+ * $Id: mbgntp.h 1.13 2018/03/09 09:57:33 martin REL_M $
*
* Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany
*
@@ -10,6 +10,14 @@
*
* -----------------------------------------------------------------------
* $Log: mbgntp.h $
+ * Revision 1.13 2018/03/09 09:57:33 martin
+ * New inline function ntp_refid_should_be_text().
+ * Updated function prototypes.
+ * Revision 1.12 2017/12/14 16:25:19 martin
+ * Fixed some clang compiler warnings.
+ * Revision 1.11 2017/09/07 08:11:37 martin
+ * Renamed NTP_FLAGS to NTP_FLAG_FIELD to avoid
+ * a naming collision.
* Revision 1.10 2017/08/15 15:45:02 martin
* Define NSECS_PER_SEC only if it hasn't been defined before.
* Revision 1.9 2016/12/01 17:05:24 martin
@@ -201,7 +209,7 @@ typedef struct
unsigned int poll : 8;
unsigned int precision : 8;
-} NTP_FLAGS;
+} NTP_FLAG_FIELD;
@@ -247,7 +255,7 @@ typedef union
*/
typedef struct
{
- NTP_FLAGS flags;
+ NTP_FLAG_FIELD flags;
NTP_U_FP root_delay;
NTP_U_FP root_dispersion;
NTP_REFID refid;
@@ -329,7 +337,7 @@ typedef struct
static __mbg_inline /*HDR*/
size_t get_mac_len( const NTP_PACKET_INFO *p )
{
- size_t mac_len = p->len - NTP_BASE_PACKET_SIZE;
+ ssize_t mac_len = p->len - NTP_BASE_PACKET_SIZE;
// don't return negative values
return ( mac_len < 0 ) ? 0 : mac_len;
@@ -348,7 +356,7 @@ size_t get_mac_len( const NTP_PACKET_INFO *p )
static __mbg_inline /*HDR*/
size_t get_digest_len( const NTP_PACKET_INFO *p )
{
- size_t digest_len = get_mac_len( p ) - sizeof( NTP_KEY_ID );
+ ssize_t digest_len = get_mac_len( p ) - sizeof( NTP_KEY_ID );
// don't return negative values
return ( digest_len < 0 ) ? 0 : digest_len;
@@ -486,6 +494,30 @@ bool leap_smearing_active( const NTP_REFID *p, double *p_offs )
+static __mbg_inline /*HDR*/
+/**
+ * @brief Check if the refid in an NTP packet should be ASCII text or binary
+ *
+ * Depending on the stratum number, the refid can be interpreted
+ * as ASCII string up to 4 characters, or as a binary number representing
+ * an IPv4 address or the 4 LSBs of the MD5 hash of an IPv6 address.
+ *
+ * @param[out] p Pointer to an ::NTP_BASE_PACKET
+ *
+ * @return true if the refid should be ASCII, else false.
+ *
+ * @see ::snprintf_ntp_refid_as_text
+ * @see ::snprintf_ntp_refid_as_dotted_quad
+ */
+bool ntp_refid_should_be_text( int stratum, const NTP_REFID *p )
+{
+ return ( stratum <= 1 || stratum >= 16 )
+ && !leap_smearing_active( p, NULL );
+
+} // ntp_refid_should_be_text
+
+
+
/* function prototypes: */
#ifdef __cplusplus
@@ -497,7 +529,61 @@ extern "C" {
/* This section was generated automatically */
/* by MAKEHDR, do not remove the comments. */
-/* (no header definitions found) */
+ /**
+ * @brief Print the value of the 'precision' field from an NTP packet to a string buffer
+ *
+ * @param[out] s Address of a string buffer to be filled.
+ * @param[in] max_len Size of the string buffer.
+ * @param[in] prec_exp The precision value from the NTP packet.
+ */
+ int snprint_ntp_prec( char *s, size_t max_len, int8_t prec_exp ) ;
+
+ /**
+ * @brief Print an NTP refid as text to a string buffer
+ *
+ * The function ::ntp_refid_should_be_text can be called to determine
+ * if the refid is to be interpreted as printable text, so this function
+ * can be used to print it into a string buffer.
+ *
+ * Please note the 4 char refid may not be 0-terminated, so you can't
+ * simply cast the original refid to a string, and then print it.
+ *
+ * @param[out] s Address of a string buffer to be filled.
+ * @param[in] max_len Size of the string buffer.
+ * @param[in] p Pointer to a ::NTP_REFID.
+ *
+ * @return Number of characters copied to the destination buffer, without the terminating 0
+ *
+ * @see ::ntp_refid_should_be_text
+ * @see ::snprintf_ntp_refid_as_dotted_quad
+ */
+ int snprintf_ntp_refid_as_text( char *s, size_t max_len, const NTP_REFID *p ) ;
+
+ /**
+ * @brief Print an NTP refid as dotted quad to a string buffer
+ *
+ * The function ::ntp_refid_should_be_text can be called to determine
+ * if the refid is to be interpreted as printable text, in which case
+ * ::snprintf_ntp_refid_as_text should be used to print it, or as binary
+ * number, in which case this function should be called to print it.
+ *
+ * Historically, a binary refid was always the IPv4 address of the upstream
+ * time source, so it is usually displayed as dotted quad string.
+ * Actually the upstream IP address can also be an IPv6 address which
+ * doesn't fit into the 4 byte refid field, so in case of an IPv6 address
+ * the binary refid are the 4 LSBs of the MD5 hash of the IPv6 address.
+ *
+ * @param[out] s Address of a string buffer to be filled.
+ * @param[in] max_len Size of the string buffer.
+ * @param[in] p Pointer to a ::NTP_REFID.
+ *
+ * @return Number of characters copied to the destination buffer, without the terminating 0
+ *
+ * @see ::ntp_refid_should_be_text
+ * @see ::snprintf_ntp_refid_as_dotted_quad
+ */
+ int snprintf_ntp_refid_as_dotted_quad( char *s, size_t max_len, const NTP_REFID *p ) ;
+
/* ----- function prototypes end ----- */
diff --git a/mbglib/common/mbgtime.h b/mbglib/common/mbgtime.h
index 02f5fd9..6ca8fd5 100755
--- a/mbglib/common/mbgtime.h
+++ b/mbglib/common/mbgtime.h
@@ -1,7 +1,7 @@
/**************************************************************************
*
- * $Id: mbgtime.h 1.25 2017/08/15 15:48:59 martin REL_M $
+ * $Id: mbgtime.h 1.29 2018/02/28 16:58:10 martin REL_M $
*
* Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany
*
@@ -10,6 +10,15 @@
*
* -----------------------------------------------------------------------
* $Log: mbgtime.h $
+ * Revision 1.29 2018/02/28 16:58:10 martin
+ * Removed reference to frac_sec_from_bin().
+ * Revision 1.28 2018/01/15 18:18:49 martin
+ * Renamed symbol NSECS_PER_SEC to NSEC_PER_SEC
+ * according to namings of similar symbols.
+ * Revision 1.27 2017/11/29 11:14:57 gregoire
+ * Added Multiplier MSEC_TO_NSEC_MULTIPLIER, MSEC_TO_USEC_MULTIPLIER
+ * Revision 1.26 2017/11/16 13:33:46 philipp
+ * Added USEC_PER_SEC define
* Revision 1.25 2017/08/15 15:48:59 martin
* Define NSECS_PER_SEC only if it hasn't been defined before.
* Revision 1.24 2017/07/04 14:02:25 martin
@@ -239,8 +248,12 @@ typedef struct
#define MSEC_PER_HOUR ( MSEC_PER_SEC * SECS_PER_HOUR )
#define MSEC_PER_DAY ( MSEC_PER_SEC * SECS_PER_DAY )
-#if !defined( NSECS_PER_SEC )
- #define NSECS_PER_SEC 1000000000L
+#if !defined( USEC_PER_SEC )
+ #define USEC_PER_SEC 1000000L
+#endif
+
+#if !defined( NSEC_PER_SEC )
+ #define NSEC_PER_SEC 1000000000L
#endif
#if !defined( HNS_PER_SEC )
@@ -252,6 +265,10 @@ typedef struct
#endif
+#define MSEC_TO_NSEC_MULTIPLIER ( NSEC_PER_SEC / MSEC_PER_SEC )
+#define MSEC_TO_USEC_MULTIPLIER ( USEC_PER_SEC / MSEC_PER_SEC )
+
+
/**
* @brief A table with the days of month
*
@@ -384,7 +401,6 @@ _ext DAYS_OF_MONTH_TABLE days_of_month
* @see ::dec_frac_to_bin_frac_16
* @see ::dec_frac_to_bin_frac_32
* @see ::bin_frac_32_to_dec_frac
- * @see ::frac_sec_from_bin
*/
static __mbg_inline
uint32_t bin_frac_16_to_dec_frac( uint16_t bin, uint32_t scale )
diff --git a/mbglib/common/timeutil.c b/mbglib/common/timeutil.c
index a239f04..ec42d02 100755
--- a/mbglib/common/timeutil.c
+++ b/mbglib/common/timeutil.c
@@ -1,7 +1,7 @@
/**************************************************************************
*
- * $Id: timeutil.c 1.3 2017/08/24 13:51:48 martin REL_M $
+ * $Id: timeutil.c 1.7 2018/01/30 09:51:35 martin REL_M $
*
* Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany
*
@@ -10,6 +10,17 @@
*
* -----------------------------------------------------------------------
* $Log: timeutil.c $
+ * Revision 1.7 2018/01/30 09:51:35 martin
+ * Let snprint_gmtime_error() return an int instead of size_t.
+ * Updated mbg_clock_gettime():
+ * Revision 1.6 2018/01/15 18:31:08Z martin
+ * Account for renamed library symbol NSEC_PER_SEC.
+ * Moved function snprint_utc_offs() here.
+ * Changed return type of some printing functions to int.
+ * Revision 1.5 2017/11/16 13:34:09 philipp
+ * Extended ISO printing helper functions
+ * Revision 1.4 2017/11/16 11:33:28 philipp
+ * Added functions to print a time_t to ISO format
* Revision 1.3 2017/08/24 13:51:48 martin
* Fixed a xcompiler warning under Windows (x64).
* Revision 1.2 2017/07/05 07:10:48Z martin
@@ -28,30 +39,29 @@
#include <str_util.h>
#if defined( MBG_TGT_WIN32 )
- #include <mbgerror.h> // NSECS_PER_SEC
#include <stdio.h>
#endif
/*HDR*/
-size_t snprint_gmtime_error( char *s, size_t max_len, int mbg_errno, time_t t, const char *calling_fnc )
+int snprint_gmtime_error( char *s, size_t max_len, int mbg_errno, time_t t, const char *calling_fnc )
{
size_t n = snprintf_safe( s, max_len, "gmtime() call failed" );
if ( calling_fnc )
n += snprintf_safe( &s[n], max_len - n, " in %s", calling_fnc );
- #if defined( _MSC_VER ) && ( _MSC_VER < 1500 )
+ #if defined( MBG_TGT_MISSING_64_BIT_TYPES )
//### TODO E.g. in VC6 time_t is only 32 bit anyway.
n += snprintf_safe( &s[n], max_len - n, " for time_t %lu: %s",
(unsigned long) t, mbg_strerror( mbg_errno ) );
#else
- n += snprintf_safe( &s[n], max_len - n, " for time_t %llu: %s",
- (unsigned long long) t, mbg_strerror( mbg_errno ) );
+ n += snprintf_safe( &s[n], max_len - n, " for time_t %" PRIu64 ": %s",
+ (uint64_t) t, mbg_strerror( mbg_errno ) );
#endif
- return n;
+ return _int_from_size_t( n );
} // snprint_gmtime_error
@@ -67,11 +77,30 @@ typedef int clockid_t;
/*HDR*/
int mbg_clock_gettime( clockid_t clock_id, struct timespec *tp )
{
+ // FIXME TODO Should we return a POSIX-compatible return code
+ // with 0 for success and -1 indicating an error?
+ //
+ // If we'd do we had to set "errno" or the value returned
+ // by Windows' GetLastError() to some specific error code
+ // that can be retrieved by the application. However, there's
+ // a problem when timespec_get() is used to implement this.
+
+ // On success, timespec_get() returns the value of the "base"
+ // parameter that has been passed to timespec_get(), e.g.
+ // TIME_UTC. On error, it returns 0, but the usual docs for
+ // timespec_get() don't mention if there's a way to determine
+ // the reason for the failure, e.g. by retrieving a value
+ // from"errno" or so.
+ //
+ // So for now we return 0 on success as usual, and -1
+ // on error, but the caller is unable to determine the
+ // reason for the fauilure.
+
if ( clock_id == CLOCK_REALTIME )
{
#if defined( TIME_UTC ) // C11 / VS2015+
- int rc = timespec_get( tp, TIME_UTC ); // TODO Check this code
- return ( rc == 0 ) ? -1 : 0 // rc == 0 means error
+ int rc = timespec_get( tp, TIME_UTC );
+ return ( rc == 0 ) ? -1 : 0;
#else
#define EPOCH_HNS 116444736000000000i64
FILETIME ft;
@@ -80,13 +109,13 @@ int mbg_clock_gettime( clockid_t clock_id, struct timespec *tp )
tmp = ( (__int64) ft.dwHighDateTime << 32 ) | ft.dwLowDateTime;
tmp -= EPOCH_HNS; // convert to Unix epoch
tmp *= 100; // convert to nanoseconds
- tp->tv_sec = ( tmp / NSECS_PER_SEC );
- tp->tv_nsec = (long) ( tmp % NSECS_PER_SEC );
+ tp->tv_sec = ( tmp / NSEC_PER_SEC );
+ tp->tv_nsec = (long) ( tmp % NSEC_PER_SEC );
return 0;
#endif
}
else
- return -1; // TODO this is e.g. in case of CLOCK_MONOTONIC, we could use QPC then.
+ return -1; // TODO this is e.g. in case of CLOCK_MONOTONIC, we could use QPC then.
} // mbg_clock_gettime
@@ -109,8 +138,8 @@ int mbg_clock_settime( clockid_t clock_id, const struct timespec *tp )
tmp = ( (__int64) ft.dwHighDateTime << 32 ) | ft.dwLowDateTime;
tmp -= EPOCH_HNS; // convert to Unix epoch
tmp *= 100; // convert to nanoseconds
- res->tv_sec = ( tmp / NSECS_PER_SEC );
- res->tv_nsec = ( tmp % NSECS_PER_SEC );
+ res->tv_sec = ( tmp / NSEC_PER_SEC );
+ res->tv_nsec = ( tmp % NSEC_PER_SEC );
return 0;
#endif
#endif
@@ -164,3 +193,162 @@ out:
#endif
+
+
+/*HDR*/
+/**
+ * @brief Print a UTC offset into a string
+ *
+ * Format of the string is "[info]+hh[:mm[:ss]]h"
+ *
+ * @param[out] s Address of a string buffer to be filled.
+ * @param[in] max_len Size of the string buffer.
+ * @param[in] info An optional info string to be prepended, may be NULL.
+ * @param[in] utc_offs The UTC offset to be printed, in [s].
+ *
+ * @return The number of characters written to the output buffer, except the terminating 0.
+ */
+int snprint_utc_offs( char *s, size_t max_len, const char *info, long utc_offs )
+{
+ size_t n = 0;
+
+ // utc_offs is in [s]
+ char utc_offs_sign = ( utc_offs < 0 ) ? '-' : '+';
+ ulong abs_utc_offs = labs( utc_offs );
+ ulong utc_offs_hours = abs_utc_offs / SECS_PER_HOUR;
+ ulong tmp = abs_utc_offs % SECS_PER_HOUR;
+ ulong utc_offs_mins = tmp / MINS_PER_HOUR;
+ ulong utc_offs_secs = tmp % MINS_PER_HOUR;
+
+ if ( info )
+ n += snprintf_safe( &s[n], max_len - n, "%s", info );
+
+ n += snprintf_safe( &s[n], max_len - n, "%c%lu", utc_offs_sign, utc_offs_hours );
+
+ if ( utc_offs_mins || utc_offs_secs )
+ n += snprintf_safe( &s[n], max_len - n, ":%02lu", utc_offs_mins );
+
+ if ( utc_offs_secs )
+ n += snprintf_safe( &s[n], max_len - n, ":%02lu", utc_offs_secs );
+
+ n += sn_cpy_str_safe( &s[n], max_len - n, "h" );
+
+ return _int_from_size_t( n );
+
+} // snprint_utc_offs
+
+
+
+/*HDR*/
+int snprint_time_t_to_iso( time_t tstamp, int offs_hours, char *buf, size_t len )
+{
+ struct tm tm = { 0 };
+ size_t n;
+ int rc;
+
+ if ( offs_hours )
+ tstamp += offs_hours * SECS_PER_HOUR;
+
+ rc = mbg_gmtime( &tm, &tstamp );
+
+ if ( mbg_rc_is_error( rc ) )
+ {
+ // TODO Error: conversion failed.
+ }
+
+ n = snprintf_safe( buf, len, "%04d-%02d-%02d, %02d:%02d:%02d",
+ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
+ tm.tm_hour, tm.tm_min, tm.tm_sec );
+
+ return _int_from_size_t( n );
+
+} // snprint_time_t_to_iso
+
+
+
+static __mbg_inline /*HDR*/
+int __to_iso_frac( time_t tstamp, int offset, time_t frac,
+ const char* fmt, char *buf, size_t max_len )
+{
+ size_t n = snprint_time_t_to_iso( tstamp, offset, buf, max_len );
+ n += snprintf_safe( &buf[n], max_len - n, fmt, frac );
+
+ return _int_from_size_t( n );
+
+} // __to_iso_frac
+
+
+
+/*HDR*/
+int snprint_time_t_to_iso_ms( time_t tstamp, int offs_hours, time_t frac,
+ char *buf, size_t len )
+{
+ tstamp += frac / MSEC_PER_SEC;
+ frac %= MSEC_PER_SEC;
+
+ return __to_iso_frac( tstamp, offs_hours, frac, ".%03lu", buf, len );
+
+} // snprint_time_t_to_iso_ms
+
+
+
+/*HDR*/
+int snprint_time_t_to_iso_us( time_t tstamp, int offs_hours, time_t frac,
+ char *buf, size_t len )
+{
+ tstamp += frac / USEC_PER_SEC;
+ frac %= USEC_PER_SEC;
+
+ return __to_iso_frac( tstamp, offs_hours, frac, ".%06lu", buf, len );
+
+} // snprint_time_t_to_iso_us
+
+
+
+/*HDR*/
+int snprint_time_t_to_iso_ns( time_t tstamp, int offs_hours, time_t frac,
+ char *buf, size_t len )
+{
+ tstamp += frac / NSEC_PER_SEC;
+ frac %= NSEC_PER_SEC;
+
+ return __to_iso_frac( tstamp, offs_hours, frac, ".%09lu", buf, len );
+
+} // snprint_time_t_to_iso_ns
+
+
+
+/*HDR*/
+int snprint_ntp_tstamp_to_iso_ms( const NTP_TSTAMP *ts, char *buf, size_t len )
+{
+ time_t secs = cvt_to_time_t( ts->seconds ) - NTP_SEC_BIAS;
+ time_t fracs = bin_frac_32_to_msec( ts->fractions );
+
+ return snprint_time_t_to_iso_ms( secs, 0, fracs, buf, len );
+
+} // snprint_ntp_tstamp_to_iso_ms
+
+
+
+/*HDR*/
+int snprint_ntp_tstamp_to_iso_us( const NTP_TSTAMP *ts, char *buf, size_t len )
+{
+ time_t secs = cvt_to_time_t( ts->seconds ) - NTP_SEC_BIAS;
+ time_t fracs = bin_frac_32_to_usec( ts->fractions );
+
+ return snprint_time_t_to_iso_us( secs, 0, fracs, buf, len );
+
+} // snprint_ntp_tstamp_to_iso_us
+
+
+
+/*HDR*/
+int snprint_ntp_tstamp_to_iso_ns( const NTP_TSTAMP *ts, char *buf, size_t len )
+{
+ time_t secs = cvt_to_time_t( ts->seconds ) - NTP_SEC_BIAS;
+ time_t fracs = bin_frac_32_to_nsec( ts->fractions );
+
+ return snprint_time_t_to_iso_ns( secs, 0, fracs, buf, len );
+
+} // snprint_ntp_tstamp_to_iso_ns
+
diff --git a/mbglib/common/timeutil.h b/mbglib/common/timeutil.h
index 233c174..517a725 100755
--- a/mbglib/common/timeutil.h
+++ b/mbglib/common/timeutil.h
@@ -1,7 +1,7 @@
/**************************************************************************
*
- * $Id: timeutil.h 1.3 2017/07/05 07:15:00 martin REL_M $
+ * $Id: timeutil.h 1.7 2018/01/30 09:54:12 martin REL_M $
*
* Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany
*
@@ -10,6 +10,14 @@
*
* -----------------------------------------------------------------------
* $Log: timeutil.h $
+ * Revision 1.7 2018/01/30 09:54:12 martin
+ * Updated function prototypes.
+ * Revision 1.6 2018/01/15 18:31:21Z martin
+ * Updated function prototypes.
+ * Revision 1.5 2017/11/16 13:34:09 philipp
+ * Extended ISO printing helper functions
+ * Revision 1.4 2017/11/16 11:33:28 philipp
+ * Added functions to print a time_t to ISO format
* Revision 1.3 2017/07/05 07:15:00 martin
* Provide basic support for clock_gettime()/clock_settime()
* compatible functions for Windows.
@@ -24,7 +32,7 @@
/* Other headers to be included */
-#include <words.h> // implicitly includes mbg_tgt.h for non-firmware projects
+#include <gpsdefs.h>
#include <mbgerror.h>
#include <time.h>
@@ -109,10 +117,31 @@ int mbg_gmtime( struct tm *p_tm, const time_t *p_time )
/* This section was generated automatically */
/* by MAKEHDR, do not remove the comments. */
- size_t snprint_gmtime_error( char *s, size_t max_len, int mbg_errno, time_t t, const char *calling_fnc ) ;
+ int snprint_gmtime_error( char *s, size_t max_len, int mbg_errno, time_t t, const char *calling_fnc ) ;
int mbg_clock_gettime( clockid_t clock_id, struct timespec *tp ) ;
int mbg_clock_settime( clockid_t clock_id, const struct timespec *tp ) ;
void check_precise_time_api( void ) ;
+ /**
+ * @brief Print a UTC offset into a string
+ *
+ * Format of the string is "[info]+hh[:mm[:ss]]h"
+ *
+ * @param[out] s Address of a string buffer to be filled.
+ * @param[in] max_len Size of the string buffer.
+ * @param[in] info An optional info string to be prepended, may be NULL.
+ * @param[in] utc_offs The UTC offset to be printed, in [s].
+ *
+ * @return The number of characters written to the output buffer, except the terminating 0.
+ */
+ int snprint_utc_offs( char *s, size_t max_len, const char *info, long utc_offs ) ;
+
+ int snprint_time_t_to_iso( time_t tstamp, int offs_hours, char *buf, size_t len ) ;
+ int snprint_time_t_to_iso_ms( time_t tstamp, int offs_hours, time_t frac, char *buf, size_t len ) ;
+ int snprint_time_t_to_iso_us( time_t tstamp, int offs_hours, time_t frac, char *buf, size_t len ) ;
+ int snprint_time_t_to_iso_ns( time_t tstamp, int offs_hours, time_t frac, char *buf, size_t len ) ;
+ int snprint_ntp_tstamp_to_iso_ms( const NTP_TSTAMP *ts, char *buf, size_t len ) ;
+ int snprint_ntp_tstamp_to_iso_us( const NTP_TSTAMP *ts, char *buf, size_t len ) ;
+ int snprint_ntp_tstamp_to_iso_ns( const NTP_TSTAMP *ts, char *buf, size_t len ) ;
/* ----- function prototypes end ----- */
diff --git a/mbglib/common/words.h b/mbglib/common/words.h
index 9cbc841..3d4f2d5 100755
--- a/mbglib/common/words.h
+++ b/mbglib/common/words.h
@@ -1,7 +1,7 @@
/**************************************************************************
*
- * $Id: words.h 1.42 2017/07/26 14:28:50 martin REL_M $
+ * $Id: words.h 1.43 2018/01/29 10:30:23 martin REL_M $
*
* Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany
*
@@ -10,7 +10,9 @@
*
* -----------------------------------------------------------------------
* $Log: words.h $
- * Revision 1.42 2017/07/26 14:28:50 martin
+ * Revision 1.43 2018/01/29 10:30:23 martin
+ * Modified some comments.
+ * Revision 1.42 2017/07/26 14:28:50Z martin
* Fixed build for NetBSD.
* Revision 1.41 2017/07/05 12:06:35 martin
* Moved macro _int_from_size_t() here.
@@ -223,7 +225,7 @@
#if defined( MBG_TGT_MISSING_64_BIT_TYPES )
// The build environment does not support 64 bit types. However,
- // 64 bit types need to be defined to avoid build errors
+ // 64 bit types need to be defined to avoid build errors e.g.
// if these types are formally used in function prototypes.
// We explicitly use abnormal data types to hopefully
// cause compiler errors in case these types are
@@ -235,8 +237,8 @@
#else
// Define C99 types using non-standard exact-size types
- // which are usually supported by build envonronments
- // supporting 64 bit types but no C99 types.
+ // which are usually supported by build environments that
+ // support 64 bit types but don't support C99 types.
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
diff --git a/ntptest.c b/ntptest.c
index f9be4f0..dbc0581 100755
--- a/ntptest.c
+++ b/ntptest.c
@@ -1,7 +1,7 @@
/**************************************************************************
*
- * $Id: ntptest.c 1.11 2017/09/06 14:26:59 martin REL_M $
+ * $Id: ntptest.c 1.12 2018/03/09 09:59:29 martin REL_M $
*
* Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany
*
@@ -12,6 +12,8 @@
*
* -----------------------------------------------------------------------
* $Log: ntptest.c $
+ * Revision 1.12 2018/03/09 09:59:29 martin
+ * Updated version number to 1.8 and copyright year to 2018.
* Revision 1.11 2017/09/06 14:26:59 martin
* Support build under Windows.
* Revision 1.10 2017/09/06 14:14:40Z martin
@@ -70,8 +72,8 @@
static const char program_name[] = "ntptest";
-static const char program_version[] = "v1.7";
-static const char program_copyright[] = "(c) Meinberg 2014-2017";
+static const char program_version[] = "v1.8";
+static const char program_copyright[] = "(c) Meinberg 2014-2018";
static const char program_contact[] = "contact: <martin.burnicki@meinberg.de>";
diff --git a/unix/Makefile b/unix/Makefile
index cc0cdb2..9ad5b1d 100755
--- a/unix/Makefile
+++ b/unix/Makefile
@@ -1,13 +1,15 @@
#########################################################################
#
-# $Id: Makefile 1.2 2016/08/05 12:40:28 martin REL_M $
+# $Id: Makefile 1.4 2018/03/09 09:58:03 martin REL_M $
#
# Description:
# Makefile for ntptest.
#
# -----------------------------------------------------------------------
# $Log: Makefile $
+# Revision 1.4 2018/03/09 09:58:03 martin
+# Added new module mbgntp.o.
# Revision 1.2 2016/08/05 12:40:28 martin
# Account for modified directory structure.
# Makefile has been moved to subdirectory unix/.
@@ -23,6 +25,7 @@ MBGLIB = ../mbglib
MBGLIB_DIRS = common
OBJS = $(TARGET).o
+OBJS += mbgntp.o
OBJS += mbg_ntp_test_util.o
OBJS += timeutil.o
OBJS += str_util.o