From aff6504db82f1ff615cdad8953cf129f567e3efe Mon Sep 17 00:00:00 2001 From: Martin Burnicki Date: Wed, 26 Aug 2020 17:32:59 +0200 Subject: Add example program 'set-serial-port' Update unix/Makefile to be able to build multiple targets, and add 'set-serial-port' to the targets. Add a 'set-serial-port' project to the Windows/VS2008 solution. The Windows/VC6 workspace has not been updated. --- set-serial-port.c | 379 +++++++++++++++++++++++++ unix/Makefile | 135 +++++---- windows/vs2008/gpsxmple.sln | 10 + windows/vs2008/set-serial-port.vcproj | 518 ++++++++++++++++++++++++++++++++++ 4 files changed, 991 insertions(+), 51 deletions(-) create mode 100644 set-serial-port.c create mode 100644 windows/vs2008/set-serial-port.vcproj diff --git a/set-serial-port.c b/set-serial-port.c new file mode 100644 index 0000000..a9835e1 --- /dev/null +++ b/set-serial-port.c @@ -0,0 +1,379 @@ + +/************************************************************************** + * + * Example program demonstrating how to configure the serial port + * of a Meinberg device using the Meinberg binary protocol. + * + **************************************************************************/ + +#include +#include + + + +// NOTE: Future versions of the API will provide this type, +// and the local declaration here will then becomme obsolete, +// but for now we already use it in the subsequent code. +typedef int16_t MBG_MSG_IDX; + + + +// A local array of the names of known string modes that may +// be supported by a the serial port of a device. +static const char *mode_names[N_STR_MODE] = DEFAULT_ENG_MODE_NAMES; + + + +static /*HDR*/ +/** + * @brief Print the list of time string formats supported by a device. + * + * The function ::mbgextio_get_serial_settings must have been called before + * to read the current settings and configuration options and store them + * in a ::RECEIVER_PORT_CFG structure. + * + * @param[in,out] pmctl Pointer to a valid message control structure. + * @param[in] p_rpcfg Pointer to a ::RECEIVER_PORT_CFG structure containing valid data. + * + * @return One of the @ref MBG_RETURN_CODES + */ +void print_supp_str_types( MBG_MSG_CTL *pmctl, const RECEIVER_PORT_CFG *p_rpcfg ) +{ + // Set up a pointer to the RECEIVER_INFO structure associated + // with the device to access basic device information. + const RECEIVER_INFO *p_ri = mbgextio_get_receiver_info_addr( pmctl ); + + int i; + + + printf( "Supported String Types with Index:\n" ); + + for ( i = 0; i < p_ri->n_str_type; i++ ) + { + // Set up a pointer to the STR_TYPE_INFO structure for index i. + const STR_TYPE_INFO *p_sti = &p_rpcfg->stii[i].str_type_info; + + printf( " %2i %s\n", i, p_sti->long_name ); + } + +} // print_supp_str_types + + + +static /*HDR*/ +/** + * @brief Print the serial setting of a specific port of the device. + * + * The function ::mbgextio_get_serial_settings must have been called before + * to read the current settings and configuration options and store them + * in a ::RECEIVER_PORT_CFG structure. + * + * @param[in,out] pmctl Pointer to a valid message control structure. + * @param[in] port_idx Index of the serial port for which to print the settings. + * @param[in] p_rpcfg Pointer to a ::RECEIVER_PORT_CFG structure containing valid data. + * + * @return One of the @ref MBG_RETURN_CODES + */ +void print_serial_settings( MBG_MSG_CTL *pmctl, MBG_MSG_IDX port_idx, const RECEIVER_PORT_CFG *p_rpcfg ) +{ + // A pointer to the PORT_INFO structure of the specific port + // that provides a sub-structure with the current settings + // as well as the supported configuration options. + const PORT_INFO *p_pi = &p_rpcfg->pii[port_idx].port_info; + + // And another pointer to the configuration settings. + const PORT_SETTINGS *p_ps = &p_pi->port_settings; + + // The port configuration provides an index to an array of supported string + // types. This pointer will be set to the associated STR_TYPE_INFO entry. + const STR_TYPE_INFO *p_sti; + + + // Display the configuration settings. + printf( " COM%i: %5lu Baud, %s", + port_idx, + (ulong) p_ps->parm.baud_rate, + p_ps->parm.framing + ); + + + // Make sure the indices included in the settings read from the device + // don't exceed the maximum numbers supported by this program. + + if ( p_ps->str_type >= MAX_PARM_STR_TYPE ) + { + printf( " (string type index %i exceeds max %i)", p_ps->str_type, MAX_PARM_STR_TYPE - 1 ); + goto out; + } + + + if ( p_ps->mode >= N_STR_MODE ) + { + printf( " (string mode %i exceeds max %i)", p_ps->mode, N_STR_MODE - 1 ); + goto out; + } + + + // The port configuration provides an index to an array of supported string + // types, so set up a pointer to the associated STR_TYPE_INFO entry. + p_sti = &p_rpcfg->stii[p_ps->str_type].str_type_info; + + // Now we can print the name of the string type, and the configured string mode. + printf( ", \"%s\" string %s", p_sti->long_name, mode_names[p_ps->mode] ); + + +out: + printf( "\n" ); + +} // print_serial_settings + + + +static /*HDR*/ +/** + * @brief Check if new serial port setting yield a valid configuration. + * + * The function ::mbgextio_get_serial_settings must have been called before + * to read the current settings and configuration options and store them + * in a ::RECEIVER_PORT_CFG structure. + * + * @param[in,out] pmctl Pointer to a valid message control structure. + * @param[in] p_rpcfg Pointer to a ::RECEIVER_PORT_CFG structure containing valid data. + * @param[in] port_idx Index of the serial port for which to check the settings. + * @param[in] new_str_type_idx New string type index to be set. Supported values depend on device. + * @param[in] new_str_mode New string mode to be set. See enum STR_MODES. + * + * @return One of the @ref MBG_RETURN_CODES + */ +int check_serial_port_settings( MBG_MSG_CTL *pmctl, RECEIVER_PORT_CFG *p_rpcfg, + MBG_MSG_IDX port_idx, int new_str_type_idx, int new_str_mode ) +{ + // Set up a pointer to the RECEIVER_INFO structure associated + // with the device to access basic device information. + const RECEIVER_INFO *p_ri = mbgextio_get_receiver_info_addr( pmctl ); + + // A pointer to the PORT_INFO structure of the specific port + // that provides a sub-structure with the current settings + // as well as the supported configuration options. + PORT_INFO *p_pi; + + // A pointer that will be set to the address of a specific + // string type info in the array read from the device. + const STR_TYPE_INFO *p_sti; + + int rc; + + + // First make sure the given port_idx doesn't exceed the number of ports + // supported by the device. + if ( port_idx >= p_ri->n_com_ports ) + { + rc = MBG_ERR_N_COM_EXCEEDS_SUPP; + goto out; + } + + + // Get a pointer to the PORT_INFO structure associated with port_idx, + // which provides a mask of string types supported by this port. + p_pi = &p_rpcfg->pii[port_idx].port_info; + + if ( !( p_pi->supp_str_types & ( 1UL << new_str_type_idx ) ) ) + { + rc = MBG_ERR_NOT_SUPP_BY_DEV; + goto out; + } + + + // The new string type index is valid. Now check if the + // new mode is supported, which depends on the string type. + p_sti = &p_rpcfg->stii[new_str_type_idx].str_type_info; + + if ( !( p_sti->supp_modes & ( 1UL << new_str_mode ) ) ) + { + rc = MBG_ERR_NOT_SUPP_BY_DEV; + goto out; + } + + // All parameters are in range and supported. + rc = MBG_SUCCESS; + +out: + return rc; + +} // check_serial_port_settings + + + +static /*HDR*/ +/** + * @brief Example function to print and change a serial port configuration. + * + * The function ::mbgextio_get_serial_settings must have been called before + * to read the current settings and configuration options and store them + * in a ::RECEIVER_PORT_CFG structure. + * + * @param[in,out] pmctl Pointer to a valid message control structure. + * @param[in] p_addr Pointer to an XBP address specifier, or NULL. + * + * @return One of the @ref MBG_RETURN_CODES + * + * @see ::mbgextio_get_serial_settings + * @see ::mbgextio_save_serial_settings + */ +int do_configure_serial_port( MBG_MSG_CTL *pmctl, XBP_ADDR *p_addr ) +{ + // Index of the serial port to be configured. + // Can be 0..RECEIVER_INFO::n_com_ports-1. + MBG_MSG_IDX port_idx = 1; + + // Index of the new string type to be set. Depends on device, + // but usually 0 refers to the Meinberg Standard Time String. + int new_str_type_idx = 0; + + // New string mode to be set. See enum STR_MODES. + int new_str_mode = STR_PER_SEC; + + // Set up a pointer to the RECEIVER_INFO structure associated + // with the device to access basic device information. + const RECEIVER_INFO *p_ri = mbgextio_get_receiver_info_addr( pmctl ); + + // This structure takes up the current configuration and + // the supported configuration options of all serial ports + // of a device. + RECEIVER_PORT_CFG rpcfg; + + // A pointer to the PORT_INFO structure of the specific port + // that provides a sub-structure with the current settings + // as well as the supported configuration options. + PORT_INFO *p_pi; + + // And another pointer to the configuration settings to be updated. + PORT_SETTINGS *p_ps; + + int i; + + // Read all serial port configuration info from the device. + int rc = mbgextio_get_serial_settings( pmctl, p_addr, &rpcfg ); + + if ( mbg_rc_is_error( rc ) ) + { + fprintf( stderr, "Failed to read serial settings: %s\n", mbg_strerror( rc ) ); + goto out; + } + + + // Print a list of time string types supported by the device. + print_supp_str_types( pmctl, &rpcfg ); + printf( "\n" ); + + + // Print the current configuration of all serial ports. + // show_all_serial_settings( pmctl, &rpcfg, "Current " ); + + printf( "Current Serial Port Settings:\n" ); + + for ( i = 0; i < p_ri->n_com_ports; i++ ) + print_serial_settings( pmctl, i, &rpcfg ); + + printf( "\n" ); + + + // Check if the new settings to be sent to the device are valid. + rc = check_serial_port_settings( pmctl, &rpcfg, port_idx, + new_str_type_idx, new_str_mode ); + + if ( mbg_rc_is_error( rc ) ) + { + fprintf( stderr, "New serial port settings are invalid: %s\n", mbg_strerror( rc ) ); + goto out; + } + + + // Set up a pointer to the settings for the port, and + // update the relevant settings. + p_pi = &rpcfg.pii[port_idx].port_info; + p_ps = &p_pi->port_settings; + + p_ps->str_type = new_str_type_idx; + p_ps->mode = new_str_mode; + + // Write the new settings to the device. + rc = mbgextio_save_serial_settings( pmctl, p_addr, &rpcfg, port_idx ); + + if ( mbg_rc_is_error( rc ) ) + { + fprintf( stderr, "Failed to write new settings for COM%i: %s\n", port_idx, mbg_strerror( rc ) ); + goto out; + } + + printf( "Successfully wrote new settings for COM%i.\n", port_idx ); + printf( "\n" ); + + // Re-read the new settings. + rc = mbgextio_get_serial_settings( pmctl, p_addr, &rpcfg ); + + if ( mbg_rc_is_error( rc ) ) + { + fprintf( stderr, "Failed to re-read serial settings: %s\n", mbg_strerror( rc ) ); + goto out; + } + + // Print the new settings for the port that has been changed. + print_serial_settings( pmctl, port_idx, &rpcfg ); + +out: + return rc; + +} // do_configure_serial_port + + + +int main( int argc, char *argv[] ) +{ + // Device "handle" set up when a device is opened. + MBG_MSG_CTL *pmctl = NULL; + + // A sub-device address, not used here, so NULL + XBP_ADDR *p_addr = NULL; + + // Default baud rate and framing used to connect to a device. + // Newer devices may use MBG_DEFAULT_BAUDRATE_HS by default. + BAUD_RATE baudrate = MBG_DEFAULT_BAUDRATE; + const char framing[] = MBG_DEFAULT_FRAMING; + + // Name of the serial port of the computer, to which the device + // is connected, e.g. COM1 (Windows), or /dev/ttyS0 (Linux). + const char *port_name; + + int rc; + + // Check if a port name has been specified on the command line. + if ( argc < 2 ) + { + fprintf( stderr, "Serial port identifier expected as parameter, exiting.\n" ); + return 1; + } + + + // Now open a connection to the device. Here we connect via a serial line. + // For other types of connection use one of the other use mbgextio_open_...() + // functions. See mbgextio.h. + port_name = argv[1]; + rc = mbgextio_open_serial( port_name, &pmctl, baudrate, framing ); + + if ( mbg_rc_is_error( rc ) ) // Connection couldn't be established. + { + fprintf( stderr, "Failed to connect via %s: %s\n", port_name, mbg_strerror( rc ) ); + return 2; + } + + // Now configure the serial port of the connected device. + rc = do_configure_serial_port( pmctl, p_addr ); + + // Finally close the connection-> + mbgextio_close_connection( &pmctl ); + + return mbg_rc_is_error( rc ) ? 3 : 0; + +} // main + diff --git a/unix/Makefile b/unix/Makefile index 9b856d6..dba01df 100644 --- a/unix/Makefile +++ b/unix/Makefile @@ -1,41 +1,30 @@ - ######################################################################### # -# $Id: Makefile 1.9 2017/04/12 08:49:33 martin TEST $ -# -# Description: -# Makefile for gpsxmple for Unix-like systems. -# Currently supported OSs: Linux, QNX 6.x -# -# ----------------------------------------------------------------------- -# $Log: Makefile $ -# Revision 1.9 2017/04/12 08:49:33 martin -# Changed CFLAGS to CPPFLAGS. -# Revision 1.8 2017/04/05 16:08:53 martin -# Added some library modules. -# Revision 1.7 2014/10/30 13:50:04 martin -# Added module mbgerror.o. -# Revision 1.6 2013/02/01 16:11:27 martin -# Added extiohlp module to the list of object files. -# Revision 1.5 2011/08/19 07:26:40 martin -# Modified the way to define targets etc. -# Revision 1.4 2011/04/18 08:08:41 martin -# Modified DEBUG handling. -# Revision 1.3 2009/10/01 14:09:19 martin -# Added mbgserio.c source module. -# Revision 1.2 2006/08/22 15:49:27 martin -# Moved this makefile for Unix-like systems to folder unix. -# This build environment now supports Linux and QNX 6.x. -# Network socket I/O is supported for both Linux and QNX. -# Serial I/O is not yet supprted for QNX, but for Linux. -# Account for mbglib files having been moved to subdirectory mbglib. -# Build with debug if make is called with DEBUG=1. -# Added library modules mbgextio.c and aes128.c. -# Revision 1.1 2004/06/01 14:55:27 martin +# Makefile for 'gpsxmple' for Unix-like systems. +# Currently supported OSs: Linux, QNX 6.x # ######################################################################### -TARGET = gpsxmple +MBG_TARGET_1 = gpsxmple +MBG_TARGET_2 = set-serial-port +MBG_TARGETS = $(MBG_TARGET_1) $(MBG_TARGET_2) + + +# Set V to 1 to build verbosely. +V ?= 0 + +# The lines below make the build output non-verbose by default. +# Call make with parameter "V=1" to get verbose output. +ifneq ("$(V)","0") + Q := + QM := + vecho = @true +else + Q := @ + QM := -s + vecho = @echo +endif + MBGLIB = ../mbglib MBGLIB_DIRS += common @@ -43,19 +32,30 @@ MBGLIB_DIRS += common VPATH += .. VPATH += $(foreach dir,$(MBGLIB_DIRS),$(MBGLIB)/$(dir)) -OBJS = $(TARGET).o -OBJS += extiohlp.o -OBJS += xtiocomm.o -OBJS += cfg_hlp.o -OBJS += mbgextio.o -OBJS += mbgserio.o -OBJS += gpsserio.o -OBJS += gpsutils.o -OBJS += aes128.o -OBJS += mbgerror.o -OBJS += str_util.o -OBJS += lan_util.o -OBJS += xdevfeat.o + +# List of object files for an intermediate, static library. +LIB_OBJS += extiohlp.o +LIB_OBJS += xtiocomm.o +LIB_OBJS += cfg_hlp.o +LIB_OBJS += mbgextio.o +LIB_OBJS += mbgserio.o +LIB_OBJS += gpsserio.o +LIB_OBJS += gpsutils.o +LIB_OBJS += aes128.o +LIB_OBJS += mbgerror.o +LIB_OBJS += str_util.o +LIB_OBJS += lan_util.o +LIB_OBJS += xdevfeat.o + + + +MBG_LIB_BASENAME = mbg +MBG_LIB_FILE = lib$(MBG_LIB_BASENAME).a + + +LDLIBS += $(MBG_LIB_FILE) + + # Try to determine whether the OS is QNX OS_IS_QNX := $(shell uname | grep -i QNX && echo "QNX" ) @@ -88,19 +88,52 @@ else endif -LD = $(CC) + +%.o: %.c + $(vecho) " $(CC) $@" + $(Q)$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $< + + +%.o: %.cpp + $(vecho) " $(CC) $@" + $(Q)$(CC) $(CPPFLAGS) $(CXXLAGS) -c -o $@ $< + + .PHONY: all -all: $(TARGET) +all: $(MBG_TARGETS) + + + +$(MBG_TARGETS): $(MBG_LIB_FILE) + $(vecho) " Linking $@" + $(Q)$(CC) -o $@ $(LDFLAGS) $@.o $(OBJS) $(LDLIBS) + +$(MBG_TARGET_1): $(MBG_TARGET_1).o +$(MBG_TARGET_2): $(MBG_TARGET_2).o + + + +# Options for the archiver to build a static library +ARFLAGS := rcs +ifneq ("$(V)","0") + # In verbose mode we also make the archiver verbose. + ARFLAGS := $(ARFLAGS)v +endif + + +$(MBG_LIB_FILE): $(LIB_OBJS) + $(vecho) " $(AR) $@" + $(Q)$(AR) $(ARFLAGS) $@ $(LIB_OBJS) + -$(TARGET): $(OBJS) - $(LD) $(LDFLAGS) -o $@ $(OBJS) .PHONY: clean clean: rm -f *.o *~ core - rm -f $(TARGET) + rm -f $(MBG_LIB_FILE) + rm -f $(MBG_TARGETS) .PHONY: distclean distclean: clean diff --git a/windows/vs2008/gpsxmple.sln b/windows/vs2008/gpsxmple.sln index 53f7478..0a18edf 100644 --- a/windows/vs2008/gpsxmple.sln +++ b/windows/vs2008/gpsxmple.sln @@ -3,6 +3,8 @@ Microsoft Visual Studio Solution File, Format Version 10.00 # Visual C++ Express 2008 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gpsxmple", "gpsxmple.vcproj", "{7F92F474-7257-4F71-B218-43491D36CAA3}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "set-serial-port", "set-serial-port.vcproj", "{72684B0F-1D39-4845-8B83-DF10A2C25A5D}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -19,6 +21,14 @@ Global {7F92F474-7257-4F71-B218-43491D36CAA3}.Release|Win32.Build.0 = Release|Win32 {7F92F474-7257-4F71-B218-43491D36CAA3}.Release|x64.ActiveCfg = Release|Win32 {7F92F474-7257-4F71-B218-43491D36CAA3}.Release|x64.Build.0 = Release|Win32 + {72684B0F-1D39-4845-8B83-DF10A2C25A5D}.Debug|Win32.ActiveCfg = Debug|Win32 + {72684B0F-1D39-4845-8B83-DF10A2C25A5D}.Debug|Win32.Build.0 = Debug|Win32 + {72684B0F-1D39-4845-8B83-DF10A2C25A5D}.Debug|x64.ActiveCfg = Debug|Win32 + {72684B0F-1D39-4845-8B83-DF10A2C25A5D}.Debug|x64.Build.0 = Debug|Win32 + {72684B0F-1D39-4845-8B83-DF10A2C25A5D}.Release|Win32.ActiveCfg = Release|Win32 + {72684B0F-1D39-4845-8B83-DF10A2C25A5D}.Release|Win32.Build.0 = Release|Win32 + {72684B0F-1D39-4845-8B83-DF10A2C25A5D}.Release|x64.ActiveCfg = Release|Win32 + {72684B0F-1D39-4845-8B83-DF10A2C25A5D}.Release|x64.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/windows/vs2008/set-serial-port.vcproj b/windows/vs2008/set-serial-port.vcproj new file mode 100644 index 0000000..0303096 --- /dev/null +++ b/windows/vs2008/set-serial-port.vcproj @@ -0,0 +1,518 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- cgit v1.2.3