From ae391fe9fe79964b1cfa0d75918954a81a03fbf8 Mon Sep 17 00:00:00 2001 From: Mihai Stefanescu Date: Wed, 21 Mar 2018 15:44:36 +0200 Subject: [PATCH] String based IO initialization for MRAA Signed-off-by: Mihai Stefanescu Signed-off-by: Noel Eck --- api/mraa/iio.hpp | 41 +- api/mraa/initio.h | 149 +++++ api/mraa/initio.hpp | 167 +++++ api/mraa/uart_ow.hpp | 19 +- examples/c/initio.c | 49 ++ include/initio/initio_keys.h | 84 +++ include/mraa_internal_types.h | 14 +- src/CMakeLists.txt | 1 + src/initio/initio.c | 852 +++++++++++++++++++++++++ tests/unit/CMakeLists.txt | 7 + tests/unit/api/api_common_h_unit.cxx | 4 - tests/unit/api/api_common_hpp_unit.cxx | 4 - tests/unit/api/mraa_initio_h_unit.cxx | 180 ++++++ 13 files changed, 1540 insertions(+), 31 deletions(-) create mode 100644 api/mraa/initio.h create mode 100644 api/mraa/initio.hpp create mode 100644 examples/c/initio.c create mode 100644 include/initio/initio_keys.h create mode 100644 src/initio/initio.c create mode 100644 tests/unit/api/mraa_initio_h_unit.cxx diff --git a/api/mraa/iio.hpp b/api/mraa/iio.hpp index 4987cfe..ec3090f 100644 --- a/api/mraa/iio.hpp +++ b/api/mraa/iio.hpp @@ -24,17 +24,16 @@ #pragma once -#include -#include #include "iio.h" #include "types.hpp" +#include +#include namespace mraa { /** Iio Event Data */ -struct IioEventData -{ +struct IioEventData { /** Channel Type */ int channelType; /** Modifier */ @@ -54,11 +53,11 @@ struct IioEventData /** Iio Handler */ class IioHandler { -public: - /** onIioEvent Handler */ - virtual void onIioEvent(const IioEventData& eventData) = 0; - /** Destructor */ - virtual ~IioHandler() {}; // add an empty destructor to get rid of warning + public: + /** onIioEvent Handler */ + virtual void onIioEvent(const IioEventData& eventData) = 0; + /** Destructor */ + virtual ~IioHandler(){}; // add an empty destructor to get rid of warning }; @@ -112,6 +111,19 @@ class Iio } } + /** + * IIO constructor, takes a pointer to a IIO context and initialises the IIO class + * + * @param iio_context void * to an IIO context + */ + Iio(void* iio_context) + { + m_iio = (mraa_iio_context) iio_context; + if (m_iio == NULL) { + throw std::invalid_argument("Invalid IIO context"); + } + } + /** * Iio destructor */ @@ -193,7 +205,6 @@ class Iio oss << "IIO writeInt for attibute " << attributeName << " failed"; throw std::runtime_error(oss.str()); } - } /** @@ -213,7 +224,6 @@ class Iio oss << "IIO writeFloat for attibute " << attributeName << " failed"; throw std::runtime_error(oss.str()); } - } /** @@ -233,13 +243,15 @@ class Iio } private: - static void private_event_handler(iio_event_data* data, void *args) + static void + private_event_handler(iio_event_data* data, void* args) { if (args != NULL) { - IioHandler* handler = (IioHandler*)args; + IioHandler* handler = (IioHandler*) args; IioEventData eventData; int chan_type, modifier, type, direction, channel, channel2, different; - mraa_iio_event_extract_event(data, &chan_type, &modifier, &type, &direction, &channel, &channel2, &different); + mraa_iio_event_extract_event(data, &chan_type, &modifier, &type, &direction, &channel, + &channel2, &different); eventData.channelType = chan_type; eventData.modifier = modifier; eventData.type = type; @@ -253,5 +265,4 @@ class Iio mraa_iio_context m_iio; }; - } diff --git a/api/mraa/initio.h b/api/mraa/initio.h new file mode 100644 index 0000000..d0ba23d --- /dev/null +++ b/api/mraa/initio.h @@ -0,0 +1,149 @@ +/* + * Author: Noel Eck + * Copyright (c) 2014-2016 Intel Corporation. + * + * 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. + */ + +#pragma once +/** + * @file + * @brief I/O initializer + * + * initio allows for string initialization of mraa resources. + * + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include "aio.h" +#include "gpio.h" +#include "i2c.h" +#include "iio.h" +#include "pwm.h" +#include "spi.h" +#include "uart.h" +#include "uart_ow.h" + +typedef struct _mraa_io_descriptor { + int n_aio; + mraa_aio_context* aios; + int n_gpio; + mraa_gpio_context* gpios; + int n_i2c; + mraa_i2c_context* i2cs; + int n_iio; + mraa_iio_context* iios; + int n_pwm; + mraa_pwm_context* pwms; + int n_spi; + mraa_spi_context* spis; + int n_uart; + mraa_uart_context* uarts; + int n_uart_ow; + mraa_uart_ow_context* uart_ows; + + char* leftover_str; +} mraa_io_descriptor; + +/** + * Initialize a structure of MRAA context elements given a description string. + * + * @param strdesc of one or more MRAA IO + * io:io_ndx[:option_0:option_1:option_2:option_n][,io:io_ndx] + * + * AIO + * AIO_KEY:aio pin[:num_bits] + * + * examples: + * a:13 # aio 13 + * a:13:10 # aio 13, 10 bits + * + * GPIO + * GPIO_KEY:gpio pin[:dir:value:mode:edge:input:driver] + * + * examples: + * g:13:input # gpio 13, input + * g:13:0:output # gpio 13, value 0, output + * + * I2C + * I2C_KEY:i2c bus[:address:mode] + * + * examples: + * i:1:std # i2c bus 1, STD speed (100 KHz) + * i:1:16 # i2c bus 1, address 16 + * i:0x1:0x10 # i2c bus 1, address 16 + * + * IIO + * IIO_KEY:iio device + * + * examples: + * ii:1 # iio device 1 + * ii:0x1 # iio device 1 + * + * PWM + * PWM_KEY:pwm pin + * + * examples: + * p:1 # pwm pin 1 + * p:0x1 # pwm pin 1 + * + * SPI + * SPI_KEY:spi bus[:mode:frequency] + * + * examples: + * s:1 # spi bus 1 + * s:0x1:mode2:400000 # spi bus 1, mode2 (CPOL = 1, CPHA = 0), 400 KHz + * + * UART + * UART_KEY:uart ndx[:baud:mode] + * + * examples: + * u:1 # uart bus 1 + * u:0x1:9600:8N1 # uart bus 1, 9600 baud, 8 bit byte, no parity, 1 stop bit + * + * UART_OW + * UART_OW_KEY:uart_ow ndx + * + * examples: + * ow:1 # uart_ow bus 1 + * ow:0x1 # uart_ow bus 1 + * + * + * @param desc Pointer to structure containing number/pointer collections for initialized IO. + * @return Result of operation + */ +mraa_result_t mraa_io_init(const char* strdesc, mraa_io_descriptor** desc); + +/** + * Free and close resources used by mraa_io_descriptor structure. + * + * @param desc mraa_io_descriptor structure + * @return Result of operation + */ +mraa_result_t mraa_io_close(mraa_io_descriptor* desc); + +#ifdef __cplusplus +} +#endif diff --git a/api/mraa/initio.hpp b/api/mraa/initio.hpp new file mode 100644 index 0000000..3639dd9 --- /dev/null +++ b/api/mraa/initio.hpp @@ -0,0 +1,167 @@ +/* + * Author: Mihai Stefanescu + * Copyright (c) 2018 Intel Corporation. + * + * 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. + */ + +#pragma once + +#include "initio.h" +#include +#include +#include + +#include "aio.hpp" +#include "gpio.hpp" +#include "i2c.hpp" +#include "iio.hpp" +#include "pwm.hpp" +#include "spi.hpp" +#include "uart.hpp" +#include "uart_ow.hpp" + +namespace mraa +{ +class MraaIo +{ + private: + mraa_io_descriptor* descs; + + public: + MraaIo(const std::string& initStr) : descs() + { + if (mraa_io_init(initStr.c_str(), &descs) != MRAA_SUCCESS) { + throw std::runtime_error("mraa_io_init error"); + } + + aios.reserve(descs->n_aio); + for (int i = 0; i < descs->n_aio; ++i) { + aios.emplace_back(descs->aios[i]); + } + + gpios.reserve(descs->n_gpio); + for (int i = 0; i < descs->n_gpio; ++i) { + gpios.emplace_back(descs->gpios[i]); + } + + i2cs.reserve(descs->n_i2c); + for (int i = 0; i < descs->n_i2c; ++i) { + i2cs.emplace_back(descs->i2cs[i]); + } + + iios.reserve(descs->n_iio); + for (int i = 0; i < descs->n_iio; ++i) { + iios.emplace_back(descs->iios[i]); + } + + pwms.reserve(descs->n_pwm); + for (int i = 0; i < descs->n_pwm; ++i) { + pwms.emplace_back(descs->pwms[i]); + } + + spis.reserve(descs->n_spi); + for (int i = 0; i < descs->n_spi; ++i) { + spis.emplace_back(descs->spis[i]); + } + + uarts.reserve(descs->n_uart); + for (int i = 0; i < descs->n_uart; ++i) { + uarts.emplace_back(descs->uarts[i]); + } + + uart_ows.reserve(descs->n_uart_ow); + for (int i = 0; i < descs->n_uart_ow; ++i) { + uart_ows.emplace_back(descs->uart_ows[i]); + } + + if (descs->leftover_str) { + leftoverStr = std::string(descs->leftover_str); + } else { + leftoverStr = std::string(""); + } + } + + MraaIo() : descs() {} + + ~MraaIo() + { + if (descs->leftover_str) { + free(descs->leftover_str); + } + + if (descs->n_aio) { + free(descs->aios); + } + if (descs->n_gpio) { + free(descs->gpios); + } + if (descs->n_i2c) { + free(descs->i2cs); + } + if (descs->n_iio) { + free(descs->iios); + } + if (descs->n_pwm) { + free(descs->pwms); + } + if (descs->n_spi) { + free(descs->spis); + } + if (descs->n_uart) { + free(descs->uarts); + } + if (descs->n_uart_ow) { + free(descs->uart_ows); + } + + /* Finally free the mraa_io_descriptor structure. */ + free(descs); + } + + public: + std::vector aios; + std::vector gpios; + std::vector i2cs; + std::vector iios; + std::vector pwms; + std::vector spis; + std::vector uarts; + std::vector uart_ows; + + private: + /* Used exclusively by the UPM library. */ + std::string leftoverStr; + + public: + /* This is used mainly by sensors that use C structs/functions in C++ code. */ + mraa_io_descriptor* + getMraaDescriptors() + { + return descs; + } + + std::string + getLeftoverStr() + { + return leftoverStr; + } +}; +} diff --git a/api/mraa/uart_ow.hpp b/api/mraa/uart_ow.hpp index 05607e3..2d7b459 100644 --- a/api/mraa/uart_ow.hpp +++ b/api/mraa/uart_ow.hpp @@ -24,10 +24,10 @@ #pragma once -#include "uart_ow.h" #include "types.hpp" -#include +#include "uart_ow.h" #include +#include namespace mraa { @@ -74,6 +74,21 @@ class UartOW } } + /** + * UartOW Constructor, takes a pointer to the UartOW context and initialises + * the UartOW class + * + * @param uart_ow_context void * to a UartOW context + */ + UartOW(void* uart_ow_context) + { + m_uart = (mraa_uart_ow_context) uart_ow_context; + + if (m_uart == NULL) { + throw std::invalid_argument("Invalid UART_OW context"); + } + } + /** * Uart destructor */ diff --git a/examples/c/initio.c b/examples/c/initio.c new file mode 100644 index 0000000..1968a2d --- /dev/null +++ b/examples/c/initio.c @@ -0,0 +1,49 @@ +/* + * Author: Mihai Stefanescu + * Copyright (c) 2018 Intel Corporation. + * + * 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 "mraa/initio.h" + +int +main() +{ + printf("Starting example\n"); + + mraa_io_descriptor* desc; + if (mraa_io_init("g:3:1-upm_stuff", &desc) != MRAA_SUCCESS) { + printf("Error in mraa_io_init()\n"); + } + + printf("Leftover string = %s\n", desc->leftover_str); + + /* Check value set in mraa_io_init. */ + printf("Gpio value = %d\n", mraa_gpio_read(desc->gpios[0])); + + if (mraa_io_close(desc) != MRAA_SUCCESS) { + printf("failed to close mraa io descriptor\n"); + } + + printf("Done\n"); +} \ No newline at end of file diff --git a/include/initio/initio_keys.h b/include/initio/initio_keys.h new file mode 100644 index 0000000..94562cf --- /dev/null +++ b/include/initio/initio_keys.h @@ -0,0 +1,84 @@ +/* + * Author: Mihai Stefanescu + * Copyright (c) 2018 Intel Corporation. + * + * 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. + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +/*gpio modes */ +#define G_MODE_STRONG "mode_strong" +#define G_MODE_PULLUP "mode_pullup" +#define G_MODE_PULLDOWN "mode_pulldown" +#define G_MODE_HIZ "mode_hiz" +#define G_MODE_ACTIVE_LOW "mode_active_low" +#define G_MODE_OPEN_DRAIN "mode_open_drain" +#define G_MODE_OPEN_SOURCE "mode_open_source" + +/*gpio direction modes */ +#define G_DIR_OUT "out" +#define G_DIR_IN "in" +#define G_DIR_OUT_HIGH "out_high" +#define G_DIR_OUT_LOW "out_low" + +/*gpio edge modes */ +#define G_EDGE_NONE "edge_none" +#define G_EDGE_BOTH "edge_both" +#define G_EDGE_RISING "edge_rising" +#define G_EDGE_FALLING "edge_falling" + +/*gpio input modes */ +#define G_INPUT_ACTIVE_HIGH "input_high" +#define G_INPUT_ACTIVE_LOW "input_low" + +/*gpio output driver modes */ +#define G_OUTPUT_OPEN_DRAIN "output_open_drain" +#define G_OUTPUT_PUSH_PULL "output_push_pull" +/*---------------------------------------------*/ + +/* i2c modes */ +#define I_MODE_STD "std" +#define I_MODE_FAST "fast" +#define I_MODE_HIGH "high" +/*---------------------------------------------*/ + +/* spi modes */ +#define S_MODE_0 "mode0" +#define S_MODE_1 "mode1" +#define S_MODE_2 "mode2" +#define S_MODE_3 "mode3" +/*---------------------------------------------*/ + +/* uart parity types */ +#define U_PARITY_NONE "N" +#define U_PARITY_EVEN "E" +#define U_PARITY_ODD "O" +#define U_PARITY_MARK "M" +#define U_PARITY_SPACE "S" +/*---------------------------------------------*/ + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/include/mraa_internal_types.h b/include/mraa_internal_types.h index 3900fbe..a64c7fa 100644 --- a/include/mraa_internal_types.h +++ b/include/mraa_internal_types.h @@ -86,12 +86,14 @@ #define BUS_KEY "bus" // IO keys -#define GPIO_KEY "GPIO" -#define SPI_KEY "SPI" -#define UART_KEY "UART" -#define I2C_KEY "I2C" -#define PWM_KEY "PWM" -#define AIO_KEY "AIO" +#define AIO_KEY "a" +#define GPIO_KEY "g" +#define I2C_KEY "i" +#define IIO_KEY "ii" +#define PWM_KEY "p" +#define SPI_KEY "s" +#define UART_KEY "u" +#define UART_OW_KEY "ow" #define MRAA_JSONPLAT_ENV_VAR "MRAA_JSON_PLATFORM" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1e9b97c..35c5488 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -30,6 +30,7 @@ set (mraa_LIB_SRCS_NOAUTO ${PROJECT_SOURCE_DIR}/src/aio/aio.c ${PROJECT_SOURCE_DIR}/src/uart/uart.c ${PROJECT_SOURCE_DIR}/src/led/led.c + ${PROJECT_SOURCE_DIR}/src/initio/initio.c ${mraa_LIB_SRCS_NOAUTO} ) diff --git a/src/initio/initio.c b/src/initio/initio.c new file mode 100644 index 0000000..52c2b5f --- /dev/null +++ b/src/initio/initio.c @@ -0,0 +1,852 @@ +/* + * Author: Mihai Stefanescu + * Copyright (c) 2018 Intel Corporation. + * + * 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 "initio.h" +#include "initio/initio_keys.h" +#include "mraa_internal.h" + +#define DESC_SEP "," +#define TOK_SEP ":" + +static mraa_result_t +mraa_atoi_x(const char* intStr, char** str_end, int* value, int base) +{ + long val = strtol(intStr, str_end, base); + if (errno == ERANGE || val > INT_MAX || val < INT_MIN) { + *value = 0; + return MRAA_ERROR_UNSPECIFIED; + } + *value = (int) val; + return MRAA_SUCCESS; +} + +static char** +mraa_tokenize_string(const char* str, const char* delims, int* num_tokens) +{ + char *saveptr, *tok, *s, *p_str; + char** output = NULL; + size_t output_size = 0; + + p_str = strdup(str); + + for (s = p_str;; s = NULL) { + tok = strtok_r(s, delims, &saveptr); + if (tok == NULL) { + break; + } + output = realloc(output, (++output_size) * sizeof(char*)); + output[output_size - 1] = calloc(strlen(tok) + 1, sizeof(char)); + strncpy(output[output_size - 1], tok, strlen(tok)); + } + *num_tokens = output_size; + + free(p_str); + + return output; +} + +static void +mraa_delete_tokenized_string(char** str, int num_tokens) +{ + if (str == NULL) { + syslog(LOG_ERR, "mraa_delete_tokenized_string: NULL string"); + return; + } + + for (int i = 0; i < num_tokens; ++i) { + free(str[i]); + } + + free(str); +} + +static mraa_uart_ow_context +parse_uart_ow(char** proto, size_t n) +{ + if (proto == NULL || n <= 1) { + syslog(LOG_ERR, "parse_uart_ow: invalid parameters"); + return NULL; + } + + mraa_uart_ow_context dev = NULL; + + int bus = -1; + if (proto[1] && (mraa_atoi_x(proto[1], NULL, &bus, 0) == MRAA_SUCCESS)) { + dev = mraa_uart_ow_init(bus); + if (dev == NULL) { + syslog(LOG_ERR, "parse_uart_ow: could not init uart_ow bus %d", bus); + } + } else { + syslog(LOG_ERR, "parse_uart_ow: invalid uart_ow bus number"); + } + + return dev; +} + +static mraa_uart_context +parse_uart(char** proto, size_t n) +{ + if (proto == NULL || n <= 1) { + syslog(LOG_ERR, "parse_uart: invalid parameters"); + return NULL; + } + + int idx = 1; + mraa_uart_context dev = NULL; + + int uart = -1; + if (proto[idx] && (mraa_atoi_x(proto[idx], NULL, &uart, 0) == MRAA_SUCCESS)) { + dev = mraa_uart_init(uart); + if (dev == NULL) { + syslog(LOG_ERR, "parse_uart: could not init uart index %d", uart); + return NULL; + } else { + if (++idx == n) { + return dev; + } + } + } else { + syslog(LOG_ERR, "parse_uart: invalid uart index"); + return NULL; + } + + /* Check for baudrate. */ + unsigned int baudrate = -1; + if (proto[idx] && (mraa_atoi_x(proto[idx], NULL, &baudrate, 0) == MRAA_SUCCESS)) { + if (mraa_uart_set_baudrate(dev, baudrate) != MRAA_SUCCESS) { + syslog(LOG_ERR, "parse_uart: could not set uart baudrate %d", baudrate); + mraa_uart_stop(dev); + return NULL; + } else { + if (++idx == n) { + return dev; + } + } + } else { + syslog(LOG_ERR, "parse_uart: invalid uart baudrate"); + } + + /* Check for mode - [int] bytesize, [mraa_uart_parity_t] parity, [int] stopbits. */ + char* end = proto[idx]; + /* Check for bytesize. */ + int bytesize = -1; + if (mraa_atoi_x(proto[idx], &end, &bytesize, 0) != MRAA_SUCCESS) { + syslog(LOG_ERR, "parse_uart: error reading uart bytesize %d", bytesize); + mraa_uart_stop(dev); + return NULL; + } + + int parity = -1; + if (strncmp(end, U_PARITY_NONE, strlen(U_PARITY_NONE)) == 0) { + parity = MRAA_UART_PARITY_NONE; + end += strlen(U_PARITY_NONE); + } else if (strncmp(end, U_PARITY_EVEN, strlen(U_PARITY_EVEN)) == 0) { + parity = MRAA_UART_PARITY_EVEN; + end += strlen(U_PARITY_EVEN); + } else if (strncmp(end, U_PARITY_ODD, strlen(U_PARITY_ODD)) == 0) { + parity = MRAA_UART_PARITY_ODD; + end += strlen(U_PARITY_ODD); + } else if (strncmp(end, U_PARITY_MARK, strlen(U_PARITY_MARK)) == 0) { + parity = MRAA_UART_PARITY_MARK; + end += strlen(U_PARITY_MARK); + } else if (strncmp(end, U_PARITY_SPACE, strlen(U_PARITY_SPACE)) == 0) { + parity = MRAA_UART_PARITY_SPACE; + end += strlen(U_PARITY_SPACE); + } + + if (parity == -1) { + syslog(LOG_ERR, "parse_uart: error reading uart parity"); + mraa_uart_stop(dev); + return NULL; + } + + int stopbits = -1; + if (mraa_atoi_x(end, NULL, &stopbits, 0) != MRAA_SUCCESS) { + syslog(LOG_ERR, "parse_uart: error reading uart bytesize %d", bytesize); + mraa_uart_stop(dev); + return NULL; + } + + if (mraa_uart_set_mode(dev, bytesize, (mraa_uart_parity_t) parity, stopbits) != MRAA_SUCCESS) { + syslog(LOG_ERR, "parse_uart: error setting up uart mode"); + mraa_uart_stop(dev); + return NULL; + } + + return dev; +} + +static mraa_spi_context +parse_spi(char** proto, size_t n) +{ + if (proto == NULL || n <= 1) { + syslog(LOG_ERR, "parse_spi: invalid parameters"); + return NULL; + } + + int idx = 1; + mraa_spi_context dev = NULL; + + int bus = -1; + if (proto[idx] && (mraa_atoi_x(proto[idx], NULL, &bus, 0) == MRAA_SUCCESS)) { + dev = mraa_spi_init(bus); + if (dev == NULL) { + syslog(LOG_ERR, "parse_spi: could not init spi bus %d", bus); + return NULL; + } else { + if (++idx == n) { + return dev; + } + } + } else { + syslog(LOG_ERR, "parse_spi: invalid spi bus number"); + return NULL; + } + + /* Check for mode. */ + int mode = -1; + if (strncmp(proto[idx], S_MODE_0, strlen(S_MODE_0)) == 0) { + mode = MRAA_SPI_MODE0; + } else if (strncmp(proto[idx], S_MODE_1, strlen(S_MODE_1)) == 0) { + mode = MRAA_SPI_MODE1; + } else if (strncmp(proto[idx], S_MODE_2, strlen(S_MODE_2)) == 0) { + mode = MRAA_SPI_MODE2; + } else if (strncmp(proto[idx], S_MODE_3, strlen(S_MODE_3)) == 0) { + mode = MRAA_SPI_MODE3; + } + + if (mode != -1) { + if (mraa_spi_mode(dev, (mraa_spi_mode_t) mode) != MRAA_SUCCESS) { + syslog(LOG_ERR, "parse_spi: error setting up spi mode %s", proto[idx]); + mraa_spi_stop(dev); + return NULL; + } else { + if (++idx == n) { + return dev; + } + } + } + + int frequency; + if (proto[idx] && (mraa_atoi_x(proto[idx], NULL, &frequency, 0) == MRAA_SUCCESS)) { + if (mraa_spi_frequency(dev, frequency) != MRAA_SUCCESS) { + syslog(LOG_ERR, "parse_spi: error setting up spi frequency %d", frequency); + mraa_spi_stop(dev); + return NULL; + } + } else { + syslog(LOG_ERR, "parse_spi: invalid spi frequency"); + } + + return dev; +} + +static mraa_pwm_context +parse_pwm(char** proto, size_t n) +{ + if (proto == NULL || n <= 1) { + syslog(LOG_ERR, "parse_pwm: invalid parameters"); + return NULL; + } + + mraa_pwm_context dev = NULL; + + int pin = -1; + if (proto[1] && (mraa_atoi_x(proto[1], NULL, &pin, 0) == MRAA_SUCCESS)) { + dev = mraa_pwm_init(pin); + if (dev == NULL) { + syslog(LOG_ERR, "parse_pwm: could not init pwm pin %d", pin); + } + } else { + syslog(LOG_ERR, "parse_pwm: invalid pwm pin number"); + } + + return dev; +} + +static mraa_iio_context +parse_iio(char** proto, size_t n) +{ + if (proto == NULL || n <= 1) { + syslog(LOG_ERR, "parse_iio: invalid parameters"); + return NULL; + } + + mraa_iio_context dev = NULL; + + int device = -1; + if (proto[1] && (mraa_atoi_x(proto[1], NULL, &device, 0) == MRAA_SUCCESS)) { + dev = mraa_iio_init(device); + if (dev == NULL) { + syslog(LOG_ERR, "parse_iio: could not init iio device %d", device); + } + } else { + syslog(LOG_ERR, "parse_iio: invalid iio device number"); + } + + return dev; +} + +static mraa_i2c_context +parse_i2c(char** proto, size_t n) +{ + if (proto == NULL || n <= 1) { + syslog(LOG_ERR, "parse_i2c: invalid parameters"); + return NULL; + } + + int idx = 1; + mraa_i2c_context dev = NULL; + + int bus = -1; + if (proto[idx] && (mraa_atoi_x(proto[idx], NULL, &bus, 0) == MRAA_SUCCESS)) { + dev = mraa_i2c_init(bus); + if (dev == NULL) { + syslog(LOG_ERR, "parse_i2c: could not init i2c bus %d", bus); + return NULL; + } else { + if (++idx == n) + return dev; + } + } else { + syslog(LOG_ERR, "parse_i2c: invalid i2c bus number"); + return NULL; + } + + int address = -1; + if (proto[idx] && (mraa_atoi_x(proto[idx], NULL, &address, 0) == MRAA_SUCCESS)) { + if (mraa_i2c_address(dev, (uint8_t) address) != MRAA_SUCCESS) { + syslog(LOG_ERR, "parse_i2c: error setting up i2c address"); + mraa_i2c_stop(dev); + return NULL; + } else { + if (++idx == n) { + return dev; + } + } + } + + int mode = -1; + if (strncmp(proto[idx], I_MODE_STD, strlen(I_MODE_STD)) == 0) { + mode = MRAA_I2C_STD; + } else if (strncmp(proto[idx], I_MODE_FAST, strlen(I_MODE_FAST)) == 0) { + mode = MRAA_I2C_FAST; + } else if (strncmp(proto[idx], I_MODE_HIGH, strlen(I_MODE_HIGH)) == 0) { + mode = MRAA_GPIO_PULLDOWN; + } + + if (mode != -1) { + if (mraa_i2c_frequency(dev, (mraa_i2c_mode_t) mode) != MRAA_SUCCESS) { + syslog(LOG_ERR, "parse_i2c: error setting up gpio driver mode %s", proto[idx]); + mraa_i2c_stop(dev); + return NULL; + } + } + + return dev; +} + +static mraa_aio_context +parse_aio(char** proto, size_t n) +{ + if (proto == NULL || n <= 1) { + syslog(LOG_ERR, "parse_aio: invalid parameters"); + return NULL; + } + + int idx = 1; + mraa_aio_context dev = NULL; + + int aio_num = -1; + if (proto[idx] && (mraa_atoi_x(proto[idx], NULL, &aio_num, 0) == MRAA_SUCCESS)) { + dev = mraa_aio_init(aio_num); + if (dev == NULL) { + syslog(LOG_ERR, "parse_aio: could not init aio number %d", aio_num); + return NULL; + } else { + if (++idx == n) { + return dev; + } + } + } else { + syslog(LOG_ERR, "parse_aio: invalid aio number"); + return NULL; + } + + int num_bits = -1; + if (proto[idx] && (mraa_atoi_x(proto[idx], NULL, &num_bits, 0) == MRAA_SUCCESS)) { + if (mraa_aio_set_bit(dev, num_bits) != MRAA_SUCCESS) { + syslog(LOG_ERR, "parse_aio: error setting up aio bit"); + mraa_aio_close(dev); + return NULL; + } + } else { + syslog(LOG_ERR, "parse_aio: invalid aio bit number"); + mraa_aio_close(dev); + return NULL; + } + + return dev; +} + +static mraa_gpio_context +parse_gpio(char** proto, size_t n) +{ + if (proto == NULL || n <= 1) { + syslog(LOG_ERR, "parse_gpio: invalid parameters"); + return NULL; + } + + int idx = 1; + mraa_gpio_context dev = NULL; + + int gpio_num = -1; + if (proto[idx] && (mraa_atoi_x(proto[idx], NULL, &gpio_num, 0) == MRAA_SUCCESS)) { + dev = mraa_gpio_init(gpio_num); + if (dev == NULL) { + syslog(LOG_ERR, "parse_gpio: could not init gpio number %d", gpio_num); + return NULL; + } + } else { + syslog(LOG_ERR, "parse_gpio: invalid gpio number"); + return NULL; + } + if (++idx == n) { + return dev; + } + + /* Check for direction. */ + int dir = -1; + if (strncmp(proto[idx], G_DIR_OUT, strlen(G_DIR_OUT)) == 0) { + dir = MRAA_GPIO_OUT; + } else if (strncmp(proto[idx], G_DIR_IN, strlen(G_DIR_IN)) == 0) { + dir = MRAA_GPIO_IN; + } else if (strncmp(proto[idx], G_DIR_OUT_HIGH, strlen(G_DIR_OUT_HIGH)) == 0) { + dir = MRAA_GPIO_OUT_HIGH; + } else if (strncmp(proto[idx], G_DIR_OUT_LOW, strlen(G_DIR_OUT_LOW)) == 0) { + dir = MRAA_GPIO_OUT_LOW; + } + + if (dir != -1) { + if (mraa_gpio_dir(dev, (mraa_gpio_dir_t) dir) != MRAA_SUCCESS) { + syslog(LOG_ERR, "parse_gpio: error setting up gpio direction %s", proto[idx]); + mraa_gpio_close(dev); + return NULL; + } else { + if (++idx == n) { + return dev; + } + } + } else { + /* Set direction to default - output. */ + if (mraa_gpio_dir(dev, MRAA_GPIO_OUT) != MRAA_SUCCESS) { + syslog(LOG_ERR, "parse_gpio: error setting up gpio direction %s", G_DIR_OUT); + mraa_gpio_close(dev); + return NULL; + } + } + + /* Check the value. */ + int value = -1; + if (mraa_atoi_x(proto[idx], NULL, &value, 0) == MRAA_SUCCESS) { + if (mraa_gpio_write(dev, value) != MRAA_SUCCESS) { + syslog(LOG_ERR, "parse_gpio: could not init gpio number %d with value %d", gpio_num, value); + mraa_gpio_close(dev); + return NULL; + } else { + if (++idx == n) { + return dev; + } + } + } + + /* Check for mode. */ + int mode = -1; + if (strncmp(proto[idx], G_MODE_STRONG, strlen(G_MODE_STRONG)) == 0) { + mode = MRAA_GPIO_STRONG; + } else if (strncmp(proto[idx], G_MODE_PULLUP, strlen(G_MODE_PULLUP)) == 0) { + mode = MRAA_GPIO_PULLUP; + } else if (strncmp(proto[idx], G_MODE_PULLDOWN, strlen(G_MODE_PULLDOWN)) == 0) { + mode = MRAA_GPIO_PULLDOWN; + } else if (strncmp(proto[idx], G_MODE_HIZ, strlen(G_MODE_HIZ)) == 0) { + mode = MRAA_GPIO_HIZ; + } else if (strncmp(proto[idx], G_MODE_ACTIVE_LOW, strlen(G_MODE_ACTIVE_LOW)) == 0) { + mode = MRAA_GPIOD_ACTIVE_LOW; + } else if (strncmp(proto[idx], G_MODE_OPEN_DRAIN, strlen(G_MODE_OPEN_DRAIN)) == 0) { + mode = MRAA_GPIOD_OPEN_DRAIN; + } else if (strncmp(proto[idx], G_MODE_OPEN_SOURCE, strlen(G_MODE_OPEN_SOURCE)) == 0) { + mode = MRAA_GPIOD_OPEN_SOURCE; + } + + if (mode != -1) { + if (mraa_gpio_mode(dev, (mraa_gpio_mode_t) mode) != MRAA_SUCCESS) { + syslog(LOG_ERR, "parse_gpio: error setting up gpio mode %s", proto[idx]); + mraa_gpio_close(dev); + return NULL; + } else { + if (++idx == n) { + return dev; + } + } + } + + /* Check for edge. */ + int edge = -1; + if (strncmp(proto[idx], G_EDGE_NONE, strlen(G_EDGE_NONE)) == 0) { + edge = MRAA_GPIO_EDGE_NONE; + } else if (strncmp(proto[idx], G_EDGE_BOTH, strlen(G_EDGE_BOTH)) == 0) { + edge = MRAA_GPIO_EDGE_BOTH; + } else if (strncmp(proto[idx], G_EDGE_RISING, strlen(G_EDGE_RISING)) == 0) { + edge = MRAA_GPIO_EDGE_RISING; + } else if (strncmp(proto[idx], G_EDGE_FALLING, strlen(G_EDGE_FALLING)) == 0) { + edge = MRAA_GPIO_EDGE_FALLING; + } + + if (edge != -1) { + if (mraa_gpio_edge_mode(dev, (mraa_gpio_edge_t) edge) != MRAA_SUCCESS) { + syslog(LOG_ERR, "parse_gpio: error setting up gpio edge %s", proto[idx]); + mraa_gpio_close(dev); + return NULL; + } else { + if (++idx == n) { + return dev; + } + } + } + + /* Check for input mode. */ + int input_mode = -1; + if (strncmp(proto[idx], G_INPUT_ACTIVE_HIGH, strlen(G_INPUT_ACTIVE_HIGH)) == 0) { + input_mode = MRAA_GPIO_ACTIVE_HIGH; + } else if (strncmp(proto[idx], G_INPUT_ACTIVE_LOW, strlen(G_INPUT_ACTIVE_LOW)) == 0) { + input_mode = MRAA_GPIO_ACTIVE_LOW; + } + + if (input_mode != -1) { + if (mraa_gpio_input_mode(dev, (mraa_gpio_input_mode_t) input_mode) != MRAA_SUCCESS) { + syslog(LOG_ERR, "parse_gpio: error setting up gpio input mode %s", proto[idx]); + mraa_gpio_close(dev); + return NULL; + } else { + if (++idx == n) { + return dev; + } + } + } + + /* Check for driver output mode. */ + int driver_mode = -1; + if (strncmp(proto[idx], G_OUTPUT_OPEN_DRAIN, strlen(G_OUTPUT_OPEN_DRAIN)) == 0) { + driver_mode = MRAA_GPIO_OPEN_DRAIN; + } else if (strncmp(proto[idx], G_OUTPUT_PUSH_PULL, strlen(G_OUTPUT_PUSH_PULL)) == 0) { + driver_mode = MRAA_GPIO_PUSH_PULL; + } + + if (driver_mode != -1) { + if (mraa_gpio_out_driver_mode(dev, (mraa_gpio_out_driver_mode_t) driver_mode) != MRAA_SUCCESS) { + syslog(LOG_ERR, "parse_gpio: error setting up gpio driver mode %s", proto[idx]); + mraa_gpio_close(dev); + return NULL; + } + } + + return dev; +} + +mraa_result_t +mraa_io_init(const char* strdesc, mraa_io_descriptor** desc) +{ + mraa_result_t status = MRAA_SUCCESS; + size_t leftover_str_len = 0; + mraa_io_descriptor* new_desc = calloc(1, sizeof(mraa_io_descriptor)); + if (new_desc == NULL) { + syslog(LOG_ERR, "mraa_io_init: Failed to allocate memory for context"); + desc = NULL; + return MRAA_ERROR_NO_RESOURCES; + } + + int num_descs = 0; + char** str_descs = mraa_tokenize_string(strdesc, DESC_SEP, &num_descs); + for (int i = 0; i < num_descs; ++i) { + int num_desc_tokens = 0; + char** str_tokens = mraa_tokenize_string(str_descs[i], TOK_SEP, &num_desc_tokens); + + if (strncmp(str_tokens[0], AIO_KEY, strlen(AIO_KEY)) == 0 && + strlen(str_tokens[0]) == strlen(AIO_KEY)) { + mraa_aio_context dev = parse_aio(str_tokens, num_desc_tokens); + if (!dev) { + syslog(LOG_ERR, "mraa_io_init: error parsing aio"); + status = MRAA_ERROR_INVALID_HANDLE; + } + + if (status == MRAA_SUCCESS) { + new_desc->aios = realloc(new_desc->aios, sizeof(mraa_aio_context) * (new_desc->n_aio + 1)); + if (!new_desc->aios) { + syslog(LOG_ERR, "mraa_io_init: error allocating memory for aio"); + status = MRAA_ERROR_NO_RESOURCES; + } else { + new_desc->aios[new_desc->n_aio++] = dev; + } + } + } else if (strncmp(str_tokens[0], GPIO_KEY, strlen(GPIO_KEY)) == 0 && + strlen(str_tokens[0]) == strlen(GPIO_KEY)) { + mraa_gpio_context dev = parse_gpio(str_tokens, num_desc_tokens); + if (!dev) { + syslog(LOG_ERR, "mraa_io_init: error parsing gpio"); + status = MRAA_ERROR_INVALID_HANDLE; + } + + if (status == MRAA_SUCCESS) { + new_desc->gpios = + realloc(new_desc->gpios, sizeof(mraa_gpio_context) * (new_desc->n_gpio + 1)); + if (!new_desc->gpios) { + syslog(LOG_ERR, "mraa_io_init: error allocating memory for gpio"); + status = MRAA_ERROR_NO_RESOURCES; + } else { + new_desc->gpios[new_desc->n_gpio++] = dev; + } + } + } else if (strncmp(str_tokens[0], IIO_KEY, strlen(IIO_KEY)) == 0 && + strlen(str_tokens[0]) == strlen(IIO_KEY)) { + mraa_iio_context dev = parse_iio(str_tokens, num_desc_tokens); + if (!dev) { + syslog(LOG_ERR, "mraa_io_init: error parsing iio"); + status = MRAA_ERROR_INVALID_HANDLE; + } + + if (status == MRAA_SUCCESS) { + new_desc->iios = realloc(new_desc->iios, sizeof(mraa_iio_context) * (new_desc->n_iio + 1)); + if (!new_desc->iios) { + syslog(LOG_ERR, "mraa_io_init: error allocating memory for iio"); + status = MRAA_ERROR_NO_RESOURCES; + } else { + new_desc->iios[new_desc->n_iio++] = dev; + } + } + } else if (strncmp(str_tokens[0], I2C_KEY, strlen(I2C_KEY)) == 0 && + strlen(str_tokens[0]) == strlen(I2C_KEY)) { + mraa_i2c_context dev = parse_i2c(str_tokens, num_desc_tokens); + if (!dev) { + syslog(LOG_ERR, "mraa_io_init: error parsing i2c"); + status = MRAA_ERROR_INVALID_HANDLE; + } + + if (status == MRAA_SUCCESS) { + new_desc->i2cs = realloc(new_desc->i2cs, sizeof(mraa_i2c_context) * (new_desc->n_i2c + 1)); + if (!new_desc->i2cs) { + syslog(LOG_ERR, "mraa_io_init: error allocating memory for i2c"); + status = MRAA_ERROR_NO_RESOURCES; + } else { + new_desc->i2cs[new_desc->n_i2c++] = dev; + } + } + } else if (strncmp(str_tokens[0], PWM_KEY, strlen(PWM_KEY)) == 0 && + strlen(str_tokens[0]) == strlen(PWM_KEY)) { + mraa_pwm_context dev = parse_pwm(str_tokens, num_desc_tokens); + if (!dev) { + syslog(LOG_ERR, "mraa_io_init: error parsing pwm"); + status = MRAA_ERROR_INVALID_HANDLE; + } + + if (status == MRAA_SUCCESS) { + new_desc->pwms = realloc(new_desc->pwms, sizeof(mraa_pwm_context) * (new_desc->n_pwm + 1)); + if (!new_desc->pwms) { + syslog(LOG_ERR, "mraa_io_init: error allocating memory for pwm"); + status = MRAA_ERROR_NO_RESOURCES; + } else { + new_desc->pwms[new_desc->n_pwm++] = dev; + } + } + } else if (strncmp(str_tokens[0], SPI_KEY, strlen(SPI_KEY)) == 0 && + strlen(str_tokens[0]) == strlen(SPI_KEY)) { + mraa_spi_context dev = parse_spi(str_tokens, num_desc_tokens); + if (!dev) { + syslog(LOG_ERR, "mraa_io_init: error parsing spi"); + status = MRAA_ERROR_INVALID_HANDLE; + } + + if (status == MRAA_SUCCESS) { + new_desc->spis = realloc(new_desc->spis, sizeof(mraa_spi_context) * (new_desc->n_spi + 1)); + if (!new_desc->spis) { + syslog(LOG_ERR, "mraa_io_init: error allocating memory for spi"); + status = MRAA_ERROR_NO_RESOURCES; + } else { + new_desc->spis[new_desc->n_spi++] = dev; + } + } + } else if (strncmp(str_tokens[0], UART_KEY, strlen(UART_KEY)) == 0 && + strlen(str_tokens[0]) == strlen(UART_KEY)) { + mraa_uart_context dev = parse_uart(str_tokens, num_desc_tokens); + if (!dev) { + syslog(LOG_ERR, "mraa_io_init: error parsing uart"); + status = MRAA_ERROR_INVALID_HANDLE; + } + + if (status == MRAA_SUCCESS) { + new_desc->uarts = + realloc(new_desc->uarts, sizeof(mraa_uart_context) * (new_desc->n_uart + 1)); + if (!new_desc->uarts) { + syslog(LOG_ERR, "mraa_io_init: error allocating memory for uart"); + status = MRAA_ERROR_NO_RESOURCES; + } else { + new_desc->uarts[new_desc->n_uart++] = dev; + } + } + } else if (strncmp(str_tokens[0], UART_OW_KEY, strlen(UART_OW_KEY)) == 0 && + strlen(str_tokens[0]) == strlen(UART_OW_KEY)) { + mraa_uart_ow_context dev = parse_uart_ow(str_tokens, num_desc_tokens); + if (!dev) { + syslog(LOG_ERR, "mraa_io_init: error parsing uart_ow"); + status = MRAA_ERROR_INVALID_HANDLE; + } + + if (status == MRAA_SUCCESS) { + new_desc->uart_ows = + realloc(new_desc->uart_ows, sizeof(mraa_uart_ow_context) * (new_desc->n_uart_ow + 1)); + if (!new_desc->uart_ows) { + syslog(LOG_ERR, "mraa_io_init: error allocating memory for uart_ow"); + status = MRAA_ERROR_NO_RESOURCES; + } else { + new_desc->uart_ows[new_desc->n_uart_ow++] = dev; + } + } + } else { + /* Here we build the leftover string. */ + new_desc->leftover_str = + realloc(new_desc->leftover_str, sizeof(char) * (leftover_str_len + strlen(str_descs[i]) + 2)); + if (!new_desc->leftover_str) { + syslog(LOG_ERR, "mraa_io_init: error allocating memory for leftover string"); + status = MRAA_ERROR_NO_RESOURCES; + } else { + if (leftover_str_len == 0) { + strncpy(new_desc->leftover_str, str_descs[i], strlen(str_descs[i])); + } else { + strncat(new_desc->leftover_str, str_descs[i], strlen(str_descs[i])); + } + + strncat(new_desc->leftover_str, str_descs[i], strlen(str_descs[i])); + leftover_str_len += strlen(str_descs[i]) + 1; + new_desc->leftover_str[leftover_str_len - 1] = ','; + new_desc->leftover_str[leftover_str_len] = '\0'; + } + } + + mraa_delete_tokenized_string(str_tokens, num_desc_tokens); + + if (status != MRAA_SUCCESS) { + break; + } + } + mraa_delete_tokenized_string(str_descs, num_descs); + + if (new_desc->leftover_str) { + /* We don't need the last comma. */ + new_desc->leftover_str[leftover_str_len - 1] = '\0'; + } + + if (status == MRAA_SUCCESS) { + *desc = new_desc; + } + + return status; +} + +mraa_result_t +mraa_io_close(mraa_io_descriptor* desc) +{ + if (desc == NULL) { + syslog(LOG_ERR, "mraa_io_close: NULL mraa_io_descriptor"); + return MRAA_ERROR_INVALID_PARAMETER; + } + + for (int i = 0; i < desc->n_aio; ++i) { + mraa_aio_close(desc->aios[i]); + } + if (desc->n_aio) { + free(desc->aios); + } + + for (int i = 0; i < desc->n_gpio; ++i) { + mraa_gpio_close(desc->gpios[i]); + } + if (desc->n_gpio) { + free(desc->gpios); + } + + for (int i = 0; i < desc->n_i2c; ++i) { + mraa_i2c_stop(desc->i2cs[i]); + } + if (desc->n_i2c) { + free(desc->i2cs); + } + + for (int i = 0; i < desc->n_iio; ++i) { + mraa_iio_close(desc->iios[i]); + } + if (desc->n_iio) { + free(desc->iios); + } + + for (int i = 0; i < desc->n_pwm; ++i) { + mraa_pwm_close(desc->pwms[i]); + } + if (desc->n_pwm) { + free(desc->pwms); + } + + for (int i = 0; i < desc->n_spi; ++i) { + mraa_spi_stop(desc->spis[i]); + } + if (desc->n_spi) { + free(desc->spis); + } + + for (int i = 0; i < desc->n_uart; ++i) { + mraa_uart_stop(desc->uarts[i]); + } + if (desc->n_uart) { + free(desc->uarts); + } + + for (int i = 0; i < desc->n_uart_ow; ++i) { + mraa_uart_ow_stop(desc->uart_ows[i]); + } + if (desc->n_uart_ow) { + free(desc->uart_ows); + } + + if (desc->leftover_str) { + free(desc->leftover_str); + } + + free(desc); + + return MRAA_SUCCESS; +} diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index 1db9421..3634387 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -30,10 +30,17 @@ if (FTDI4222) gtest_add_tests(platform_extender "" AUTO) endif () +# Unit tests - C initio header methods +add_executable(mraa_initio_h_unit api/mraa_initio_h_unit.cxx) +target_link_libraries(mraa_initio_h_unit GTest::GTest GTest::Main mraa) +target_include_directories(mraa_initio_h_unit PRIVATE "${CMAKE_SOURCE_DIR}/api") +gtest_add_tests(mraa_initio_h_unit "" AUTO) + # Add a custom target for unit tests add_custom_target(tests-unit ALL DEPENDS api_common_h_unit api_common_hpp_unit platform_extender + mraa_initio_h_unit COMMENT "mraa unit test collection") diff --git a/tests/unit/api/api_common_h_unit.cxx b/tests/unit/api/api_common_h_unit.cxx index 8b7c3c9..73a013b 100644 --- a/tests/unit/api/api_common_h_unit.cxx +++ b/tests/unit/api/api_common_h_unit.cxx @@ -111,10 +111,6 @@ TEST_F(api_common_h_unit, test_libmraa_common_methods) /* MOCK does NOT have a subplatform */ ASSERT_FALSE(mraa_has_sub_platform()); - - /* Test the string init methods (via the internal struct type) */ - struct _gpio* sg0 = (struct _gpio*)mraa_init_io("GPIO-0"); - ASSERT_EQ(0, sg0->pin); } /* Set the priority of this process */ diff --git a/tests/unit/api/api_common_hpp_unit.cxx b/tests/unit/api/api_common_hpp_unit.cxx index 9f3f52d..7063b97 100644 --- a/tests/unit/api/api_common_hpp_unit.cxx +++ b/tests/unit/api/api_common_hpp_unit.cxx @@ -95,9 +95,5 @@ TEST_F(api_common_hpp_unit, test_libmraa_common_methods) /* MOCK does NOT have a subplatform */ ASSERT_FALSE(mraa::hasSubPlatform()); - - /* Test the string init methods (via the internal struct type) */ - mraa::Gpio* sg0 = mraa::initIo("GPIO-0"); - ASSERT_EQ(0, sg0->getPin()); } } diff --git a/tests/unit/api/mraa_initio_h_unit.cxx b/tests/unit/api/mraa_initio_h_unit.cxx new file mode 100644 index 0000000..b3c0980 --- /dev/null +++ b/tests/unit/api/mraa_initio_h_unit.cxx @@ -0,0 +1,180 @@ +/* + * Author: Mihai Stefanescu + * Copyright (c) 2018 Intel Corporation. + * + * 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 "mraa/initio.h" +#include "gtest/gtest.h" +#include + +/* MRAA API common test fixture */ +class mraa_initio_h_unit : public ::testing::Test +{ + protected: + /* One-time setup logic if needed */ + mraa_initio_h_unit() {} + + /* One-time tear-down logic if needed */ + virtual ~mraa_initio_h_unit() {} + + /* Per-test setup logic if needed */ + virtual void SetUp() {} + + /* Per-test tear-down logic if needed */ + virtual void TearDown() {} +}; + +/* Test for a successful AIO init. */ +TEST_F(mraa_initio_h_unit, test_aio_init) +{ + mraa_io_descriptor* desc; + mraa_result_t status; + + status = mraa_io_init("a:0:10", &desc); + ASSERT_EQ(status, MRAA_SUCCESS); + + status = mraa_io_close(desc); + ASSERT_EQ(status, MRAA_SUCCESS); +} + +/* Test for a successful GPIO init. */ +TEST_F(mraa_initio_h_unit, test_gpio_init) +{ + mraa_io_descriptor* desc; + mraa_result_t status; + + status = mraa_io_init("g:0:1", &desc); + ASSERT_EQ(status, MRAA_SUCCESS); + + status = mraa_io_close(desc); + ASSERT_EQ(status, MRAA_SUCCESS); +} + +/* Test for a successful I2C init. */ +TEST_F(mraa_initio_h_unit, test_i2c_init) +{ + mraa_io_descriptor* desc; + mraa_result_t status; + + status = mraa_io_init("i:0:16", &desc); + ASSERT_EQ(status, MRAA_SUCCESS); + + status = mraa_io_close(desc); + ASSERT_EQ(status, MRAA_SUCCESS); +} + +/* Test for a successful IIO init. */ +TEST_F(mraa_initio_h_unit, test_iio_init) +{ + /*mraa_io_descriptor* desc; + mraa_result_t status; + + status = mraa_io_init("ii:0x1", &desc); + ASSERT_EQ(status, MRAA_SUCCESS); + + status = mraa_io_close(desc); + ASSERT_EQ(status, MRAA_SUCCESS);*/ +} + +/* Test for a successful PWM init. */ +TEST_F(mraa_initio_h_unit, test_pwm_init) +{ + /*mraa_io_descriptor* desc; + mraa_result_t status; + + status = mraa_io_init("p:1", &desc); + ASSERT_EQ(status, MRAA_SUCCESS); + + status = mraa_io_close(desc); + ASSERT_EQ(status, MRAA_SUCCESS);*/ +} + +/* Test for a successful SPI init. */ +TEST_F(mraa_initio_h_unit, test_spi_init) +{ + mraa_io_descriptor* desc; + mraa_result_t status; + + status = mraa_io_init("s:0x0:mode2:400000", &desc); + ASSERT_EQ(status, MRAA_SUCCESS); + + status = mraa_io_close(desc); + ASSERT_EQ(status, MRAA_SUCCESS); +} + +/* Test for a successful UART init. */ +TEST_F(mraa_initio_h_unit, test_uart_init) +{ + mraa_io_descriptor* desc; + mraa_result_t status; + + status = mraa_io_init("u:0x0:9600:8N1", &desc); + ASSERT_EQ(status, MRAA_SUCCESS); + + status = mraa_io_close(desc); + ASSERT_EQ(status, MRAA_SUCCESS); +} + +/* Test for a successful UART_OW init. */ +TEST_F(mraa_initio_h_unit, test_uart_ow_init) +{ + /*mraa_io_descriptor* desc; + mraa_result_t status; + + status = mraa_io_init("ow:0x1", &desc); + ASSERT_EQ(status, MRAA_SUCCESS); + + status = mraa_io_close(desc); + ASSERT_EQ(status, MRAA_SUCCESS);*/ +} + +/* Test for multiple IO initialization and access the structs for + read/write operations. */ +TEST_F(mraa_initio_h_unit, test_multiple_init) +{ + /*mraa_io_descriptor* desc; + mraa_result_t status; + + status = mraa_io_init("g:13:out:1,g:11:out:1", &desc); + ASSERT_EQ(status, MRAA_SUCCESS); + + for (int i = 0; i < 2; ++i) { + ASSERT_EQ(mraa_gpio_read(desc->gpios[i]), 1); + } + + status = mraa_io_close(desc); + ASSERT_EQ(status, MRAA_SUCCESS);*/ +} + +TEST_F(mraa_initio_h_unit, test_leftover_string) +{ + mraa_io_descriptor* desc; + mraa_result_t status; + + status = mraa_io_init("a:0:10,any_string", &desc); + ASSERT_EQ(status, MRAA_SUCCESS); + + ASSERT_STREQ(desc->leftover_str, "any_string"); + + status = mraa_io_close(desc); + ASSERT_EQ(status, MRAA_SUCCESS); +}