diff options
author | Martin Burnicki <martin.burnicki@meinberg.de> | 2018-03-09 12:00:00 +0100 |
---|---|---|
committer | Martin Burnicki <martin.burnicki@meinberg.de> | 2018-03-09 12:00:00 +0100 |
commit | 8af775dc00e14dc74e7cd74dc202cec636efbddd (patch) | |
tree | 4b849e9646d65ab21b25de736a4c1179e989f473 | |
parent | c839fb5b430388eff87487e9a1ce58b38921c807 (diff) | |
download | ntptest-8af775dc00e14dc74e7cd74dc202cec636efbddd.tar.gz ntptest-8af775dc00e14dc74e7cd74dc202cec636efbddd.zip |
Improve printing of refid using functions from new module mbgntp.c1.8
-rwxr-xr-x | mbglib/common/mbg_ntp_test_util.c | 121 | ||||
-rwxr-xr-x | mbglib/common/mbg_ntp_test_util.h | 7 | ||||
-rwxr-xr-x | mbglib/common/mbgntp.c | 170 | ||||
-rwxr-xr-x | mbglib/common/mbgntp.h | 98 | ||||
-rwxr-xr-x | mbglib/common/mbgtime.h | 24 | ||||
-rwxr-xr-x | mbglib/common/timeutil.c | 216 | ||||
-rwxr-xr-x | mbglib/common/timeutil.h | 35 | ||||
-rwxr-xr-x | mbglib/common/words.h | 12 | ||||
-rwxr-xr-x | ntptest.c | 8 | ||||
-rwxr-xr-x | unix/Makefile | 5 |
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; @@ -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 |