diff --git a/Makefile.am b/Makefile.am index 426ceac..d7e9fad 100644 --- a/Makefile.am +++ b/Makefile.am @@ -66,7 +66,8 @@ EXTRA_DIST = Doxyfile \ examples/README \ examples/list_ports.c \ examples/port_info.c \ - examples/port_config.c + examples/port_config.c \ + examples/handle_errors.c MAINTAINERCLEANFILES = ChangeLog diff --git a/examples/.gitignore b/examples/.gitignore index 6f681be..80e56ce 100644 --- a/examples/.gitignore +++ b/examples/.gitignore @@ -1,3 +1,4 @@ +handle_errors list_ports port_info port_config diff --git a/examples/handle_errors.c b/examples/handle_errors.c new file mode 100644 index 0000000..da8e8e9 --- /dev/null +++ b/examples/handle_errors.c @@ -0,0 +1,116 @@ +#include +#include +#include + +/* Example of how to handle errors from libserialport. + * + * This example file is released to the public domain. */ + +/* Pointers used in the program to resources that may need to be freed. */ +struct sp_port **port_list = NULL; +struct sp_port_config *config = NULL; +struct sp_port *port = NULL; + +/* Example of a function to clean up and exit the program with a given return code. */ +void end_program(int return_code) +{ + /* Free any structures we allocated. */ + if (port_list != NULL) + sp_free_port_list(port_list); + if (config != NULL) + sp_free_config(config); + if (port != NULL) + sp_free_port(port); + + /* Exit with the given return code. */ + exit(return_code); +} + +/* Example of a helper function for error handling. */ +int check(enum sp_return result) +{ + int error_code; + char *error_message; + switch (result) { + + /* Handle each of the four negative error codes that can be returned. + * + * In this example, we will end the program on any error, using + * a different return code for each possible class of error. */ + + case SP_ERR_ARG: + /* When SP_ERR_ARG is returned, there was a problem with one + * or more of the arguments passed to the function, e.g. a null + * pointer or an invalid value. This generally implies a bug in + * the calling code. */ + printf("Error: Invalid argument.\n"); + end_program(1); + + case SP_ERR_FAIL: + /* When SP_ERR_FAIL is returned, there was an error from the OS, + * which we can obtain the error code and message for. These + * calls must be made in the same thread as the call that + * returned SP_ERR_FAIL, and before any other system functions + * are called in that thread, or they may not return the + * correct results. */ + error_code = sp_last_error_code(); + error_message = sp_last_error_message(); + printf("Error: Failed: OS error code: %d, message: '%s'\n", + error_code, error_message); + /* The error message should be freed after use. */ + sp_free_error_message(error_message); + end_program(2); + + case SP_ERR_SUPP: + /* When SP_ERR_SUPP is returned, the function was asked to do + * something that isn't supported by the current OS or device, + * or that libserialport doesn't know how to do in the current + * version. */ + printf("Error: Not supported.\n"); + end_program(3); + + case SP_ERR_MEM: + /* When SP_ERR_MEM is returned, libserialport wasn't able to + * allocate some memory it needed. Since the library doesn't + * normally use any large data structures, this probably means + * the system is critically low on memory and recovery will + * require very careful handling. The library itself will + * always try to handle any allocation failure safely. + * + * In this example, we'll just try to exit gracefully without + * calling printf, which might need to allocate further memory. */ + end_program(4); + + case SP_OK: + default: + /* A return value of SP_OK, defined as zero, means that the + * operation succeeded. */ + printf("Operation succeeded.\n"); + + /* Some fuctions can also return a value greater than zero to + * indicate a numeric result, such as the number of bytes read by + * sp_blocking_read(). So when writing an error handling wrapper + * function like this one, it's helpful to return the result so + * that it can be used. */ + return result; + } +} + +int main(int argc, char **argv) +{ + /* Call some functions that should not result in errors. */ + + printf("Getting list of ports.\n"); + check(sp_list_ports(&port_list)); + + printf("Creating a new port configuration.\n"); + check(sp_new_config(&config)); + + /* Now make a function call that will result in an error. */ + + printf("Trying to find a port that doesn't exist.\n"); + check(sp_get_port_by_name("NON-EXISTENT-PORT", &port)); + + /* We could now clean up and exit normally if an error hadn't occured. */ + end_program(0); +} diff --git a/libserialport.h b/libserialport.h index 09af4ff..65f9679 100644 --- a/libserialport.h +++ b/libserialport.h @@ -68,6 +68,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. + * - @ref handle_errors.c - Handling errors returned from the library. * * These examples are linked with the API documentation. Each function * in the API reference includes links to where it is used in an example @@ -1596,6 +1597,8 @@ SP_API enum sp_return sp_end_break(struct sp_port *port); * * Obtaining error information. * + * See @ref handle_errors.c for an example of error handling. + * * @{ */ @@ -1806,6 +1809,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. + * @example handle_errors.c - Handling errors returned from the library. */ #ifdef __cplusplus