From 56d5666ae908ba140d34cc2d13253c837fa53c5a Mon Sep 17 00:00:00 2001 From: Tapani Utriainen Date: Fri, 19 May 2017 21:31:39 +0800 Subject: [PATCH] mraa-uart: add a tool for testing, using and debugging UARTs using MRAA This patch introduces examples/mraa-uart that can be used as a general tool for UART communication and UART settings. The syntax mimics the one used for mraa-gpio. This is an initial version, beware of insects. Signed-off-by: Tapani Utriainen Signed-off-by: Brendan Le Foll --- examples/CMakeLists.txt | 3 + examples/mraa-uart.c | 306 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 309 insertions(+) create mode 100644 examples/mraa-uart.c diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 118140f..3adc6ac 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -11,6 +11,7 @@ add_executable (blink_onboard blink_onboard.c) add_executable (uart uart.c) add_executable (mraa-gpio mraa-gpio.c) add_executable (mraa-i2c mraa-i2c.c) +add_executable (mraa-uart mraa-uart.c) add_executable (spi_max7219 spi_max7219.c) if (NOT ANDROID_TOOLCHAIN) add_executable (iio_driver iio_driver.c) @@ -34,6 +35,7 @@ target_link_libraries (blink_onboard mraa) target_link_libraries (uart mraa) target_link_libraries (mraa-gpio mraa) target_link_libraries (mraa-i2c mraa) +target_link_libraries (mraa-uart mraa) target_link_libraries (spi_max7219 mraa) if (NOT ANDROID_TOOLCHAIN) target_link_libraries (iio_driver mraa) @@ -63,4 +65,5 @@ endif() if (INSTALLTOOLS) install (TARGETS mraa-gpio DESTINATION bin) install (TARGETS mraa-i2c DESTINATION bin) + install (TARGETS mraa-uart DESTINATION bin) endif() diff --git a/examples/mraa-uart.c b/examples/mraa-uart.c new file mode 100644 index 0000000..b829457 --- /dev/null +++ b/examples/mraa-uart.c @@ -0,0 +1,306 @@ +/* + * Author: Tapani Utriainen + * Copyright (c) 2017 TechNexion Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +#include "mraa.h" + +#ifndef FALSE +#define FALSE 0 +#define TRUE (!FALSE) +#endif + +static const char *undefined = ""; + +static const char paritymode_table[] = { + [MRAA_UART_PARITY_NONE] = 'N', + [MRAA_UART_PARITY_EVEN] = 'E', + [MRAA_UART_PARITY_ODD] = 'O', + [MRAA_UART_PARITY_MARK] = 'M', + [MRAA_UART_PARITY_SPACE] = 'S' +}; + +/* ------------------------------------------------------------------------ */ + +mraa_uart_context +uarttool_find(const char *str) { + /* Try to find the uart by name, then by index, by devpath and as last resort create a raw uart */ + int uart_index = mraa_uart_lookup(str); + if (uart_index < 0) { + /* name lookup failed, try index if the first character is a digit */ + if (isdigit(*str)) { + uart_index = atoi(str); + } else { + const char *devpath; + int number_of_uarts = mraa_get_uart_count(); + for (uart_index = 0; uart_index < number_of_uarts; uart_index++) { + mraa_result_t res = mraa_uart_settings(uart_index, NULL, &devpath, NULL, NULL, NULL, NULL, NULL, NULL); + if (res == MRAA_SUCCESS && devpath != NULL && !strcmp(devpath, str)) break; + } + if (uart_index >= number_of_uarts) { + return mraa_uart_init_raw(str); + } + } + } + + return mraa_uart_init(uart_index); +} + +/* ------------------------------------------------------------------------ */ + +double +now(void) { + struct timeval tv; + gettimeofday(&tv, NULL); + return (double)tv.tv_usec * 1e-6 + (double)tv.tv_sec; +} + +/* ------------------------------------------------------------------------ */ + +void +uarttool_read_and_print(mraa_uart_context uart, double receive_timeout) { + char buf; + do { + double start = now(); + if (mraa_uart_data_available(uart, 1.0 + receive_timeout * 1000.0)) { + mraa_uart_read(uart, &buf, 1); + putchar(buf); + fflush(stdout); + } + receive_timeout -= now() - start; + } while (receive_timeout > 0.0); +} + +/* ------------------------------------------------------------------------ */ + +void +uarttool_usage(const char *name) { + printf("Usage: %s { list | dev device } [ baud bps ] [ databits d ] [ parity p ] [ stopbits s ] [ ctsrts mode ] [ send string ] [ recv timeout ] [ show ]\n\n", name); + printf("Simple tool to test UART functionality. Needs either list or dev arguments, the others are optional\n"); + printf(" list : lists uarts on the system (non intrusive)\n"); + printf(" dev : select uart device, can be by name, by device name or by index (as listed in list)\n"); + printf(" baud : set the baudrate to given parameter, in bits per second\n"); + printf(" parity : set parity mode to given parameter - can be E, O, or N\n"); + printf(" stopbits : set the number of stopbits - can be 1 or 2\n"); + printf(" ctsrts : set CTS/RTS flow control to either on or off\n"); + printf(" send : transmits a string\n"); + printf(" recv : reads data on uart for timeout seconds, and displays the result on stdout\n"); + printf(" show : show settings of selected uart\n"); +} + +/* ------------------------------------------------------------------------ */ + +int +main(int argc, const char** argv) { + mraa_uart_context uart = NULL; + int uart_index, i; + + int baudrate = 115200, stopbits = 1, databits = 8; + mraa_uart_parity_t parity = MRAA_UART_PARITY_NONE; + unsigned int ctsrts = FALSE, xonxoff = FALSE; + const char *name = NULL, *dev = NULL; + + double recieve_timeout = 0.0; + int recieve = FALSE; /* whether we are requested to receive */ + int send = FALSE; /* whether we are requested to send or not */ + const char *to_send; /* data to send, assigned during parsing of command line */ + int show = FALSE; /* whether to show uart settings after everything else*/ + + /* Initialize MRAA. Init is done automatically if libmraa is compiled + with a compiler that supports __attribute__((constructor)), like + GCC and CLANG + */ + mraa_init(); + + if (argc <= 1) { + uarttool_usage(argv[0]); + } else + if (!strcmp(argv[1], "list")) { + int number_of_uarts = mraa_get_uart_count(); + for (uart_index = 0; uart_index < number_of_uarts; uart_index++) { + mraa_result_t res = mraa_uart_settings(uart_index, &name, &dev, &baudrate, &databits, &stopbits, &parity, &ctsrts, &xonxoff); + if (res == MRAA_SUCCESS) { + if (name == NULL) name = undefined; + if (dev == NULL) dev = undefined; + printf("%i. %-12s %-16s %7i %i%c%i %s %s\n", uart_index, name, dev, baudrate, databits, paritymode_table[parity], stopbits, ctsrts?"CTSRTS":"(none)", xonxoff?"XONXOFF":"(none) "); + } else { + printf("%i. ---- error reading uart information ----\n", uart_index); + } + } + } else { + for (i=1; i= argc || !isdigit(argv[i+1][0])) { + fprintf(stderr, "%s : %s needs number as argument\n", argv[0], argv[i]); + break; + } + baudrate = atoi(argv[i+1]); + if (uart != NULL) { + mraa_uart_set_baudrate(uart, baudrate); + } + i++; + } else + + /* Accept a few variants of the flow control setting name */ + if (!strcmp(argv[i], "ctsrts") || !strcmp(argv[i], "rtscts") || !strcmp(argv[i], "crtscts")) { + if (i+1 >= argc || argv[i+1][0] != 'o') { + fprintf(stderr, "%s : ctsrts needs either on or off as argument\n", argv[0]); + break; + } + ctsrts = !strcmp(argv[i+1], "on") ? 1u : 0u; + xonxoff = 0u; + if (uart != NULL) { + mraa_uart_set_flowcontrol(uart, xonxoff, ctsrts); + } + i++; + } else + + /* Number of stopbits */ + if (!strcmp(argv[i], "stopbits")) { + if (i+1 >= argc || !isdigit(argv[i+1][0])) { + fprintf(stderr, "%s : %s needs number as argument\n", argv[0], argv[i]); + break; + } + stopbits = atoi(argv[i+1]); + if (stopbits < 1 || stopbits > 2) { + stopbits = 1; + fprintf(stderr, "%s : invalid number of stopbits, bust be 1 or 2\n", argv[0]); + } + if (uart != NULL) { + mraa_uart_set_mode(uart, databits, parity, stopbits); + } + i++; + } else + + /* Databits */ + if (!strcmp(argv[i], "databits") || !strcmp(argv[i], "bytesize")) { + if (i+1 >= argc || !isdigit(argv[i+1][0])) { + fprintf(stderr, "%s : %s needs number as argument\n", argv[0], argv[i]); + break; + } + databits = atoi(argv[i+1]); + if (uart != NULL) { + mraa_uart_set_mode(uart, databits, parity, stopbits); + } + i++; + } else + + /* Parity mode, uses paritmode array */ + if (!strcmp(argv[i], "paritybits") || !strcmp(argv[i], "parity")) { + int j; + if (i+1 >= argc) { + fprintf(stderr, "%s : %s needs 'O','E' or 'N' as argument\n", argv[0], argv[i]); + break; + } + /* Even if there were gaps between declared array elements, they would be initialized to 0 compile time */ + for (j=0; j= sizeof(paritymode_table)) { + fprintf(stderr, "warning: unrecognized parity mode %s (ignoring)\n", argv[i+1]); + } + if (uart != NULL) { + mraa_uart_set_mode(uart, databits, parity, stopbits); + } + i++; + } else + + /* Show settings */ + if (!strcmp(argv[i], "show")) { + show = TRUE; + } else + + /* Send data */ + if (!strcmp(argv[i], "send")) { + if (i+1 >= argc) { + fprintf(stderr, "%s : %s needs string as argument\n", argv[0], argv[i]); + break; + } + send = TRUE; + to_send = argv[i+1]; + i++; + } else + + if (!strcmp(argv[i], "receive") || !strcmp(argv[i], "recieve") || !strcmp(argv[i], "recv")) { + if (i+1 >= argc) { + fprintf(stderr, "%s : %s needs a timeout (in seconds, fractional ok) as argument\n", argv[0], argv[i]); + break; + } + recieve = TRUE; + recieve_timeout = atof(argv[i+1]); + i++; + } + } + + if (i == argc && uart != NULL) { + if (send) { + mraa_uart_write(uart, to_send, strlen(to_send)+1); + } + + if (recieve) { + uarttool_read_and_print(uart, recieve_timeout); + } + + if (show) { + if (recieve) putchar('\n'); + dev = mraa_uart_get_dev_path(uart); + mraa_uart_settings(-1, &dev, &name, &baudrate, &databits, &stopbits, &parity, &ctsrts, &xonxoff); + printf("%-12s %-16s %7i %i%c%i %s %s\n", name!=NULL?name:undefined, dev, baudrate, databits, paritymode_table[parity], stopbits, ctsrts?"CTS/RTS":"(no hw)", xonxoff?"XONXOFF":"(no sw)"); + } + } else { + uarttool_usage(argv[0]); + } + } + mraa_deinit(); + + return EXIT_SUCCESS; +} +