diff options
Diffstat (limited to 'set-serial-port.c')
-rw-r--r-- | set-serial-port.c | 379 |
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 + |