diff --git a/Makefile.am b/Makefile.am index b2a1293..426ceac 100644 --- a/Makefile.am +++ b/Makefile.am @@ -65,7 +65,8 @@ EXTRA_DIST = Doxyfile \ examples/Makefile \ examples/README \ examples/list_ports.c \ - examples/port_info.c + examples/port_info.c \ + examples/port_config.c MAINTAINERCLEANFILES = ChangeLog diff --git a/examples/.gitignore b/examples/.gitignore index 08bb5d3..6f681be 100644 --- a/examples/.gitignore +++ b/examples/.gitignore @@ -1,2 +1,3 @@ list_ports port_info +port_config diff --git a/examples/port_config.c b/examples/port_config.c new file mode 100644 index 0000000..2966e63 --- /dev/null +++ b/examples/port_config.c @@ -0,0 +1,166 @@ +#include +#include +#include + +/* Example of how to configure a serial port. + * + * This example file is released to the public domain. */ + +/* Helper function for error handling. */ +int check(enum sp_return result); + +/* Helper function to give a name for each parity mode. */ +const char *parity_name(enum sp_parity parity); + +int main(int argc, char **argv) +{ + /* Get the port name from the command line. */ + if (argc != 2) { + printf("Usage: %s \n", argv[0]); + return -1; + } + char *port_name = argv[1]; + + /* A pointer to a struct sp_port, which will refer to + * the port found. */ + struct sp_port *port; + + printf("Looking for port %s.\n", port_name); + + /* Call sp_get_port_by_name() to find the port. The port + * pointer will be updated to refer to the port found. */ + check(sp_get_port_by_name(port_name, &port)); + + /* Display some basic information about the port. */ + printf("Port name: %s\n", sp_get_port_name(port)); + printf("Description: %s\n", sp_get_port_description(port)); + + /* The port must be open to access its configuration. */ + printf("Opening port.\n"); + check(sp_open(port, SP_MODE_READ_WRITE)); + + /* There are two ways to access a port's configuration: + * + * 1. You can read and write a whole configuration (all settings at + * once) using sp_get_config() and sp_set_config(). This is handy + * if you want to change between some preset combinations, or save + * and restore an existing configuration. It also ensures the + * changes are made together, via an efficient set of calls into + * the OS - in some cases a single system call can be used. + * + * Use accessor functions like sp_get_config_baudrate() and + * sp_set_config_baudrate() to get and set individual settings + * from a configuration. + * + * Configurations are allocated using sp_new_config() and freed + * with sp_free_config(). You need to manage them yourself. + * + * 2. As a shortcut, you can set individual settings on a port + * directly by calling functions like sp_set_baudrate() and + * sp_set_parity(). This saves you the work of allocating + * a temporary config, setting it up, applying it to a port + * and then freeing it. + * + * In this example we'll do a bit of both: apply some initial settings + * to the port, read out that config and display it, then switch to a + * different configuration and back using sp_set_config(). */ + + /* First let's set some initial settings directly on the port. + * + * You should always configure all settings before using a port. + * There are no "default" settings applied by libserialport. + * When you open a port it has the defaults from the OS or driver, + * or the settings left over by the last program to use it. */ + printf("Setting port to 115200 8N1, no flow control.\n"); + check(sp_set_baudrate(port, 115200)); + check(sp_set_bits(port, 8)); + check(sp_set_parity(port, SP_PARITY_NONE)); + check(sp_set_stopbits(port, 1)); + check(sp_set_flowcontrol(port, SP_FLOWCONTROL_NONE)); + + /* A pointer to a struct sp_port_config, which we'll use for the config + * read back from the port. The pointer will be set by sp_new_config(). */ + struct sp_port_config *initial_config; + + /* Allocate a configuration for us to read the port config into. */ + check(sp_new_config(&initial_config)); + + /* Read the current config from the port into that configuration. */ + check(sp_get_config(port, initial_config)); + + /* Display some of the settings read back from the port. */ + int baudrate, bits, stopbits; + enum sp_parity parity; + check(sp_get_config_baudrate(initial_config, &baudrate)); + check(sp_get_config_bits(initial_config, &bits)); + check(sp_get_config_stopbits(initial_config, &stopbits)); + check(sp_get_config_parity(initial_config, &parity)); + printf("Baudrate: %d, data bits: %d, parity: %s, stop bits: %d\n", + baudrate, bits, parity_name(parity), stopbits); + + /* Create a different configuration to have ready for use. */ + printf("Creating new config for 9600 7E2, XON/XOFF flow control.\n"); + struct sp_port_config *other_config; + check(sp_new_config(&other_config)); + check(sp_set_config_baudrate(other_config, 9600)); + check(sp_set_config_bits(other_config, 7)); + check(sp_set_config_parity(other_config, SP_PARITY_EVEN)); + check(sp_set_config_stopbits(other_config, 2)); + check(sp_set_config_flowcontrol(other_config, SP_FLOWCONTROL_XONXOFF)); + + /* We can apply the new config to the port in one call. */ + printf("Applying new configuration.\n"); + check(sp_set_config(port, other_config)); + + /* And now switch back to our original config. */ + printf("Setting port back to previous config.\n"); + check(sp_set_config(port, initial_config)); + + /* Now clean up by closing the port and freeing structures. */ + check(sp_close(port)); + sp_free_port(port); + sp_free_config(initial_config); + sp_free_config(other_config); + + return 0; +} + +/* Helper function for error handling. */ +int check(enum sp_return result) +{ + /* For this example we'll just exit on any error by calling abort(). */ + char *error_message; + switch (result) { + case SP_ERR_ARG: + printf("Error: Invalid argument.\n"); + abort(); + case SP_ERR_FAIL: + error_message = sp_last_error_message(); + printf("Error: Failed: %s\n", error_message); + sp_free_error_message(error_message); + abort(); + case SP_ERR_SUPP: + printf("Error: Not supported.\n"); + abort(); + case SP_ERR_MEM: + printf("Error: Couldn't allocate memory.\n"); + abort(); + case SP_OK: + default: + return result; + } +} + +/* Helper function to give a name for each parity mode. */ +const char *parity_name(enum sp_parity parity) +{ + switch (parity) { + case SP_PARITY_INVALID: return "(Invalid)"; + case SP_PARITY_NONE: return "None"; + case SP_PARITY_ODD: return "Odd"; + case SP_PARITY_EVEN: return "Even"; + case SP_PARITY_MARK: return "Mark"; + case SP_PARITY_SPACE: return "Space"; + default: return NULL; + } +} diff --git a/libserialport.h b/libserialport.h index 33f3e91..1bed953 100644 --- a/libserialport.h +++ b/libserialport.h @@ -67,6 +67,7 @@ * * - @ref list_ports.c - Getting a list of ports present on the system. * - @ref port_info.c - Getting information on a particular serial port. + * - @ref port_config.c - Accessing configuration settings of a port. * * These examples are linked with the API documentation. Each function * in the API reference includes links to where it is used in an example @@ -1747,6 +1748,7 @@ SP_API const char *sp_get_lib_version_string(void); /** * @example list_ports.c Getting a list of ports present on the system. * @example port_info.c Getting information on a particular serial port. + * @example port_config.c Accessing configuration settings of a port. */ #ifdef __cplusplus