summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Burnicki <martin.burnicki@meinberg.de>2022-07-08 17:10:00 +0200
committerMartin Burnicki <martin.burnicki@meinberg.de>2022-07-08 17:21:00 +0200
commit849dfcf9a25394b844a6560db7ab3b6734ea842e (patch)
treee498143fcf7bc5d70e35041e93663baee094fc3b
parent20f8c6015b91cf1df2814a77972d551c538e0c91 (diff)
downloadmbgtools-win-849dfcf9a25394b844a6560db7ab3b6734ea842e.tar.gz
mbgtools-win-849dfcf9a25394b844a6560db7ab3b6734ea842e.zip
Update mbgstatus: Support reading XMR status information from devices that support this
New option -F to force reading XMR stuff if the feature is not enabled, which should only be used with very much care. Support SYN1588 insync range boundary codes in mbgstatus. Add some mbglib files to support these features, and update the project files accordingly.
-rw-r--r--mbglib/common/mbg_syn1588_defs.h157
-rw-r--r--mbglib/common/mbg_syn1588_util.c155
-rw-r--r--mbglib/common/mbg_syn1588_util.h561
-rw-r--r--mbglib/common/mbg_xmr_util.c159
-rw-r--r--mbglib/common/mbg_xmr_util.h73
-rw-r--r--mbglib/common/mbg_xmr_util_devio.c259
-rw-r--r--mbglib/common/mbg_xmr_util_devio.h127
-rw-r--r--mbgstatus/mbgstatus.c176
-rw-r--r--mingw/libmbg/makefile7
-rw-r--r--vc6/mbgstatus/mbgstatus.dsp28
-rw-r--r--vs2008/mbgstatus/mbgstatus.vcproj12
11 files changed, 1689 insertions, 25 deletions
diff --git a/mbglib/common/mbg_syn1588_defs.h b/mbglib/common/mbg_syn1588_defs.h
new file mode 100644
index 0000000..32bc3c9
--- /dev/null
+++ b/mbglib/common/mbg_syn1588_defs.h
@@ -0,0 +1,157 @@
+
+/**************************************************************************
+ *
+ * $Id: mbg_syn1588_defs.h 1.2 2022/07/06 15:09:08Z martin.burnicki REL_M $
+ *
+ * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany
+ *
+ * Definitions for the SYN1588 API.
+ *
+ * The original definitions are distributed and hidden in the C++
+ * source code which is not very portable, so some definitions have
+ * been duplicated here.
+ *
+ * Of course this is dangerous because care must be taken that the
+ * original and duplicated definitions yield the same results, but
+ * it makes maintenance of an external projects very much easier.
+ *
+ * -----------------------------------------------------------------------
+ * $Log: mbg_syn1588_defs.h $
+ * Revision 1.2 2022/07/06 15:09:08Z martin.burnicki
+ * Support SYN1588 insync range boundary code instead of the original enum.
+ * Revision 1.1 2022/05/31 13:41:42 martin.burnicki
+ * Initial revision.
+ *
+ **************************************************************************/
+
+#ifndef _MBG_SYN1588_DEFS_H
+#define _MBG_SYN1588_DEFS_H
+
+/* Other headers to be included */
+
+#include <words.h>
+
+
+/* Start of header body */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+/**
+ * @brief The minimum required SYN1588 NIC build number.
+ *
+ * The ::PTP_SYNC_STATUS register is only supported by SYN1588 PCIe NICs
+ * running firmware versions with build number 867 or later.
+ *
+ * Also, the PTP stack has to be current enough to populate the status
+ * register. Version 1.14 of the stack, which does this, requires
+ * firmware build 876 or later for the NIC, or it fails to read the
+ * hardware timestamps from the card.
+ *
+ * So this is the smallest firmware build number required
+ * for the SYN1588 PCIe NIC.
+ */
+#define SYN1588_MIN_REQ_BUILD_NUM 876
+
+
+
+/**
+ * @brief Type of a bit-coded PTP sync status.
+ *
+ * Can be read from the ::PTP_SYNC_STATUS register
+ * of a SYN1588 PCI NIC.
+ *
+ * @note Requires firmware ::SYN1588_MIN_REQ_BUILD_NUM or later.
+ *
+ * @see @ref SYN1588_PTP_SYNC_STATUS_DEFS
+ */
+typedef uint32_t SYN1588_PTP_SYNC_STATUS;
+
+
+
+/**
+ * @brief Bit masks and fields used with ::SYN1588_PTP_SYNC_STATUS.
+ *
+ * The original definitions of these numbers are only compatible
+ * with C++, but not with standard C, so some associated, portable
+ * definitions are provided here as workaround.
+ *
+ * @see ::SYN1588_PTP_SYNC_STATUS
+ * @see ::PTP_SYNC_STATUS
+ *
+ * @anchor SYN1588_PTP_SYNC_STATUS_DEFS @{ */
+
+#define DEF_PSS_BITMASK_UTC_OFFSET 0x000000FF ///< Bitfield mask for UTC Offset in [s], see ::PSS_BITMASK_UTC_OFFSET
+#define DEF_PSS_BIT_UTC_OFFSET_VALID 0x00000100 ///< Bit signalling of UTC Offset is valid or not, see ::PSS_BIT_UTC_OFFSET_VALID
+#define DEF_PSS_BIT_LEAP59 0x00000200 ///< Bit signalling an upcoming negative leap second, see ::PSS_BIT_LEAP59
+#define DEF_PSS_BIT_LEAP61 0x00000400 ///< Bit signalling an upcoming positive leap second, see ::PSS_BIT_LEAP61
+#define DEF_PSS_BITMASK_PTP_STATE 0x00007800 ///< Bitfield mask for the field representing the PTP State, see ::PSS_BITMASK_PTP_STATE
+#define DEF_PSS_SHIFT_PTP_STATE 11 ///< Shift offset for the field representing the PTP State, see ::PSS_SHIFT_PTP_STATE
+#define DEF_PSS_BIT_PTP_INSYNC 0x00008000 ///< Bit signalling that the PTP Stack is in-sync, see ::PSS_BIT_PTP_INSYNC
+#define DEF_PSS_BITMASK_PTP_INSYNC_BND_CODE 0x003F0000 ///< Bitfield mask for the code indicating the insync boundary, see ::PTP_STATE_RANGE_TABLE_INIT and::PSS_BITMASK_PTP_INSYNC_BND_CODE
+#define DEF_PSS_SHIFT_PTP_INSYNC_BND_CODE 16 ///< Shift offset for the field representing the in sync boundary, see ::PSS_SHIFT_PTP_INSYNC_BND_CODE
+#define DEF_PSS_BIT_PTP_TIMESCALE 0x00400000 ///< Bit signalling the current PTP Timescale ('1' = PTP, '0' = ARB), see ::PSS_BIT_PTP_TIMESCALE
+#define DEF_PSS_BIT_LSYNC_RUNNING 0x40000000 ///< Bit signalling that lSync is active, see ::LSS_BIT_LSYNC_RUNNING
+#define DEF_PSS_BIT_VALID 0x80000000 ///< Bit signalling that the register content is valid, see ::PSS_BIT_VALID
+
+/** @} anchor MBG_DEBUG_STATUS_BIT_MASKS */
+
+
+
+/**
+ * @brief Possible states of the PTP stack.
+ *
+ * Reported by the ::DEF_PSS_BITMASK_PTP_STATE bit field
+ * of the ::SYN1588_PTP_SYNC_STATUS type.
+ *
+ * @see ::SYN1588_PTP_STATE_STRS for an initializer for name strings.
+ */
+enum SYN1588_PTP_STATES
+{
+ SYN1588_PTP_STATE_UNDEFINED, ///< Undefined state.
+ SYN1588_PTP_STATE_INITIALIZING, ///< Initializing, see ::SInitializing.
+ SYN1588_PTP_STATE_FAULTY, ///< Faulty, see ::SFaulty.
+ SYN1588_PTP_STATE_DISABLED, ///< Disabled, see ::SDisabled.
+ SYN1588_PTP_STATE_LISTENING, ///< Listening, see ::SListening.
+ SYN1588_PTP_STATE_PRE_MASTER, ///< Pre-Master, see ::SPreMaster.
+ SYN1588_PTP_STATE_MASTER, ///< Master, see ::SMaster.
+ SYN1588_PTP_STATE_PASSIVE, ///< Passive, see ::SPassive.
+ SYN1588_PTP_STATE_UNCALIBRATED, ///< Uncalibrated, see ::SUncalibrated.
+ SYN1588_PTP_STATE_SLAVE, ///< Slave, see ::SSlave.
+ N_SYN1588_PTP_STATES ///< Number of defined states, see ::SMaxStateArray.
+};
+
+
+/**
+ * @brief Initializer for an array of PTP state name strings.
+ *
+ * The array that is initialized should have ::N_SYN1588_PTP_STATES entries.
+ *
+ * @see ::SYN1588_PTP_STATES.
+ */
+#define SYN1588_PTP_STATE_STRS \
+{ \
+ "Undefined", \
+ "Initializing", \
+ "Faulty", \
+ "Disabled", \
+ "Listening", \
+ "PreMaster", \
+ "Master", \
+ "Passive", \
+ "Uncalibrated", \
+ "Slave" \
+}
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+/* End of header body */
+
+#endif /* _MBG_SYN1588_DEFS_H */
diff --git a/mbglib/common/mbg_syn1588_util.c b/mbglib/common/mbg_syn1588_util.c
new file mode 100644
index 0000000..035247e
--- /dev/null
+++ b/mbglib/common/mbg_syn1588_util.c
@@ -0,0 +1,155 @@
+
+/**************************************************************************
+ *
+ * $Id: mbg_syn1588_util.c 1.2 2022/07/06 15:09:08Z martin.burnicki REL_M $
+ *
+ * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany
+ *
+ * Utility functions for the handling of SYN1588 PTP NICs.
+ *
+ * -----------------------------------------------------------------------
+ * $Log: mbg_syn1588_util.c $
+ * Revision 1.2 2022/07/06 15:09:08Z martin.burnicki
+ * Support SYN1588 insync range boundary code instead of the original enum.
+ * Revision 1.1 2022/05/31 13:41:42 martin.burnicki
+ * Initial revision.
+ *
+ **************************************************************************/
+
+#define _MBG_SYN1588_UTIL
+ #include <mbg_syn1588_util.h>
+#undef _MBG_SYN1588_UTIL
+
+#include <str_util.h>
+
+
+
+/**
+ * @brief Insync boundary code indicating out-of-bounds.
+ *
+ * This insync boundary code is the maximum possible value
+ * that can be stored in the ::PTP_SYNC_STATUS word.
+ * It should be used to indicate that the boundary is out of
+ * the well-defined limits, similar to ::EOver10s.
+ */
+#define PTP_STATE_RANGE_MAX_CODE 0x3F
+
+
+static const char *ptp_state_strs[N_SYN1588_PTP_STATES] = SYN1588_PTP_STATE_STRS;
+
+
+/*HDR*/
+/**
+ * @brief Retrieve a string representing the state of the PTP stack.
+ *
+ * @param[in] state The state of the PTP stack, see ::SYN1588_PTP_STATES.
+ *
+ * @return One of the strings defined in ::SYN1588_PTP_STATE_STRS.
+ */
+const char *mbg_syn1588_chk_get_ptp_state_str( uint state )
+{
+ if ( state < N_SYN1588_PTP_STATES )
+ return ptp_state_strs[state];
+
+ return "unknown";
+
+} // mbg_syn1588_chk_get_ptp_state_str
+
+
+
+/*HDR*/
+/**
+ * @brief Write the decoded value of an insync range boundary code to a string buffer.
+ *
+ * @param[out] s Pointer to the output buffer.
+ * @param[in] max_len Size of the output buffer.
+ * @param[in] code The insync range boundary code, see ::PTP_STATE_RANGE_TABLE_INIT.
+ * @param[in] check_max If @a true, ::PTP_STATE_RANGE_MAX_CODE causes special string.
+ *
+ * @return The number of characters written to the output buffer,
+ * except the terminating 0.
+ */
+int mbg_syn1588_snprint_insync_boundary_code( char *s, size_t max_len,
+ uint code, bool check_max )
+{
+ #define N_PREFIXES 4
+
+ static const char *unit_prefixes[N_PREFIXES] =
+ {
+ "p",
+ "n",
+ "u",
+ "m"
+ };
+
+ div_t dt;
+ int range_idx;
+ int range_mul;
+ #if DEBUG_INSYNC_BOUNDARY
+ int range_mul_raw;
+ #endif
+ long m;
+ long l;
+ int i;
+ int n = 0;
+
+ if ( check_max && ( code >= PTP_STATE_RANGE_MAX_CODE ) )
+ return snprintf_safe( s, max_len, "(out of bounds)" );
+
+ dt = div( code, 12 );
+
+ range_idx = dt.quot;
+ range_mul = dt.rem / 4;
+
+ if ( dt.quot > N_PREFIXES )
+ range_mul += ( dt.quot - 2 ); // TODO
+
+ #if DEBUG_INSYNC_BOUNDARY
+ range_mul_raw = range_mul;
+ #endif
+
+ if ( ( dt.rem % 4 ) == 0 )
+ range_mul--;
+
+ #if DEBUG_INSYNC_BOUNDARY
+ printf( "%2i", dt.quot );
+ printf( " %2i", dt.rem );
+ printf( " %2i", range_mul_raw );
+ printf( " %2i", range_mul );
+ #endif
+
+ m = syn1588_insync_boundary_mantissa( code );
+
+ // Take care of scale range boundaries.
+ l = ( m == 0 ) ? 100 : ( m * 25 );
+
+ for ( i = 0; i < range_mul; i++ )
+ l *= 10;
+
+ for ( i = range_mul; i < 0; i++ )
+ l /= 10;
+
+ #if OMIT_INSYNC_BOUNDARY_FRAC
+ n = snprintf_safe( s, max_len, "%li %ss", l, ( range_idx < N_PREFIXES ) ?
+ unit_prefixes[range_idx] : "" );
+ #else
+ {
+ ldiv_t ldt = ldiv( l, 10 );
+
+ n = snprintf_safe( s, max_len, "%li", ldt.quot );
+
+ #if !PRINT_INSYNC_BOUNDARY_FRAC
+ if ( ldt.rem )
+ #endif
+ n += snprintf_safe( &s[n], max_len - n, ".%li", ldt.rem );
+
+ n += snprintf_safe( &s[n], max_len - n, " %ss", ( range_idx < N_PREFIXES ) ?
+ unit_prefixes[range_idx] : "" );
+ }
+ #endif
+
+ return n;
+
+} // mbg_syn1588_snprint_insync_boundary_code
+
+
diff --git a/mbglib/common/mbg_syn1588_util.h b/mbglib/common/mbg_syn1588_util.h
new file mode 100644
index 0000000..30fc437
--- /dev/null
+++ b/mbglib/common/mbg_syn1588_util.h
@@ -0,0 +1,561 @@
+
+/**************************************************************************
+ *
+ * $Id: mbg_syn1588_util.h 1.2 2022/07/06 15:09:08Z martin.burnicki REL_M $
+ *
+ * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany
+ *
+ * Definitions and prototypes for mbg_syn1588_util.c.
+ *
+ * -----------------------------------------------------------------------
+ * $Log: mbg_syn1588_util.h $
+ * Revision 1.2 2022/07/06 15:09:08Z martin.burnicki
+ * Support SYN1588 insync range boundary code instead of the original enum.
+ * Revision 1.1 2022/05/31 13:41:41 martin.burnicki
+ * Initial revision.
+ *
+ **************************************************************************/
+
+#ifndef _MBG_SYN1588_UTIL_H
+#define _MBG_SYN1588_UTIL_H
+
+/* Other headers to be included */
+
+#include <mbg_syn1588_defs.h>
+
+#include <mbg_tgt.h>
+#include <pcpsdefs.h>
+#include <mbgtime.h>
+#include <mbgerror.h>
+#include <cnv_wday.h>
+#include <timeutil.h>
+
+#include <stdio.h>
+
+
+#if !defined( PRINT_INSYNC_BOUNDARY_FRAC )
+ // If not 0, fractions of insync boundary values are
+ // always printed, even if they are 0.
+ // Useful for debugging, but output is prettier
+ // without this.
+ #define PRINT_INSYNC_BOUNDARY_FRAC 0
+#endif
+
+#if !defined( DEBUG_INSYNC_BOUNDARY )
+ // If not 0, print intermediate values to stdout.
+ // Just for debugging, should be 0 otherwise.
+ #define DEBUG_INSYNC_BOUNDARY 0
+#endif
+
+#if !defined( OMIT_INSYNC_BOUNDARY_FRAC )
+ // If not 0, print values * 10, without fractions.
+ // Just for debugging, should be 0 otherwise.
+ #define OMIT_INSYNC_BOUNDARY_FRAC 0
+#endif
+
+
+#ifdef _MBG_SYN1588_UTIL
+ #define _ext
+ #define _DO_INIT
+#else
+ #define _ext extern
+#endif
+
+
+/* Start of header body */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+static __mbg_inline /*HDR*/
+/**
+ * @brief Check if a PTP sync status word is valid.
+ *
+ * This is usually the case if the PTP stack is runnung.
+ *
+ * @param[in] ptp_sync_status The sync status word read from a device.
+ *
+ * @return @a true, if the status word is valid, else @a false.
+ */
+bool syn1588_ptp_sync_status_valid( SYN1588_PTP_SYNC_STATUS ptp_sync_status )
+{
+ return ( ptp_sync_status & DEF_PSS_BIT_VALID ) != 0;
+
+} // syn1588_ptp_sync_status_valid
+
+
+
+static __mbg_inline /*HDR*/
+/**
+ * @brief Decode the PTP stack state from the sync status word.
+ *
+ * The function ::syn1588_ptp_sync_status_valid can be used to
+ * determine if the decoded state is valid.
+ *
+ * @param[in] ptp_sync_status The sync status word read from a device.
+ *
+ * @return The decoded state of the PTP stack, see ::SYN1588_PTP_STATES.
+ */
+uint syn1588_ptp_state_from_sync_status( SYN1588_PTP_SYNC_STATUS ptp_sync_status )
+{
+ return ( ptp_sync_status & DEF_PSS_BITMASK_PTP_STATE ) >> DEF_PSS_SHIFT_PTP_STATE;
+
+} // syn1588_ptp_state_from_sync_status
+
+
+
+static __mbg_inline /*HDR*/
+/**
+ * @brief Check if the PTP stack is in sync.
+ *
+ * This is the case if the determined time offset is inside
+ * a specified boundary. See ::syn1588_get_in_sync_boundary_code.
+ *
+ * @param[in] ptp_sync_status The sync status word read from a device.
+ *
+ * @return @a true, if in sync, else @a false.
+ *
+ * @see ::syn1588_get_in_sync_boundary_code
+ */
+bool syn1588_ptp_in_sync( SYN1588_PTP_SYNC_STATUS ptp_sync_status )
+{
+ return ( ptp_sync_status & DEF_PSS_BIT_PTP_INSYNC ) != 0;
+
+} // syn1588_ptp_in_sync
+
+
+
+static __mbg_inline /*HDR*/
+/**
+ * @brief Check if the PTP stack is in slave mode and in sync.
+ *
+ * This is useful to check if the device is a synchronized PTP slave,
+ *
+ * @param[in] ptp_sync_status The sync status word read from a device.
+ *
+ * @return @a true, if in sync, else @a false.
+ *
+ * @see ::syn1588_ptp_state_from_sync_status
+ * @see ::syn1588_ptp_in_sync
+ */
+bool syn1588_ptp_slave_in_sync( SYN1588_PTP_SYNC_STATUS ptp_sync_status )
+{
+ return ( syn1588_ptp_state_from_sync_status( ptp_sync_status ) == SYN1588_PTP_STATE_SLAVE )
+ && syn1588_ptp_in_sync( ptp_sync_status );
+
+} // syn1588_ptp_slave_in_sync
+
+
+
+static __mbg_inline /*HDR*/
+/**
+ * @brief Decode the PTP in sync boundary from the sync status word.
+ *
+ * The function ::syn1588_ptp_sync_status_valid can be used to
+ * determine if the decoded number is valid.
+ *
+ * @param[in] ptp_sync_status The sync status word read from a device.
+ *
+ * @return The decoded in sync boundary. TODO Units?
+ *
+ * @see ::syn1588_ptp_in_sync
+ */
+uint syn1588_get_in_sync_boundary_code( SYN1588_PTP_SYNC_STATUS ptp_sync_status )
+{
+ return ( ptp_sync_status & DEF_PSS_BITMASK_PTP_INSYNC_BND_CODE ) >> DEF_PSS_SHIFT_PTP_INSYNC_BND_CODE;
+
+} // syn1588_get_in_sync_boundary_code
+
+
+
+static __mbg_inline /*HDR*/
+/**
+ * @brief Check if the PTP stack uses the PTP (TAI) time scale.
+ *
+ * If this is @a true, the original timestamp is TAI, and
+ * can be converted to %UTC if ::syn1588_sync_status_utc_valid.
+ *
+ * Unlike ::syn1588_is_timescale_ptp, this function also checks
+ * if the ::PTP_SYNC_STATUS is valid at all. This is faster if
+ * we need to check the status, and execution time matters.
+ *
+ * @param[in] ptp_sync_status The sync status word read from a device.
+ *
+ * @return @a true, if in sync, else @a false.
+ *
+ * @see ::syn1588_is_timescale_ptp
+ * @see ::syn1588_sync_status_utc_valid
+ */
+bool syn1588_is_valid_timescale_ptp( SYN1588_PTP_SYNC_STATUS ptp_sync_status )
+{
+ // The flags to test to see if the timescale is TAI.
+ SYN1588_PTP_SYNC_STATUS flags = DEF_PSS_BIT_VALID | DEF_PSS_BIT_PTP_TIMESCALE;
+
+ return ( ptp_sync_status & flags ) == flags;
+
+} // syn1588_is_valid_timescale_ptp
+
+
+
+static __mbg_inline /*HDR*/
+/**
+ * @brief Check if the PTP stack uses the PTP (TAI) time scale.
+ *
+ * If this is @a true, the original timestamp is TAI, and
+ * can be converted to %UTC if ::syn1588_sync_status_utc_valid.
+ *
+ * Unlike ::syn1588_is_valid_timescale_ptp, this function only
+ * checks the ::DEF_PSS_BIT_PTP_TIMESCALE bit, but dosn't check
+ * if the ::PTP_SYNC_STATUS is valid at all. This can be helpful
+ * for detailed inspection of the status.
+ *
+ * @param[in] ptp_sync_status The sync status word read from a device.
+ *
+ * @return @a true, if in sync, else @a false.
+ *
+ * @see ::syn1588_is_valid_timescale_ptp
+ * @see ::syn1588_sync_status_utc_valid
+ */
+bool syn1588_is_timescale_ptp( SYN1588_PTP_SYNC_STATUS ptp_sync_status )
+{
+ return ( ptp_sync_status & DEF_PSS_BIT_PTP_TIMESCALE ) != 0;
+
+} // syn1588_is_timescale_ptp
+
+
+
+static __mbg_inline /*HDR*/
+/**
+ * @brief Check if the %UTC offset field is valid.
+ *
+ * The function ::syn1588_utc_offs_from_sync_status can be used
+ * to decode the current %UTC/TAI offset from the PTP sync status word.
+ *
+ * @param[in] ptp_sync_status The sync status word read from a device.
+ *
+ * @return @a true, if valid, else @a false.
+ *
+ * @see ::syn1588_utc_offs_from_sync_status
+ */
+bool syn1588_sync_status_utc_valid( SYN1588_PTP_SYNC_STATUS ptp_sync_status )
+{
+ return ( ptp_sync_status & DEF_PSS_BIT_UTC_OFFSET_VALID ) != 0;
+
+} // syn1588_sync_status_utc_valid
+
+
+
+static __mbg_inline /*HDR*/
+/**
+ * @brief Decode the %UTC/TAI offset from the sync status word.
+ *
+ * The function ::syn1588_sync_status_utc_valid can be used to
+ * determine if the decoded offset is valid.
+ *
+ * @param[in] ptp_sync_status The sync status word read from a device.
+ *
+ * @return The decoded %UTC/TAI offset, in seconds.
+ *
+ * @see ::syn1588_sync_status_utc_valid
+ */
+int syn1588_utc_offs_from_sync_status( SYN1588_PTP_SYNC_STATUS ptp_sync_status )
+{
+ return (int) ( ptp_sync_status & DEF_PSS_BITMASK_UTC_OFFSET ); // TODO Is this always unsigned?
+
+} // syn1588_utc_offs_from_sync_status
+
+
+
+static __mbg_inline /*HDR*/
+/**
+ * @brief Check if the @a lSync program is running.
+ *
+ * This function returns @a true if the @a lSync program is running.
+ *
+ * On Windows, device access needs to be serialized in a multitasking
+ * or multithreaded environment, which is done using a semaphore
+ * implemented in the mbgdevio DLL.
+ *
+ * The @a lSync program does not use the DLL and thus does not use the semaphore,
+ * so concurrent access can result in inconsistent data being returned.
+ *
+ * A programs that is aware of this problem can display a warning
+ * when it detects that the @a lSync program is running, too.
+ *
+ * On Linux, a different API to the kernel driver is used, so there is
+ * need to care about serialization, and no need to display a warning
+ * if @a lSync is running.
+ *
+ * @param[in] ptp_sync_status The sync status word read from a device.
+ *
+ * @return @a true, if the status reflects tha @ lSync is running, else @a false.
+ */
+bool syn1588_lsync_running( SYN1588_PTP_SYNC_STATUS ptp_sync_status )
+{
+ return ( ptp_sync_status & DEF_PSS_BIT_LSYNC_RUNNING ) != 0;
+
+} // syn1588_lsync_running
+
+
+
+static __mbg_inline /*HDR*/
+/**
+ * @brief Get the exponent from an insync range boundary code.
+ *
+ * @param[in] code The insync range boundary code to be decoded, see ::PTP_STATE_RANGE_TABLE_INIT.
+ *
+ * @return The decoded exponent, scaled to shift results to a useful range.
+ *
+ * @see ::syn1588_insync_boundary_mantissa
+ * @see ::mbg_syn1588_snprint_insync_boundary_code
+ */
+int syn1588_insync_boundary_exponent( int code )
+{
+ return ( code >> 2 ) - 11;
+
+} // syn1588_insync_boundary_exponent
+
+
+
+static __mbg_inline /*HDR*/
+/**
+ * @brief Get the mantissa from an insync range boundary code.
+ *
+ * The decoded mantissa still needs special handling on range boundaries,
+ * see implementation in ::mbg_syn1588_snprint_insync_boundary_code.
+ *
+ * @param[in] code The insync range boundary code to be decoded, see ::PTP_STATE_RANGE_TABLE_INIT.
+ *
+ * @return The decoded mantissa.
+ *
+ * @see ::syn1588_insync_boundary_mantissa
+ * @see ::mbg_syn1588_snprint_insync_boundary_code
+ */
+int syn1588_insync_boundary_mantissa( int code )
+{
+ return code & 0x03;
+
+} // syn1588_insync_boundary_mantissa
+
+
+
+/* function prototypes: */
+
+/* ----- function prototypes begin ----- */
+
+/* This section was generated automatically */
+/* by MAKEHDR, do not remove the comments. */
+
+ /**
+ * @brief Retrieve a string representing the state of the PTP stack.
+ *
+ * @param[in] state The state of the PTP stack, see ::SYN1588_PTP_STATES.
+ *
+ * @return One of the strings defined in ::SYN1588_PTP_STATE_STRS.
+ */
+ const char *mbg_syn1588_chk_get_ptp_state_str( uint state ) ;
+
+ /**
+ * @brief Write the decoded value of an insync range boundary code to a string buffer.
+ *
+ * @param[out] s Pointer to the output buffer.
+ * @param[in] max_len Size of the output buffer.
+ * @param[in] code The insync range boundary code, see ::PTP_STATE_RANGE_TABLE_INIT.
+ * @param[in] check_max If @a true, ::PTP_STATE_RANGE_MAX_CODE causes special string.
+ *
+ * @return The number of characters written to the output buffer,
+ * except the terminating 0.
+ */
+ int mbg_syn1588_snprint_insync_boundary_code( char *s, size_t max_len, uint code, bool check_max ) ;
+
+
+/* ----- function prototypes end ----- */
+
+
+static __mbg_inline /*HDR*/
+/**
+ * @brief Determine the time scale from the status of a SYN1588 clock.
+ *
+ * Check the flags and bit fields in @p ptp_sync_status to see if %UTC
+ * can be unambiguously derived from the timestamp.
+ *
+ * Only if the timescale is PTP/TAI (and not arbitrary), we know that
+ * the original timestamp refers to TAI, and only if the %UTC offset
+ * is valid, too, we can convert the original TAI timestamp to %UTC.
+ *
+ * The determined %UTC/TAI offset is returned, and the the status
+ * @p *p_st is updated accordingly.
+ *
+ * @param[in] ptp_sync_status The sync status flags read from a SYN1588 device.
+ * @param[in,out] p_st Address of a ::PCPS_TIME_STATUS_X variable to be updated, or @a NULL.
+ *
+ * @return The %UTC offset, if it can be determined, else 0.
+ */
+int syn1588_check_timescale( SYN1588_PTP_SYNC_STATUS ptp_sync_status, PCPS_TIME_STATUS_X *p_st )
+{
+ // First check if the timestamps refer to the PTP/TAI time scale.
+ if ( syn1588_is_valid_timescale_ptp( ptp_sync_status ) )
+ {
+ // If the UTC offset is also valid, we can determine UTC.
+ if ( syn1588_sync_status_utc_valid( ptp_sync_status ) )
+ {
+ if ( p_st )
+ *p_st |= PCPS_UTC;
+
+ return syn1588_utc_offs_from_sync_status( ptp_sync_status );
+ }
+
+ if ( p_st ) // UTC offset is not available.
+ *p_st |= PCPS_SCALE_TAI;
+ }
+
+ return 0;
+
+} // syn1588_check_timescale
+
+
+
+static __mbg_inline /*HDR*/
+/**
+ * @brief Evaluate the status assiociated with a timestamp from a SYN1588 clock.
+ *
+ * Update the ::PCPS_HR_TIME structure @p *p accordingly.
+ *
+ * @param[in] ptp_sync_status The sync status flags read from a SYN1588 device.
+ * @param[in,out] p Address of a ::PCPS_HR_TIME structure to be updated.
+ */
+void syn1588_decode_sync_status( SYN1588_PTP_SYNC_STATUS ptp_sync_status, PCPS_HR_TIME *p )
+{
+ PCPS_TIME_STATUS_X status_x = PCPS_INVT | PCPS_FREER;
+ PCPS_SIG_VAL sig_val = PCPS_SIG_LVL_SIG_NOT_AVAIL;
+
+ if ( !syn1588_ptp_sync_status_valid( ptp_sync_status ) ) // Status not available.
+ {
+ #if DEBUG_SYN1588_C_API
+ fprintf( stderr, "syn1588 PTP sync status not available.\n" );
+ #endif
+ goto out;
+ }
+
+ #if DEBUG_SYN1588_C_API
+ {
+ bool ptp_sync_status_valid = syn1588_ptp_sync_status_valid( ptp_sync_status );
+
+ int utc_tai_offs = syn1588_utc_offs_from_sync_status( ptp_sync_status );
+ bool utc_tai_offs_valid = syn1588_sync_status_utc_valid( ptp_sync_status );
+
+ bool leap_59 = ( ptp_sync_status & DEF_PSS_BIT_LEAP59 ) != 0;
+ bool leap_61 = ( ptp_sync_status & DEF_PSS_BIT_LEAP61 ) != 0;
+
+ uint32_t ptp_state = syn1588_ptp_state_from_sync_status( ptp_sync_status );
+
+ bool ptp_in_sync = syn1588_ptp_in_sync( ptp_sync_status );
+ uint32_t in_sync_boundary_idx = syn1588_get_in_sync_boundary_code( ptp_sync_status );
+
+ bool timescale_is_ptp = ( ptp_sync_status & DEF_PSS_BIT_PTP_TIMESCALE ) != 0;
+
+ bool lsync_running = syn1588_lsync_running( ptp_sync_status );
+
+ fprintf( stderr, " PTP sync status: %svalid (0x%08lX)\n", ptp_sync_status_valid ? "" : "NOT ",
+ (ulong) ptp_sync_status );
+ fprintf( stderr, " Time scale: %s\n", timescale_is_ptp ? "PTP/TAI" : "arbitrary" );
+ fprintf( stderr, " UTC/TAI offs valid: %i, offs: %i (0x%04X) s,\n", utc_tai_offs_valid,
+ utc_tai_offs, utc_tai_offs );
+ fprintf( stderr, " Leap 59: %i, Leap 61: %i\n", leap_59, leap_61 );
+ fprintf( stderr, " PTP State: 0x%08X (%s), in sync: %i, boundary: %u (%s)\n", ptp_state,
+ mbg_syn1588_chk_get_ptp_state_str( ptp_state ),
+ ptp_in_sync, in_sync_boundary_idx,
+ mbg_syn1588_get_boundary_str( in_sync_boundary_idx ) );
+ fprintf( stderr, " lSync runnig: %s\n\n", lsync_running ? "Yes" : "No" );
+ }
+ #endif
+
+ // The PTP270PEX card checks if a network link is available
+ // to report if a signal is available. The SYN1588
+ // device can only synchronize if the PTP stack is running
+ // and has updated the PTP_SYNC_STATUS register.
+ // This is the case if we get here.
+ sig_val = PCPS_SIG_LVL_SIG_AVAIL;
+
+ // Set the initial status depending on whether the device is synchronized,
+ // or not.
+ //
+ // Unfortunately, ::syn1588_ptp_in_sync() can also be set if the PTP stack
+ // is in master mode, even if the on-board time is not disciplined
+ // from a reference time source. So we only consider the device to
+ // be synchronized if the stack is also in slave state.
+ if ( syn1588_ptp_state_from_sync_status( ptp_sync_status ) == SYN1588_PTP_STATE_SLAVE )
+ status_x = syn1588_ptp_in_sync( ptp_sync_status ) ? PCPS_SYNCD : PCPS_FREER;
+
+ // Check the time scale and adjust the time stamp accordingly.
+ p->tstamp.sec -= syn1588_check_timescale( ptp_sync_status, &status_x );
+
+ // Evaluate the leap second status. Actually, leap second warnings
+ // should only be available if the time scale is UTC or local time.
+ // We assume that the stack takes care about this.
+ if ( ptp_sync_status & DEF_PSS_BIT_LEAP61 )
+ {
+ if ( ptp_sync_status & DEF_PSS_BIT_LEAP59 )
+ status_x |= PCPS_INVT; // Invalid state: both announcements set.
+ else
+ status_x |= PCPS_LS_ANN; // Positive leap second announced.
+ }
+ else
+ if ( ptp_sync_status & DEF_PSS_BIT_LEAP59 )
+ status_x |= PCPS_LS_ANN | PCPS_LS_ANN_NEG; // Negative leap second announced.
+
+out:
+ p->status = status_x;
+ p->signal = sig_val;
+ p->utc_offs = 0; // Always 0 here because it refers to UTC/Local time, not UTC/TAI.
+
+} // syn1588_decode_sync_status
+
+
+
+static __mbg_inline /*HDR*/
+int pcps_time_from_pcps_hr_time( PCPS_TIME *p, const PCPS_HR_TIME *p_ht, int64_t nsec )
+{
+ struct tm tm = { 0 };
+ MBG_TIME64_T t64 = p_ht->tstamp.sec; // Will need extrapolation for Y2038.
+ int rc = mbg_gmtime64( &tm, &t64 );
+
+ if ( mbg_rc_is_error( rc ) )
+ return rc;
+
+ // Save the computed calendar date and time.
+ p->sec = tm.tm_sec;
+ p->min = tm.tm_min;
+ p->hour = tm.tm_hour;
+ p->mday = tm.tm_mday;
+ p->wday = _wday_sun06_to_mon17( tm.tm_wday );
+ p->month = tm.tm_mon + 1;
+ p->year = tm.tm_year % 100;
+
+ // Convert fractions of the second.
+ p->sec100 = (uint8_t) ( nsec / ( NSEC_PER_SEC / 100 ) );
+
+ // Convert the remaining fields.
+ p->status = (PCPS_TIME_STATUS) p_ht->status;
+ p->signal = p_ht->signal;
+ p->offs_utc = p_ht->utc_offs / SECS_PER_HOUR;
+
+ return MBG_SUCCESS;
+
+} // pcps_time_from_pcps_hr_time
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+/* End of header body */
+
+#undef _ext
+#undef _DO_INIT
+
+#endif /* _MBG_SYN1588_UTIL_H */
diff --git a/mbglib/common/mbg_xmr_util.c b/mbglib/common/mbg_xmr_util.c
new file mode 100644
index 0000000..7b7a5c2
--- /dev/null
+++ b/mbglib/common/mbg_xmr_util.c
@@ -0,0 +1,159 @@
+
+/**************************************************************************
+ *
+ * $Id: mbg_xmr_util.c 1.3 2022/07/06 14:56:09Z martin.burnicki REL_M $
+ *
+ * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany
+ *
+ * Common Meinberg utility functions for XMR/MRS.
+ *
+ * -----------------------------------------------------------------------
+ * $Log: mbg_xmr_util.c $
+ * Revision 1.3 2022/07/06 14:56:09Z martin.burnicki
+ * Code cleanup.
+ * Revision 1.2 2022/06/30 09:44:23 martin.burnicki
+ * Added some doxygen comments and made a function static.
+ * Revision 1.1 2022/06/24 12:54:33 martin.burnicki
+ * Initial revision.
+ *
+ **************************************************************************/
+
+#define _MBG_XMR_UTIL
+ #include <mbg_xmr_util.h>
+#undef _MBG_XMR_UTIL
+
+#include <str_util.h>
+#include <nanotime.h>
+
+#include <stdio.h>
+
+
+#define XMR_STATUS_NAMES \
+{ \
+ "not supp.", /* XMRS_BIT_NOT_SUPP, */ \
+ "not conn.", /* XMRS_BIT_NO_CONN, */ \
+ "no signal", /* XMRS_BIT_NO_SIGNAL, */ \
+ "is master", /* XMRS_BIT_IS_MASTER, */ \
+ "is locked", /* XMRS_BIT_IS_LOCKED, */ \
+ "is accurate", /* XMRS_BIT_IS_ACCURATE, */ \
+ "not settled", /* XMRS_BIT_NOT_SETTLED, */ \
+ "not phase-locked", /* XMRS_BIT_NOT_PHASE_LOCKED, */ \
+ "exceeds supp.", /* XMRS_BIT_NUM_SRC_EXC, */ \
+ "is external", /* XMRS_BIT_IS_EXTERNAL, */ \
+ "low jitter", /* XMRS_BIT_LOW_JITTER, */ \
+ "ITU limit violated", /* XMRS_BIT_ITU_LIMIT_VIOLATED, */ \
+ "TRS limit violated", /* XMRS_BIT_TRS_LIMIT_VIOLATED, */ \
+}
+
+static const char *xmr_status_names[N_XMRS_BITS] = XMR_STATUS_NAMES;
+
+
+static const char *multi_ref_names[N_MULTI_REF] = DEFAULT_MULTI_REF_NAMES;
+
+
+
+static /*HDR*/
+/**
+ * @brief Print info on ::XMULTI_REF_STATUS::status bits to a string.
+ *
+ * @param[out] s The string buffer to be filled.
+ * @param[in] max_len Size of the output buffer for 0-terminated string.
+ * @param[in] xmr_status The XMR status from ::XMULTI_REF_STATUS::status to decode.
+ *
+ * @return Length of the string in the buffer.
+ */
+int snprint_xmr_src_status( char *s, size_t max_len, unsigned xmr_status )
+{
+ int n = 0;
+ bool seen = false;
+ int i;
+
+ s[0] = 0; // Make string empty.
+
+ for ( i = 0; i < N_XMRS_BITS; i++ )
+ {
+ if ( xmr_status & 0x01 )
+ {
+ n += snprintf_safe( &s[n], max_len - n, "%s%s",
+ seen ? ", " : "", xmr_status_names[i] );
+ seen = true;
+ }
+
+ xmr_status >>= 1;
+ }
+
+ return n;
+
+} // snprint_xmr_src_status
+
+
+
+/*HDR*/
+/**
+ * @brief Print all XMR status info.
+ *
+ * @param[in] p_axrs Pointer to an XMR status info structure read from a device.
+ * @param[in] n_src Number of XMR ref. sources, from ::ALL_XMULTI_REF_INFO::instances.
+ * @param[in] info An optional header string to print, may be @a NULL.
+ * @param[in] indent_str An optional indentation string, may be @a NULL.
+ * @param[in] verbosity_level Level of verbosity of the printed output.
+ */
+void print_all_xmr_status( ALL_XMULTI_REF_STATUS *p_axrs, int n_src,
+ const char *info, const char *indent_str,
+ int verbosity_level )
+{
+ size_t max_ref_name_len = 0;
+ int i;
+
+ // Determine the maximum length of the names of the
+ // ref types in use.
+
+ for ( i = 0; i < n_src; i++ )
+ {
+ int ref_type = p_axrs->status[i].status.id.type;
+
+ if ( ref_type < N_MULTI_REF )
+ {
+ size_t l = strlen( multi_ref_names[ref_type] );
+
+ if ( l > max_ref_name_len )
+ max_ref_name_len = l;
+ }
+ }
+
+ if ( info )
+ printf( "%s\n", info );
+
+ for ( i = 0; i < n_src; i++ )
+ {
+ char s[128];
+ size_t sz = sizeof( s );
+ int n;
+ const XMULTI_REF_STATUS *p_xrs = &p_axrs->status[i].status;
+ int ref_type = p_xrs->id.type;
+
+ if ( ref_type == (uint8_t) -1 ) // No source configured.
+ continue;
+
+ n = snprintf_safe( s, sz, "Src %i:", i );
+
+ n += snprintf_safe( &s[n], sz - n, " type %2i", ref_type );
+
+ n += snprintf_safe( &s[n], sz - n, " (%s):", ( ref_type < N_MULTI_REF ) ?
+ multi_ref_names[ref_type] : "unknown" );
+
+ n += snprintf_safe( &s[n], sz - n, "%*s", (int) ( 19 + max_ref_name_len - n ), "" );
+
+ n += snprintf_safe( &s[n], sz - n, "offs: " );
+ n += snprint_nano_time( &s[n], sz - n, &p_xrs->offset );
+
+ n += snprintf_safe( &s[n], sz - n, " s, status 0x%04X: ", p_xrs->status );
+
+ n += snprint_xmr_src_status( &s[n], sz - n, p_xrs->status );
+
+ printf( "%s%s\n", indent_str ? indent_str : "", s );
+ }
+
+} // print_all_xmr_status
+
+
diff --git a/mbglib/common/mbg_xmr_util.h b/mbglib/common/mbg_xmr_util.h
new file mode 100644
index 0000000..6bb1cf0
--- /dev/null
+++ b/mbglib/common/mbg_xmr_util.h
@@ -0,0 +1,73 @@
+
+/**************************************************************************
+ *
+ * $Id: mbg_xmr_util.h 1.2 2022/06/30 09:47:33Z martin.burnicki REL_M $
+ *
+ * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany
+ *
+ * Definitions and prototypes for mbg_xmr_util.c.
+ *
+ * -----------------------------------------------------------------------
+ * $Log: mbg_xmr_util.h $
+ * Revision 1.2 2022/06/30 09:47:33Z martin.burnicki
+ * Updated function prototypes.
+ * Revision 1.1 2022/06/24 12:54:36 martin.burnicki
+ * Initial revision.
+ *
+ **************************************************************************/
+
+#ifndef _MBG_XMR_UTIL_H
+#define _MBG_XMR_UTIL_H
+
+
+/* Other headers to be included */
+
+#include <cfg_hlp.h>
+
+
+#ifdef _MBG_XMR_UTIL
+ #define _ext
+ #define _DO_INIT
+#else
+ #define _ext extern
+#endif
+
+
+/* Start of header body */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* function prototypes: */
+
+/* ----- function prototypes begin ----- */
+
+/* This section was generated automatically */
+/* by MAKEHDR, do not remove the comments. */
+
+ /**
+ * @brief Print all XMR status info.
+ *
+ * @param[in] p_axrs Pointer to an XMR status info structure read from a device.
+ * @param[in] n_src Number of XMR ref. sources, from ::ALL_XMULTI_REF_INFO::instances.
+ * @param[in] info An optional header string to print, may be @a NULL.
+ * @param[in] indent_str An optional indentation string, may be @a NULL.
+ * @param[in] verbosity_level Level of verbosity of the printed output.
+ */
+ void print_all_xmr_status( ALL_XMULTI_REF_STATUS *p_axrs, int n_src, const char *info, const char *indent_str, int verbosity_level ) ;
+
+
+/* ----- function prototypes end ----- */
+
+#ifdef __cplusplus
+}
+#endif
+
+
+/* End of header body */
+
+#undef _ext
+#undef _DO_INIT
+
+#endif /* _MBG_XMR_UTIL_H */
diff --git a/mbglib/common/mbg_xmr_util_devio.c b/mbglib/common/mbg_xmr_util_devio.c
new file mode 100644
index 0000000..82bf091
--- /dev/null
+++ b/mbglib/common/mbg_xmr_util_devio.c
@@ -0,0 +1,259 @@
+
+/**************************************************************************
+ *
+ * $Id: mbg_xmr_util_devio.c 1.2 2022/06/30 09:47:10Z martin.burnicki REL_M $
+ *
+ * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany
+ *
+ * Meinberg functions to show XMR info for bus level devices.
+ *
+ * -----------------------------------------------------------------------
+ * $Log: mbg_xmr_util_devio.c $
+ * Revision 1.2 2022/06/30 09:47:10Z martin.burnicki
+ * Support force-reading XMR info and status, which is useful for debugging
+ * but can be dangerous if the device generally doesn't support XMR.
+ * Added some doxygen comments.
+ * Revision 1.1 2022/06/24 12:54:31 martin.burnicki
+ * Initial revision.
+ *
+ **************************************************************************/
+
+#define _MBG_XMR_UTIL_DEVIO
+ #include <mbg_xmr_util_devio.h>
+#undef _MBG_XMR_UTIL_DEVIO
+
+#include <mbg_xmr_util.h>
+
+#include <stdio.h>
+
+
+
+/*HDR*/
+/**
+ * @brief Force-read all XMR info into a newly or re-allocated ::ALL_XMULTI_REF_INFO.
+ *
+ * @note This variant of ::mbg_get_all_xmulti_ref_info function bypasses the check
+ * whether XMR is supported by the device, and accesses the device in any case.
+ * Calling this function with a device that generally doesn't support the XMR feature
+ * may cause the device and even the whole computer to hang.
+ *
+ * An ::ALL_XMULTI_REF_INFO and a number of ::XMULTI_REF_INSTANCES::n_xmr_settings
+ * of ::XMULTI_REF_INFO_IDX and ::XMR_EXT_SRC_INFO_IDX will be allocated and need
+ * to be freed by calling ::free_all_xmulti_ref_info.
+ *
+ * @param[in] dh Valid handle to a Meinberg device.
+ * @param[out] p Pointer to a pointer of ::ALL_XMULTI_REF_INFO.
+ *
+ * @return One of the @ref MBG_RETURN_CODES.
+ *
+ * @see ::free_all_xmulti_ref_info
+ */
+int mbg_get_all_xmulti_ref_info_forced( MBG_DEV_HANDLE dh, ALL_XMULTI_REF_INFO **p )
+{
+ ALL_XMULTI_REF_INFO *xmr_info = *p;
+ size_t data_sz;
+ int rc;
+
+ if ( xmr_info == NULL )
+ {
+ xmr_info = (ALL_XMULTI_REF_INFO *) calloc( 1, sizeof( *xmr_info ) );
+
+ if ( xmr_info == NULL )
+ {
+ rc = MBG_ERR_NO_MEM;
+ goto out;
+ }
+ }
+
+ // First, get the XMULTI_REF_INSTANCES to check how many sources are supported.
+ rc = _mbgdevio_gen_read_gps( dh, PC_GPS_XMR_INSTANCES, &xmr_info->instances,
+ sizeof( xmr_info->instances ) );
+
+ if ( mbg_rc_is_error( rc ) )
+ goto out;
+
+
+ data_sz = xmr_info->instances.n_xmr_settings * sizeof( *xmr_info->infos );
+
+ if ( xmr_info->infos == NULL )
+ {
+ xmr_info->infos = (XMULTI_REF_INFO_IDX *) calloc( 1, data_sz );
+
+ if ( xmr_info->infos == NULL )
+ {
+ rc = MBG_ERR_NO_MEM;
+ goto out;
+ }
+ }
+
+ rc = _mbgdevio_gen_read_gps( dh, PC_GPS_ALL_XMR_INFO, xmr_info->infos, data_sz );
+
+ if ( mbg_rc_is_error( rc ) )
+ goto out;
+
+ if ( mbg_rc_is_success( chk_dev_xmulti_ref_supp_ext_src_info( xmr_info ) ) )
+ {
+ // TODO
+ // XMR_EXT_SRC_INFO_IDX can not yet be read from bus devices.
+ // Therefore, remove the feature bit from this card.
+ // Has to be changed as soon as low level functions are ready
+ // TODO
+ xmr_info->instances.flags &= ~XMRIF_MSK_EXT_SRC_INFO_SUPP;
+ }
+
+out:
+ if ( mbg_rc_is_error( rc ) )
+ {
+ free_all_xmulti_ref_info( xmr_info );
+ xmr_info = NULL;
+ }
+
+ *p = xmr_info;
+
+ return rc;
+
+} // mbg_get_all_xmulti_ref_info_forced
+
+
+
+/*HDR*/
+/**
+ * @brief Force-read all XMR status info into a newly or re-allocated ::ALL_XMULTI_REF_STATUS.
+ *
+ * @note This variant of ::mbg_get_all_xmulti_ref_status function bypasses the check
+ * whether XMR is supported by the device, and accesses the device in any case.
+ * Calling this function with a device that generally doesn't support the XMR feature
+ * may cause the device and even the whole computer to hang.
+ *
+ * An ::ALL_XMULTI_REF_STATUS and a number of ::XMULTI_REF_INSTANCES::n_xmr_settings
+ * of ::XMULTI_REF_STATUS_IDX will be allocated and need to be freed by calling
+ * ::free_all_xmulti_ref_status.
+ *
+ * @param[in] dh Valid handle to a Meinberg device.
+ * @param[in] info Pointer to the appropriate info structure.
+ * @param[out] p Pointer to a pointer of ::ALL_XMULTI_REF_STATUS.
+ *
+ * @return One of the @ref MBG_RETURN_CODES
+ *
+ * @see ::free_all_xmulti_ref_status
+ */
+int mbg_get_all_xmulti_ref_status_forced( MBG_DEV_HANDLE dh, const ALL_XMULTI_REF_INFO *info, ALL_XMULTI_REF_STATUS **p )
+{
+ ALL_XMULTI_REF_STATUS *xmr_status = *p;
+ size_t data_sz;
+ int rc;
+
+ if ( info == NULL )
+ return MBG_ERR_INV_PARM;
+
+ if ( xmr_status == NULL )
+ {
+ xmr_status = (ALL_XMULTI_REF_STATUS *) calloc( 1, sizeof( *xmr_status ) );
+
+ if ( xmr_status == NULL )
+ {
+ rc = MBG_ERR_NO_MEM;
+ goto out;
+ }
+ }
+
+ data_sz = info->instances.n_xmr_settings * sizeof( *xmr_status->status );
+
+ if ( xmr_status->status == NULL )
+ {
+ xmr_status->status = (XMULTI_REF_STATUS_IDX *) calloc( 1, data_sz );
+
+ if ( xmr_status->status == NULL )
+ {
+ rc = MBG_ERR_NO_MEM;
+ goto out;
+ }
+ }
+
+ rc = _mbgdevio_gen_read_gps( dh, PC_GPS_ALL_XMR_STATUS, xmr_status->status, data_sz );
+
+ if ( mbg_rc_is_error( rc ) )
+ goto out;
+
+ #if 0
+ // TODO Some more detailed status info could be read here,
+ // if supported by bus level devices, using code similar to this:
+
+ if ( mbg_rc_is_success( chk_dev_xmulti_ref_supp_...() ) )
+ {
+ ...
+ }
+ #endif
+
+out:
+ if ( mbg_rc_is_error( rc ) )
+ {
+ free_all_xmulti_ref_status( xmr_status );
+ xmr_status = NULL;
+ }
+
+ *p = xmr_status;
+
+ return rc;
+
+} // mbg_get_all_xmulti_ref_status_forced
+
+
+
+/*HDR*/
+/**
+ * @brief Read and show all XMR status info.
+ *
+ * @note If @p force is true, the device is accessed to read the XMR data
+ * even if the feature flag is not set. Use this very carefully only:
+ * Doing so with a device that generally doesn't support the XMR feature
+ * may cause the device and even the whole computer to hang!
+
+ * @param[in] dh Valid handle to a Meinberg device.
+ * @param[in] info An optional header string to print, may be @a NULL.
+ * @param[in] indent_str An optional indentation string, may be @a NULL.
+ * @param[in] verbosity_level Level of verbosity of the printed output.
+ * @param[in] force If @a true, force-read XMR data even if the feature flag is not set.
+ *
+ * @return One of the @ref MBG_RETURN_CODES
+ *
+ * @see ::print_all_xmr_status
+ */
+void show_all_xmr_status( MBG_DEV_HANDLE dh, const char *info, const char *indent_str,
+ int verbosity_level, bool force )
+{
+ ALL_XMULTI_REF_INFO *p_axri = NULL;
+ ALL_XMULTI_REF_STATUS *p_axrs = NULL;
+
+ int rc = force ? mbg_get_all_xmulti_ref_info_forced( dh, &p_axri ) :
+ mbg_get_all_xmulti_ref_info( dh, &p_axri );
+
+ if ( mbg_rc_is_error( rc ) )
+ {
+ fprintf( stderr, "Failed to read all XMR info: %s\n", mbg_strerror( rc ) );
+ goto done;
+ }
+
+ rc = force ? mbg_get_all_xmulti_ref_status_forced( dh, p_axri, &p_axrs )
+ : mbg_get_all_xmulti_ref_status( dh, p_axri, &p_axrs );
+
+ if ( mbg_rc_is_error( rc ) )
+ {
+ fprintf( stderr, "Failed to read all XMR status: %s\n", mbg_strerror( rc ) );
+ goto done;
+ }
+
+
+ print_all_xmr_status( p_axrs, p_axri->instances.n_xmr_settings,
+ info, indent_str, verbosity_level );
+
+done:
+ if ( p_axri )
+ free_all_xmulti_ref_info( p_axri );
+
+ if ( p_axrs )
+ free_all_xmulti_ref_status( p_axrs );
+
+} // show_all_xmr_status
+
+
diff --git a/mbglib/common/mbg_xmr_util_devio.h b/mbglib/common/mbg_xmr_util_devio.h
new file mode 100644
index 0000000..0769642
--- /dev/null
+++ b/mbglib/common/mbg_xmr_util_devio.h
@@ -0,0 +1,127 @@
+
+/**************************************************************************
+ *
+ * $Id: mbg_xmr_util_devio.h 1.2 2022/06/30 09:47:42Z martin.burnicki REL_M $
+ *
+ * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany
+ *
+ * Definitions and prototypes for mbg_xmr_util_devio.c.
+ *
+ * -----------------------------------------------------------------------
+ * $Log: mbg_xmr_util_devio.h $
+ * Revision 1.2 2022/06/30 09:47:42Z martin.burnicki
+ * Updated function prototypes.
+ * Revision 1.1 2022/06/24 12:54:29 martin.burnicki
+ * Initial revision.
+ *
+ **************************************************************************/
+
+#ifndef _MBG_XMR_UTIL_DEVIO_H
+#define _MBG_XMR_UTIL_DEVIO_H
+
+
+/* Other headers to be included */
+
+#include <deviohlp.h>
+#include <cfg_hlp.h>
+
+
+#ifdef _MBG_XMR_UTIL_DEVIO
+ #define _ext
+ #define _DO_INIT
+#else
+ #define _ext extern
+#endif
+
+
+/* Start of header body */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* function prototypes: */
+
+/* ----- function prototypes begin ----- */
+
+/* This section was generated automatically */
+/* by MAKEHDR, do not remove the comments. */
+
+ /**
+ * @brief Force-read all XMR info into a newly or re-allocated ::ALL_XMULTI_REF_INFO.
+ *
+ * @note This variant of ::mbg_get_all_xmulti_ref_info function bypasses the check
+ * whether XMR is supported by the device, and accesses the device in any case.
+ * Calling this function with a device that generally doesn't support the XMR feature
+ * may cause the device and even the whole computer to hang.
+ *
+ * An ::ALL_XMULTI_REF_INFO and a number of ::XMULTI_REF_INSTANCES::n_xmr_settings
+ * of ::XMULTI_REF_INFO_IDX and ::XMR_EXT_SRC_INFO_IDX will be allocated and need
+ * to be freed by calling ::free_all_xmulti_ref_info.
+ *
+ * @param[in] dh Valid handle to a Meinberg device.
+ * @param[out] p Pointer to a pointer of ::ALL_XMULTI_REF_INFO.
+ *
+ * @return One of the @ref MBG_RETURN_CODES.
+ *
+ * @see ::free_all_xmulti_ref_info
+ */
+ int mbg_get_all_xmulti_ref_info_forced( MBG_DEV_HANDLE dh, ALL_XMULTI_REF_INFO **p ) ;
+
+ /**
+ * @brief Force-read all XMR status info into a newly or re-allocated ::ALL_XMULTI_REF_STATUS.
+ *
+ * @note This variant of ::mbg_get_all_xmulti_ref_status function bypasses the check
+ * whether XMR is supported by the device, and accesses the device in any case.
+ * Calling this function with a device that generally doesn't support the XMR feature
+ * may cause the device and even the whole computer to hang.
+ *
+ * An ::ALL_XMULTI_REF_STATUS and a number of ::XMULTI_REF_INSTANCES::n_xmr_settings
+ * of ::XMULTI_REF_STATUS_IDX will be allocated and need to be freed by calling
+ * ::free_all_xmulti_ref_status.
+ *
+ * @param[in] dh Valid handle to a Meinberg device.
+ * @param[in] info Pointer to the appropriate info structure.
+ * @param[out] p Pointer to a pointer of ::ALL_XMULTI_REF_STATUS.
+ *
+ * @return One of the @ref MBG_RETURN_CODES
+ *
+ * @see ::free_all_xmulti_ref_status
+ */
+ int mbg_get_all_xmulti_ref_status_forced( MBG_DEV_HANDLE dh, const ALL_XMULTI_REF_INFO *info, ALL_XMULTI_REF_STATUS **p ) ;
+
+ /**
+ * @brief Read and show all XMR status info.
+ *
+ * @note If @p force is true, the device is accessed to read the XMR data
+ * even if the feature flag is not set. Use this very carefully only:
+ * Doing so with a device that generally doesn't support the XMR feature
+ * may cause the device and even the whole computer to hang!
+
+ * @param[in] dh Valid handle to a Meinberg device.
+ * @param[in] info An optional header string to print, may be @a NULL.
+ * @param[in] indent_str An optional indentation string, may be @a NULL.
+ * @param[in] verbosity_level Level of verbosity of the printed output.
+ * @param[in] force If @a true, force-read XMR data even if the feature flag is not set.
+ *
+ * @return One of the @ref MBG_RETURN_CODES
+ *
+ * @see ::print_all_xmr_status
+ */
+ void show_all_xmr_status( MBG_DEV_HANDLE dh, const char *info, const char *indent_str, int verbosity_level, bool force ) ;
+
+
+/* ----- function prototypes end ----- */
+
+#ifdef __cplusplus
+}
+#endif
+
+
+/* End of header body */
+
+#undef _ext
+#undef _DO_INIT
+
+#endif /* _MBG_XMR_UTIL_DEVIO_H */
diff --git a/mbgstatus/mbgstatus.c b/mbgstatus/mbgstatus.c
index 8fce92b..58ae679 100644
--- a/mbgstatus/mbgstatus.c
+++ b/mbgstatus/mbgstatus.c
@@ -1,7 +1,7 @@
/**************************************************************************
*
- * $Id: mbgstatus.c 1.34 2022/04/01 15:01:09Z martin.burnicki REL_M $
+ * $Id: mbgstatus.c 1.37 2022/07/06 15:09:51Z martin.burnicki REL_M $
*
* Description:
* Main file for mbgstatus program which demonstrates how to
@@ -10,7 +10,15 @@
*
* -----------------------------------------------------------------------
* $Log: mbgstatus.c $
- * Revision 1.34 2022/04/01 15:01:09Z martin.burnicki
+ * Revision 1.37 2022/07/06 15:09:51Z martin.burnicki
+ * Support SYN1588 insync range boundary code.
+ * Revision 1.36 2022/06/30 13:00:22 martin.burnicki
+ * Support reading XMR status information from devices that support this.
+ * New option -F to force reading XMR stuff if the feature is not enabled,
+ * which should only be used with very much care.
+ * Revision 1.35 2022/05/31 14:03:30 martin.burnicki
+ * Improved display of SYN1588 sync status.
+ * Revision 1.34 2022/04/01 15:01:09 martin.burnicki
* Print the firmware ID string in verbose mode.
* Revision 1.33 2021/11/15 17:08:52 martin.burnicki
* Improved printing of usage information.
@@ -116,6 +124,8 @@
// Include Meinberg headers.
#include <mbgdevio.h>
#include <mbgutil.h>
+#include <mbg_xmr_util_devio.h>
+#include <mbg_syn1588_util.h>
#include <mbgtimex.h>
#include <pcpslstr.h>
#include <toolutil.h> // Common utility functions.
@@ -141,7 +151,8 @@ static int list_only; // List only which devices are installed.
static int list_only_unique_names; // List only the unique names of all devices.
static long sleep_secs;
static long sleep_usecs;
-static unsigned int verbose;
+static int verbose;
+static int force_read;
static const char *ref_name[N_PCPS_REF]= PCPS_REF_NAMES_ENG;
static const char *icode_rx_names[N_ICODE_RX] = DEFAULT_ICODE_RX_NAMES;
@@ -271,8 +282,8 @@ typedef struct
bool raw_irig_data_avail;
bool is_syn1588;
- uint32_t syn1588_ptp_syn_status;
- bool syn1588_ptp_syn_status_avail;
+ SYN1588_PTP_SYNC_STATUS syn1588_ptp_sync_status;
+ bool syn1588_ptp_sync_status_avail;
} DEVICE_STATUS;
@@ -897,34 +908,136 @@ int collect_ext_stat_info( MBG_DEV_HANDLE dh, DEVICE_STATUS *p_ds )
static /*HDR*/
-void show_syn1588_info( const DEVICE_STATUS *p_ds )
+void show_syn1588_ptp_sync_status( const DEVICE_STATUS *p_ds )
{
- if ( verbose )
+ bool sync_status_valid;
+ uint32_t ptp_state;
+ const char *ptp_state_str;
+ bool ptp_in_sync;
+ uint32_t insync_boundary_code;
+ char insync_boundary_str[80];
+ bool lsync_running;
+
+ printf( "PTP state: " );
+
+ // If the status could not be read, there are no details to display.
+ if ( !p_ds->syn1588_ptp_sync_status_avail )
{
- printf( "PTP Sync Status: " );
+ printf( "%s\n", str_not_avail );
+ return;
+ }
- if ( p_ds->syn1588_ptp_syn_status_avail )
- {
- printf( "0x%08lX", (ulong) p_ds->syn1588_ptp_syn_status );
- if ( p_ds->syn1588_ptp_syn_status == 0 )
- printf( " (unknown, Stack not running?)");
- }
- else
- printf( "%s", str_not_avail );
+ // The status word could be read, so we can decode some fields
+ // in any case.
+ ptp_state = syn1588_ptp_state_from_sync_status( p_ds->syn1588_ptp_sync_status );
+ ptp_state_str = mbg_syn1588_chk_get_ptp_state_str( ptp_state );
+
+ ptp_in_sync = syn1588_ptp_in_sync( p_ds->syn1588_ptp_sync_status );
+ insync_boundary_code = syn1588_get_in_sync_boundary_code( p_ds->syn1588_ptp_sync_status );
+ mbg_syn1588_snprint_insync_boundary_code( insync_boundary_str, sizeof( insync_boundary_str ),
+ insync_boundary_code, true );
+ lsync_running = syn1588_lsync_running( p_ds->syn1588_ptp_sync_status );
+
+
+ // Show if the status is valid, or not.
+ sync_status_valid = syn1588_ptp_sync_status_valid( p_ds->syn1588_ptp_sync_status );
+
+ if ( !sync_status_valid )
+ {
+ printf( "NOT VALID!\n" );
+
+ if ( verbose < 3 )
+ goto out;
+
+ goto print_details;
+ }
+
+
+ // The PTP sync status is valid, so we can now display
+ // the state of the PTP stack.
+ printf( "%s", ptp_state_str );
+
+ if ( ( ( verbose > 1 ) && ( ptp_state == SYN1588_PTP_STATE_SLAVE ) )
+ || ( verbose > 2 ) )
+ if ( ptp_in_sync )
+ printf( ", sync to boundary %s", insync_boundary_str );
+
+ printf( "\n" );
+
+ if ( verbose < 2 )
+ goto out;
+
+
+print_details:
+ printf( "PTP sync status details:\n" );
+ {
+ bool must_show_values = verbose > 2;
+ int utc_tai_offs = syn1588_utc_offs_from_sync_status( p_ds->syn1588_ptp_sync_status );
+ bool utc_tai_offs_valid = syn1588_sync_status_utc_valid( p_ds->syn1588_ptp_sync_status );
+ bool leap_59 = ( p_ds->syn1588_ptp_sync_status & DEF_PSS_BIT_LEAP59 ) != 0;
+ bool leap_61 = ( p_ds->syn1588_ptp_sync_status & DEF_PSS_BIT_LEAP61 ) != 0;
+ bool timescale_is_ptp = syn1588_is_timescale_ptp( p_ds->syn1588_ptp_sync_status );
+
+ printf( " Time scale: %s\n", timescale_is_ptp ? "PTP/TAI" : "arbitrary" );
+ printf( " UTC/TAI offs valid: %i, offs: %i s,\n", utc_tai_offs_valid, utc_tai_offs );
+ printf( " Leap 59: %i, Leap 61: %i\n", leap_59, leap_61 );
+ printf( " PTP State: %s", ptp_state_str );
+
+ if ( must_show_values )
+ printf( " (0x%02X)", ptp_state );
+
+ printf( ", in sync: %i, boundary: %s", ptp_in_sync, sync_status_valid ?
+ insync_boundary_str : "undefined" );
+
+ if ( must_show_values )
+ printf( " (0x%02X)", insync_boundary_code );
printf( "\n" );
+
+ printf( " lSync runnig: %s\n", lsync_running ? "Yes" : "No" );
}
-} // show_syn1588_info
+out:
+ // Display a warning if the firmware of a SYN1588 NIC is too old.
+ // If the firmware is too old, the PTP sync status may not
+ // be supported, either.
+ if ( _pcps_fw_rev_num( &p_ds->dev_info ) < SYN1588_MIN_REQ_BUILD_NUM )
+ {
+ printf( "\n"
+ "** Warning: FW build %i is required, please update!\n"
+ "Without an update, this SYN1588 card may not work properly!",
+ SYN1588_MIN_REQ_BUILD_NUM );
+ }
+ else
+ {
+ // If the status could be read, but is not valid, show a hint
+ // what could be the reason.
+ if ( p_ds->syn1588_ptp_sync_status_avail && !sync_status_valid )
+ printf( "\n"
+ "** Warning: The PTP sync status is not available!\n"
+ "Make sure the PTP stack is running, adjusting the time\n"
+ "and updating the status on the card.\n" );
+
+ #if defined( MBG_TGT_WIN32 )
+ // This warning is only significant for Windows, not for Linux.
+ if ( lsync_running )
+ printf( "\n"
+ "** Warning: The lSync program is also running!\n"
+ "lSync is not thread-safe and concurrent access with these tools\n"
+ "may cause inconsistent data to bread from the card.\n" );
+ #endif // defined( MBG_TGT_WIN32 )
+ }
+
+} // show_syn1588_ptp_sync_status
static /*HDR*/
void collect_syn1588_info( MBG_DEV_HANDLE dh, DEVICE_STATUS *p_ds )
{
- int rc = mbg_get_syn1588_ptp_sync_status( dh, &p_ds->syn1588_ptp_syn_status );
- p_ds->syn1588_ptp_syn_status_avail = !mbg_cond_err_msg( rc, "mbg_get_syn1588_ptp_sync_status" );
+ int rc = mbg_get_syn1588_ptp_sync_status( dh, &p_ds->syn1588_ptp_sync_status );
+ p_ds->syn1588_ptp_sync_status_avail = !mbg_cond_err_msg( rc, "mbg_get_syn1588_ptp_sync_status" );
} // collect_syn1588_info
@@ -1553,7 +1666,7 @@ int check_all_device_features( MBG_DEV_HANDLE dh, DEVICE_STATUS *p_ds,
// p_ds->has_generic_io = mbg_rc_is_success( ( dh ) );
// p_ds->has_asic_version = mbg_rc_is_success( ( dh ) );
// p_ds->has_asic_features = mbg_rc_is_success( ( dh ) );
- // p_ds->has_xmr = mbg_rc_is_success( ( dh ) );
+ p_ds->has_xmr = mbg_rc_is_success( mbg_chk_dev_has_xmr( dh ) );
// p_ds->is_isa = mbg_rc_is_success( ( dh ) );
// p_ds->is_mca = mbg_rc_is_success( ( dh ) );
// p_ds->is_pci = mbg_rc_is_success( ( dh ) );
@@ -1639,9 +1752,7 @@ int collect_all_device_status( MBG_DEV_HANDLE dh, DEVICE_STATUS *p_ds )
static /*HDR*/
void print_all_device_status( const DEVICE_STATUS *p_ds )
{
- if ( p_ds->is_syn1588 )
- show_syn1588_info( p_ds );
- else
+ if ( !p_ds->is_syn1588 )
show_ext_stat_info( p_ds );
show_time_and_status( p_ds );
@@ -1651,6 +1762,9 @@ void print_all_device_status( const DEVICE_STATUS *p_ds )
show_irig_ctrl_bits( p_ds );
show_raw_irig_data( p_ds );
+ if ( p_ds->is_syn1588 )
+ show_syn1588_ptp_sync_status( p_ds );
+
} // print_all_device_status
@@ -1696,6 +1810,15 @@ int do_mbgstatus( MBG_DEV_HANDLE dh, const PCPS_DEV *p_dev )
if ( mbg_rc_is_success( mbg_chk_dev_has_ptp( dh ) ) )
show_ptp_state( dh );
+ if ( verbose >= 4 )
+ {
+ bool do_force_read = p_ds->has_xmr ? false : force_read;
+
+ if ( p_ds->has_xmr || do_force_read )
+ show_all_xmr_status( dh, do_force_read ? "MRS status (disabled, forced access):" : "MRS status:",
+ " ", verbose - 4, do_force_read );
+ }
+
show_invt_reason();
if ( loops > 0 )
@@ -1740,6 +1863,7 @@ void usage( void )
mbg_print_opt_info( "-s num", "Sleep num seconds between calls (implies -c)" );
mbg_print_opt_info( "-u num", "Sleep num microseconds between calls (implies -c)" );
mbg_print_opt_info( "-v", "Increase verbosity" );
+ mbg_print_opt_info( "-F", "Force-read data. This can be very dangerous, so use with care!" );
mbg_print_usage_outro( DEV_OPT_PRINT_BUS_LEVEL, true );
} // usage
@@ -1759,7 +1883,7 @@ int main( int argc, char *argv[] )
mbg_print_program_info( pname, MBG_FIRST_COPYRIGHT_YEAR, MBG_LAST_COPYRIGHT_YEAR );
// Check command line parameters.
- while ( ( c = getopt( argc, argv, "clLn:s:u:vh?" ) ) != -1 )
+ while ( ( c = getopt( argc, argv, "cFlLn:s:u:vh?" ) ) != -1 )
{
switch ( c )
{
@@ -1767,6 +1891,10 @@ int main( int argc, char *argv[] )
loops = -1;
break;
+ case 'F':
+ force_read = 1;
+ break;
+
case 'l':
list_only = 1;
break;
diff --git a/mingw/libmbg/makefile b/mingw/libmbg/makefile
index 0a89058..f0c01e0 100644
--- a/mingw/libmbg/makefile
+++ b/mingw/libmbg/makefile
@@ -1,13 +1,15 @@
#########################################################################
#
-# $Id: makefile 1.1 2021/11/11 16:03:28Z martin REL_M $
+# $Id: makefile 1.2 2022/07/08 12:00:00Z martin.burnicki REL_M $
#
# Description:
# Makefile for libmbg.
#
# -----------------------------------------------------------------------
# $Log: makefile $
+# Revision 1.2 2022/07/08 12:00:00Z martin.burnicki
+# Updated object file list.
# Revision 1.1 2021/11/11 16:03:28Z martin
# Initial revision
#
@@ -32,6 +34,9 @@ OBJS += pcpsmktm.o
OBJS += str_util.o
OBJS += timeutil.o
OBJS += toolutil.o
+OBJS += mbg_syn1588_util.o
+OBJS += mbg_xmr_util.o
+OBJS += mbg_xmr_util_devio.o
BASEDIR := ..
include $(BASEDIR)/Makefile
diff --git a/vc6/mbgstatus/mbgstatus.dsp b/vc6/mbgstatus/mbgstatus.dsp
index 6f8f664..a639b6f 100644
--- a/vc6/mbgstatus/mbgstatus.dsp
+++ b/vc6/mbgstatus/mbgstatus.dsp
@@ -107,6 +107,18 @@ SOURCE=..\..\mbglib\common\lan_util.c
# End Source File
# Begin Source File
+SOURCE=..\..\mbglib\common\mbg_syn1588_util.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\mbglib\common\mbg_xmr_util.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\mbglib\common\mbg_xmr_util_devio.c
+# End Source File
+# Begin Source File
+
SOURCE=..\..\mbglib\common\mbgerror.c
# End Source File
# Begin Source File
@@ -203,6 +215,14 @@ SOURCE=..\..\mbglib\common\mbg_serclock_cfg.h
# End Source File
# Begin Source File
+SOURCE=..\..\mbglib\common\mbg_syn1588_defs.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\mbglib\common\mbg_syn1588_util.h
+# End Source File
+# Begin Source File
+
SOURCE=..\..\mbglib\common\mbg_tgt.h
# End Source File
# Begin Source File
@@ -211,6 +231,14 @@ SOURCE=..\..\mbglib\win32\mbg_w32.h
# End Source File
# Begin Source File
+SOURCE=..\..\mbglib\common\mbg_xmr_util.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\mbglib\common\mbg_xmr_util_devio.h
+# End Source File
+# Begin Source File
+
SOURCE=..\..\mbglib\common\mbgadjtm_cfg.h
# End Source File
# Begin Source File
diff --git a/vs2008/mbgstatus/mbgstatus.vcproj b/vs2008/mbgstatus/mbgstatus.vcproj
index d3a1e5b..600f774 100644
--- a/vs2008/mbgstatus/mbgstatus.vcproj
+++ b/vs2008/mbgstatus/mbgstatus.vcproj
@@ -333,6 +333,18 @@
>
</File>
<File
+ RelativePath="..\..\mbglib\common\mbg_syn1588_util.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\mbglib\common\mbg_xmr_util.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\mbglib\common\mbg_xmr_util_devio.c"
+ >
+ </File>
+ <File
RelativePath="..\..\mbglib\common\mbgerror.c"
>
</File>