summaryrefslogtreecommitdiff
path: root/set-serial-port.c
diff options
context:
space:
mode:
Diffstat (limited to 'set-serial-port.c')
-rw-r--r--set-serial-port.c379
1 files changed, 379 insertions, 0 deletions
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 <mbgextio.h>
+#include <extiohlp.h>
+
+
+
+// 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
+