diff -Nru mraa-1.9.0/api/mraa/common.h mraa-2.0.0/api/mraa/common.h --- mraa-1.9.0/api/mraa/common.h 2018-02-15 23:08:49.000000000 +0000 +++ mraa-2.0.0/api/mraa/common.h 2018-09-06 12:34:41.000000000 +0000 @@ -50,6 +50,17 @@ if (res != MRAA_SUCCESS) \ return res;} while(0) +/** + * Simple deprecated macro + */ +#ifdef __GNUC__ +#define DEPRECATED __attribute__((deprecated)) +#elif defined(_MSC_VER) +#define DEPRECATED __declspec(deprecated) +#else +#pragma message("WARNING: You need to implement DEPRECATED for this compiler") +#define DEPRECATED +#endif /** @file * @@ -212,35 +223,35 @@ * * @return number of usable UARTs on the platform, returns -1 on failure. */ -int mraa_get_uart_count(void); +int mraa_get_uart_count(); /** * Get the number of usable SPI buses, board must be initialised. * * @return number of usable SPI buses on the platform, returns -1 on failure. */ -int mraa_get_spi_bus_count(void); +int mraa_get_spi_bus_count(); /** * Get the number of usable PWM pins, board must be initialised. * * @return number of PWMs on the current platform, -1 on failure. */ -int mraa_get_pwm_count(void); +int mraa_get_pwm_count(); /** * Get the number of usable GPIOs, board must be initialised. * * @return number of usable external GPIO pins on the board, -1 on failure. */ -int mraa_get_gpio_count(void); +int mraa_get_gpio_count(); /** * Get the number of usable analog pins, board must be initialised. * * @return number of usable ADC inputs on the platform and -1 on failure. */ -int mraa_get_aio_bus_count(void); +int mraa_get_aio_count(); /** * Get platform usable I2C bus count, board must be initialised. diff -Nru mraa-1.9.0/api/mraa/common.hpp mraa-2.0.0/api/mraa/common.hpp --- mraa-1.9.0/api/mraa/common.hpp 2018-02-15 23:08:49.000000000 +0000 +++ mraa-2.0.0/api/mraa/common.hpp 2018-09-06 12:34:41.000000000 +0000 @@ -143,27 +143,31 @@ } /** - * Return Platform Name. Returns NULL if no platform inited. + * Return platform name. * - * @return platform name + * @return platform name or empty string if not initialised */ inline std::string getPlatformName() { - std::string ret_val(mraa_get_platform_name()); + std::string ret_val; + const char * pn = mraa_get_platform_name(); + if (pn) ret_val = pn; return ret_val; } /** - * Return platform versioning info. Returns NULL if no info present. + * Return platform versioning info. * * @param platform_offset optional subplatform identifier - * @return platform versioning info + * @return platform versioning info or empty string if no info is present */ inline std::string getPlatformVersion(int platform_offset=MRAA_MAIN_PLATFORM_OFFSET) { - std::string ret_val(mraa_get_platform_version(platform_offset)); + std::string ret_val; + const char* pv = mraa_get_platform_version(platform_offset); + if (pv) ret_val = pv; return ret_val; } @@ -219,12 +223,14 @@ * * @param pin number * -* @return char* of pin name +* @return Pin name or empty string on failure */ inline std::string getPinName(int pin) { - std::string ret_val(mraa_get_pin_name(pin)); + std::string ret_val; + const char* pn = mraa_get_pin_name(pin); + if (pn) ret_val = pn; return ret_val; } diff -Nru mraa-1.9.0/api/mraa/gpio.h mraa-2.0.0/api/mraa/gpio.h --- mraa-1.9.0/api/mraa/gpio.h 2018-02-15 23:08:49.000000000 +0000 +++ mraa-2.0.0/api/mraa/gpio.h 2018-09-06 12:34:41.000000000 +0000 @@ -61,7 +61,10 @@ MRAA_GPIO_STRONG = 0, /**< Default. Strong high and low */ MRAA_GPIO_PULLUP = 1, /**< Resistive High */ MRAA_GPIO_PULLDOWN = 2, /**< Resistive Low */ - MRAA_GPIO_HIZ = 3 /**< High Z State */ + MRAA_GPIO_HIZ = 3, /**< High Z State */ + MRAA_GPIOD_ACTIVE_LOW = 4, + MRAA_GPIOD_OPEN_DRAIN = 5, + MRAA_GPIOD_OPEN_SOURCE = 6, } mraa_gpio_mode_t; /** @@ -101,6 +104,18 @@ MRAA_GPIO_PUSH_PULL = 1, /**< Push Pull Configuration */ } mraa_gpio_out_driver_mode_t; +typedef long long unsigned int mraa_timestamp_t; + +/** + * Gpio event object + */ +typedef struct { + int id; /**< id of event */ + mraa_timestamp_t timestamp; /**< timestamp */ +} mraa_gpio_event; + +typedef mraa_gpio_event* mraa_gpio_events_t; + /** * Initialise gpio_context, based on board number * @@ -110,6 +125,16 @@ mraa_gpio_context mraa_gpio_init(int pin); /** + * Initialise gpio_context, based on board number, for multiple pins (can be one). + * + * @param pins Pin array read from the board + * @param num_pins Number of pins - must be the same as the pins array length provided + * as the first argument. + * @returns gpio context or NULL + */ +mraa_gpio_context mraa_gpio_init_multi(int pins[], int num_pins); + +/** * Initialise gpio context without any mapping to a pin * * @param gpiopin gpio pin as listed in SYSFS @@ -127,10 +152,10 @@ mraa_result_t mraa_gpio_edge_mode(mraa_gpio_context dev, mraa_gpio_edge_t mode); /** - * Set an interrupt on pin + * Set an interrupt on pin(s). * * @param dev The Gpio context - * @param edge The edge mode to set the gpio into + * @param edge The edge mode to set the gpio(s) into * @param fptr Function pointer to function to be called when interrupt is * triggered * @param args Arguments passed to the interrupt handler (fptr) @@ -139,8 +164,18 @@ mraa_result_t mraa_gpio_isr(mraa_gpio_context dev, mraa_gpio_edge_t edge, void (*fptr)(void*), void* args); /** + * Get an array of structures describing triggered events. + * + * @param dev The Gpio context + * @return Array of structures containing pairs of pin id's and the associated timestamp. + * An event with negative id value indicates that no event was triggered for the respective pin. + * The array length is that of the number of pins provided in mraa_gpio_init_multi(). + */ +mraa_gpio_events_t mraa_gpio_get_events(mraa_gpio_context dev); + +/** * Stop the current interrupt watcher on this Gpio, and set the Gpio edge mode - * to MRAA_GPIO_EDGE_NONE + * to MRAA_GPIO_EDGE_NONE(only for sysfs interface). * * @param dev The Gpio context * @return Result of operation @@ -148,35 +183,36 @@ mraa_result_t mraa_gpio_isr_exit(mraa_gpio_context dev); /** - * Set Gpio Output Mode, + * Set Gpio(s) Output Mode, * * @param dev The Gpio context - * @param mode The Gpio Output Mode + * @param mode The Gpio(s) Output Mode * @return Result of operation */ mraa_result_t mraa_gpio_mode(mraa_gpio_context dev, mraa_gpio_mode_t mode); /** - * Set Gpio direction + * Set Gpio(s) direction * * @param dev The Gpio context - * @param dir The direction of the Gpio + * @param dir The direction of the Gpio(s) * @return Result of operation */ mraa_result_t mraa_gpio_dir(mraa_gpio_context dev, mraa_gpio_dir_t dir); /** - * Read Gpio direction + * Read Gpio(s) direction * * @param dev The Gpio context - * @param dir The address where to store the Gpio direction + * @param dir The address where to store the Gpio(s) direction * @return Result of operation */ mraa_result_t mraa_gpio_read_dir(mraa_gpio_context dev, mraa_gpio_dir_t *dir); /** * Close the Gpio context - * - Will free the memory for the context and unexport the Gpio + * - Will free the memory for the context and unexport the Gpio - sysfs interface. + * - Will free up the memory used by context and close related file descriptors - chardev interface. * * @param dev The Gpio context * @return Result of operation @@ -193,6 +229,16 @@ int mraa_gpio_read(mraa_gpio_context dev); /** + * Read the Gpio(s) value. The user must provide an integer array with a length equal to the + * number of pins provided to mraa_gpio_init_multi() function. + * + * @param dev The Gpio context + * @param output_values The array provided by the user. Existing values will be overwritten with the newly read ones. + * @return Result of operation + */ +mraa_result_t mraa_gpio_read_multi(mraa_gpio_context dev, int output_values[]); + +/** * Write to the Gpio Value. * * @param dev The Gpio context @@ -202,6 +248,17 @@ mraa_result_t mraa_gpio_write(mraa_gpio_context dev, int value); /** + * Write to the Gpio(s) Value. The user must provide an integer array with a length equal to the + * number of pins provided to mraa_gpio_init_multi() function. + * + * @param dev The Gpio context + * @param output_values The array provided by the user. It must contain the values intended to be written + * to the gpio pins, in the same order as the init function. + * @return Result of operation + */ +mraa_result_t mraa_gpio_write_multi(mraa_gpio_context dev, int input_values[]); + +/** * Change ownership of the context. * * @param dev The Gpio context @@ -211,13 +268,15 @@ mraa_result_t mraa_gpio_owner(mraa_gpio_context dev, mraa_boolean_t owner); /** - * Enable using memory mapped io instead of sysfs + * Enable using memory mapped io instead of sysfs, chardev based I/O can be + * considered memorymapped * + * @deprecated * @param dev The Gpio context * @param mmap Use mmap instead of sysfs * @return Result of operation */ -mraa_result_t mraa_gpio_use_mmaped(mraa_gpio_context dev, mraa_boolean_t mmap); +DEPRECATED mraa_result_t mraa_gpio_use_mmaped(mraa_gpio_context dev, mraa_boolean_t mmap); /** * Get a pin number of the gpio, invalid will return -1 diff -Nru mraa-1.9.0/api/mraa/iio.hpp mraa-2.0.0/api/mraa/iio.hpp --- mraa-1.9.0/api/mraa/iio.hpp 2018-02-15 23:08:49.000000000 +0000 +++ mraa-2.0.0/api/mraa/iio.hpp 2018-09-06 12:34:41.000000000 +0000 @@ -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 @@ /** 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 }; @@ -113,6 +112,19 @@ } /** + * 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 */ ~Iio() @@ -193,7 +205,6 @@ oss << "IIO writeInt for attibute " << attributeName << " failed"; throw std::runtime_error(oss.str()); } - } /** @@ -213,7 +224,6 @@ oss << "IIO writeFloat for attibute " << attributeName << " failed"; throw std::runtime_error(oss.str()); } - } /** @@ -233,13 +243,15 @@ } 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 @@ mraa_iio_context m_iio; }; - } diff -Nru mraa-1.9.0/api/mraa/initio.h mraa-2.0.0/api/mraa/initio.h --- mraa-1.9.0/api/mraa/initio.h 1970-01-01 00:00:00.000000000 +0000 +++ mraa-2.0.0/api/mraa/initio.h 2018-09-06 12:34:41.000000000 +0000 @@ -0,0 +1,155 @@ +/* + * 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" + +#if !defined(PERIPHERALMAN) +#include "iio.h" +#endif + +#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; +#if !defined(PERIPHERALMAN) + int n_iio; + mraa_iio_context* iios; +#endif + 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 -Nru mraa-1.9.0/api/mraa/initio.hpp mraa-2.0.0/api/mraa/initio.hpp --- mraa-1.9.0/api/mraa/initio.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mraa-2.0.0/api/mraa/initio.hpp 2018-09-06 12:34:41.000000000 +0000 @@ -0,0 +1,177 @@ +/* + * 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" + +#if !defined(PERIPHERALMAN) +#include "iio.hpp" +#endif + +#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]); + } + +#if !defined(PERIPHERALMAN) + iios.reserve(descs->n_iio); + for (int i = 0; i < descs->n_iio; ++i) { + iios.emplace_back(descs->iios[i]); + } +#endif + + 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 !defined(PERIPHERALMAN) + if (descs->n_iio) { + free(descs->iios); + } +#endif + 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; +#if !defined(PERIPHERALMAN) + std::vector iios; +#endif + 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 -Nru mraa-1.9.0/api/mraa/led.h mraa-2.0.0/api/mraa/led.h --- mraa-1.9.0/api/mraa/led.h 2018-02-15 23:08:49.000000000 +0000 +++ mraa-2.0.0/api/mraa/led.h 2018-09-06 12:34:41.000000000 +0000 @@ -47,15 +47,23 @@ typedef struct _led* mraa_led_context; /** + * Initialise led_context, based on led index. + * + * @param led ID of the LED + * @returns LED context or NULL + */ +mraa_led_context mraa_led_init(int led); + +/** * Initialise led_context, based on led function name. * The structure of LED entry in sysfs is "devicename:colour:function" * This api expects only one unique LED identifier which would be - * "function" name most often. For instance, `mraa_led_init("user4");` + * "function" name most often. For instance, `mraa_led_init_raw("user4");` * - * @param led Name of the LED + * @param led_dev Name of the LED device * @returns LED context or NULL */ -mraa_led_context mraa_led_init(const char* led); +mraa_led_context mraa_led_init_raw(const char* led_dev); /** * Set LED brightness diff -Nru mraa-1.9.0/api/mraa/led.hpp mraa-2.0.0/api/mraa/led.hpp --- mraa-1.9.0/api/mraa/led.hpp 2018-02-15 23:08:49.000000000 +0000 +++ mraa-2.0.0/api/mraa/led.hpp 2018-09-06 12:34:41.000000000 +0000 @@ -44,14 +44,28 @@ /** * Instantiates an LED object * - * @param led LED fuction name to use + * @param led LED index to use */ - Led(const char* led) + Led(int led) { m_led = mraa_led_init(led); if (m_led == NULL) { throw std::invalid_argument("Invalid LED name specified"); + } + } + + /** + * Instantiates an LED object + * + * @param led_dev LED function name to use + */ + Led(std::string led_dev) + { + m_led = mraa_led_init_raw(led_dev.c_str()); + + if (m_led == NULL) { + throw std::invalid_argument("Invalid LED name specified"); } } diff -Nru mraa-1.9.0/api/mraa/types.h mraa-2.0.0/api/mraa/types.h --- mraa-1.9.0/api/mraa/types.h 2018-02-15 23:08:49.000000000 +0000 +++ mraa-2.0.0/api/mraa/types.h 2018-09-06 12:34:41.000000000 +0000 @@ -59,6 +59,7 @@ MRAA_UP2 = 16, /**< The UP^2 Board */ MRAA_MTK_LINKIT = 17, /**< Mediatek MT7688 based Linkit boards */ MRAA_MTK_OMEGA2 = 18, /**< MT7688 based Onion Omega2 board */ + MRAA_IEI_TANK = 19, /**< IEI Tank System*/ // USB platform extenders start at 256 MRAA_FTDI_FT4222 = 256, /**< FTDI FT4222 USB to i2c bridge */ diff -Nru mraa-1.9.0/api/mraa/types.hpp mraa-2.0.0/api/mraa/types.hpp --- mraa-1.9.0/api/mraa/types.hpp 2018-02-15 23:08:49.000000000 +0000 +++ mraa-2.0.0/api/mraa/types.hpp 2018-09-06 12:34:41.000000000 +0000 @@ -55,6 +55,9 @@ PHYBOARD_WEGA = 14, /**< The phyBOARD-Wega */ DE_NANO_SOC = 15, /**< Terasic DE-Nano-SoC Board */ INTEL_UP2 = 16, /**< The UP^2 Board */ + MTK_LINKIT = 17, /**< Mediatek MT7688 based Linkit boards */ + MTK_OMEGA2 = 18, /**< MT7688 based Onion Omega2 board */ + IEI_TANK = 19, /**< IEI Tank System*/ FTDI_FT4222 = 256, /**< FTDI FT4222 USB to i2c bridge */ @@ -62,6 +65,7 @@ GENERIC_FIRMATA = 1280, /**< Firmata uart platform/bridge */ ANDROID_PERIPHERALMANAGER = 95, /**< Android Things peripheral manager platform */ + MOCK_PLATFORM = 96, /**< Mock platform, which requires no real hardware */ NULL_PLATFORM = 98, UNKNOWN_PLATFORM = 99 /**< An unknown platform type, typically will load INTEL_GALILEO_GEN1 */ } Platform; diff -Nru mraa-1.9.0/api/mraa/uart_ow.hpp mraa-2.0.0/api/mraa/uart_ow.hpp --- mraa-1.9.0/api/mraa/uart_ow.hpp 2018-02-15 23:08:49.000000000 +0000 +++ mraa-2.0.0/api/mraa/uart_ow.hpp 2018-09-06 12:34:41.000000000 +0000 @@ -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 @@ } } + /** + * 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 -Nru mraa-1.9.0/cmake/modules/CPackDeb.cmake mraa-2.0.0/cmake/modules/CPackDeb.cmake --- mraa-1.9.0/cmake/modules/CPackDeb.cmake 2018-02-15 23:08:49.000000000 +0000 +++ mraa-2.0.0/cmake/modules/CPackDeb.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,222 +0,0 @@ -# - The builtin (binary) CPack Deb generator (Unix only) -# CPackDeb may be used to create Deb package using CPack. -# CPackDeb is a CPack generator thus it uses the CPACK_XXX variables -# used by CPack : http://www.cmake.org/Wiki/CMake:CPackConfiguration -# -# However CPackRPM has specific features which are controlled by -# the specifics CPACK_RPM_XXX variables.You'll find a detailed usage on -# the wiki: -# http://www.cmake.org/Wiki/CMake:CPackPackageGenerators#DEB_.28UNIX_only.29 -# However as a handy reminder here comes the list of specific variables: -# -# CPACK_DEBIAN_PACKAGE_NAME -# Mandatory : YES -# Default : CPACK_PACKAGE_NAME (lower case) -# The debian package summary -# CPACK_DEBIAN_PACKAGE_VERSION -# Mandatory : YES -# Default : CPACK_PACKAGE_VERSION -# The debian package version -# CPACK_DEBIAN_PACKAGE_ARCHITECTURE) -# Mandatory : YES -# Default : Output of dpkg --print-architecture or i386 -# The debian package architecture -# CPACK_DEBIAN_PACKAGE_DEPENDS -# Mandatory : NO -# Default : - -# May be used to set deb dependencies. -# CPACK_DEBIAN_PACKAGE_MAINTAINER -# Mandatory : YES -# Default : CPACK_PACKAGE_CONTACT -# The debian package maintainer -# CPACK_DEBIAN_PACKAGE_DESCRIPTION -# Mandatory : YES -# Default : CPACK_PACKAGE_DESCRIPTION_SUMMARY -# The debian package description -# CPACK_DEBIAN_PACKAGE_SECTION -# Mandatory : YES -# Default : 'devel' -# The debian package section -# CPACK_DEBIAN_PACKAGE_PRIORITY -# Mandatory : YES -# Default : 'optional' -# The debian package priority - -#============================================================================= -# Copyright 2007-2009 Kitware, Inc. -# Copyright 2007-2009 Mathieu Malaterre -# -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. -#============================================================================= -# (To distributed this file outside of CMake, substitute the full -# License text for the above reference.) - -# CPack script for creating Debian package -# Author: Mathieu Malaterre -# -# http://wiki.debian.org/HowToPackageForDebian - -IF(CMAKE_BINARY_DIR) - MESSAGE(FATAL_ERROR "CPackDeb.cmake may only be used by CPack internally.") -ENDIF(CMAKE_BINARY_DIR) - -IF(NOT UNIX) - MESSAGE(FATAL_ERROR "CPackDeb.cmake may only be used under UNIX.") -ENDIF(NOT UNIX) - -# Let's define the control file found in debian package: - -# Binary package: -# http://www.debian.org/doc/debian-policy/ch-controlfields.html#s-binarycontrolfiles - -# DEBIAN/control -# debian policy enforce lower case for package name -# Package: (mandatory) -IF(NOT CPACK_DEBIAN_PACKAGE_NAME) - STRING(TOLOWER "${CPACK_PACKAGE_NAME}" CPACK_DEBIAN_PACKAGE_NAME) -ENDIF(NOT CPACK_DEBIAN_PACKAGE_NAME) - -# Version: (mandatory) -IF(NOT CPACK_DEBIAN_PACKAGE_VERSION) - IF(NOT CPACK_PACKAGE_VERSION) - MESSAGE(FATAL_ERROR "Debian package requires a package version") - ENDIF(NOT CPACK_PACKAGE_VERSION) - SET(CPACK_DEBIAN_PACKAGE_VERSION ${CPACK_PACKAGE_VERSION}) -ENDIF(NOT CPACK_DEBIAN_PACKAGE_VERSION) - -# Architecture: (mandatory) -IF(NOT CPACK_DEBIAN_PACKAGE_ARCHITECTURE) - # There is no such thing as i686 architecture on debian, you should use i386 instead - # $ dpkg --print-architecture - FIND_PROGRAM(DPKG_CMD dpkg) - IF(NOT DPKG_CMD) - MESSAGE(STATUS "Can not find dpkg in your path, default to i386.") - SET(CPACK_DEBIAN_PACKAGE_ARCHITECTURE i386) - ENDIF(NOT DPKG_CMD) - EXECUTE_PROCESS(COMMAND "${DPKG_CMD}" --print-architecture - OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_ARCHITECTURE - OUTPUT_STRIP_TRAILING_WHITESPACE - ) -ENDIF(NOT CPACK_DEBIAN_PACKAGE_ARCHITECTURE) - -# have a look at GET_PROPERTY(result GLOBAL PROPERTY ENABLED_FEATURES), -# this returns the successful FIND_PACKAGE() calls, maybe this can help -# Depends: -# You should set: DEBIAN_PACKAGE_DEPENDS -# TODO: automate 'objdump -p | grep NEEDED' -IF(NOT CPACK_DEBIAN_PACKAGE_DEPENDS) - MESSAGE(STATUS "CPACK_DEBIAN_PACKAGE_DEPENDS not set, the package will have no dependencies.") -ENDIF(NOT CPACK_DEBIAN_PACKAGE_DEPENDS) - -# Maintainer: (mandatory) -IF(NOT CPACK_DEBIAN_PACKAGE_MAINTAINER) - IF(NOT CPACK_PACKAGE_CONTACT) - MESSAGE(FATAL_ERROR "Debian package requires a maintainer for a package, set CPACK_PACKAGE_CONTACT or CPACK_DEBIAN_PACKAGE_MAINTAINER") - ENDIF(NOT CPACK_PACKAGE_CONTACT) - SET(CPACK_DEBIAN_PACKAGE_MAINTAINER ${CPACK_PACKAGE_CONTACT}) -ENDIF(NOT CPACK_DEBIAN_PACKAGE_MAINTAINER) - -# Description: (mandatory) -IF(NOT CPACK_DEBIAN_PACKAGE_DESCRIPTION) - IF(NOT CPACK_PACKAGE_DESCRIPTION_SUMMARY) - MESSAGE(FATAL_ERROR "Debian package requires a summary for a package, set CPACK_PACKAGE_DESCRIPTION_SUMMARY or CPACK_DEBIAN_PACKAGE_DESCRIPTION") - ENDIF(NOT CPACK_PACKAGE_DESCRIPTION_SUMMARY) - SET(CPACK_DEBIAN_PACKAGE_DESCRIPTION ${CPACK_PACKAGE_DESCRIPTION_SUMMARY}) -ENDIF(NOT CPACK_DEBIAN_PACKAGE_DESCRIPTION) - -# Section: (recommended) -IF(NOT CPACK_DEBIAN_PACKAGE_SECTION) - SET(CPACK_DEBIAN_PACKAGE_SECTION "devel") -ENDIF(NOT CPACK_DEBIAN_PACKAGE_SECTION) - -# Priority: (recommended) -IF(NOT CPACK_DEBIAN_PACKAGE_PRIORITY) - SET(CPACK_DEBIAN_PACKAGE_PRIORITY "optional") -ENDIF(NOT CPACK_DEBIAN_PACKAGE_PRIORITY ) - -# Recommends: -# You should set: CPACK_DEBIAN_PACKAGE_RECOMMENDS - -# Suggests: -# You should set: CPACK_DEBIAN_PACKAGE_SUGGESTS - -# CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA -# This variable allow advanced user to add custom script to the control.tar.gz (inside the .deb archive) -# Typical examples are: -# - conffiles -# - postinst -# - postrm -# - prerm" -# Usage: -# SET(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA -# "${CMAKE_CURRENT_SOURCE_DIR/prerm;${CMAKE_CURRENT_SOURCE_DIR}/postrm") - - -# For debian source packages: -# debian/control -# http://www.debian.org/doc/debian-policy/ch-controlfields.html#s-sourcecontrolfiles - -# .dsc -# http://www.debian.org/doc/debian-policy/ch-controlfields.html#s-debiansourcecontrolfiles - -# Builds-Depends: -#IF(NOT CPACK_DEBIAN_PACKAGE_BUILDS_DEPENDS) -# SET(CPACK_DEBIAN_PACKAGE_BUILDS_DEPENDS -# "debhelper (>> 5.0.0), libncurses5-dev, tcl8.4" -# ) -#ENDIF(NOT CPACK_DEBIAN_PACKAGE_BUILDS_DEPENDS) - -# Description: (mandatory) -#if(NOT CPACK_SECTION) -# message(FATAL_ERROR "opkg package requires a package section") -#endif(NOT CPACK_SECTION) - -# Package for opkg -FIND_PROGRAM(OPKG_CMD opkg-build) -if( ${OPKG_CMD} STREQUAL "OPKG_CMD-NOTFOUND" ) - message("CPack: opkg-build not found. Skipping packaging") -else( ${OPKG_CMD} STREQUAL "OPKG_CMD-NOTFOUND" ) - SET(CPACK_OPKG_ROOTDIR "${CPACK_TOPLEVEL_DIRECTORY}/${CPACK_PACKAGE_FILE_NAME}") - FILE(MAKE_DIRECTORY ${CPACK_OPKG_ROOTDIR}/CONTROL) - set(CPACK_OPKG_CONTROL_FILE "${CPACK_OPKG_ROOTDIR}/CONTROL/control") - # Write controlfile - FILE(WRITE ${CPACK_OPKG_CONTROL_FILE} - "Package: ${CPACK_PACKAGE_NAME} -Version: ${CPACK_PACKAGE_VERSION} -Description: ${CPACK_PACKAGE_DESCRIPTION_SUMMARY} -Architecture: ${CPACK_DEBIAN_PACKAGE_ARCHITECTURE} -Section: ${CPACK_DEBIAN_PACKAGE_SECTION} -Priority: optional -Maintainer: ${CPACK_DEBIAN_PACKAGE_MAINTAINER} -Depends: -Provides: ${CPACK_DEBIAN_PACKAGE_PROVIDES} -Replaces: ${CPACK_DEBIAN_PACKAGE_REPLACES} -Conflicts: ${CPACK_DEBIAN_PACKAGE_CONFLICTS} -Source: https://github.com/intel-iot-devkit/mraa -#Essential: no -") - -set(OPKG_FILE_NAME "${CPACK_PACKAGE_NAME}_${CPACK_PACKAGE_VERSION}_${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}") - execute_process( - COMMAND "${OPKG_CMD}" "-o" "0" "${CPACK_PACKAGE_FILE_NAME}" "." - RESULT_VARIABLE _result - OUTPUT_VARIABLE _res_output - ERROR_VARIABLE _res_error - WORKING_DIRECTORY ${CPACK_TOPLEVEL_DIRECTORY} - ) - - if(${_result}) - message("Result '${_result}'") - message("Output '${_res_output}'") - message("Error '${_res_error}'") - else(${_result}) - message("CPack: Package ${OPKG_FILE_NAME}.ipk generated.") - set(WDIR "${CPACK_TOPLEVEL_DIRECTORY}/${CPACK_PACKAGE_FILE_NAME}") - file(RENAME ${CPACK_TOPLEVEL_DIRECTORY}/${OPKG_FILE_NAME}.ipk ${CPACK_BINARY_DIR}/${OPKG_FILE_NAME}.ipk) - endif(${_result}) -endif( ${OPKG_CMD} STREQUAL "OPKG_CMD-NOTFOUND" ) diff -Nru mraa-1.9.0/cmake/modules/FindFtd2xx.cmake mraa-2.0.0/cmake/modules/FindFtd2xx.cmake --- mraa-1.9.0/cmake/modules/FindFtd2xx.cmake 2018-02-15 23:08:49.000000000 +0000 +++ mraa-2.0.0/cmake/modules/FindFtd2xx.cmake 2018-09-06 12:34:41.000000000 +0000 @@ -27,11 +27,11 @@ /usr/local/include /opt/local/include /sw/include - ) + ) SET(FTD2XX_LIBNAME ftd2xx) IF(WIN32) - SET(FTD2XX_LIBNAME ftd2xx.lib) + SET(FTD2XX_LIBNAME ftd2xx.lib) ENDIF(WIN32) find_library(LIBFTD2XX_LIBRARY @@ -42,16 +42,16 @@ /usr/local/lib /opt/local/lib /sw/lib - ) + ) if(LIBFTD2XX_INCLUDE_DIR) - set(LIBFTD2XX_INCLUDE_DIRS + set(LIBFTD2XX_INCLUDE_DIRS ${LIBFTD2XX_INCLUDE_DIR} - ) + ) endif(LIBFTD2XX_INCLUDE_DIR) set(LIBFTD2XX_LIBRARIES ${LIBFTD2XX_LIBRARY} - ) + ) if (LIBFTD2XX_INCLUDE_DIRS AND LIBFTD2XX_LIBRARIES) set(LIBFTD2XX_FOUND TRUE) @@ -59,14 +59,17 @@ if (LIBFTD2XX_FOUND) if (NOT libftd2xx_FIND_QUIETLY) - message(STATUS "Found libftd2xx: ${LIBFTD2XX_LIBRARIES}") + message(STATUS "Found libftd2xx: ${LIBFTD2XX_LIBRARIES}") endif (NOT libftd2xx_FIND_QUIETLY) else (LIBFTD2XX_FOUND) if (libftd2xx_FIND_REQUIRED) - message(FATAL_ERROR "Could not find libftd2xx") + message(FATAL_ERROR "Could not find libftd2xx") endif (libftd2xx_FIND_REQUIRED) endif (LIBFTD2XX_FOUND) + find_package_handle_standard_args(Ftd2xx + REQUIRED_VARS LIBFTD2XX_INCLUDE_DIRS) + # show the LIBFTD2XX_INCLUDE_DIRS and LIBFTD2XX_LIBRARIES variables only in the advanced view mark_as_advanced(LIBFTD2XX_INCLUDE_DIRS LIBFTD2XX_LIBRARIES) diff -Nru mraa-1.9.0/cmake/modules/FindFtd4222.cmake mraa-2.0.0/cmake/modules/FindFtd4222.cmake --- mraa-1.9.0/cmake/modules/FindFtd4222.cmake 2018-02-15 23:08:49.000000000 +0000 +++ mraa-2.0.0/cmake/modules/FindFtd4222.cmake 2018-09-06 12:34:41.000000000 +0000 @@ -28,11 +28,11 @@ /usr/local/include /opt/local/include /sw/include - ) + ) SET(FTD4222_LIBNAME ft4222) IF(WIN32) - SET(FTD4222_LIBNAME LibFT4222.lib) + SET(FTD4222_LIBNAME LibFT4222.lib) ENDIF(WIN32) find_library(LIBFT4222_LIBRARY @@ -43,16 +43,16 @@ /usr/local/lib /opt/local/lib /sw/lib - ) + ) if(LIBFT4222_INCLUDE_DIR) - set(LIBFT4222_INCLUDE_DIRS + set(LIBFT4222_INCLUDE_DIRS ${LIBFT4222_INCLUDE_DIR} - ) + ) endif(LIBFT4222_INCLUDE_DIR) set(LIBFT4222_LIBRARIES ${LIBFT4222_LIBRARY} - ) + ) if (LIBFT4222_INCLUDE_DIRS AND LIBFT4222_LIBRARIES) set(LIBFT4222_FOUND TRUE) @@ -60,14 +60,17 @@ if (LIBFT4222_FOUND) if (NOT LIBFT4222_FIND_QUIETLY) - message(STATUS "Found LIBFT4222: ${LIBFT4222_LIBRARIES}") + message(STATUS "Found LIBFT4222: ${LIBFT4222_LIBRARIES}") endif (NOT LIBFT4222_FIND_QUIETLY) else (LIBFT4222_FOUND) if (LIBFT4222_FIND_REQUIRED) - message(FATAL_ERROR "Could not find LIBFT4222") + message(FATAL_ERROR "Could not find LIBFT4222") endif (LIBFT4222_FIND_REQUIRED) endif (LIBFT4222_FOUND) + find_package_handle_standard_args(Ftd4222 + REQUIRED_VARS LIBFT4222_INCLUDE_DIRS LIBFT4222_LIBRARIES) + # show the LIBFT4222_INCLUDE_DIRS and LIBFT4222_LIBRARIES variables only in the advanced view mark_as_advanced(LIBFT4222_INCLUDE_DIRS LIBFT4222_LIBRARIES) diff -Nru mraa-1.9.0/CMakeLists.txt mraa-2.0.0/CMakeLists.txt --- mraa-1.9.0/CMakeLists.txt 2018-02-15 23:08:49.000000000 +0000 +++ mraa-2.0.0/CMakeLists.txt 2018-09-06 12:34:41.000000000 +0000 @@ -1,8 +1,16 @@ -cmake_minimum_required (VERSION 2.8) +cmake_minimum_required (VERSION 2.8.11) project (mraa C CXX) FIND_PACKAGE (Threads REQUIRED) +if (CMAKE_VERSION VERSION_LESS "3.1") + if (CMAKE_C_COMPILER_ID STREQUAL "GNU") + set (CMAKE_C_FLAGS "-std=gnu99 ${CMAKE_C_FLAGS}") + endif () +else () + set (CMAKE_C_STANDARD 99) +endif () + ############################################################################### # Detect supported warning flags # Modified from work By Dan Liew (fpbench - MIT) @@ -66,6 +74,17 @@ endif () endforeach () +# This function adds the c++11 flag to a c++ target (if supported) +function(use_cxx_11 targetname) + include(CheckCXXCompilerFlag) + CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11) + if (COMPILER_SUPPORTS_CXX11) + set_target_properties(${targetname} PROPERTIES COMPILE_FLAGS "-std=c++11") + else() + message(FATAL_ERROR "Target '${targetname}' requires c++11 which is not supported by this compiler") + endif() +endfunction() + # Set CMAKE_INSTALL_LIBDIR if not defined include(GNUInstallDirs) @@ -91,7 +110,7 @@ git_describe (VERSION "--tags") if ("x_${VERSION}" STREQUAL "x_GIT-NOTFOUND" OR "x_${VERSION}" STREQUAL "x_HEAD-HASH-NOTFOUND" OR "x_${VERSION}" STREQUAL "x_-128-NOTFOUND") message (WARNING " - Install git to compile a production libmraa!") - set (VERSION "v1.9.0") + set (VERSION "v2.0.0") endif () message (STATUS "INFO - libmraa Version ${VERSION}") @@ -134,8 +153,6 @@ option (JSONPLAT "Add Platform loading via a json file." ON) option (IMRAA "Add Imraa support to mraa." OFF) option (FTDI4222 "Build with FTDI FT4222 subplatform support." OFF) -option (IPK "Generate IPK using CPack" OFF) -option (RPM "Generate RPM using CPack" OFF) option (ENABLEEXAMPLES "Disable building of examples" ON) option (INSTALLTOOLS "Install all tools" ON) option (BUILDTESTS "Override the addition of tests" ON) @@ -197,66 +214,6 @@ endif (DOXYGEN_FOUND AND DOXYGEN_VERSION VERSION_GREATER "1.8") endif () -if (IPK) - # Get target package arch from Yocto ADT sysroot if set or host OS, mapping to Ubuntu name if necessary - if (DEFINED ENV{OECORE_TARGET_SYSROOT}) - GET_FILENAME_COMPONENT (DETECTED_SYSROOT $ENV{OECORE_TARGET_SYSROOT} NAME) - string (REGEX REPLACE "-poky-linux" "" TARGET_ARCH "${DETECTED_SYSROOT}") - else () - # debian uses amd64 to denote x86_64 - if (DETECTED_ARCH STREQUAL "x86_64") - set (TARGET_ARCH "amd64") - else () - set (TARGET_ARCH ${DETECTED_ARCH}) - endif () - endif () - message (STATUS "INFO - Package arch is ${TARGET_ARCH}") - - set(CPACK_GENERATOR "DEB") - set(OPKG_ARCH ${TARGET_ARCH}) - set(CPACK_BINARY_DIR ${CMAKE_BINARY_DIR}) - set(CPACK_DEBIAN_PACKAGE_MAINTAINER "Intel IoT-Devkit") #required - set(mraa_PACKAGE_ON_TAG ".") - if ("${VERSION_COMMIT}" STREQUAL "") - set(mraa_PACKAGE_ON_TAG "") - endif() - set(CPACK_PACKAGE_VERSION - "${mraa_VERSION_MAJOR}.${mraa_VERSION_MINOR}.${mraa_VERSION_PATCH}${mraa_PACKAGE_ON_TAG}${VERSION_COMMIT}") - set(CPACK_PACKAGE_NAME "mraa") - set(CPACK_DEBIAN_PACKAGE_SECTION "libs") - set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE ${TARGET_ARCH}) - set(CPACK_SYSTEM_NAME ${TARGET_ARCH}) - set(CPACK_DEBIAN_PACKAGE_PROVIDES "mraa-dev, mraa-dbg, mraa-doc") - set(CPACK_DEBIAN_PACKAGE_REPLACES "${CPACK_DEBIAN_PACKAGE_PROVIDES}, libmraa, libmraa-dev, libmraa-doc") - set(CPACK_DEBIAN_PACKAGE_CONFLICTS ${CPACK_DEBIAN_PACKAGE_PROVIDES}) - set(WDIR "${CPACK_TOPLEVEL_DIRECTORY}/${CPACK_PACKAGE_FILE_NAME}") - include (CPack) -endif() - -if (RPM) - message (STATUS "INFO - Enabled RPM packaging for ${DETECTED_ARCH}") - set(CMAKE_INSTALL_PREFIX "/usr") - set(CPACK_PACKAGE_VERSION ${VERSION}) - set(CPACK_GENERATOR "RPM") - set(CPACK_PACKAGE_NAME "libmraa${mraa_VERSION_MAJOR}") - set(CPACK_PACKAGE_RELEASE 1) - set(CPACK_PACKAGE_VERSION - "${mraa_VERSION_MAJOR}.${mraa_VERSION_MINOR}.${mraa_VERSION_PATCH}${mraa_PACKAGE_ON_TAG}${VERSION_COMMIT}") - set(CPACK_PACKAGE_CONTACT "Intel IoT-Devkit") - set(CPACK_PACKAGE_VENDOR "Intel IoT-Devkit") - set(CPACK_RPM_PACKAGE_PROVIDES "${CPACK_PACKAGE_NAME}-devel") - # Get distro tag (e.g. 'fc20') by parsing output of rpm --showrc - EXECUTE_PROCESS( - COMMAND rpm --showrc - COMMAND grep -w dist - COMMAND sed -e "s/\\t./ /" - COMMAND awk "{printf \"%s\", \$NF}" - OUTPUT_VARIABLE DIST_TAG - ) - set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${CPACK_PACKAGE_RELEASE}.${DIST_TAG}.${DETECTED_ARCH}") - include(CPack) -endif() - add_subdirectory (src) if (ENABLEEXAMPLES) add_subdirectory (examples) diff -Nru mraa-1.9.0/debian/changelog mraa-2.0.0/debian/changelog --- mraa-1.9.0/debian/changelog 2018-02-16 10:12:18.000000000 +0000 +++ mraa-2.0.0/debian/changelog 2018-09-11 11:42:03.000000000 +0000 @@ -1,3 +1,9 @@ +mraa (2.0.0-1~ubuntu18.04) bionic; urgency=medium + + * Update to mraa 2.0.0 + + -- Tom Ingleby Tue, 11 Sep 2018 11:41:25 +0000 + mraa (1.9.0-1~ubuntu18.04) bionic; urgency=medium * Update to mraa 1.9.0! diff -Nru mraa-1.9.0/debian/control mraa-2.0.0/debian/control --- mraa-1.9.0/debian/control 2017-07-25 09:32:55.000000000 +0000 +++ mraa-2.0.0/debian/control 2018-09-11 11:45:20.000000000 +0000 @@ -27,7 +27,7 @@ Package: libmraa-dev Section: libdevel Architecture: amd64 i386 arm64 armhf -Depends: libmraa1 (= ${binary:Version}), ${misc:Depends} +Depends: libmraa2 (= ${binary:Version}), ${misc:Depends} Description: userspace I/O library (development) mraa (libmraa) is library for interacting with userspace I/O on GNU/Linux platforms. The library abstracts platform quirks away from the end user. @@ -35,7 +35,7 @@ . This package contains the library development files. -Package: libmraa1 +Package: libmraa2 Architecture: amd64 i386 arm64 armhf Depends: ${misc:Depends}, ${shlibs:Depends} Description: userspace I/O library (runtime) @@ -45,11 +45,11 @@ . This package contains the library used at runtime. -Package: libmraa1-dbg +Package: libmraa2-dbg Architecture: amd64 i386 arm64 armhf Section: debug Priority: extra -Depends: libmraa1 (= ${binary:Version}), ${misc:Depends} +Depends: libmraa2 (= ${binary:Version}), ${misc:Depends} Description: debugging symbols for mraa mraa (libmraa) is library for interacting with userspace I/O on GNU/Linux platforms. The library abstracts platform quirks away from the end user. @@ -184,7 +184,7 @@ Package: libmraa-java Architecture: amd64 i386 arm64 armhf Section: java -Depends: libmraa1 (= ${binary:Version}), ${misc:Depends} +Depends: libmraa2 (= ${binary:Version}), ${misc:Depends} Description: java bindings for mraa mraa (libmraa) is library for interacting with userspace I/O on GNU/Linux platforms. The library abstracts platform quirks away from the end user. @@ -206,7 +206,7 @@ Package: node-mraa Architecture: amd64 i386 arm64 armhf -Depends: libmraa1 (= ${binary:Version}), ${misc:Depends} +Depends: libmraa2 (= ${binary:Version}), ${misc:Depends} Description: nodejs bindings for mraa mraa (libmraa) is library for interacting with userspace I/O on GNU/Linux platforms. The library abstracts platform quirks away from the end user. diff -Nru mraa-1.9.0/debian/libmraa1.install mraa-2.0.0/debian/libmraa1.install --- mraa-1.9.0/debian/libmraa1.install 2016-11-04 12:38:18.000000000 +0000 +++ mraa-2.0.0/debian/libmraa1.install 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -usr/lib/*/libmraa.so.* diff -Nru mraa-1.9.0/debian/libmraa2.install mraa-2.0.0/debian/libmraa2.install --- mraa-1.9.0/debian/libmraa2.install 1970-01-01 00:00:00.000000000 +0000 +++ mraa-2.0.0/debian/libmraa2.install 2016-11-04 12:38:18.000000000 +0000 @@ -0,0 +1 @@ +usr/lib/*/libmraa.so.* diff -Nru mraa-1.9.0/debian/rules mraa-2.0.0/debian/rules --- mraa-1.9.0/debian/rules 2017-07-25 09:33:11.000000000 +0000 +++ mraa-2.0.0/debian/rules 2018-09-11 11:43:12.000000000 +0000 @@ -46,7 +46,7 @@ find debian -name underscore.js -exec ln -sfv /usr/share/javascript/underscore/underscore.js {} \; override_dh_strip: - dh_strip -plibmraa1 --dbg-package=libmraa1-dbg + dh_strip -plibmraa2 --dbg-package=libmraa2-dbg dh_strip -pmraa-tools --dbg-package=mraa-tools-dbg dh_strip -ppython-mraa --dbg-package=python-mraa-dbg dh_strip -ppython3-mraa --dbg-package=python3-mraa-dbg diff -Nru mraa-1.9.0/docker-compose.yaml mraa-2.0.0/docker-compose.yaml --- mraa-1.9.0/docker-compose.yaml 2018-02-15 23:08:49.000000000 +0000 +++ mraa-2.0.0/docker-compose.yaml 2018-09-06 12:34:41.000000000 +0000 @@ -21,8 +21,6 @@ - JSONPLAT=${JSONPLAT:-OFF} - IMRAA=${IMRAA:-OFF} - FTDI4222=${FTDI4222:-OFF} - - IPK=${IPK:-OFF} - - RPM=${RPM:-OFF} - ENABLEEXAMPLES=${ENABLEEXAMPLES:-OFF} - INSTALLTOOLS=${INSTALLTOOLS:-ON} - CC=${CC:-clang-3.8} @@ -35,6 +33,14 @@ extends: base image: inteliotdevkit/mraa-all + minimal: + extends: base + environment: + - BUILDSWIG=OFF + - INSTALLTOOLS=OFF + - JSONPLAT=OFF + command: bash -c "./scripts/run-cmake.sh && cd build && make && ctest -R unit --output-on-failure" + doc: extends: all environment: @@ -102,36 +108,23 @@ ftdi4442: extends: all environment: + - USBPLAT=ON - FTDI4222=ON command: bash -c "./scripts/run-cmake.sh && make -Cbuild" - ipk: - extends: all - environment: - - IPK=ON - - ENABLEEXAMPLES=ON - command: bash -c "./scripts/run-cmake.sh && make -Cbuild package" - - rpm: - extends: all - environment: - - RPM=ON - - ENABLEEXAMPLES=ON - command: bash -c "./scripts/run-cmake.sh && make -Cbuild package" - python2: extends: base image: inteliotdevkit/mraa-python environment: - BUILDSWIG=ON - BUILDSWIGPYTHON=ON - command: bash -c "./scripts/run-cmake.sh && cd build && make _python2-mraa && ctest --output-on-failure" + command: bash -c "./scripts/run-cmake.sh && cd build && make _python2-mraa test_unit_all && ctest --output-on-failure" python3: extends: python2 environment: - USEPYTHON3TESTS=ON - command: bash -c "./scripts/run-cmake.sh && cd build && make _python3-mraa && ctest --output-on-failure" + command: bash -c "./scripts/run-cmake.sh && cd build && make _python3-mraa test_unit_all && ctest --output-on-failure" java: extends: base @@ -139,7 +132,7 @@ environment: - BUILDSWIG=ON - BUILDSWIGJAVA=ON - command: bash -c "./scripts/run-cmake.sh && cd build && make mraajava && ctest --output-on-failure" + command: bash -c "./scripts/run-cmake.sh && cd build && make mraajava test_unit_all && ctest --output-on-failure" android: extends: java diff -Nru mraa-1.9.0/docs/96boards.md mraa-2.0.0/docs/96boards.md --- mraa-1.9.0/docs/96boards.md 2018-02-15 23:08:49.000000000 +0000 +++ mraa-2.0.0/docs/96boards.md 2018-09-06 12:34:41.000000000 +0000 @@ -8,9 +8,13 @@ Board Support ------------- +- [Bubblegum-96](http://www.96boards.org/product/bubblegum-96/) - [DragonBoard 410c](http://www.96boards.org/product/dragonboard410c/) +- [DragonBoard 820c](http://www.96boards.org/product/dragonboard820c/) - [HiKey](http://www.96boards.org/product/hikey/) -- [Bubblegum-96](http://www.96boards.org/product/bubblegum-96/) +- [HiKey960](http://www.96boards.org/product/hikey960/) +- [Rock960](http://www.96boards.org/product/rock960/) +- [Ultra96](https://www.96boards.org/product/ultra96/) Interface notes --------------- diff -Nru mraa-1.9.0/docs/building.md mraa-2.0.0/docs/building.md --- mraa-1.9.0/docs/building.md 2018-02-15 23:08:49.000000000 +0000 +++ mraa-2.0.0/docs/building.md 2018-09-06 12:34:41.000000000 +0000 @@ -10,7 +10,7 @@ Not all these are required but if you're unsure of what you're doing this is what you'll need: -* [SWIG](http://swig.org) 3.0.5+ +* [SWIG](http://swig.org) 3.0.5+ (3.0.12 recommended, on Xenial this can be installed via 3rd party PPAs) * [git](http://git-scm.com) * [python](http://python.org) 2.7 or 3.4+ (you'll need not just the interpreter but python-dev) * [node.js](http://nodejs.org) 4.x recommended (you'll need not just the interpreter but nodejs-dev) @@ -23,6 +23,13 @@ sudo apt-get install git build-essential swig3.0 python-dev nodejs-dev cmake libjson-c-dev ``` +Adjust as needed, for instance Python 3 builds will require `python3-dev`. +On Ubuntu Bionic you'll need to downgrade node.js (see [nodesource](https://github.com/nodesource/distributions) +for some handy install scripts) or patch SWIG. This is explained more in the +advanced dependencies list below. + +### Documentation dependencies + To build the documentation you'll also need: * [Doxygen](http://www.stack.nl/~dimitri/doxygen/) 1.8.9.1+ * [Graphviz](http://graphviz.org/) 2+ (For Doxygen graph generation) @@ -118,12 +125,37 @@ ## Dependencies continued -You'll need at least SWIG version 3.0.2 and we recommend 3.0.5 to build the +You'll need at least SWIG version 3.0.2 and we recommend 3.0.12 to build the JavaScript & Python modules. If your version of SWIG is older than this then please see above for disabling `SWIGNODE`. Otherwise you will get a weird build failure when building the JavaScript module. The Python module builds with SWIG 2.x but we don't test it. +### JavaScript bindings for node.js 7.0.0+ + +Building the JavaScript bindings using the latest versions of node.js does +involve additional steps due to our dependency on SWIG. In short, a patch is +needed to compile correctly with node.js 7.0.0 or newer. We found the install +scripts from nodesource to be very handy for switching versions and they +support all versions of Ubuntu. + +The patch applies cleanly on SWIG 3.0.12, available by default on Ubuntu Bionic +and through 3rd party PPAs for older distributions. For example, with Xenial or +Zesty you could use [this](https://launchpad.net/~timsc/+archive/ubuntu/swig-3.0.12). + +To patch SWIG on Ubuntu (assumes you start in the home folder): + +``` +wget https://git.yoctoproject.org/cgit.cgi/poky/plain/meta/recipes-devtools/swig/swig/0001-Add-Node-7.x-aka-V8-5.2-support.patch +cd /usr/share/swig3.0 +sudo patch -p2 <~/0001-Add-Node-7.x-aka-V8-5.2-support.patch +``` + +Keep in mind that Ubuntu Bionic ships with node.js version 8. You'll need to +either use the patch or downgrade node.js. + +### Build version + During the build, we'll assume you're building from git, note that if you compile with `git` installed your version of mraa will be versioned with `git describe --tag` to make it easy for identification. You can easily modify @@ -164,23 +196,6 @@ If you want to add or improve Java bindings for mraa, please follow the Creating Java Bindings Guide. -## Building an IPK/RPM package using `cpack` - -You can get `cpack` to generate an IPK or RPM package fairly easily if you have -the correct packaging tools - -~~~~~~~~~~~~~{.sh} -cmake -DIPK=ON -DCMAKE_INSTALL_PREFIX=/usr .. -make package -~~~~~~~~~~~~~ - -To use RPM simply enable the RPM option. You'll need `rpmbuild` installed on your -build machine. - -~~~~~~~~~~~~~{.sh} -cmake -DRPM=ON -DCMAKE_INSTALL_PREFIX=/usr .. -~~~~~~~~~~~~~ - ## Building for the Android Things Peripheralmanager Client Requirements: diff -Nru mraa-1.9.0/docs/changelog.md mraa-2.0.0/docs/changelog.md --- mraa-1.9.0/docs/changelog.md 2018-02-15 23:08:49.000000000 +0000 +++ mraa-2.0.0/docs/changelog.md 2018-09-06 12:34:41.000000000 +0000 @@ -5,6 +5,15 @@ versions. The API is now fairly stable but when new calls/features are added they are listed here. Anything pre 0.2.x is ignored. +**2.0.0** + * New platforms IEI Tank, Ultra-96, Rock960, Hikey960, Dragonboard 820c + * Added support for chardev GPIO devices with implementation on several boards + * Added string based I/O initialization for simpler integration with other frameworks + * Added GTest support for unit testing + * Extended named LED device APIs allowing them to be listed during board definition + * Removed packaging and CI for obsolete devkits + * Multiple bug fixes and cmake improvements + **1.9.0** * Added support for RPi Zero W * Added support for MIPS based Omega2 and Linkit Smart 7688 diff -Nru mraa-1.9.0/docs/iei-tank.md mraa-2.0.0/docs/iei-tank.md --- mraa-1.9.0/docs/iei-tank.md 1970-01-01 00:00:00.000000000 +0000 +++ mraa-2.0.0/docs/iei-tank.md 2018-09-06 12:34:41.000000000 +0000 @@ -0,0 +1,40 @@ +IEI TANK AIoT Dev. Kit {#iei-tank} +================================ +TANK AIoT Dev. Kit features rich I/O and dual PCIe by 16 slots with by 8 signal +for add-on card installation such as PoE (IPCEI-4POE) card or acceleration card +(Mustang-F100-A10 & Mustang-V100-RX8) to enhance function and performance for +various applications. + +For the full specifications please visit the product page: + +https://www.ieiworld.com/tank-aiot-development-kit + +Interface notes +----------------------- +The MRAA platform file was developed using an IEI TANK-870-Q170 and may not +be compatible with other TANK systems. 6 serial ports and 8 digital pins are +available and can be controlled using MRAA on this system. + +**UART** + * 4 x RS-232 (2 x RJ-45, 2 x DB-9 w/2.5KV isolation protection) + * 2 x RS-232/422/485 (DB-9) + +**GPIO** + * 8-bit digital I/O , 4-bit input / 4-bit output (DB9) + +Pin Mapping +-------------------- +The GPIO numbering in MRAA is explained in the table below. To use the pins +the *gpio_f7188x* Linux kernel module must be available and loaded. + +| MRAA Pin | DB9 Pin | Sysfs GPIO | Function | +|----------|--------------|------------|-----------------| +| 0 | 1 | 4 | DIN0 | +| 1 | 2 | 0 | DOUT0 | +| 2 | 3 | 11 | DIN1 | +| 3 | 4 | 1 | DOUT1 | +| 4 | 5 | 12 | DIN2 | +| 5 | 6 | 2 | DOUT2 | +| 6 | 7 | 13 | DIN3 | +| 7 | 8 | 3 | DOUT3 | +| 8 | 9 | | +5V | diff -Nru mraa-1.9.0/docs/index.java.md mraa-2.0.0/docs/index.java.md --- mraa-1.9.0/docs/index.java.md 2018-02-15 23:08:49.000000000 +0000 +++ mraa-2.0.0/docs/index.java.md 2018-09-06 12:34:41.000000000 +0000 @@ -51,6 +51,7 @@ - @ref up - @ref joule - @ref ft4222 +- @ref iei-tank ## DEBUGGING diff -Nru mraa-1.9.0/docs/index.md mraa-2.0.0/docs/index.md --- mraa-1.9.0/docs/index.md 2018-02-15 23:08:49.000000000 +0000 +++ mraa-2.0.0/docs/index.md 2018-09-06 12:34:41.000000000 +0000 @@ -59,6 +59,7 @@ - @ref mock - @ref linkit_7688 - @ref omega2 +- @ref iei-tank ## DEBUGGING diff -Nru mraa-1.9.0/docs/minnow_max.md mraa-2.0.0/docs/minnow_max.md --- mraa-1.9.0/docs/minnow_max.md 2018-02-15 23:08:49.000000000 +0000 +++ mraa-2.0.0/docs/minnow_max.md 2018-09-06 12:34:41.000000000 +0000 @@ -12,21 +12,23 @@ Supported Firmware ------------------ -mraa has only been tested with 64 bit firmware version 0.73 or later. +MRAA has only been tested with 64 bit firmware version 0.73 or later. SPI --- For SPI support you need to load the low_speed_spidev kernel module and that -will create the /dev/spidev0.0 device node. Mraa only knows about this one SPI +will create the /dev/spidev0.0 device node. MRAA only knows about this one SPI bus and no other. Interface notes --------------- The low speed I/O connector supported as per table below. This assumes default BIOS settings, as they are not dynamcially detected If any changes are mode -(Device Manager -> System Setup -> South Cluster -> LPSS & CSS) them mraa calls +(Device Manager -> System Setup -> South Cluster -> LPSS & CSS) them MRAA calls will not behave as expected. +The platform is chardev capable on newer kernels. + Documentation shows i2c on bus #5, ACPI shows it on bus #6, but driver uses bus #7. @@ -60,3 +62,14 @@ | 26 | 26 | IBL_8254 | 208 | GPIO / I2S MCLK (tb) | *(tb) New assignment on the MinnowBoard Turbot +** On 3.18+ kernels, sysfs GPIO numbers are computed using: +`new_value = old_value | 0x100` + +User LED +--------------- +The MinnowBoard Turbot has one user programmable built-in LED. This is exposed +as a GPIO from MRAA. + +| MRAA Number | Physical Pin | Function | Sysfs GPIO | Notes | +|-------------|---------------|------------|------------|----------------------| +| 27 | N/A | D2_LED | 104 | Active low | diff -Nru mraa-1.9.0/docs/static_code_analysis.md mraa-2.0.0/docs/static_code_analysis.md --- mraa-1.9.0/docs/static_code_analysis.md 2018-02-15 23:08:49.000000000 +0000 +++ mraa-2.0.0/docs/static_code_analysis.md 2018-09-06 12:34:41.000000000 +0000 @@ -67,7 +67,7 @@ -Dsonar.sources=/PATH/TO/YOUR/MRAA/REPO/CLONE \ -Dsonar.inclusions='api/**/*,CMakeLists.txt,examples/**/*,imraa/**/*,include/**/*,src/*,src/**/*,tests/**/*' \ -Dsonar.cfamily.build-wrapper-output=/PATH/TO/YOUR/MRAA/REPO/CLONE/YOUR_BUILD_DIR/bw-output \ - -Dsonar.host.url=https://sonarqube.com \ + -Dsonar.host.url=https://sonarcloud.io \ -Dsonar.organization=mraa-github \ -Dsonar.login=YOUR_SONAR_LOGIN_TOKEN_HERE ``` diff -Nru mraa-1.9.0/examples/c/initio.c mraa-2.0.0/examples/c/initio.c --- mraa-1.9.0/examples/c/initio.c 1970-01-01 00:00:00.000000000 +0000 +++ mraa-2.0.0/examples/c/initio.c 2018-09-06 12:34:41.000000000 +0000 @@ -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 -Nru mraa-1.9.0/examples/c/led.c mraa-2.0.0/examples/c/led.c --- mraa-1.9.0/examples/c/led.c 2018-02-15 23:08:49.000000000 +0000 +++ mraa-2.0.0/examples/c/led.c 2018-09-06 12:34:41.000000000 +0000 @@ -36,7 +36,7 @@ #include "mraa/led.h" /* LED name */ -#define USER_LED "user1" +#define USER_LED 0 /* trigger type */ #define LED_TRIGGER "heartbeat" diff -Nru mraa-1.9.0/examples/gpio_multiple_rw.c mraa-2.0.0/examples/gpio_multiple_rw.c --- mraa-1.9.0/examples/gpio_multiple_rw.c 1970-01-01 00:00:00.000000000 +0000 +++ mraa-2.0.0/examples/gpio_multiple_rw.c 2018-09-06 12:34:41.000000000 +0000 @@ -0,0 +1,103 @@ +/* This currently works only on Intel Joule Platform. */ + +#include +#include +#include +#include +#include + +#include "mraa/gpio.h" + +int running = 0; + +void +sig_handler(int signo) +{ + if (signo == SIGINT) { + printf("Closing down nicely\n"); + running = -1; + } +} + +int main(int argc, char** argv) +{ + mraa_result_t r = MRAA_SUCCESS; + /* These are Joule's onboard LED's. */ + int default_joule_leds[] = {100, 101, 102, 103}; + int *gpio_pins; + int num_pins; + int *input_values, *output_values; + + printf("Provide int arg(s) if you want to toggle gpio pins other than Joule's onboard LED's\n"); + + if (argc < 2) { + gpio_pins = default_joule_leds; + num_pins = 4; + } else { + num_pins = argc - 1; + gpio_pins = malloc(num_pins * sizeof(int)); + + for (int i = 0; i < num_pins; ++i) { + gpio_pins[i] = strtol(argv[i+1], NULL, 10); + } + } + + /* Allocate input and output values arrays. */ + input_values = malloc(num_pins * sizeof(int)); + output_values = malloc(num_pins * sizeof(int)); + + mraa_init(); + fprintf(stdout, "MRAA Version: %s\nStarting program...\n", mraa_get_version()); + + mraa_gpio_context gpio = mraa_gpio_init_multi(gpio_pins, num_pins); + if (gpio == NULL) { + fprintf(stderr, "Error during gpio initialization\n"); + exit(1); + } + + r = mraa_gpio_dir(gpio, MRAA_GPIO_OUT); + if (r != MRAA_SUCCESS) { + mraa_result_print(r); + } + + signal(SIGINT, sig_handler); + + /* Set input values first. */ + memset(input_values, 0, num_pins * sizeof(int)); + + while (running == 0) { + r = mraa_gpio_write_multi(gpio, input_values); + + sleep(1); + + if (r != MRAA_SUCCESS) { + mraa_result_print(r); + } else { + r = mraa_gpio_read_multi(gpio, output_values); + if (r != MRAA_SUCCESS) { + mraa_result_print(r); + } + } + + for (int i = 0; i < num_pins; ++i) { + input_values[i] = (input_values[i] + 1) % 2; + } + } + + memset(input_values, 0, num_pins * sizeof(int)); + mraa_gpio_write_multi(gpio, input_values); + + r = mraa_gpio_close(gpio); + if (r != MRAA_SUCCESS) { + mraa_result_print(r); + } + + /* Cleanup. */ + if (argc >= 2) { + free(gpio_pins); + } + free(input_values); + free(output_values); + + return r; +} \ No newline at end of file diff -Nru mraa-1.9.0/examples/platform/CMakeLists.txt mraa-2.0.0/examples/platform/CMakeLists.txt --- mraa-1.9.0/examples/platform/CMakeLists.txt 2018-02-15 23:08:49.000000000 +0000 +++ mraa-2.0.0/examples/platform/CMakeLists.txt 2018-09-06 12:34:41.000000000 +0000 @@ -1,6 +1,9 @@ add_executable (gpio_edison gpio_edison.c) target_link_libraries (gpio_edison mraa) +add_executable (up2-leds up2-leds.cpp) +target_link_libraries (up2-leds mraa) + include_directories(${PROJECT_SOURCE_DIR}/api) include_directories(${PROJECT_SOURCE_DIR}/api/mraa) diff -Nru mraa-1.9.0/examples/platform/up2-leds.cpp mraa-2.0.0/examples/platform/up2-leds.cpp --- mraa-1.9.0/examples/platform/up2-leds.cpp 1970-01-01 00:00:00.000000000 +0000 +++ mraa-2.0.0/examples/platform/up2-leds.cpp 2018-09-06 12:34:41.000000000 +0000 @@ -0,0 +1,95 @@ +/* + * Author: Mihai Tudor Panu + * 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 "mraa/common.hpp" +#include "mraa/led.hpp" + +// Define min and max brightness +#define LED_ON 255 +#define LED_OFF 0 + +// This boolean controls the main loop +volatile bool should_run = true; + +// Interrupt signal handler function +void +sig_handler(int signum) +{ + if (signum == SIGINT) { + std::cout << "Exiting..." << std::endl; + should_run = false; + } +} + +// Main function +int +main() +{ + // Perform a basic platform and version check + if (mraa::getPlatformType() != mraa::INTEL_UP2) { + std::cout << "This example is meant for the UP Squared board." << std::endl; + std::cout << "Running it on different platforms will likely require code changes!" << std::endl; + } + + if (mraa::getVersion().compare("v1.9.0") < 0) { + std::cout << "You need MRAA version 1.9.0 or newer to run this sample!" << std::endl; + return 1; + } + + // Register handler for keyboard interrupts + signal(SIGINT, sig_handler); + + // Define our LEDs + std::string led_names[] = {"red", "green", "yellow", "blue"}; + int led_no = sizeof(led_names)/sizeof(led_names[0]); + mraa::Led **leds = new mraa::Led*[led_no]; + + // Initialize them + for (int i = 0; i < led_no; i++) { + leds[i] = new mraa::Led(led_names[i].c_str()); + } + + // Blink them in order and pause in-between + while (should_run) { + for (int i = 0; i < led_no; i++) { + leds[i]->setBrightness(LED_ON); + usleep(200000); + leds[i]->setBrightness(LED_OFF); + } + usleep(200000); + } + + // Cleanup and exit + for (int i = 0; i < led_no; i++) { + delete leds[i]; + } + delete [] leds; + return 0; +} diff -Nru mraa-1.9.0/examples/platform/Up2Leds.java mraa-2.0.0/examples/platform/Up2Leds.java --- mraa-1.9.0/examples/platform/Up2Leds.java 1970-01-01 00:00:00.000000000 +0000 +++ mraa-2.0.0/examples/platform/Up2Leds.java 2018-09-06 12:34:41.000000000 +0000 @@ -0,0 +1,87 @@ +/* + * Author: Mihai Tudor Panu + * 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. + */ + +import mraa.Led; +import mraa.Platform; +import mraa.mraa; + +public class Up2Leds { + static { + try { + System.loadLibrary("mraajava"); + } catch (UnsatisfiedLinkError e) { + System.err.println( "Native code library failed to load." + + " See the chapter on Dynamic Linking Problems in the SWIG Java documentation for help.\n" + e); + System.exit(1); + } + } + + // Define led names and min/max brightness + final static String[] ledNames = {"red", "green", "yellow", "blue"}; + final static int minBrightness = 0; + final static int maxBrightness = 255; + + public static void main(String argv[]) throws InterruptedException { + + // Perform a basic platform and version check + if (mraa.getPlatformType() != Platform.INTEL_UP2) { + System.out.println("This example is meant for the UP Squared board."); + System.out.println("Running it on different platforms will likely require code changes!"); + } + + if (mraa.getVersion().compareTo("v1.9.0") < 0) { + System.out.println("You need MRAA version 1.9.0 or newer to run this sample!"); + System.exit(1); + } + + // Define and initialize our LEDs + Led[] leds = new Led[ledNames.length]; + for (int i = 0; i < ledNames.length; i++) { + leds[i] = new Led(ledNames[i]); + } + + // Add a hook for handling keyboard interrupts and cleanup + Runtime.getRuntime().addShutdownHook(new Thread() + { + @Override + public void run() + { + System.out.println("Exiting..."); + for (Led led : leds) { + led.setBrightness(minBrightness); + } + } + }); + + // Main loop + while (!Thread.interrupted()) { + for (Led led : leds) { + led.setBrightness(maxBrightness); + Thread.sleep(200); + led.setBrightness(minBrightness); + } + Thread.sleep(200); + } + } +} diff -Nru mraa-1.9.0/include/arm/96boards.h mraa-2.0.0/include/arm/96boards.h --- mraa-1.9.0/include/arm/96boards.h 2018-02-15 23:08:49.000000000 +0000 +++ mraa-2.0.0/include/arm/96boards.h 2018-09-06 12:34:41.000000000 +0000 @@ -38,6 +38,7 @@ #define MRAA_96BOARDS_LS_SPI_COUNT 1 #define MRAA_96BOARDS_LS_UART_COUNT 2 #define MRAA_96BOARDS_LS_PIN_COUNT 40 +#define MRAA_96BOARDS_LED_COUNT 6 mraa_board_t* mraa_96boards(); diff -Nru mraa-1.9.0/include/gpio/gpio_chardev.h mraa-2.0.0/include/gpio/gpio_chardev.h --- mraa-1.9.0/include/gpio/gpio_chardev.h 1970-01-01 00:00:00.000000000 +0000 +++ mraa-2.0.0/include/gpio/gpio_chardev.h 2018-09-06 12:34:41.000000000 +0000 @@ -0,0 +1,74 @@ +/* + * Author: Brendan Le Foll + * 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 + +#include "mraa_internal.h" +#include "linux/gpio.h" + +typedef struct { + int chip_fd; + struct gpiochip_info chip_info; +} mraa_gpiod_chip_info; + +typedef struct gpioline_info mraa_gpiod_line_info; + +void _mraa_free_gpio_groups(mraa_gpio_context dev); +void _mraa_close_gpio_event_handles(mraa_gpio_context dev); +void _mraa_close_gpio_desc(mraa_gpio_context dev); +int _mraa_gpiod_ioctl(int fd, unsigned long gpio_request, void* data); + +mraa_gpiod_chip_info* mraa_get_chip_info_by_path(const char* path); +mraa_gpiod_chip_info* mraa_get_chip_info_by_name(const char* name); +mraa_gpiod_chip_info* mraa_get_chip_info_by_label(const char* label); +mraa_gpiod_chip_info* mraa_get_chip_info_by_number(unsigned number); + +mraa_gpiod_line_info* mraa_get_line_info_from_descriptor(int chip_fd, unsigned line_number); +mraa_gpiod_line_info* mraa_get_line_info_by_chip_number(unsigned chip_number, unsigned line_number); +mraa_gpiod_line_info* mraa_get_line_info_by_chip_name(const char* chip_name, unsigned line_number); +mraa_gpiod_line_info* mraa_get_line_info_by_chip_label(const char* chip_label, unsigned line_number); + +int mraa_get_lines_handle(int chip_fd, unsigned line_offsets[], unsigned num_lines, unsigned flags, unsigned default_value); +int mraa_set_line_values(int line_handle, unsigned int num_lines, unsigned char input_values[]); +int mraa_get_line_values(int line_handle, unsigned int num_lines, unsigned char output_values[]); + +mraa_boolean_t mraa_is_gpio_line_kernel_owned(mraa_gpiod_line_info *linfo); +mraa_boolean_t mraa_is_gpio_line_dir_out(mraa_gpiod_line_info *linfo); +mraa_boolean_t mraa_is_gpio_line_active_low(mraa_gpiod_line_info *linfo); +mraa_boolean_t mraa_is_gpio_line_open_drain(mraa_gpiod_line_info *linfo); +mraa_boolean_t mraa_is_gpio_line_open_source(mraa_gpiod_line_info *linfo); + +int mraa_get_number_of_gpio_chips(); + +/* Multiple gpio support. */ +typedef struct _gpio_group* mraa_gpiod_group_t; + + +#ifdef __cplusplus +} +#endif diff -Nru mraa-1.9.0/include/initio/initio_keys.h mraa-2.0.0/include/initio/initio_keys.h --- mraa-1.9.0/include/initio/initio_keys.h 1970-01-01 00:00:00.000000000 +0000 +++ mraa-2.0.0/include/initio/initio_keys.h 2018-09-06 12:34:41.000000000 +0000 @@ -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 -Nru mraa-1.9.0/include/linux/gpio.h mraa-2.0.0/include/linux/gpio.h --- mraa-1.9.0/include/linux/gpio.h 1970-01-01 00:00:00.000000000 +0000 +++ mraa-2.0.0/include/linux/gpio.h 2018-09-06 12:34:41.000000000 +0000 @@ -0,0 +1,81 @@ +/* + * This header was manually generated from a Linux kernel header linux/gpio.h, + * to make information necessary for compilation to be available. It contains + * only constants, structures, and macros generated from the original header, + * and thus, contains no copyrightable information. + */ +#ifndef _GPIO_H_ +#define _GPIO_H_ + +#include +#include + +struct gpiochip_info { + char name[32]; + char label[32]; + __u32 lines; +}; + +#define GPIOLINE_FLAG_KERNEL (1UL << 0) +#define GPIOLINE_FLAG_IS_OUT (1UL << 1) +#define GPIOLINE_FLAG_ACTIVE_LOW (1UL << 2) +#define GPIOLINE_FLAG_OPEN_DRAIN (1UL << 3) +#define GPIOLINE_FLAG_OPEN_SOURCE (1UL << 4) + +struct gpioline_info { + __u32 line_offset; + __u32 flags; + char name[32]; + char consumer[32]; +}; + +#define GPIOHANDLES_MAX 64 + +#define GPIOHANDLE_REQUEST_INPUT (1UL << 0) +#define GPIOHANDLE_REQUEST_OUTPUT (1UL << 1) +#define GPIOHANDLE_REQUEST_ACTIVE_LOW (1UL << 2) +#define GPIOHANDLE_REQUEST_OPEN_DRAIN (1UL << 3) +#define GPIOHANDLE_REQUEST_OPEN_SOURCE (1UL << 4) + +struct gpiohandle_request { + __u32 lineoffsets[GPIOHANDLES_MAX]; + __u32 flags; + __u8 default_values[GPIOHANDLES_MAX]; + char consumer_label[32]; + __u32 lines; + int fd; +}; + +struct gpiohandle_data { + __u8 values[GPIOHANDLES_MAX]; +}; + +#define GPIOHANDLE_GET_LINE_VALUES_IOCTL _IOWR(0xB4, 0x08, struct gpiohandle_data) +#define GPIOHANDLE_SET_LINE_VALUES_IOCTL _IOWR(0xB4, 0x09, struct gpiohandle_data) + +#define GPIOEVENT_REQUEST_RISING_EDGE (1UL << 0) +#define GPIOEVENT_REQUEST_FALLING_EDGE (1UL << 1) +#define GPIOEVENT_REQUEST_BOTH_EDGES ((1UL << 0) | (1UL << 1)) + +struct gpioevent_request { + __u32 lineoffset; + __u32 handleflags; + __u32 eventflags; + char consumer_label[32]; + int fd; +}; + +#define GPIOEVENT_EVENT_RISING_EDGE 0x01 +#define GPIOEVENT_EVENT_FALLING_EDGE 0x02 + +struct gpioevent_data { + __u64 timestamp; + __u32 id; +}; + +#define GPIO_GET_CHIPINFO_IOCTL _IOR(0xB4, 0x01, struct gpiochip_info) +#define GPIO_GET_LINEINFO_IOCTL _IOWR(0xB4, 0x02, struct gpioline_info) +#define GPIO_GET_LINEHANDLE_IOCTL _IOWR(0xB4, 0x03, struct gpiohandle_request) +#define GPIO_GET_LINEEVENT_IOCTL _IOWR(0xB4, 0x04, struct gpioevent_request) + +#endif /* _GPIO_H_ */ diff -Nru mraa-1.9.0/include/mraa_internal.h mraa-2.0.0/include/mraa_internal.h --- mraa-1.9.0/include/mraa_internal.h 2018-02-15 23:08:49.000000000 +0000 +++ mraa-2.0.0/include/mraa_internal.h 2018-09-06 12:34:41.000000000 +0000 @@ -80,13 +80,6 @@ mraa_platform_t mraa_mock_platform(); /** - * runtime detect running usb platform extender - * - * @return mraa_platform_t of the detected platform extender - */ -mraa_platform_t mraa_usb_platform_extender(mraa_board_t* board); - -/** * runtime detect iio subsystem * * @return mraa_result_t indicating success of iio detection @@ -168,6 +161,16 @@ */ int mraa_find_i2c_bus_pci(const char* pci_device, const char *pci_id, const char* adapter_name); +/** + * helper function to find the uart device based on pci data + * + * @param pci_dev_path points to the location of tty device which corresponds + * to the uart device available on the platform + * @param dev_name as retrieved from pci_dev_path + * @return Result of the operation + */ +mraa_result_t mraa_find_uart_bus_pci(const char* pci_dev_path, char** dev_name); + #if defined(IMRAA) /** * read Imraa subplatform lock file, caller is responsible to free return diff -Nru mraa-1.9.0/include/mraa_internal_types.h mraa-2.0.0/include/mraa_internal_types.h --- mraa-1.9.0/include/mraa_internal_types.h 2018-02-15 23:08:49.000000000 +0000 +++ mraa-2.0.0/include/mraa_internal_types.h 2018-09-06 12:34:41.000000000 +0000 @@ -46,7 +46,7 @@ #define MAX_AIO_COUNT 7 #define MAX_UART_COUNT 6 #define MAX_PWM_COUNT 6 - +#define MAX_LED_COUNT 12 // general status failures for internal functions #define MRAA_PLATFORM_NO_INIT -3 @@ -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" @@ -106,6 +108,26 @@ }; #endif +struct _gpio_group { + int is_required; + int dev_fd; + int gpiod_handle; + unsigned int gpio_chip; + /* We can have multiple lines in a gpio group. */ + unsigned int num_gpio_lines; + unsigned int *gpio_lines; + + /* R/W stuff.*/ + unsigned char *rw_values; + /* Reverse mapping to original pin number indexes. */ + unsigned int *gpio_group_to_pins_table; + + unsigned int flags; + + /* Event specific fields. */ + int *event_handles; +}; + /** * A structure representing a gpio pin. */ @@ -134,8 +156,24 @@ #ifdef PERIPHERALMAN AGpio *bgpio; #endif + + struct _gpio_group *gpio_group; + unsigned int num_chips; + int *pin_to_gpio_table; + unsigned int num_pins; + mraa_gpio_events_t events; + int *provided_pins; + + struct _gpio *next; }; +/* Macro for looping over gpio chips. */ +#define for_each_gpio_group(group, dev) \ + for (int k = 0; \ + k < dev->num_chips && (group = &dev->gpio_group[k]); \ + ++k) \ + if (dev->gpio_group[k].is_required) + /** * A structure representing a I2C bus */ @@ -315,6 +353,10 @@ mraa_mux_t mux[6]; /** Array holding information about mux */ unsigned int output_enable; /** Output Enable GPIO, for level shifting */ mraa_pin_cap_complex_t complex_cap; + + /* GPIOD_INTERFACE */ + unsigned int gpio_chip; + unsigned int gpio_line; /*@}*/ } mraa_pin_t; @@ -413,6 +455,16 @@ } mraa_aio_dev_t; /** + * Structure representing an LED device. + */ +typedef struct { + /*@{*/ + char *name; /**< LED device function name */ + unsigned int index; /**< Index as exposed in the platform */ + /*@}*/ +} mraa_led_dev_t; + +/** * A Structure representing a platform/board. */ typedef struct _board_t { @@ -447,6 +499,9 @@ mraa_pininfo_t* pins; /**< Pointer to pin array */ mraa_adv_func_t* adv_func; /**< Pointer to advanced function disptach table */ struct _board_t* sub_platform; /**< Pointer to sub platform */ + mraa_boolean_t chardev_capable; /**< Decide what interface is being used: old sysfs or new char device*/ + mraa_led_dev_t led_dev[MAX_LED_COUNT]; /**< Array of LED devices */ + unsigned int led_dev_count; /**< Total onboard LED device count */ /*@}*/ } mraa_board_t; @@ -456,3 +511,15 @@ uint8_t iio_device_count; /**< IIO device count */ } mraa_iio_info_t; #endif + +/** + * Function pointer typedef for use with platform extender libraries. + * Currently only the FT42222. + * + * @param board Pointer to valid board structure. If a mraa_board_t + * is initialized, it will be added to board->sub_platform + * + * @return MRAA_SUCCESS if a valid subplaform has been initialized, + * otherwise return MRAA_ERROR_PLATFORM_NOT_INITIALISED + */ +typedef mraa_result_t (*fptr_add_platform_extender)(mraa_board_t* board); diff -Nru mraa-1.9.0/include/usb/ftdi_ft4222.h mraa-2.0.0/include/usb/ftdi_ft4222.h --- mraa-1.9.0/include/usb/ftdi_ft4222.h 2018-02-15 23:08:49.000000000 +0000 +++ mraa-2.0.0/include/usb/ftdi_ft4222.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,41 +0,0 @@ -/* - * Author: Henry Bruce - * Copyright (c) 2015 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 - -#include -#include "mraa_internal.h" - -mraa_result_t mraa_ftdi_ft4222_init(); -mraa_result_t mraa_ftdi_ft4222_get_version(unsigned int* versionChip, unsigned int* versionLib); -mraa_board_t* mraa_ftdi_ft4222(); -void *libft4222_lib; - -#ifdef __cplusplus -} -#endif diff -Nru mraa-1.9.0/include/x86/iei_tank.h mraa-2.0.0/include/x86/iei_tank.h --- mraa-1.9.0/include/x86/iei_tank.h 1970-01-01 00:00:00.000000000 +0000 +++ mraa-2.0.0/include/x86/iei_tank.h 2018-09-06 12:34:41.000000000 +0000 @@ -0,0 +1,41 @@ +/* + * Author: Mihai Tudor Panu + * 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 + +#include "mraa_internal.h" + +#define MRAA_IEI_TANK_PINCOUNT 9 +#define MRAA_IEI_TANK_UARTCOUNT 6 + +mraa_board_t* +mraa_iei_tank(); + +#ifdef __cplusplus +} +#endif diff -Nru mraa-1.9.0/include/x86/intel_joule_expansion.h mraa-2.0.0/include/x86/intel_joule_expansion.h --- mraa-1.9.0/include/x86/intel_joule_expansion.h 2018-02-15 23:08:49.000000000 +0000 +++ mraa-2.0.0/include/x86/intel_joule_expansion.h 2018-09-06 12:34:41.000000000 +0000 @@ -32,7 +32,8 @@ // +1 as pins are "1 indexed" // we have 20 useless pins then the 4 LEDS and the 2 LEDs on the module. -#define MRAA_INTEL_JOULE_EXPANSION_PINCOUNT (40*2 + 23 +1 +2) +// There is another pin for the built-in button. + #define MRAA_INTEL_JOULE_EXPANSION_PINCOUNT (40 * 2 + 23 + 1 + 2 + 1) mraa_board_t* mraa_joule_expansion_board(); diff -Nru mraa-1.9.0/README.md mraa-2.0.0/README.md --- mraa-1.9.0/README.md 2018-02-15 23:08:49.000000000 +0000 +++ mraa-2.0.0/README.md 2018-09-06 12:34:41.000000000 +0000 @@ -32,6 +32,7 @@ * [UP](../master/docs/up.md) * [UP Squared](../master/docs/up2.md) * [Intel Joule](../master/docs/joule.md) +* [IEI Tank](../master/docs/iei-tank.md) ARM --- @@ -73,7 +74,7 @@ Installing on Ubuntu -------------------- -Here is a PPA for installing on ubuntu: +Here is a PPA for installing on Ubuntu Xenial or Bionic: https://launchpad.net/~mraa/+archive/ubuntu/mraa ```bash @@ -105,11 +106,12 @@ Installing for Node.js only --------------------------- -> Note: Node.js 7.0.0+ is not currently supported. You'll have to downgrade to 6.x.x. +> Note: Node.js 7.0.0+ is not currently supported unless compiling with a patched +vesion of SWIG. See the corresponding section and document below. You can also install just the node.js mraa module by using npm. You will need a C++ compiler and the node development headers, however it's not required to -have SWIG installed. +have SWIG installed. This works for node versions 6.x.x and prior. ```bash npm install mraa @@ -123,28 +125,6 @@ Subplatforms (i.e. Firmata) have to be added manually with this kind of install from your application, as shown in [this example](examples/javascript/firmata.js). -Installing on Intel 32bit Yocto based opkg image ------------------------------------------------- - -See the section below on compiling or use our repository to install on a glibc -based yocto poky image that supports opkg. Adding this repository is as simple -as and you'll have the latest stable tagged build of mraa installed! - -``` bash -echo "src mraa-upm http://iotdk.intel.com/repos/3.5/intelgalactic/opkg/i586" > /etc/opkg/mraa-upm.conf -opkg update -opkg install mraa -``` - -If you would like to get the latest & greatest builds from master HEAD you can -use our -dev repository - -```bash -echo "src mraa-upm http://iotdk.intel.com/repos/3.5/intelgalactic-dev/opkg/i586" > /etc/opkg/mraa-upm.conf -opkg update -opkg install mraa -``` - Compiling ========= diff -Nru mraa-1.9.0/scripts/build-android.sh mraa-2.0.0/scripts/build-android.sh --- mraa-1.9.0/scripts/build-android.sh 2018-02-15 23:08:49.000000000 +0000 +++ mraa-2.0.0/scripts/build-android.sh 2018-09-06 12:34:41.000000000 +0000 @@ -72,8 +72,6 @@ -DJSONPLAT=$JSONPLAT \ -DIMRAA=$IMRAA \ -DFTDI4222=$FTDI4222 \ - -DIPK=$IPK \ - -DRPM=$RPM \ -DENABLEEXAMPLES=$ENABLEEXAMPLES \ -DINSTALLTOOLS=$INSTALLTOOLS \ -DBUILDTESTS=$BUILDTESTS \ diff -Nru mraa-1.9.0/scripts/run-cmake.sh mraa-2.0.0/scripts/run-cmake.sh --- mraa-1.9.0/scripts/run-cmake.sh 2018-02-15 23:08:49.000000000 +0000 +++ mraa-2.0.0/scripts/run-cmake.sh 2018-09-06 12:34:41.000000000 +0000 @@ -17,8 +17,6 @@ -DJSONPLAT=$JSONPLAT \ -DIMRAA=$IMRAA \ -DFTDI4222=$FTDI4222 \ - -DIPK=$IPK \ - -DRPM=$RPM \ -DENABLEEXAMPLES=$ENABLEEXAMPLES \ -DINSTALLTOOLS=$INSTALLTOOLS \ -DBUILDTESTS=$BUILDTESTS \ diff -Nru mraa-1.9.0/scripts/sonar-scan.sh mraa-2.0.0/scripts/sonar-scan.sh --- mraa-1.9.0/scripts/sonar-scan.sh 2018-02-15 23:08:49.000000000 +0000 +++ mraa-2.0.0/scripts/sonar-scan.sh 2018-09-06 12:34:41.000000000 +0000 @@ -54,7 +54,7 @@ -Dsonar.java.binaries='src' \ -Dsonar.coverage.exclusions='**/*' \ -Dsonar.cfamily.build-wrapper-output=${bw_output_path} \ - -Dsonar.host.url=https://sonarqube.com \ + -Dsonar.host.url=https://sonarcloud.io \ -Dsonar.organization=${SONAR_ORG} \ -Dsonar.login=${SONAR_TOKEN} \ " diff -Nru mraa-1.9.0/src/arm/96boards.c mraa-2.0.0/src/arm/96boards.c --- mraa-1.9.0/src/arm/96boards.c 2018-02-15 23:08:49.000000000 +0000 +++ mraa-2.0.0/src/arm/96boards.c 2018-09-06 12:34:41.000000000 +0000 @@ -36,29 +36,82 @@ #define DT_BASE "/proc/device-tree" +#define PLATFORM_NAME_BBGUM "BBGUM" #define PLATFORM_NAME_DB410C "DB410C" +#define PLATFORM_NAME_DB820C "DB820C" #define PLATFORM_NAME_HIKEY "HIKEY" -#define PLATFORM_NAME_BBGUM "BBGUM" +#define PLATFORM_NAME_HIKEY960 "HIKEY960" +#define PLATFORM_NAME_ROCK960 "ROCK960" +#define PLATFORM_NAME_ULTRA96 "ULTRA96" + #define MAX_SIZE 64 #define MMAP_PATH "/dev/mem" #define DB410C_MMAP_REG 0x01000000 +// Bubblegum-96 +int bbgum_ls_gpio_pins[MRAA_96BOARDS_LS_GPIO_COUNT] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 155, 154 }; + +const char* bbgum_serialdev[MRAA_96BOARDS_LS_UART_COUNT] = { "/dev/ttyS3", "/dev/ttyS5" }; + +// Dragonboard410c int db410c_ls_gpio_pins[MRAA_96BOARDS_LS_GPIO_COUNT] = { 36, 12, 13, 69, 115, 4, 24, 25, 35, 34, 28, 33, }; +int db410c_chardev_map[MRAA_96BOARDS_LS_GPIO_COUNT][2] = { + { 0, 36 }, { 0, 12 }, { 0, 13 }, { 0, 69 }, { 0, 115 }, { 2, 3 }, + { 0, 24 }, { 0, 25 }, { 0, 35 }, { 0, 34 }, { 0, 28 }, { 0, 33 }, +}; + const char* db410c_serialdev[MRAA_96BOARDS_LS_UART_COUNT] = { "/dev/ttyMSM0", "/dev/ttyMSM1" }; +const char* db410c_led[MRAA_96BOARDS_LED_COUNT] = { "user1", "user2", "user3", "user4", "bt", "wlan" }; + +// Dragonboard820c +int db820c_ls_gpio_pins[MRAA_96BOARDS_LS_GPIO_COUNT] = { + 80, 29, 124, 24, 62, 507, 10, 8, 25, 26, 23, 133, +}; + +int db820c_chardev_map[MRAA_96BOARDS_LS_GPIO_COUNT][2] = { + { 0, 80 }, { 0, 29 }, { 0, 125 }, { 0, 24 }, { 0, 62 }, { 1, 4 }, + { 0, 10 }, { 0, 8 }, { 0, 25 }, { 0, 26 }, { 0, 23 }, { 0, 133 }, +}; + +const char* db820c_serialdev[MRAA_96BOARDS_LS_UART_COUNT] = { "/dev/ttyMSM0", "/dev/ttyMSM1" }; +// HiKey int hikey_ls_gpio_pins[MRAA_96BOARDS_LS_GPIO_COUNT] = { 488, 489, 490, 491, 492, 415, 463, 495, 426, 433, 427, 434, }; +int hikey_chardev_map[MRAA_96BOARDS_LS_GPIO_COUNT][2] = { + { 2, 0 }, { 2, 1 }, { 2, 2 }, { 2, 3 }, { 2, 4 }, { 12, 7 }, + { 6, 7 }, { 2, 7 }, { 10, 2 }, { 9, 1 }, { 10, 3 }, { 9, 2 }, +}; const char* hikey_serialdev[MRAA_96BOARDS_LS_UART_COUNT] = { "/dev/ttyAMA2", "/dev/ttyAMA3" }; -int bbgum_ls_gpio_pins[MRAA_96BOARDS_LS_GPIO_COUNT] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 155, 154 }; +// HiKey960 +int hikey960_chardev_map[MRAA_96BOARDS_LS_GPIO_COUNT][2] = { + { 26, 0 }, { 26, 1 }, { 26, 2 }, { 26, 3 }, { 26, 4 }, { 22, 6 }, + { 2, 7 }, { 5, 0 }, { 6, 4 }, { 2, 3 }, { 9, 3 }, { 2, 5 }, +}; -const char* bbgum_serialdev[MRAA_96BOARDS_LS_UART_COUNT] = { "/dev/ttyS3", "/dev/ttyS5" }; +const char* hikey960_serialdev[MRAA_96BOARDS_LS_UART_COUNT] = { "/dev/ttyAMA3", "/dev/ttyAMA6" }; + +// Rock960 +int rock960_ls_gpio_pins[MRAA_96BOARDS_LS_GPIO_COUNT] = { + 1006, 1002, 1041, 1042, 1121, 1128, 1124, 1131, 1125, 1132, 1050, 1055 +}; + +const char* rock960_serialdev[MRAA_96BOARDS_LS_UART_COUNT] = { "/dev/ttyS3", "/dev/ttyS4" }; + +// Ultra96 +int ultra96_chardev_map[MRAA_96BOARDS_LS_GPIO_COUNT][2] = { + { 0, 36 }, { 0, 37 }, { 0, 39 }, { 0, 40 }, { 0, 44 }, { 0, 45 }, + { 0, 78 }, { 0, 79 }, { 0, 80 }, { 0, 81 }, { 0, 82 }, { 0, 83 }, +}; + +const char* ultra96_serialdev[MRAA_96BOARDS_LS_UART_COUNT] = { "/dev/ttyPS0", "/dev/ttyS0" }; // MMAP static uint8_t* mmap_reg = NULL; @@ -67,7 +120,7 @@ static unsigned int mmap_count = 0; void -mraa_96boards_pininfo(mraa_board_t* board, int index, int sysfs_pin, char* fmt, ...) +mraa_96boards_pininfo(mraa_board_t* board, int index, int sysfs_pin, int is_gpio, char* fmt, ...) { va_list arg_ptr; if (index > board->phy_pin_count) @@ -76,11 +129,16 @@ mraa_pininfo_t* pininfo = &board->pins[index]; va_start(arg_ptr, fmt); vsnprintf(pininfo->name, MRAA_PIN_NAME_SIZE, fmt, arg_ptr); - va_end(arg_ptr); - if (sysfs_pin >= 0) + if (is_gpio) { + // skip the read argument + va_arg(arg_ptr, int); + pininfo->gpio.gpio_chip = va_arg(arg_ptr, int); + pininfo->gpio.gpio_line = va_arg(arg_ptr, int); pininfo->capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }; - else + } else { pininfo->capabilities = (mraa_pincapabilities_t){ 0, 0, 0, 0, 0, 0, 0, 0 }; + } + va_end(arg_ptr); pininfo->gpio.pinmap = sysfs_pin; pininfo->gpio.mux_total = 0; } @@ -88,92 +146,92 @@ static mraa_result_t mraa_db410c_mmap_unsetup() { - if (mmap_reg == NULL) { - syslog(LOG_WARNING, "db410c mmap: null register nothing to unsetup"); - return MRAA_ERROR_INVALID_RESOURCE; - } - munmap(mmap_reg, mmap_size); - mmap_reg = NULL; - close(mmap_fd); + if (mmap_reg == NULL) { + syslog(LOG_WARNING, "db410c mmap: null register nothing to unsetup"); + return MRAA_ERROR_INVALID_RESOURCE; + } + munmap(mmap_reg, mmap_size); + mmap_reg = NULL; + close(mmap_fd); - return MRAA_SUCCESS; + return MRAA_SUCCESS; } mraa_result_t mraa_db410c_mmap_write(mraa_gpio_context dev, int value) { - uint32_t offset = (0x1000 * dev->pin); + uint32_t offset = (0x1000 * dev->pin); - if (value) { - *(volatile uint32_t*) (mmap_reg + offset + 0x04) |= (uint32_t) (1 << 1); - } else { - *(volatile uint32_t*) (mmap_reg + offset + 0x04) &= ~(uint32_t) (1 << 1); - } + if (value) { + *(volatile uint32_t*) (mmap_reg + offset + 0x04) |= (uint32_t)(1 << 1); + } else { + *(volatile uint32_t*) (mmap_reg + offset + 0x04) &= ~(uint32_t)(1 << 1); + } - return MRAA_SUCCESS; + return MRAA_SUCCESS; } int mraa_db410c_mmap_read(mraa_gpio_context dev) { - uint32_t value; - uint32_t offset = (0x1000 * dev->pin); + uint32_t value; + uint32_t offset = (0x1000 * dev->pin); - value = *(volatile uint32_t*) (mmap_reg + offset + 0x04); - if (value & (uint32_t) (1 << 0)) { - return 1; - } + value = *(volatile uint32_t*) (mmap_reg + offset + 0x04); + if (value & (uint32_t)(1 << 0)) { + return 1; + } - return 0; + return 0; } mraa_result_t mraa_db410c_mmap_setup(mraa_gpio_context dev, mraa_boolean_t en) { - if (dev == NULL) { - syslog(LOG_ERR, "db410c mmap: context not valid"); - return MRAA_ERROR_INVALID_HANDLE; - } - - /* disable mmap if already enabled */ - if (en == 0) { - if (dev->mmap_write == NULL && dev->mmap_read == NULL) { - syslog(LOG_ERR, "db410c mmap: can't disable disabled mmap gpio"); - return MRAA_ERROR_INVALID_PARAMETER; - } - dev->mmap_write = NULL; - dev->mmap_read = NULL; - mmap_count--; - if (mmap_count == 0) { - return mraa_db410c_mmap_unsetup(); - } - return MRAA_SUCCESS; - } - - if (dev->mmap_write != NULL && dev->mmap_read != NULL) { - syslog(LOG_ERR, "db410c mmap: can't enable enabled mmap gpio"); - return MRAA_ERROR_INVALID_PARAMETER; - } - - if (mmap_reg == NULL) { - if ((mmap_fd = open(MMAP_PATH, O_RDWR)) < 0) { - syslog(LOG_ERR, "db410c mmap: unable to open /dev/mem"); - return MRAA_ERROR_INVALID_HANDLE; - } - mmap_reg = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, mmap_fd, DB410C_MMAP_REG); - - if (mmap_reg == MAP_FAILED) { - syslog(LOG_ERR, "db410c mmap: failed to mmap"); - mmap_reg = NULL; - close(mmap_fd); - return MRAA_ERROR_NO_RESOURCES; - } - } - dev->mmap_write = &mraa_db410c_mmap_write; - dev->mmap_read = &mraa_db410c_mmap_read; - mmap_count++; + if (dev == NULL) { + syslog(LOG_ERR, "db410c mmap: context not valid"); + return MRAA_ERROR_INVALID_HANDLE; + } + + /* disable mmap if already enabled */ + if (en == 0) { + if (dev->mmap_write == NULL && dev->mmap_read == NULL) { + syslog(LOG_ERR, "db410c mmap: can't disable disabled mmap gpio"); + return MRAA_ERROR_INVALID_PARAMETER; + } + dev->mmap_write = NULL; + dev->mmap_read = NULL; + mmap_count--; + if (mmap_count == 0) { + return mraa_db410c_mmap_unsetup(); + } + return MRAA_SUCCESS; + } + + if (dev->mmap_write != NULL && dev->mmap_read != NULL) { + syslog(LOG_ERR, "db410c mmap: can't enable enabled mmap gpio"); + return MRAA_ERROR_INVALID_PARAMETER; + } - return MRAA_SUCCESS; + if (mmap_reg == NULL) { + if ((mmap_fd = open(MMAP_PATH, O_RDWR)) < 0) { + syslog(LOG_ERR, "db410c mmap: unable to open /dev/mem"); + return MRAA_ERROR_INVALID_HANDLE; + } + mmap_reg = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, mmap_fd, DB410C_MMAP_REG); + + if (mmap_reg == MAP_FAILED) { + syslog(LOG_ERR, "db410c mmap: failed to mmap"); + mmap_reg = NULL; + close(mmap_fd); + return MRAA_ERROR_NO_RESOURCES; + } + } + dev->mmap_write = &mraa_db410c_mmap_write; + dev->mmap_read = &mraa_db410c_mmap_read; + mmap_count++; + + return MRAA_SUCCESS; } mraa_board_t* @@ -181,17 +239,18 @@ { int i; int* ls_gpio_pins = NULL; + int(*chardev_map)[MRAA_96BOARDS_LS_GPIO_COUNT][2] = NULL; mraa_board_t* b = (mraa_board_t*) calloc(1, sizeof(mraa_board_t)); if (b == NULL) { return NULL; } - b->adv_func = (mraa_adv_func_t*) calloc(1, sizeof(mraa_adv_func_t)); - if (b->adv_func == NULL) { - free(b); - return NULL; - } + b->adv_func = (mraa_adv_func_t*) calloc(1, sizeof(mraa_adv_func_t)); + if (b->adv_func == NULL) { + free(b); + return NULL; + } // pin mux for buses are setup by default by kernel so tell mraa to ignore them b->no_bus_mux = 1; @@ -199,22 +258,58 @@ if (mraa_file_exist(DT_BASE "/model")) { // We are on a modern kernel, great!!!! - if (mraa_file_contains(DT_BASE "/model", "Qualcomm Technologies, Inc. APQ 8016 SBC")) { + if (mraa_file_contains(DT_BASE "/model", "s900")) { + b->platform_name = PLATFORM_NAME_BBGUM; + ls_gpio_pins = bbgum_ls_gpio_pins; + b->uart_dev[0].device_path = (char*) bbgum_serialdev[0]; + b->uart_dev[1].device_path = (char*) bbgum_serialdev[1]; + } else if (mraa_file_contains(DT_BASE "/model", + "Qualcomm Technologies, Inc. APQ 8016 SBC")) { b->platform_name = PLATFORM_NAME_DB410C; ls_gpio_pins = db410c_ls_gpio_pins; - b->uart_dev[0].device_path = (char *)db410c_serialdev[0]; - b->uart_dev[1].device_path = (char *)db410c_serialdev[1]; + chardev_map = &db410c_chardev_map; + b->uart_dev[0].device_path = (char*) db410c_serialdev[0]; + b->uart_dev[1].device_path = (char*) db410c_serialdev[1]; + b->led_dev[0].name = (char*) db410c_led[0]; + b->led_dev[1].name = (char*) db410c_led[1]; + b->led_dev[2].name = (char*) db410c_led[2]; + b->led_dev[3].name = (char*) db410c_led[3]; + b->led_dev[4].name = (char*) db410c_led[4]; + b->led_dev[5].name = (char*) db410c_led[5]; + b->led_dev_count = MRAA_96BOARDS_LED_COUNT; b->adv_func->gpio_mmap_setup = &mraa_db410c_mmap_setup; + b->chardev_capable = 1; + } else if (mraa_file_contains(DT_BASE "/model", "Qualcomm Technologies, Inc. DB820c")) { + b->platform_name = PLATFORM_NAME_DB820C; + ls_gpio_pins = db820c_ls_gpio_pins; + chardev_map = &db820c_chardev_map; + b->uart_dev[0].device_path = (char*) db820c_serialdev[0]; + b->uart_dev[1].device_path = (char*) db820c_serialdev[1]; + b->chardev_capable = 1; } else if (mraa_file_contains(DT_BASE "/model", "HiKey Development Board")) { b->platform_name = PLATFORM_NAME_HIKEY; ls_gpio_pins = hikey_ls_gpio_pins; - b->uart_dev[0].device_path = (char *)hikey_serialdev[0]; - b->uart_dev[1].device_path = (char *)hikey_serialdev[1]; - } else if (mraa_file_contains(DT_BASE "/model", "s900")) { - b->platform_name = PLATFORM_NAME_BBGUM; - ls_gpio_pins = bbgum_ls_gpio_pins; - b->uart_dev[0].device_path = (char *)bbgum_serialdev[0]; - b->uart_dev[1].device_path = (char *)bbgum_serialdev[1]; + chardev_map = &hikey_chardev_map; + b->uart_dev[0].device_path = (char*) hikey_serialdev[0]; + b->uart_dev[1].device_path = (char*) hikey_serialdev[1]; + b->chardev_capable = 1; + } else if (mraa_file_contains(DT_BASE "/model", "HiKey960")) { + b->platform_name = PLATFORM_NAME_HIKEY960; + chardev_map = &hikey960_chardev_map; + b->uart_dev[0].device_path = (char*) hikey960_serialdev[0]; + b->uart_dev[1].device_path = (char*) hikey960_serialdev[1]; + b->chardev_capable = 1; + } else if (mraa_file_contains(DT_BASE "/model", "ROCK960")) { + b->platform_name = PLATFORM_NAME_ROCK960; + ls_gpio_pins = rock960_ls_gpio_pins; + b->uart_dev[0].device_path = (char*) rock960_serialdev[0]; + b->uart_dev[1].device_path = (char*) rock960_serialdev[1]; + } else if (mraa_file_contains(DT_BASE "/model", "ZynqMP ZCU100 RevC")) { + b->platform_name = PLATFORM_NAME_ULTRA96; + chardev_map = &ultra96_chardev_map; + b->uart_dev[0].device_path = (char*) ultra96_serialdev[0]; + b->uart_dev[1].device_path = (char*) ultra96_serialdev[1]; + b->chardev_capable = 1; } } @@ -228,6 +323,16 @@ b->def_i2c_bus = 0; b->i2c_bus[0].bus_id = 1; b->i2c_bus[1].bus_id = 2; + } else if (strncmp(b->platform_name, PLATFORM_NAME_ROCK960, MAX_SIZE) == 0) { + b->i2c_bus_count = MRAA_96BOARDS_LS_I2C_COUNT; + b->def_i2c_bus = 0; + b->i2c_bus[0].bus_id = 6; + b->i2c_bus[1].bus_id = 1; + } else if (strncmp(b->platform_name, PLATFORM_NAME_ULTRA96, MAX_SIZE) == 0) { + b->i2c_bus_count = MRAA_96BOARDS_LS_I2C_COUNT; + b->def_i2c_bus = 0; + b->i2c_bus[0].bus_id = 2; + b->i2c_bus[1].bus_id = 3; } else { b->i2c_bus_count = MRAA_96BOARDS_LS_I2C_COUNT; b->def_i2c_bus = 0; @@ -247,41 +352,55 @@ return NULL; } - mraa_96boards_pininfo(b, 0, -1, "INVALID"); - mraa_96boards_pininfo(b, 1, -1, "GND"); - mraa_96boards_pininfo(b, 2, -1, "GND"); - mraa_96boards_pininfo(b, 3, -1, "UART0_CTS"); - mraa_96boards_pininfo(b, 4, -1, "PWR_BTN_N"); - mraa_96boards_pininfo(b, 5, -1, "UART0_TXD"); - mraa_96boards_pininfo(b, 6, -1, "RST_BTN_N"); - mraa_96boards_pininfo(b, 7, -1, "UART0_RXD"); - mraa_96boards_pininfo(b, 8, -1, "SPI0_SCLK"); - mraa_96boards_pininfo(b, 9, -1, "UART0_RTS"); - mraa_96boards_pininfo(b, 10, -1, "SPI0_DIN"); - mraa_96boards_pininfo(b, 11, -1, "UART1_TXD"); - mraa_96boards_pininfo(b, 12, -1, "SPI0_CS"); - mraa_96boards_pininfo(b, 13, -1, "UART1_RXD"); - mraa_96boards_pininfo(b, 14, -1, "SPI0_DOUT"); - mraa_96boards_pininfo(b, 15, -1, "I2C0_SCL"); - mraa_96boards_pininfo(b, 16, -1, "PCM_FS"); - mraa_96boards_pininfo(b, 17, -1, "I2C0_SDA"); - mraa_96boards_pininfo(b, 18, -1, "PCM_CLK"); - mraa_96boards_pininfo(b, 19, -1, "I2C1_SCL"); - mraa_96boards_pininfo(b, 20, -1, "PCM_DO"); - mraa_96boards_pininfo(b, 21, -1, "I2C1_SDA"); - mraa_96boards_pininfo(b, 22, -1, "PCM_DI"); + mraa_96boards_pininfo(b, 0, -1, 0, "INVALID"); + mraa_96boards_pininfo(b, 1, -1, 0, "GND"); + mraa_96boards_pininfo(b, 2, -1, 0, "GND"); + mraa_96boards_pininfo(b, 3, -1, 0, "UART0_CTS"); + mraa_96boards_pininfo(b, 4, -1, 0, "PWR_BTN_N"); + mraa_96boards_pininfo(b, 5, -1, 0, "UART0_TXD"); + mraa_96boards_pininfo(b, 6, -1, 0, "RST_BTN_N"); + mraa_96boards_pininfo(b, 7, -1, 0, "UART0_RXD"); + mraa_96boards_pininfo(b, 8, -1, 0, "SPI0_SCLK"); + mraa_96boards_pininfo(b, 9, -1, 0, "UART0_RTS"); + mraa_96boards_pininfo(b, 10, -1, 0, "SPI0_DIN"); + mraa_96boards_pininfo(b, 11, -1, 0, "UART1_TXD"); + // On DB410c, configure the SPI0_CS pin as GPIO for enabling the + // user to control it manually without adding chip select property + // in Devicetree. + if (strncmp(b->platform_name, PLATFORM_NAME_DB410C, MAX_SIZE) == 0) { + mraa_96boards_pininfo(b, 12, 18, 1, "SPI0_CS", -1, 0, 18); + } else { + mraa_96boards_pininfo(b, 12, -1, 0, "SPI0_CS"); + } + mraa_96boards_pininfo(b, 13, -1, 0, "UART1_RXD"); + mraa_96boards_pininfo(b, 14, -1, 0, "SPI0_DOUT"); + mraa_96boards_pininfo(b, 15, -1, 0, "I2C0_SCL"); + mraa_96boards_pininfo(b, 16, -1, 0, "PCM_FS"); + mraa_96boards_pininfo(b, 17, -1, 0, "I2C0_SDA"); + mraa_96boards_pininfo(b, 18, -1, 0, "PCM_CLK"); + mraa_96boards_pininfo(b, 19, -1, 0, "I2C1_SCL"); + mraa_96boards_pininfo(b, 20, -1, 0, "PCM_DO"); + mraa_96boards_pininfo(b, 21, -1, 0, "I2C1_SDA"); + mraa_96boards_pininfo(b, 22, -1, 0, "PCM_DI"); // GPIOs are labelled "GPIO-A" through "GPIO-L" for (i = 0; i < MRAA_96BOARDS_LS_GPIO_COUNT; i++) { - mraa_96boards_pininfo(b, 23 + i, ls_gpio_pins ? ls_gpio_pins[i] : -1, "GPIO-%c", 'A' + i); + mraa_96boards_pininfo(b, 23 + i, ls_gpio_pins ? ls_gpio_pins[i] : -1, 1, "GPIO-%c", 'A' + i, + chardev_map ? (*chardev_map)[i][0] : -1, + chardev_map ? (*chardev_map)[i][1] : -1); + } + mraa_96boards_pininfo(b, 35, -1, 0, "1.8v"); + mraa_96boards_pininfo(b, 36, -1, 0, "SYS_DCIN"); + mraa_96boards_pininfo(b, 37, -1, 0, "5v"); + mraa_96boards_pininfo(b, 38, -1, 0, "SYS_DCIN"); + mraa_96boards_pininfo(b, 39, -1, 0, "GND"); + mraa_96boards_pininfo(b, 40, -1, 0, "GND"); + + // On DB410c, SPI0_CS pin is used as GPIO + if (strncmp(b->platform_name, PLATFORM_NAME_DB410C, MAX_SIZE) == 0) { + b->gpio_count = MRAA_96BOARDS_LS_GPIO_COUNT + 1; + } else { + b->gpio_count = MRAA_96BOARDS_LS_GPIO_COUNT; } - mraa_96boards_pininfo(b, 35, -1, "1.8v"); - mraa_96boards_pininfo(b, 36, -1, "SYS_DCIN"); - mraa_96boards_pininfo(b, 37, -1, "5v"); - mraa_96boards_pininfo(b, 38, -1, "SYS_DCIN"); - mraa_96boards_pininfo(b, 39, -1, "GND"); - mraa_96boards_pininfo(b, 40, -1, "GND"); - - b->gpio_count = MRAA_96BOARDS_LS_GPIO_COUNT; b->aio_count = 0; b->adc_raw = 0; diff -Nru mraa-1.9.0/src/arm/arm.c mraa-2.0.0/src/arm/arm.c --- mraa-1.9.0/src/arm/arm.c 2018-02-15 23:08:49.000000000 +0000 +++ mraa-2.0.0/src/arm/arm.c 2018-09-06 12:34:41.000000000 +0000 @@ -85,12 +85,20 @@ /* Get compatible string from Device tree for boards that dont have enough info in /proc/cpuinfo */ if (platform_type == MRAA_UNKNOWN_PLATFORM) { - if (mraa_file_contains("/proc/device-tree/compatible", "qcom,apq8016-sbc")) + if (mraa_file_contains("/proc/device-tree/model", "s900")) + platform_type = MRAA_96BOARDS; + else if (mraa_file_contains("/proc/device-tree/compatible", "qcom,apq8016-sbc")) + platform_type = MRAA_96BOARDS; + else if (mraa_file_contains("/proc/device-tree/compatible", "arrow,apq8096-db820c")) platform_type = MRAA_96BOARDS; else if (mraa_file_contains("/proc/device-tree/model", "HiKey Development Board")) platform_type = MRAA_96BOARDS; - else if (mraa_file_contains("/proc/device-tree/model", "s900")) + else if (mraa_file_contains("/proc/device-tree/model", "HiKey960")) + platform_type = MRAA_96BOARDS; + else if (mraa_file_contains("/proc/device-tree/model", "ROCK960")) + platform_type = MRAA_96BOARDS; + else if (mraa_file_contains("/proc/device-tree/model", "ZynqMP ZCU100 RevC")) platform_type = MRAA_96BOARDS; else if (mraa_file_contains("/proc/device-tree/compatible", "raspberrypi,")) platform_type = MRAA_RASPBERRY_PI; diff -Nru mraa-1.9.0/src/arm/raspberry_pi.c mraa-2.0.0/src/arm/raspberry_pi.c --- mraa-1.9.0/src/arm/raspberry_pi.c 2018-02-15 23:08:49.000000000 +0000 +++ mraa-2.0.0/src/arm/raspberry_pi.c 2018-09-06 12:34:41.000000000 +0000 @@ -436,14 +436,6 @@ return MRAA_SUCCESS; } -mraa_result_t -mraa_raspberry_pi_spi_frequency_replace(mraa_spi_context dev, int hz) -{ - // RPI driver doesn't like being queried for it's max speed - dev->clock = hz; - return MRAA_SUCCESS; -} - mraa_board_t* mraa_raspberry_pi() { @@ -630,7 +622,6 @@ b->adv_func->spi_init_pre = &mraa_raspberry_pi_spi_init_pre; b->adv_func->i2c_init_pre = &mraa_raspberry_pi_i2c_init_pre; b->adv_func->gpio_mmap_setup = &mraa_raspberry_pi_mmap_setup; - b->adv_func->spi_frequency_replace = &mraa_raspberry_pi_spi_frequency_replace; b->adv_func->pwm_init_raw_replace = &mraa_raspberry_pi_pwm_initraw_replace; b->adv_func->pwm_write_replace = &mraa_raspberry_pi_pwm_write_duty_replace; b->adv_func->pwm_period_replace = &mraa_raspberry_pi_pwm_period_us_replace; diff -Nru mraa-1.9.0/src/CMakeLists.txt mraa-2.0.0/src/CMakeLists.txt --- mraa-1.9.0/src/CMakeLists.txt 2018-02-15 23:08:49.000000000 +0000 +++ mraa-2.0.0/src/CMakeLists.txt 2018-09-06 12:34:41.000000000 +0000 @@ -23,12 +23,14 @@ set (mraa_LIB_SRCS_NOAUTO ${PROJECT_SOURCE_DIR}/src/mraa.c ${PROJECT_SOURCE_DIR}/src/gpio/gpio.c + ${PROJECT_SOURCE_DIR}/src/gpio/gpio_chardev.c ${PROJECT_SOURCE_DIR}/src/i2c/i2c.c ${PROJECT_SOURCE_DIR}/src/pwm/pwm.c ${PROJECT_SOURCE_DIR}/src/spi/spi.c ${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} ) @@ -52,6 +54,7 @@ ${PROJECT_SOURCE_DIR}/src/x86/up.c ${PROJECT_SOURCE_DIR}/src/x86/up2.c ${PROJECT_SOURCE_DIR}/src/x86/intel_joule_expansion.c + ${PROJECT_SOURCE_DIR}/src/x86/iei_tank.c ) message (STATUS "INFO - Adding support for platform ${MRAAPLATFORMFORCE}") @@ -81,6 +84,8 @@ set (mraa_LIB_X86_SRCS_NOAUTO ${PROJECT_SOURCE_DIR}/src/x86/x86.c ${PROJECT_SOURCE_DIR}/src/x86/up2.c) elseif( ${MRAAPLATFORMFORCE} STREQUAL "MRAA_INTEL_JOULE_EXPANSION") set (mraa_LIB_X86_SRCS_NOAUTO ${PROJECT_SOURCE_DIR}/src/x86/x86.c ${PROJECT_SOURCE_DIR}/src/x86/intel_joule_expansion.c) + elseif( ${MRAAPLATFORMFORCE} STREQUAL "MRAA_IEI_TANK") + set (mraa_LIB_X86_SRCS_NOAUTO ${PROJECT_SOURCE_DIR}/src/x86/x86.c ${PROJECT_SOURCE_DIR}/src/x86/iei_tank.c) else () message (FATAL_ERROR "Unknown x86 platform enabled!") endif () @@ -172,22 +177,26 @@ if (USBPLAT) message (STATUS "INFO - Adding USB platforms") + # USBPLAT is used in mraa.c to decide whether to attempt to load sub-platforms set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DUSBPLAT=1") + # Loading an FTDI platform extender library using dlopen requires + # mraa to link against libdl. Mraa does NOT link directly to the + # FT4222 shim library. + set (mraa_LIBS ${mraa_LIBS} dl) if (FTDID2xx) find_package (Ftd2xx) if (${LIBFTD2XX_FOUND}) - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DFTDID2XX=1") set (mraa_LIBS ${mraa_LIBS} ${LIBFTD2XX_LIBRARIES}) else () message (SEND_ERROR "Enabled FTDID2xx support but library not found") endif () endif () + # The FTDI4222 shim includes libft4222.h (which includes ftd2xx.h), make sure + # both exist if building the FTDI4222 shim library if (FTDI4222) + find_package (Ftd2xx REQUIRED) find_package (Ftd4222) - if (${LIBFT4222_FOUND}) - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DFTDI4222=1") - set (mraa_LIBS ${mraa_LIBS} dl) - else () + if (NOT ${LIBFT4222_FOUND}) message (SEND_ERROR "Enabled FTDI4222 support but library not found") endif () endif () diff -Nru mraa-1.9.0/src/firmata/firmata_mraa.c mraa-2.0.0/src/firmata/firmata_mraa.c --- mraa-1.9.0/src/firmata/firmata_mraa.c 2018-02-15 23:08:49.000000000 +0000 +++ mraa-2.0.0/src/firmata/firmata_mraa.c 2018-09-06 12:34:41.000000000 +0000 @@ -96,7 +96,7 @@ char buff[4]; buff[0] = FIRMATA_START_SYSEX; buff[1] = FIRMATA_I2C_CONFIG; - buff[2] = delay & 0xFF, (delay >> 8) & 0xFF; + buff[2] = delay & 0xFF; buff[3] = FIRMATA_END_SYSEX; mraa_uart_write(firmata_dev->uart, buff, 4); @@ -217,7 +217,7 @@ uint8_t rawdata[2]; rawdata[0] = firmata_dev->i2cmsg[dev->addr][command]; rawdata[1] = firmata_dev->i2cmsg[dev->addr][command+1]; - uint16_t data = (uint16_t) rawdata; + uint16_t data = (uint16_t) *rawdata; uint8_t high = (data & 0xFF00) >> 8; data = (data << 8) & 0xFF00; data |= high; diff -Nru mraa-1.9.0/src/gpio/gpio.c mraa-2.0.0/src/gpio/gpio.c --- mraa-1.9.0/src/gpio/gpio.c 2018-02-15 23:08:49.000000000 +0000 +++ mraa-2.0.0/src/gpio/gpio.c 2018-09-06 12:34:41.000000000 +0000 @@ -1,7 +1,7 @@ /* * Author: Thomas Ingleby * Author: Brendan Le Foll - * Copyright (c) 2014, 2015 Intel Corporation. + * Copyright (c) 2014-2018 Intel Corporation. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -23,25 +23,30 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "gpio.h" +#include "linux/gpio.h" #include "mraa_internal.h" +#include "gpio/gpio_chardev.h" -#include +#include +#include #include -#include -#include #include #include #include -#include +#include +#include +#include #include -#include +#include +#include +#include #define SYSFS_CLASS_GPIO "/sys/class/gpio" #define MAX_SIZE 64 #define POLL_TIMEOUT static mraa_result_t -mraa_gpio_get_valfp(mraa_gpio_context dev) +_mraa_gpio_get_valfp(mraa_gpio_context dev) { char bu[MAX_SIZE]; snprintf(bu, MAX_SIZE, SYSFS_CLASS_GPIO "/gpio%d/value", dev->pin); @@ -54,15 +59,29 @@ return MRAA_SUCCESS; } +void +mraa_gpio_close_event_handles_sysfs(int fds[], int num_fds) +{ + if ((fds == NULL) || (num_fds <= 0)) { + syslog(LOG_CRIT, "failed to close and free sysfs event handles"); + return; + } + + for (int i = 0; i < num_fds; ++i) { + close(fds[i]); + } + + free(fds); +} + static mraa_gpio_context mraa_gpio_init_internal(mraa_adv_func_t* func_table, int pin) { - if (pin < 0) + if (pin < 0) { return NULL; + } mraa_result_t status = MRAA_SUCCESS; - char bu[MAX_SIZE]; - int length; mraa_gpio_context dev = (mraa_gpio_context) calloc(1, sizeof(struct _gpio)); if (dev == NULL) { @@ -95,36 +114,51 @@ dev->isr_thread_terminating = 0; dev->phy_pin = -1; - // then check to make sure the pin is exported. - char directory[MAX_SIZE]; - snprintf(directory, MAX_SIZE, SYSFS_CLASS_GPIO "/gpio%d/", dev->pin); - struct stat dir; - if (stat(directory, &dir) == 0 && S_ISDIR(dir.st_mode)) { - dev->owner = 0; // Not Owner - } else { - int export = open(SYSFS_CLASS_GPIO "/export", O_WRONLY); - if (export == -1) { - syslog(LOG_ERR, "gpio%i: init: Failed to open 'export' for writing: %s", pin, strerror(errno)); - status = MRAA_ERROR_INVALID_RESOURCE; - goto init_internal_cleanup; - } - length = snprintf(bu, sizeof(bu), "%d", dev->pin); - if (write(export, bu, length * sizeof(char)) == -1) { - syslog(LOG_ERR, "gpio%i: init: Failed to write to 'export': %s", pin, strerror(errno)); + if (!plat->chardev_capable) { + char bu[MAX_SIZE]; + int length; + + // then check to make sure the pin is exported. + char directory[MAX_SIZE]; + snprintf(directory, MAX_SIZE, SYSFS_CLASS_GPIO "/gpio%d/", dev->pin); + struct stat dir; + if (stat(directory, &dir) == 0 && S_ISDIR(dir.st_mode)) { + dev->owner = 0; // Not Owner + } else { + int export = open(SYSFS_CLASS_GPIO "/export", O_WRONLY); + if (export == -1) { + syslog(LOG_ERR, "gpio%i: init: Failed to open 'export' for writing: %s", + pin, strerror(errno)); + status = MRAA_ERROR_INVALID_RESOURCE; + goto init_internal_cleanup; + } + length = snprintf(bu, sizeof(bu), "%d", dev->pin); + if (write(export, bu, length * sizeof(char)) == -1) { + syslog(LOG_ERR, "gpio%i: init: Failed to write to 'export': %s", + pin, strerror(errno)); + close(export); + status = MRAA_ERROR_INVALID_RESOURCE; + goto init_internal_cleanup; + } + dev->owner = 1; close(export); - status = MRAA_ERROR_INVALID_RESOURCE; - goto init_internal_cleanup; } - dev->owner = 1; - close(export); } + /* We only have one pin. No need for multiple pin legacy support. */ + dev->num_pins = 1; + dev->next = NULL; + + /* Initialize events array. */ + dev->events = NULL; + init_internal_cleanup: if (status != MRAA_SUCCESS) { if (dev != NULL) free(dev); return NULL; } + return dev; } @@ -132,13 +166,24 @@ mraa_gpio_init(int pin) { mraa_board_t* board = plat; + if (board == NULL) { syslog(LOG_ERR, "gpio%i: init: platform not initialised", pin); return NULL; } - if (mraa_is_sub_platform_id(pin)) { - syslog(LOG_NOTICE, "gpio%i: init: Using sub platform", pin); + /* If this pin belongs to a subplatform, then the pin member will contain + * the mraa pin index and the phy_pin will contain the subplatform's + * pin index. + * example: pin 515, dev->pin = 515, dev->phy_pin = 3 + */ + if (mraa_is_sub_platform_id(pin) && (board->sub_platform != NULL)) { + syslog(LOG_NOTICE, "gpio%i: initialised on sub platform '%s' physical pin: %i", + pin, + board->sub_platform->platform_name != NULL ? + board->sub_platform->platform_name : "", + mraa_get_sub_platform_index(pin)); + board = board->sub_platform; if (board == NULL) { syslog(LOG_ERR, "gpio%i: init: Sub platform not initialised", pin); @@ -147,8 +192,14 @@ pin = mraa_get_sub_platform_index(pin); } + if (board->chardev_capable) { + int pins[1] = { pin }; + return mraa_gpio_init_multi(pins, 1); + } + if (pin < 0 || pin >= board->phy_pin_count) { - syslog(LOG_ERR, "gpio: init: pin %i beyond platform pin count (%i)", pin, board->phy_pin_count); + syslog(LOG_ERR, "gpio: init: pin %i beyond platform pin count (%i)", + pin, board->phy_pin_count); return NULL; } if (board->pins[pin].capabilities.gpio != 1) { @@ -163,9 +214,11 @@ } mraa_gpio_context r = mraa_gpio_init_internal(board->adv_func, board->pins[pin].gpio.pinmap); + if (r == NULL) { return NULL; } + if (r->phy_pin == -1) r->phy_pin = pin; @@ -176,65 +229,363 @@ return NULL; } } + return r; } mraa_gpio_context +mraa_gpio_chardev_init(int pins[], int num_pins) +{ + int chip_id, line_offset; + mraa_gpio_context dev; + mraa_gpiod_group_t gpio_group; + + mraa_board_t* board = plat; + + dev = (mraa_gpio_context) calloc(1, sizeof(struct _gpio)); + if (dev == NULL) { + syslog(LOG_CRIT, "[GPIOD_INTERFACE]: Failed to allocate memory for context"); + return NULL; + } + + dev->pin_to_gpio_table = malloc(num_pins * sizeof(int)); + if (dev->pin_to_gpio_table == NULL) { + syslog(LOG_CRIT, "[GPIOD_INTERFACE]: Failed to allocate memory for internal member"); + mraa_gpio_close(dev); + return NULL; + } + + dev->num_chips = mraa_get_number_of_gpio_chips(); + if (dev->num_chips <= 0) { + mraa_gpio_close(dev); + return NULL; + } + + dev->num_pins = num_pins; + + gpio_group = calloc(dev->num_chips, sizeof(struct _gpio_group)); + if (gpio_group == NULL) { + syslog(LOG_CRIT, "[GPIOD_INTERFACE]: Failed to allocate memory for internal member"); + mraa_gpio_close(dev); + return NULL; + } + + for (int i = 0; i < dev->num_chips; ++i) { + gpio_group[i].gpio_chip = i; + /* Just to be sure realloc has the desired behaviour. */ + gpio_group[i].gpio_lines = NULL; + } + + for (int i = 0; i < num_pins; ++i) { + if (mraa_is_sub_platform_id(pins[i])) { + syslog(LOG_NOTICE, "[GPIOD_INTERFACE]: init: Using sub platform for %d", pins[i]); + board = board->sub_platform; + if (board == NULL) { + syslog(LOG_ERR, "[GPIOD_INTERFACE]: init: Sub platform not initialised for pin %d", pins[i]); + mraa_gpio_close(dev); + return NULL; + } + pins[i] = mraa_get_sub_platform_index(pins[i]); + } + + if (pins[i] < 0 || pins[i] >= board->phy_pin_count) { + syslog(LOG_ERR, "[GPIOD_INTERFACE]: init: pin %d beyond platform pin count (%d)", + pins[i], board->phy_pin_count); + mraa_gpio_close(dev); + return NULL; + } + + if (board->pins[pins[i]].capabilities.gpio != 1) { + syslog(LOG_ERR, "[GPIOD_INTERFACE]: init: pin %d not capable of gpio", pins[i]); + mraa_gpio_close(dev); + return NULL; + } + + if (board->pins[pins[i]].gpio.mux_total > 0) { + if (mraa_setup_mux_mapped(board->pins[pins[i]].gpio) != MRAA_SUCCESS) { + syslog(LOG_ERR, "[GPIOD_INTERFACE]: init: unable to setup muxes for pin %d", pins[i]); + mraa_gpio_close(dev); + return NULL; + } + } + + chip_id = board->pins[pins[i]].gpio.gpio_chip; + line_offset = board->pins[pins[i]].gpio.gpio_line; + + /* Map pin to _gpio_group structure. */ + dev->pin_to_gpio_table[i] = chip_id; + + if (!gpio_group[chip_id].is_required) { + mraa_gpiod_chip_info* cinfo = mraa_get_chip_info_by_number(chip_id); + if (!cinfo) { + syslog(LOG_ERR, "[GPIOD_INTERFACE]: error getting gpio_chip_info for chip %d", chip_id); + mraa_gpio_close(dev); + return NULL; + } + + gpio_group[chip_id].dev_fd = cinfo->chip_fd; + gpio_group[chip_id].is_required = 1; + gpio_group[chip_id].gpiod_handle = -1; + + free(cinfo); + } + + int line_in_group; + line_in_group = gpio_group[chip_id].num_gpio_lines; + gpio_group[chip_id].gpio_lines = realloc(gpio_group[chip_id].gpio_lines, + (line_in_group + 1) * sizeof(unsigned int)); + if (gpio_group[chip_id].gpio_lines == NULL) { + syslog(LOG_CRIT, "[GPIOD_INTERFACE]: Failed to allocate memory for internal member"); + mraa_gpio_close(dev); + return NULL; + } + + gpio_group[chip_id].gpio_lines[line_in_group] = line_offset; + gpio_group[chip_id].num_gpio_lines++; + } + + /* Initialize rw_values for read / write multiple functions. + * Also, allocate memory for inverse map: */ + for (int i = 0; i < dev->num_chips; ++i) { + gpio_group[i].rw_values = calloc(gpio_group[i].num_gpio_lines, sizeof(unsigned char)); + if (gpio_group[i].rw_values == NULL) { + syslog(LOG_CRIT, "[GPIOD_INTERFACE]: Failed to allocate memory for internal member"); + mraa_gpio_close(dev); + return NULL; + } + + gpio_group[i].gpio_group_to_pins_table = calloc(gpio_group[i].num_gpio_lines, sizeof(int)); + if (gpio_group[i].gpio_group_to_pins_table == NULL) { + syslog(LOG_CRIT, "[GPIOD_INTERFACE]: Failed to allocate memory for internal member"); + mraa_gpio_close(dev); + return NULL; + } + + /* Set event handle arrays for all lines contained on a chip to NULL. */ + gpio_group[i].event_handles = NULL; + } + + /* Finally map the inverse relation between a gpio group and its original pin numbers + * provided by user. */ + int* counters = calloc(dev->num_chips, sizeof(int)); + if (counters == NULL) { + syslog(LOG_CRIT, "[GPIOD_INTERFACE]: Failed to allocate memory for local variable"); + mraa_gpio_close(dev); + return NULL; + } + + for (int i = 0; i < num_pins; ++i) { + int chip = dev->pin_to_gpio_table[i]; + gpio_group[chip].gpio_group_to_pins_table[counters[chip]] = i; + counters[chip]++; + } + free(counters); + + dev->gpio_group = gpio_group; + + /* Save the provided array from the user to our internal structure. */ + dev->provided_pins = malloc(dev->num_pins * sizeof(int)); + if (dev->provided_pins == NULL) { + syslog(LOG_CRIT, "[GPIOD_INTERFACE]: Failed to allocate memory for internal member"); + mraa_gpio_close(dev); + return NULL; + } + + memcpy(dev->provided_pins, pins, dev->num_pins * sizeof(int)); + + /* Initialize events array. */ + dev->events = NULL; + + return dev; +} + +mraa_gpio_context +mraa_gpio_init_multi(int pins[], int num_pins) +{ + mraa_board_t* board = plat; + + if (board == NULL) { + syslog(LOG_ERR, "[GPIOD_INTERFACE]: init: platform not initialised"); + return NULL; + } + + if (board->chardev_capable) + return mraa_gpio_chardev_init(pins, num_pins); + + /* Fallback to legacy interface. */ + mraa_gpio_context head = NULL, current, tmp; + + for (int i = 0; i < num_pins; ++i) { + tmp = mraa_gpio_init(pins[i]); + if (!tmp) { + syslog(LOG_ERR, "mraa_gpio_init_multi() error initializing pin %i", pins[i]); + continue; + } + + if (head == NULL) { + head = tmp; + current = tmp; + } else { + current->next = tmp; + current = tmp; + } + + current->next = NULL; + } + + if (head != NULL) { + head->num_pins = num_pins; + } + + return head; +} + +mraa_gpio_context mraa_gpio_init_raw(int pin) { - return mraa_gpio_init_internal(plat == NULL ? NULL : plat->adv_func , pin); + return mraa_gpio_init_internal(plat == NULL ? NULL : plat->adv_func, pin); } +mraa_timestamp_t +_mraa_gpio_get_timestamp_sysfs() +{ + struct timeval time; + gettimeofday(&time, NULL); + + return (time.tv_sec * 1e6 + time.tv_usec); +} static mraa_result_t -mraa_gpio_wait_interrupt(int fd +mraa_gpio_wait_interrupt(int fds[], + int num_fds #ifndef HAVE_PTHREAD_CANCEL - , int control_fd + , + int control_fd #endif - ) + , + mraa_gpio_events_t events +) { unsigned char c; #ifdef HAVE_PTHREAD_CANCEL - struct pollfd pfd[1]; + struct pollfd pfd[num_fds]; #else - struct pollfd pfd[2]; + struct pollfd pfd[num_fds + 1]; if (control_fd < 0) { return MRAA_ERROR_INVALID_PARAMETER; } #endif - if (fd < 0) { + if (!fds) { return MRAA_ERROR_INVALID_PARAMETER; } - // setup poll on POLLPRI - pfd[0].fd = fd; - pfd[0].events = POLLPRI; - - // do an initial read to clear interrupt - lseek(fd, 0, SEEK_SET); - read(fd, &c, 1); + for (int i = 0; i < num_fds; ++i) { + pfd[i].fd = fds[i]; + // setup poll on POLLPRI + pfd[i].events = POLLPRI; + + // do an initial read to clear interrupt + lseek(fds[i], 0, SEEK_SET); + read(fds[i], &c, 1); + } #ifdef HAVE_PTHREAD_CANCEL // Wait for it forever or until pthread_cancel // poll is a cancelable point like sleep() - poll(pfd, 1, -1); + poll(pfd, num_fds, -1); #else // setup poll on the controling fd - pfd[1].fd = control_fd; - pfd[1].events = 0; // POLLHUP, POLLERR, and POLLNVAL + pfd[num_fds].fd = control_fd; + pfd[num_fds].events = 0; // POLLHUP, POLLERR, and POLLNVAL // Wait for it forever or until control fd is closed - poll(pfd, 2, -1); + poll(pfd, num_fds + 1, -1); #endif - // do a final read to clear interrupt - read(fd, &c, 1); + for (int i = 0; i < num_fds; ++i) { + if (pfd[i].revents & POLLPRI) { + read(fds[i], &c, 1); + events[i].id = i; + events[i].timestamp = _mraa_gpio_get_timestamp_sysfs(); + } else + events[i].id = -1; + } + + return MRAA_SUCCESS; +} + +static mraa_result_t +mraa_gpio_chardev_wait_interrupt(int fds[], int num_fds, mraa_gpio_events_t events) +{ + struct pollfd pfd[num_fds]; + struct gpioevent_data event_data; + + if (!fds) { + return MRAA_ERROR_INVALID_PARAMETER; + } + + for (int i = 0; i < num_fds; ++i) { + pfd[i].fd = fds[i]; + pfd[i].events = POLLIN; + + lseek(fds[i], 0, SEEK_SET); + } + + poll(pfd, num_fds, -1); + + for (int i = 0; i < num_fds; ++i) { + if (pfd[i].revents & POLLIN) { + read(fds[i], &event_data, sizeof(event_data)); + events[i].id = i; + events[i].timestamp = event_data.timestamp; + } else + events[i].id = -1; + } return MRAA_SUCCESS; } +mraa_gpio_events_t +mraa_gpio_get_events(mraa_gpio_context dev) +{ + if (dev == NULL) { + syslog(LOG_ERR, "gpio: mraa_gpio_get_events(): context is invalid"); + return NULL; + } + + unsigned int event_idx = 0; + + if (plat->chardev_capable) { + unsigned int pin_idx; + mraa_gpiod_group_t gpio_iter; + + for_each_gpio_group(gpio_iter, dev) { + for (int i = 0; i < gpio_iter->num_gpio_lines; ++i) { + if (dev->events[event_idx].id != -1) { + pin_idx = gpio_iter->gpio_group_to_pins_table[i]; + dev->events[event_idx].id = dev->provided_pins[pin_idx]; + } + event_idx++; + } + } + } else { + mraa_gpio_context it = dev; + + while (it) { + if (dev->events[event_idx].id != -1) { + dev->events[event_idx].id = it->phy_pin; + } + + event_idx++; + it = it->next; + } + } + + return dev->events; +} + static void* mraa_gpio_interrupt_handler(void* arg) { @@ -243,39 +594,67 @@ return NULL; } - mraa_gpio_context dev = (mraa_gpio_context) arg; - int fp = -1; mraa_result_t ret; + mraa_gpio_context dev = (mraa_gpio_context) arg; + int idx = 0; if (IS_FUNC_DEFINED(dev, gpio_interrupt_handler_init_replace)) { if (dev->advance_func->gpio_interrupt_handler_init_replace(dev) != MRAA_SUCCESS) return NULL; - } else { - // open gpio value with open(3) - char bu[MAX_SIZE]; - snprintf(bu, MAX_SIZE, SYSFS_CLASS_GPIO "/gpio%d/value", dev->pin); - fp = open(bu, O_RDONLY); - if (fp < 0) { - syslog(LOG_ERR, "gpio%i: interrupt_handler: failed to open 'value' : %s", dev->pin, strerror(errno)); - return NULL; + } + + int *fps = malloc(dev->num_pins * sizeof(int)); + if (!fps) { + syslog(LOG_ERR, "mraa_gpio_interrupt_handler_multiple() malloc error"); + return NULL; + } + + /* Is this pin on a subplatform? Do nothing... */ + if (mraa_is_sub_platform_id(dev->pin)) {} + /* Is the platform chardev_capable? */ + else if (plat->chardev_capable) { + mraa_gpiod_group_t gpio_group; + + for_each_gpio_group(gpio_group, dev) { + for (int i = 0; i < gpio_group->num_gpio_lines; ++i) { + fps[idx++] = gpio_group->event_handles[i]; + } + } + } + /* Else, attempt fs access */ + else { + mraa_gpio_context it = dev; + + while (it) { + // open gpio value with open(3) + char bu[MAX_SIZE]; + snprintf(bu, MAX_SIZE, SYSFS_CLASS_GPIO "/gpio%d/value", it->pin); + fps[idx] = open(bu, O_RDONLY); + if (fps[idx] < 0) { + syslog(LOG_ERR, "gpio%i: interrupt_handler: failed to open 'value' : %s", it->pin, + strerror(errno)); + mraa_gpio_close_event_handles_sysfs(fps, idx); + return NULL; + } + + idx++; + it = it->next; } } #ifndef HAVE_PTHREAD_CANCEL if (pipe(dev->isr_control_pipe)) { - syslog(LOG_ERR, "gpio%i: interrupt_handler: failed to create isr control pipe: %s", dev->pin, strerror(errno)); - close(fp); + syslog(LOG_ERR, "gpio%i: interrupt_handler: failed to create isr control pipe: %s", + dev->pin, strerror(errno)); + mraa_gpio_close_event_handles_sysfs(fps, dev->num_pins); return NULL; } #endif - dev->isr_value_fp = fp; - if (lang_func->java_attach_thread != NULL) { if (dev->isr == lang_func->java_isr_callback) { if (lang_func->java_attach_thread() != MRAA_SUCCESS) { - close(dev->isr_value_fp); - dev->isr_value_fp = -1; + mraa_gpio_close_event_handles_sysfs(fps, dev->num_pins); return NULL; } } @@ -285,12 +664,20 @@ if (IS_FUNC_DEFINED(dev, gpio_wait_interrupt_replace)) { ret = dev->advance_func->gpio_wait_interrupt_replace(dev); } else { - ret = mraa_gpio_wait_interrupt(dev->isr_value_fp + if (plat->chardev_capable) { + ret = mraa_gpio_chardev_wait_interrupt(fps, idx, dev->events); + } else { + ret = mraa_gpio_wait_interrupt(fps, idx #ifndef HAVE_PTHREAD_CANCEL - , dev->isr_control_pipe[0] + , + dev->isr_control_pipe[0] #endif + , + dev->events ); + } } + if (ret == MRAA_SUCCESS && !dev->isr_thread_terminating) { #ifdef HAVE_PTHREAD_CANCEL pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); @@ -304,14 +691,11 @@ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); #endif } else { - // we must have got an error code or exit request so die nicely + // we must have got an error code or exit request so die nicely #ifdef HAVE_PTHREAD_CANCEL pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); #endif - if (fp != -1) { - close(dev->isr_value_fp); - dev->isr_value_fp = -1; - } + mraa_gpio_close_event_handles_sysfs(fps, dev->num_pins); if (lang_func->java_detach_thread != NULL && lang_func->java_delete_global_ref != NULL) { if (dev->isr == lang_func->java_isr_callback) { @@ -326,56 +710,145 @@ } mraa_result_t -mraa_gpio_edge_mode(mraa_gpio_context dev, mraa_gpio_edge_t mode) +mraa_gpio_chardev_edge_mode(mraa_gpio_context dev, mraa_gpio_edge_t mode) { if (dev == NULL) { syslog(LOG_ERR, "gpio: edge_mode: context is invalid"); return MRAA_ERROR_INVALID_HANDLE; } - if (IS_FUNC_DEFINED(dev, gpio_edge_mode_replace)) - return dev->advance_func->gpio_edge_mode_replace(dev, mode); - - if (dev->value_fp != -1) { - close(dev->value_fp); - dev->value_fp = -1; + if (!plat->chardev_capable) { + syslog(LOG_ERR, "mraa_gpio_chardev_edge_mode() not supported for old sysfs interface"); + return MRAA_ERROR_FEATURE_NOT_IMPLEMENTED; } - char filepath[MAX_SIZE]; - snprintf(filepath, MAX_SIZE, SYSFS_CLASS_GPIO "/gpio%d/edge", dev->pin); + int status; + mraa_gpiod_group_t gpio_group; - int edge = open(filepath, O_RDWR); - if (edge == -1) { - syslog(LOG_ERR, "gpio%i: edge_mode: Failed to open 'edge' for writing: %s", dev->pin, strerror(errno)); - return MRAA_ERROR_INVALID_RESOURCE; - } + struct gpioevent_request req; - char bu[MAX_SIZE]; - int length; switch (mode) { - case MRAA_GPIO_EDGE_NONE: - length = snprintf(bu, sizeof(bu), "none"); - break; case MRAA_GPIO_EDGE_BOTH: - length = snprintf(bu, sizeof(bu), "both"); + req.eventflags = GPIOEVENT_REQUEST_BOTH_EDGES; break; case MRAA_GPIO_EDGE_RISING: - length = snprintf(bu, sizeof(bu), "rising"); + req.eventflags = GPIOEVENT_REQUEST_RISING_EDGE; break; case MRAA_GPIO_EDGE_FALLING: - length = snprintf(bu, sizeof(bu), "falling"); + req.eventflags = GPIOEVENT_REQUEST_FALLING_EDGE; break; + /* Chardev interface doesn't handle EDGE_NONE. */ + case MRAA_GPIO_EDGE_NONE: default: - close(edge); return MRAA_ERROR_FEATURE_NOT_IMPLEMENTED; } - if (write(edge, bu, length * sizeof(char)) == -1) { - syslog(LOG_ERR, "gpio%i: edge_mode: Failed to write to 'edge': %s", dev->pin, strerror(errno)); + + for_each_gpio_group(gpio_group, dev) + { + if (gpio_group->gpiod_handle != -1) { + close(gpio_group->gpiod_handle); + gpio_group->gpiod_handle = -1; + } + + gpio_group->event_handles = malloc(gpio_group->num_gpio_lines * sizeof(int)); + if (!gpio_group->event_handles) { + syslog(LOG_ERR, "mraa_gpio_chardev_edge_mode(): malloc error!"); + return MRAA_ERROR_NO_RESOURCES; + } + + for (int i = 0; i < gpio_group->num_gpio_lines; ++i) { + req.lineoffset = gpio_group->gpio_lines[i]; + req.handleflags = GPIOHANDLE_REQUEST_INPUT; + + status = _mraa_gpiod_ioctl(gpio_group->dev_fd, GPIO_GET_LINEEVENT_IOCTL, &req); + if (status < 0) { + syslog(LOG_ERR, "error getting line event handle for line %i", gpio_group->gpio_lines[i]); + return MRAA_ERROR_INVALID_RESOURCE; + } + + gpio_group->event_handles[i] = req.fd; + } + } + + return MRAA_SUCCESS; +} + +mraa_result_t +mraa_gpio_edge_mode(mraa_gpio_context dev, mraa_gpio_edge_t mode) +{ + if (dev == NULL) { + syslog(LOG_ERR, "gpio: edge_mode: context is invalid"); + return MRAA_ERROR_INVALID_HANDLE; + } + + if (IS_FUNC_DEFINED(dev, gpio_edge_mode_replace)) + return dev->advance_func->gpio_edge_mode_replace(dev, mode); + + /* Initialize events array. */ + if (dev->events == NULL && mode != MRAA_GPIO_EDGE_NONE) { + dev->events = malloc(dev->num_pins * sizeof (mraa_gpio_event)); + if (dev->events == NULL) { + syslog(LOG_ERR, "mraa_gpio_edge_mode() malloc error"); + return MRAA_ERROR_NO_RESOURCES; + } + + for (int i = 0; i < dev->num_pins; ++i) { + dev->events[i].id = -1; + } + } + + if (plat->chardev_capable) + return mraa_gpio_chardev_edge_mode(dev, mode); + + mraa_gpio_context it = dev; + + while (it) { + + if (it->value_fp != -1) { + close(it->value_fp); + it->value_fp = -1; + } + + char filepath[MAX_SIZE]; + snprintf(filepath, MAX_SIZE, SYSFS_CLASS_GPIO "/gpio%d/edge", it->pin); + + int edge = open(filepath, O_RDWR); + if (edge == -1) { + syslog(LOG_ERR, "gpio%i: edge_mode: Failed to open 'edge' for writing: %s", it->pin, + strerror(errno)); + return MRAA_ERROR_INVALID_RESOURCE; + } + + char bu[MAX_SIZE]; + int length; + switch (mode) { + case MRAA_GPIO_EDGE_NONE: + length = snprintf(bu, sizeof(bu), "none"); + break; + case MRAA_GPIO_EDGE_BOTH: + length = snprintf(bu, sizeof(bu), "both"); + break; + case MRAA_GPIO_EDGE_RISING: + length = snprintf(bu, sizeof(bu), "rising"); + break; + case MRAA_GPIO_EDGE_FALLING: + length = snprintf(bu, sizeof(bu), "falling"); + break; + default: + close(edge); + return MRAA_ERROR_FEATURE_NOT_IMPLEMENTED; + } + if (write(edge, bu, length * sizeof(char)) == -1) { + syslog(LOG_ERR, "gpio%i: edge_mode: Failed to write to 'edge': %s", it->pin, strerror(errno)); + close(edge); + return MRAA_ERROR_UNSPECIFIED; + } + close(edge); - return MRAA_ERROR_UNSPECIFIED; + + it = it->next; } - close(edge); return MRAA_SUCCESS; } @@ -396,7 +869,11 @@ return MRAA_ERROR_NO_RESOURCES; } - mraa_result_t ret = mraa_gpio_edge_mode(dev, mode); + mraa_result_t ret; + + + ret = mraa_gpio_edge_mode(dev, mode); + if (ret != MRAA_SUCCESS) { return ret; } @@ -412,6 +889,7 @@ } dev->isr_args = args; + pthread_create(&dev->thread_id, NULL, mraa_gpio_interrupt_handler, (void*) dev); return MRAA_SUCCESS; @@ -431,14 +909,17 @@ } // wasting our time, there is no isr to exit from - if (dev->thread_id == 0 && dev->isr_value_fp == -1) { + if (dev->thread_id == 0) { return ret; } // mark the beginning of the thread termination process for interested parties dev->isr_thread_terminating = 1; // stop isr being useful - ret = mraa_gpio_edge_mode(dev, MRAA_GPIO_EDGE_NONE); + if (plat && (plat->chardev_capable)) + _mraa_close_gpio_event_handles(dev); + else + ret = mraa_gpio_edge_mode(dev, MRAA_GPIO_EDGE_NONE); if ((dev->thread_id != 0)) { #ifdef HAVE_PTHREAD_CANCEL @@ -451,21 +932,20 @@ ret = MRAA_ERROR_INVALID_RESOURCE; close(dev->isr_control_pipe[0]); - dev->isr_control_pipe[0] = dev->isr_control_pipe[1] = -1; + dev->isr_control_pipe[0] = dev->isr_control_pipe[1] = -1; #endif } - // close the filehandle in case it's still open - if (dev->isr_value_fp != -1) { - if (close(dev->isr_value_fp) != 0) { - ret = MRAA_ERROR_INVALID_RESOURCE; - } - } - // assume our thread will exit either way we just lost it's handle dev->thread_id = 0; dev->isr_value_fp = -1; dev->isr_thread_terminating = 0; + + if (dev->events) { + free(dev->events); + dev->events = NULL; + } + return ret; } @@ -486,48 +966,150 @@ return pre_ret; } - if (dev->value_fp != -1) { - close(dev->value_fp); - dev->value_fp = -1; + if (plat->chardev_capable) { + unsigned flags = 0; + int line_handle; + mraa_gpiod_group_t gpio_iter; + + _mraa_close_gpio_desc(dev); + + /* We save flag values from the first valid line. */ + for_each_gpio_group(gpio_iter, dev) { + mraa_gpiod_line_info* linfo = mraa_get_line_info_by_chip_number(gpio_iter->gpio_chip, gpio_iter->gpio_lines[0]); + if (!linfo) { + syslog(LOG_ERR, "[GPIOD_INTERFACE]: error getting line info"); + return MRAA_ERROR_UNSPECIFIED; + } + flags = linfo->flags; + free(linfo); + + /* We don't need to iterate any further. */ + break; + } + + /* Without changing the API, for now, we can request only one mode per call. */ + switch (mode) { + case MRAA_GPIOD_ACTIVE_LOW: + flags |= GPIOHANDLE_REQUEST_ACTIVE_LOW; + break; + case MRAA_GPIOD_OPEN_DRAIN: + flags |= GPIOHANDLE_REQUEST_OPEN_DRAIN; + break; + case MRAA_GPIOD_OPEN_SOURCE: + flags |= GPIOHANDLE_REQUEST_OPEN_SOURCE; + break; + default: + return MRAA_ERROR_FEATURE_NOT_IMPLEMENTED; + } + + for_each_gpio_group(gpio_iter, dev) { + line_handle = mraa_get_lines_handle(gpio_iter->dev_fd, gpio_iter->gpio_lines, gpio_iter->num_gpio_lines, flags, 0); + if (line_handle <= 0) { + syslog(LOG_ERR, "[GPIOD_INTERFACE]: error getting line handle"); + return MRAA_ERROR_INVALID_RESOURCE; + } + + gpio_iter->gpiod_handle = line_handle; + } + } else { + + if (dev->value_fp != -1) { + close(dev->value_fp); + dev->value_fp = -1; + } + + char filepath[MAX_SIZE]; + snprintf(filepath, MAX_SIZE, SYSFS_CLASS_GPIO "/gpio%d/drive", dev->pin); + + int drive = open(filepath, O_WRONLY); + if (drive == -1) { + syslog(LOG_ERR, "gpio%i: mode: Failed to open 'drive' for writing: %s", dev->pin, strerror(errno)); + return MRAA_ERROR_INVALID_RESOURCE; + } + + char bu[MAX_SIZE]; + int length; + switch (mode) { + case MRAA_GPIO_STRONG: + length = snprintf(bu, sizeof(bu), "strong"); + break; + case MRAA_GPIO_PULLUP: + length = snprintf(bu, sizeof(bu), "pullup"); + break; + case MRAA_GPIO_PULLDOWN: + length = snprintf(bu, sizeof(bu), "pulldown"); + break; + case MRAA_GPIO_HIZ: + length = snprintf(bu, sizeof(bu), "hiz"); + break; + default: + close(drive); + return MRAA_ERROR_FEATURE_NOT_IMPLEMENTED; + } + if (write(drive, bu, length * sizeof(char)) == -1) { + syslog(LOG_ERR, "gpio%i: mode: Failed to write to 'drive': %s", dev->pin, strerror(errno)); + close(drive); + return MRAA_ERROR_INVALID_RESOURCE; + } + + close(drive); } - char filepath[MAX_SIZE]; - snprintf(filepath, MAX_SIZE, SYSFS_CLASS_GPIO "/gpio%d/drive", dev->pin); + if (IS_FUNC_DEFINED(dev, gpio_mode_post)) + return dev->advance_func->gpio_mode_post(dev, mode); - int drive = open(filepath, O_WRONLY); - if (drive == -1) { - syslog(LOG_ERR, "gpio%i: mode: Failed to open 'drive' for writing: %s", dev->pin, strerror(errno)); - return MRAA_ERROR_INVALID_RESOURCE; + return MRAA_SUCCESS; +} + +mraa_result_t +mraa_gpio_chardev_dir(mraa_gpio_context dev, mraa_gpio_dir_t dir) +{ + int line_handle; + unsigned flags = 0; + mraa_gpiod_group_t gpio_iter; + + for_each_gpio_group(gpio_iter, dev) { + mraa_gpiod_line_info* linfo = mraa_get_line_info_by_chip_number(gpio_iter->gpio_chip, gpio_iter->gpio_lines[0]); + if (!linfo) { + syslog(LOG_ERR, "[GPIOD_INTERFACE]: error getting line info"); + return MRAA_ERROR_UNSPECIFIED; + } + flags = linfo->flags; + free(linfo); + + /* We don't need to iterate any further. */ + break; } - char bu[MAX_SIZE]; - int length; - switch (mode) { - case MRAA_GPIO_STRONG: - length = snprintf(bu, sizeof(bu), "strong"); - break; - case MRAA_GPIO_PULLUP: - length = snprintf(bu, sizeof(bu), "pullup"); - break; - case MRAA_GPIO_PULLDOWN: - length = snprintf(bu, sizeof(bu), "pulldown"); + switch (dir) { + case MRAA_GPIO_OUT: + flags |= GPIOHANDLE_REQUEST_OUTPUT; + flags &= ~GPIOHANDLE_REQUEST_INPUT; break; - case MRAA_GPIO_HIZ: - length = snprintf(bu, sizeof(bu), "hiz"); + case MRAA_GPIO_IN: + flags |= GPIOHANDLE_REQUEST_INPUT; + flags &= ~GPIOHANDLE_REQUEST_OUTPUT; break; default: - close(drive); return MRAA_ERROR_FEATURE_NOT_IMPLEMENTED; } - if (write(drive, bu, length * sizeof(char)) == -1) { - syslog(LOG_ERR, "gpio%i: mode: Failed to write to 'drive': %s", dev->pin, strerror(errno)); - close(drive); - return MRAA_ERROR_INVALID_RESOURCE; + + for_each_gpio_group(gpio_iter, dev) { + if (gpio_iter->gpiod_handle != -1) { + close(gpio_iter->gpiod_handle); + gpio_iter->gpiod_handle = -1; + } + + line_handle = mraa_get_lines_handle(gpio_iter->dev_fd, gpio_iter->gpio_lines, + gpio_iter->num_gpio_lines, flags, 0); + if (line_handle <= 0) { + syslog(LOG_ERR, "[GPIOD_INTERFACE]: error getting line handle"); + return MRAA_ERROR_INVALID_RESOURCE; + } + + gpio_iter->gpiod_handle = line_handle; } - close(drive); - if (IS_FUNC_DEFINED(dev, gpio_mode_post)) - return dev->advance_func->gpio_mode_post(dev, mode); return MRAA_SUCCESS; } @@ -540,7 +1122,7 @@ } if (IS_FUNC_DEFINED(dev, gpio_dir_replace)) { - return dev->advance_func->gpio_dir_replace(dev, dir); + return dev->advance_func->gpio_dir_replace(dev, dir); } if (IS_FUNC_DEFINED(dev, gpio_dir_pre)) { @@ -550,105 +1132,145 @@ } } - if (dev->value_fp != -1) { - close(dev->value_fp); - dev->value_fp = -1; - } - char filepath[MAX_SIZE]; - snprintf(filepath, MAX_SIZE, SYSFS_CLASS_GPIO "/gpio%d/direction", dev->pin); + if (plat->chardev_capable) + return mraa_gpio_chardev_dir(dev, dir); + + mraa_gpio_context it = dev; + + while (it) { + if (it->value_fp != -1) { + close(it->value_fp); + it->value_fp = -1; + } + char filepath[MAX_SIZE]; + snprintf(filepath, MAX_SIZE, SYSFS_CLASS_GPIO "/gpio%d/direction", it->pin); + + int direction = open(filepath, O_RDWR); - int direction = open(filepath, O_RDWR); + if (direction == -1) { + // Direction Failed to Open. If HIGH or LOW was passed will try and set + // If not fail as usual. + switch (dir) { + case MRAA_GPIO_OUT_HIGH: + return mraa_gpio_write(it, 1); + case MRAA_GPIO_OUT_LOW: + return mraa_gpio_write(it, 0); + default: + syslog(LOG_ERR, "gpio%i: dir: Failed to open 'direction' for writing: %s", + it->pin, strerror(errno)); + return MRAA_ERROR_INVALID_RESOURCE; + } + } - if (direction == -1) { - // Direction Failed to Open. If HIGH or LOW was passed will try and set - // If not fail as usual. + char bu[MAX_SIZE]; + int length; switch (dir) { + case MRAA_GPIO_OUT: + length = snprintf(bu, sizeof(bu), "out"); + break; + case MRAA_GPIO_IN: + length = snprintf(bu, sizeof(bu), "in"); + break; case MRAA_GPIO_OUT_HIGH: - return mraa_gpio_write(dev, 1); + length = snprintf(bu, sizeof(bu), "high"); + break; case MRAA_GPIO_OUT_LOW: - return mraa_gpio_write(dev, 0); + length = snprintf(bu, sizeof(bu), "low"); + break; default: - syslog(LOG_ERR, "gpio%i: dir: Failed to open 'direction' for writing: %s", dev->pin, strerror(errno)); - return MRAA_ERROR_INVALID_RESOURCE; - } - } + close(direction); + return MRAA_ERROR_FEATURE_NOT_IMPLEMENTED; + } - char bu[MAX_SIZE]; - int length; - switch (dir) { - case MRAA_GPIO_OUT: - length = snprintf(bu, sizeof(bu), "out"); - break; - case MRAA_GPIO_IN: - length = snprintf(bu, sizeof(bu), "in"); - break; - case MRAA_GPIO_OUT_HIGH: - length = snprintf(bu, sizeof(bu), "high"); - break; - case MRAA_GPIO_OUT_LOW: - length = snprintf(bu, sizeof(bu), "low"); - break; - default: + if (write(direction, bu, length * sizeof(char)) == -1) { close(direction); - return MRAA_ERROR_FEATURE_NOT_IMPLEMENTED; - } + syslog(LOG_ERR, "gpio%i: dir: Failed to write to 'direction': %s", it->pin, strerror(errno)); + return MRAA_ERROR_UNSPECIFIED; + } - if (write(direction, bu, length * sizeof(char)) == -1) { close(direction); - syslog(LOG_ERR, "gpio%i: dir: Failed to write to 'direction': %s", dev->pin, strerror(errno)); - return MRAA_ERROR_UNSPECIFIED; + it = it->next; } - close(direction); if (IS_FUNC_DEFINED(dev, gpio_dir_post)) return dev->advance_func->gpio_dir_post(dev, dir); + return MRAA_SUCCESS; } mraa_result_t mraa_gpio_read_dir(mraa_gpio_context dev, mraa_gpio_dir_t *dir) { - char value[5]; - char filepath[MAX_SIZE]; - int fd, rc; mraa_result_t result = MRAA_SUCCESS; - if (dev == NULL) { - syslog(LOG_ERR, "gpio: read_dir: context is invalid"); - return MRAA_ERROR_INVALID_HANDLE; - } - - if (dir == NULL) { - syslog(LOG_ERR, "gpio: read_dir: output parameter for dir is invalid"); - return MRAA_ERROR_INVALID_HANDLE; - } + /* Initialize with 'unusable'. */ + unsigned flags = GPIOLINE_FLAG_KERNEL; if (IS_FUNC_DEFINED(dev, gpio_read_dir_replace)) { return dev->advance_func->gpio_read_dir_replace(dev, dir); } - snprintf(filepath, MAX_SIZE, SYSFS_CLASS_GPIO "/gpio%d/direction", dev->pin); - fd = open(filepath, O_RDONLY); - if (fd == -1) { - syslog(LOG_ERR, "gpio%i: read_dir: Failed to open 'direction' for reading: %s", dev->pin, strerror(errno)); - return MRAA_ERROR_INVALID_RESOURCE; - } + if (plat->chardev_capable) { + mraa_gpiod_group_t gpio_iter; - memset(value, '\0', sizeof(value)); - rc = read(fd, value, sizeof(value)); - close(fd); - if (rc <= 0) { - syslog(LOG_ERR, "gpio%i: read_dir: Failed to read 'direction': %s", dev->pin, strerror(errno)); - return MRAA_ERROR_INVALID_RESOURCE; - } + for_each_gpio_group(gpio_iter, dev) { + mraa_gpiod_line_info* linfo = mraa_get_line_info_by_chip_number(gpio_iter->gpio_chip, gpio_iter->gpio_lines[0]); + if (!linfo) { + syslog(LOG_ERR, "[GPIOD_INTERFACE]: error getting line info"); + return MRAA_ERROR_UNSPECIFIED; + } + flags = linfo->flags; + free(linfo); + + /* We don't need to iterate further. */ + break; + } - if (strcmp(value, "out\n") == 0) { - *dir = MRAA_GPIO_OUT; - } else if (strcmp(value, "in\n") == 0) { - *dir = MRAA_GPIO_IN; + if (flags & GPIOLINE_FLAG_KERNEL) { + syslog(LOG_ERR, "[GPIOD_INTERFACE]: cannot read gpio direction. Line used by kernel."); + return MRAA_ERROR_UNSPECIFIED; + } + + *dir = flags & GPIOLINE_FLAG_IS_OUT ? MRAA_GPIO_OUT : MRAA_GPIO_IN; } else { - syslog(LOG_ERR, "gpio%i: read_dir: unknown direction: %s", dev->pin, value); - result = MRAA_ERROR_UNSPECIFIED; + char value[5]; + char filepath[MAX_SIZE]; + int fd, rc; + + if (dev == NULL) { + syslog(LOG_ERR, "gpio: read_dir: context is invalid"); + return MRAA_ERROR_INVALID_HANDLE; + } + + if (dir == NULL) { + syslog(LOG_ERR, "gpio: read_dir: output parameter for dir is invalid"); + return MRAA_ERROR_INVALID_HANDLE; + } + + snprintf(filepath, MAX_SIZE, SYSFS_CLASS_GPIO "/gpio%d/direction", dev->pin); + fd = open(filepath, O_RDONLY); + if (fd == -1) { + syslog(LOG_ERR, "gpio%i: read_dir: Failed to open 'direction' for reading: %s", + dev->pin, strerror(errno)); + return MRAA_ERROR_INVALID_RESOURCE; + } + + memset(value, '\0', sizeof(value)); + rc = read(fd, value, sizeof(value)); + close(fd); + if (rc <= 0) { + syslog(LOG_ERR, "gpio%i: read_dir: Failed to read 'direction': %s", dev->pin, strerror(errno)); + return MRAA_ERROR_INVALID_RESOURCE; + } + + if (strcmp(value, "out\n") == 0) { + *dir = MRAA_GPIO_OUT; + } else if (strcmp(value, "in\n") == 0) { + *dir = MRAA_GPIO_IN; + } else { + syslog(LOG_ERR, "gpio%i: read_dir: unknown direction: %s", dev->pin, value); + result = MRAA_ERROR_UNSPECIFIED; + } } return result; @@ -662,14 +1284,25 @@ return -1; } - if (IS_FUNC_DEFINED(dev, gpio_read_replace)) + if (IS_FUNC_DEFINED(dev, gpio_read_replace)) { return dev->advance_func->gpio_read_replace(dev); + } + + if (plat->chardev_capable) { + int output_values[1] = { 0 }; + + if (mraa_gpio_read_multi(dev, output_values) != MRAA_SUCCESS) + return -1; + + return output_values[0]; + } - if (dev->mmap_read != NULL) + if (dev->mmap_read != NULL) { return dev->mmap_read(dev); + } if (dev->value_fp == -1) { - if (mraa_gpio_get_valfp(dev) != MRAA_SUCCESS) { + if (_mraa_gpio_get_valfp(dev) != MRAA_SUCCESS) { return -1; } } else { @@ -678,7 +1311,8 @@ } char bu[2]; if (read(dev->value_fp, bu, 2 * sizeof(char)) != 2) { - syslog(LOG_ERR, "gpio%i: read: Failed to read a sensible value from sysfs: %s", dev->pin, strerror(errno)); + syslog(LOG_ERR, "gpio%i: read: Failed to read a sensible value from sysfs: %s", + dev->pin, strerror(errno)); return -1; } lseek(dev->value_fp, 0, SEEK_SET); @@ -687,6 +1321,65 @@ } mraa_result_t +mraa_gpio_read_multi(mraa_gpio_context dev, int output_values[]) +{ + if (dev == NULL) { + syslog(LOG_ERR, "gpio: read multiple: context is invalid"); + return -1; + } + + if (plat->chardev_capable) { + memset(output_values, 0, dev->num_pins * sizeof(int)); + + mraa_gpiod_group_t gpio_iter; + + for_each_gpio_group(gpio_iter, dev) { + int status; + unsigned flags = GPIOHANDLE_REQUEST_INPUT; + + if (gpio_iter->gpiod_handle <= 0) { + gpio_iter->gpiod_handle = mraa_get_lines_handle(gpio_iter->dev_fd, gpio_iter->gpio_lines, + gpio_iter->num_gpio_lines, flags, 0); + if (gpio_iter->gpiod_handle <= 0) { + syslog(LOG_ERR, "[GPIOD_INTERFACE]: error getting gpio line handle"); + return MRAA_ERROR_INVALID_HANDLE; + } + } + + status = mraa_get_line_values(gpio_iter->gpiod_handle, gpio_iter->num_gpio_lines, + gpio_iter->rw_values); + if (status < 0) { + syslog(LOG_ERR, "[GPIOD_INTERFACE]: error writing gpio"); + return MRAA_ERROR_INVALID_RESOURCE; + } + + /* Write values back to the user provided array. */ + for (int j = 0; j < gpio_iter->num_gpio_lines; ++j) { + /* Use the internal reverse mapping table. */ + output_values[gpio_iter->gpio_group_to_pins_table[j]] = gpio_iter->rw_values[j]; + } + } + } else { + mraa_gpio_context it = dev; + int i = 0; + + while (it) { + output_values[i] = mraa_gpio_read(it); + + if (output_values[i] == -1) { + syslog(LOG_ERR, "gpio: read_multiple: failed to read multiple gpio pins"); + return MRAA_ERROR_INVALID_RESOURCE; + } + + i++; + it = it->next; + } + } + + return MRAA_SUCCESS; +} + +mraa_result_t mraa_gpio_write(mraa_gpio_context dev, int value) { if (dev == NULL) { @@ -694,9 +1387,6 @@ return MRAA_ERROR_INVALID_HANDLE; } - if (dev->mmap_write != NULL) - return dev->mmap_write(dev, value); - if (IS_FUNC_DEFINED(dev, gpio_write_pre)) { mraa_result_t pre_ret = (dev->advance_func->gpio_write_pre(dev, value)); if (pre_ret != MRAA_SUCCESS) @@ -707,15 +1397,25 @@ return dev->advance_func->gpio_write_replace(dev, value); } + if (plat->chardev_capable) { + int input_values[1] = { value }; + + return mraa_gpio_write_multi(dev, input_values); + } + + if (dev->mmap_write != NULL) { + return dev->mmap_write(dev, value); + } + if (dev->value_fp == -1) { - if (mraa_gpio_get_valfp(dev) != MRAA_SUCCESS) { + if (_mraa_gpio_get_valfp(dev) != MRAA_SUCCESS) { return MRAA_ERROR_INVALID_RESOURCE; } } if (lseek(dev->value_fp, 0, SEEK_SET) == -1) { syslog(LOG_ERR, "gpio%i: write: Failed to lseek 'value': %s", dev->pin, strerror(errno)); - return MRAA_ERROR_UNSPECIFIED; + return MRAA_ERROR_UNSPECIFIED; } char bu[MAX_SIZE]; @@ -725,8 +1425,73 @@ return MRAA_ERROR_UNSPECIFIED; } - if (IS_FUNC_DEFINED(dev, gpio_write_post)) + if (IS_FUNC_DEFINED(dev, gpio_write_post)) { return dev->advance_func->gpio_write_post(dev, value); + } + + return MRAA_SUCCESS; +} + +mraa_result_t +mraa_gpio_write_multi(mraa_gpio_context dev, int input_values[]) +{ + if (dev == NULL) { + syslog(LOG_ERR, "gpio: write: context is invalid"); + return MRAA_ERROR_INVALID_HANDLE; + } + + if (plat->chardev_capable) { + mraa_gpiod_group_t gpio_iter; + + int* counters = calloc(dev->num_chips, sizeof(int)); + if (counters == NULL) { + syslog(LOG_ERR, "mraa_gpio_write_multi() malloc error"); + return MRAA_ERROR_NO_RESOURCES; + } + + for (int i = 0; i < dev->num_pins; ++i) { + int chip_id = dev->pin_to_gpio_table[i]; + gpio_iter = &dev->gpio_group[chip_id]; + gpio_iter->rw_values[counters[chip_id]] = input_values[i]; + counters[chip_id]++; + } + free(counters); + + for_each_gpio_group(gpio_iter, dev) { + int status; + unsigned flags = GPIOHANDLE_REQUEST_OUTPUT; + + if (gpio_iter->gpiod_handle <= 0) { + gpio_iter->gpiod_handle = mraa_get_lines_handle(gpio_iter->dev_fd, gpio_iter->gpio_lines, + gpio_iter->num_gpio_lines, flags, 0); + if (gpio_iter->gpiod_handle <= 0) { + syslog(LOG_ERR, "[GPIOD_INTERFACE]: error getting gpio line handle"); + return MRAA_ERROR_INVALID_HANDLE; + } + } + + status = mraa_set_line_values(gpio_iter->gpiod_handle, gpio_iter->num_gpio_lines, + gpio_iter->rw_values); + if (status < 0) { + syslog(LOG_ERR, "[GPIOD_INTERFACE]: error writing gpio"); + return MRAA_ERROR_INVALID_RESOURCE; + } + } + } else { + mraa_gpio_context it = dev; + int i = 0; + mraa_result_t status; + + while (it) { + status = mraa_gpio_write(it, input_values[i++]); + if (status != MRAA_SUCCESS) { + syslog(LOG_ERR, "gpio: read_multiple: failed to write to multiple gpio pins"); + return status; + } + it = it->next; + } + } + return MRAA_SUCCESS; } @@ -751,6 +1516,7 @@ mraa_gpio_isr_exit(dev); return MRAA_SUCCESS; } + static mraa_result_t mraa_gpio_unexport(mraa_gpio_context dev) { @@ -762,11 +1528,12 @@ if (dev->owner) { return mraa_gpio_unexport_force(dev); } + return MRAA_ERROR_INVALID_PARAMETER; } mraa_result_t -mraa_gpio_close(mraa_gpio_context dev) +_mraa_gpio_close_internal(mraa_gpio_context dev) { mraa_result_t result = MRAA_SUCCESS; @@ -787,8 +1554,47 @@ if (dev->value_fp != -1) { close(dev->value_fp); } + mraa_gpio_unexport(dev); + free(dev); + + return result; +} + +mraa_result_t +mraa_gpio_close(mraa_gpio_context dev) +{ + mraa_result_t result = MRAA_SUCCESS; + + if (dev == NULL) { + syslog(LOG_ERR, "gpio: close: context is invalid"); + return MRAA_ERROR_INVALID_HANDLE; + } + + if (dev->events) { + free(dev->events); + } + + /* Free any ISRs */ + mraa_gpio_isr_exit(dev); + + if (plat && plat->chardev_capable) { + _mraa_free_gpio_groups(dev); + + free(dev); + } else { + mraa_gpio_context it = dev, tmp; + + while (it) { + tmp = it->next; + if (_mraa_gpio_close_internal(it) != MRAA_SUCCESS) { + result = MRAA_ERROR_UNSPECIFIED; + } + it = tmp; + } + } + return result; } @@ -799,8 +1605,10 @@ syslog(LOG_ERR, "gpio: owner: context is invalid"); return MRAA_ERROR_INVALID_HANDLE; } + syslog(LOG_DEBUG, "gpio%i: owner: Set owner to %d", dev->pin, (int) own); dev->owner = own; + return MRAA_SUCCESS; } @@ -817,6 +1625,7 @@ } syslog(LOG_ERR, "gpio%i: use_mmaped: mmap not implemented on this platform", dev->pin); + return MRAA_ERROR_FEATURE_NOT_IMPLEMENTED; } @@ -827,6 +1636,7 @@ syslog(LOG_ERR, "gpio: get_pin: context is invalid"); return -1; } + return dev->phy_pin; } @@ -837,6 +1647,7 @@ syslog(LOG_ERR, "gpio: get_pin: context is invalid"); return -1; } + return dev->pin; } @@ -893,8 +1704,7 @@ if (IS_FUNC_DEFINED(dev, gpio_out_driver_mode_replace)) { return dev->advance_func->gpio_out_driver_mode_replace(dev, mode); - } - else { + } else { return MRAA_ERROR_FEATURE_NOT_SUPPORTED; } } diff -Nru mraa-1.9.0/src/gpio/gpio_chardev.c mraa-2.0.0/src/gpio/gpio_chardev.c --- mraa-1.9.0/src/gpio/gpio_chardev.c 1970-01-01 00:00:00.000000000 +0000 +++ mraa-2.0.0/src/gpio/gpio_chardev.c 2018-09-06 12:34:41.000000000 +0000 @@ -0,0 +1,431 @@ +/* + * Author: Brendan Le Foll + * 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 "linux/gpio.h" +#include "mraa_internal.h" +#include "gpio/gpio_chardev.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SYSFS_CLASS_GPIO "/sys/class/gpio" +#define MAX_SIZE 64 +#define POLL_TIMEOUT + +#define DEV_DIR "/dev/" +#define CHIP_DEV_PREFIX "gpiochip" +#define STR_SIZE 64 + +void +_mraa_free_gpio_groups(mraa_gpio_context dev) +{ + mraa_gpiod_group_t gpio_iter; + + for_each_gpio_group(gpio_iter, dev) { + if (gpio_iter->gpio_lines) { + free(gpio_iter->gpio_lines); + } + + if (gpio_iter->rw_values) { + free(gpio_iter->rw_values); + } + + if (gpio_iter->gpio_group_to_pins_table) { + free(gpio_iter->gpio_group_to_pins_table); + } + + if (gpio_iter->gpiod_handle != -1) { + close(gpio_iter->gpiod_handle); + } + + if (gpio_iter->event_handles != NULL) { + for (int j = 0; j < gpio_iter->num_gpio_lines; ++j) { + close(gpio_iter->event_handles[j]); + } + + free(gpio_iter->event_handles); + } + + close(gpio_iter->dev_fd); + } + + if (dev->gpio_group) { + free(dev->gpio_group); + } + + /* Also delete the pin to gpio chip mapping. */ + if (dev->pin_to_gpio_table) { + free(dev->pin_to_gpio_table); + } + + /* User provided array saved internally. */ + if (dev->provided_pins) { + free(dev->provided_pins); + } + + /* Finally, delete event array. */ + if (dev->events) { + free(dev->events); + } +} + +void +_mraa_close_gpio_event_handles(mraa_gpio_context dev) +{ + mraa_gpiod_group_t gpio_iter; + + for_each_gpio_group(gpio_iter, dev) { + if (gpio_iter->event_handles != NULL) { + for (int j = 0; j < gpio_iter->num_gpio_lines; ++j) { + close(gpio_iter->event_handles[j]); + } + + free(gpio_iter->event_handles); + + /* In the end, _mraa_free_gpio_groups will be called. */ + gpio_iter->event_handles = NULL; + } + } +} + +void +_mraa_close_gpio_desc(mraa_gpio_context dev) +{ + mraa_gpiod_group_t gpio_iter; + + for_each_gpio_group(gpio_iter, dev) { + if (gpio_iter->gpiod_handle != -1) { + close(gpio_iter->gpiod_handle); + gpio_iter->gpiod_handle = -1; + } + } +} + +int +_mraa_gpiod_ioctl(int fd, unsigned long gpio_request, void* data) +{ + int status; + + status = ioctl(fd, gpio_request, data); + if (status < 0) { + syslog(LOG_ERR, "[GPIOD_INTERFACE]: ioctl() error %s", strerror(errno)); + } + + return status; +} + +int +mraa_get_lines_handle(int chip_fd, unsigned line_offsets[], unsigned num_lines, unsigned flags, unsigned default_value) +{ + int status; + struct gpiohandle_request __gpio_hreq; + + __gpio_hreq.lines = num_lines; + memcpy(__gpio_hreq.lineoffsets, line_offsets, num_lines * sizeof __gpio_hreq.lineoffsets[0]); + + if (flags & GPIOHANDLE_REQUEST_OUTPUT) { + memset(__gpio_hreq.default_values, 0, num_lines * sizeof __gpio_hreq.default_values[0]); + } + __gpio_hreq.flags = flags; + + status = _mraa_gpiod_ioctl(chip_fd, GPIO_GET_LINEHANDLE_IOCTL, &__gpio_hreq); + if (status < 0) { + syslog(LOG_ERR, "gpiod: ioctl() fail"); + return status; + } + + if (__gpio_hreq.fd <= 0) { + syslog(LOG_ERR, "[GPIOD_INTERFACE]: invalid file descriptor"); + } + + return __gpio_hreq.fd; +} + +mraa_gpiod_chip_info* +mraa_get_chip_info_by_path(const char* path) +{ + mraa_gpiod_chip_info* cinfo; + int chip_fd, status; + + if (path == NULL) { + syslog(LOG_ERR, "[GPIOD_INTERFACE]: invalid device path"); + return NULL; + } + + chip_fd = open(path, O_RDWR | O_CLOEXEC); + if (chip_fd < 0) { + syslog(LOG_ERR, "[GPIOD_INTERFACE]: could not open device file %s", path); + return NULL; + } + + cinfo = malloc(sizeof *cinfo); + if (!cinfo) { + syslog(LOG_ERR, "[GPIOD_INTERFACE]: malloc() fail"); + close(chip_fd); + return NULL; + } + cinfo->chip_fd = chip_fd; + + status = _mraa_gpiod_ioctl(cinfo->chip_fd, GPIO_GET_CHIPINFO_IOCTL, &cinfo->chip_info); + if (status < 0) { + close(cinfo->chip_fd); + free(cinfo); + return NULL; + } + + return cinfo; +} + +mraa_gpiod_chip_info* +mraa_get_chip_info_by_name(const char* name) +{ + mraa_gpiod_chip_info* cinfo; + char* full_path; + + /* TODO: check for string lengths first. */ + + full_path = malloc(STR_SIZE * sizeof *full_path); + if (!full_path) { + syslog(LOG_ERR, "[GPIOD_INTERFACE]: malloc() fail"); + return NULL; + } + + snprintf(full_path, STR_SIZE, "%s%s", DEV_DIR, name); + + cinfo = mraa_get_chip_info_by_path(full_path); + free(full_path); + + return cinfo; +} + +mraa_gpiod_chip_info* +mraa_get_chip_info_by_label(const char* label) +{ + /* TODO */ + return NULL; +} + +mraa_gpiod_chip_info* +mraa_get_chip_info_by_number(unsigned number) +{ + mraa_gpiod_chip_info* cinfo; + char* full_path; + + /* TODO: check for string lengths first. */ + + full_path = malloc(STR_SIZE * sizeof *full_path); + if (!full_path) { + syslog(LOG_ERR, "[GPIOD_INTERFACE]: malloc() fail"); + return NULL; + } + + snprintf(full_path, STR_SIZE, "%s%s%u", DEV_DIR, CHIP_DEV_PREFIX, number); + + cinfo = mraa_get_chip_info_by_path(full_path); + free(full_path); + + return cinfo; +} + +mraa_gpiod_line_info* +mraa_get_line_info_from_descriptor(int chip_fd, unsigned line_number) +{ + int status; + mraa_gpiod_line_info* linfo; + + linfo = malloc(sizeof *linfo); + + if (!linfo) { + syslog(LOG_ERR, "[GPIOD_INTERFACE]: malloc() fail"); + return NULL; + } + + linfo->line_offset = line_number; + status = _mraa_gpiod_ioctl(chip_fd, GPIO_GET_LINEINFO_IOCTL, linfo); + if (status < 0) { + free(linfo); + return NULL; + } + + return linfo; +} + +mraa_gpiod_line_info* +mraa_get_line_info_by_chip_number(unsigned chip_number, unsigned line_number) +{ + mraa_gpiod_line_info* linfo; + mraa_gpiod_chip_info* cinfo; + + cinfo = mraa_get_chip_info_by_number(chip_number); + if (!cinfo) { + syslog(LOG_ERR, "[GPIOD_INTERFACE]: invalid chip number"); + return NULL; + } + + linfo = mraa_get_line_info_from_descriptor(cinfo->chip_fd, line_number); + + close(cinfo->chip_fd); + free(cinfo); + + return linfo; +} + +mraa_gpiod_line_info* +mraa_get_line_info_by_chip_name(const char* chip_name, unsigned line_number) +{ + mraa_gpiod_line_info* linfo; + mraa_gpiod_chip_info* cinfo; + + cinfo = mraa_get_chip_info_by_name(chip_name); + if (!cinfo) { + syslog(LOG_ERR, "[GPIOD_INTERFACE]: invalid chip number"); + return NULL; + } + + linfo = mraa_get_line_info_from_descriptor(cinfo->chip_fd, line_number); + + close(cinfo->chip_fd); + free(cinfo); + + return linfo; +} + +mraa_gpiod_line_info* +mraa_get_line_info_by_chip_label(const char* chip_label, unsigned line_number) +{ + mraa_gpiod_line_info* linfo; + mraa_gpiod_chip_info* cinfo; + + cinfo = mraa_get_chip_info_by_label(chip_label); + if (!cinfo) { + syslog(LOG_ERR, "[GPIOD_INTERFACE]: invalid chip number"); + return NULL; + } + + linfo = mraa_get_line_info_from_descriptor(cinfo->chip_fd, line_number); + + close(cinfo->chip_fd); + free(cinfo); + + return linfo; +} + +int +mraa_set_line_values(int line_handle, unsigned int num_lines, unsigned char input_values[]) +{ + int status; + struct gpiohandle_data __hdata; + + memcpy(__hdata.values, input_values, num_lines * sizeof(unsigned char)); + + status = _mraa_gpiod_ioctl(line_handle, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &__hdata); + if (status < 0) { + syslog(LOG_ERR, "[GPIOD_INTERFACE]: ioctl() fail"); + } + + return status; +} + +int +mraa_get_line_values(int line_handle, unsigned int num_lines, unsigned char output_values[]) +{ + int status; + struct gpiohandle_data __hdata; + + status = _mraa_gpiod_ioctl(line_handle, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &__hdata); + if (status < 0) { + syslog(LOG_ERR, "[GPIOD_INTERFACE]: ioctl() fail"); + return status; + } + + memcpy(output_values, __hdata.values, num_lines * sizeof(unsigned char)); + + return status; +} + + +mraa_boolean_t +mraa_is_gpio_line_kernel_owned(mraa_gpiod_line_info *linfo) +{ + return (linfo->flags & GPIOLINE_FLAG_KERNEL); +} + +mraa_boolean_t +mraa_is_gpio_line_dir_out(mraa_gpiod_line_info *linfo) +{ + return (linfo->flags & GPIOLINE_FLAG_IS_OUT); +} + +mraa_boolean_t +mraa_is_gpio_line_active_low(mraa_gpiod_line_info *linfo) +{ + return (linfo->flags & GPIOLINE_FLAG_ACTIVE_LOW); +} + +mraa_boolean_t +mraa_is_gpio_line_open_drain(mraa_gpiod_line_info *linfo) +{ + return (linfo->flags & GPIOLINE_FLAG_OPEN_DRAIN); +} + +mraa_boolean_t +mraa_is_gpio_line_open_source(mraa_gpiod_line_info *linfo) +{ + return (linfo->flags & GPIOLINE_FLAG_OPEN_SOURCE); +} + +int +mraa_get_number_of_gpio_chips() +{ + int num_chips = 0; + DIR* dev_dir; + struct dirent* dir; + const unsigned int len = strlen(CHIP_DEV_PREFIX); + + dev_dir = opendir(DEV_DIR); + if (dev_dir) { + while ((dir = readdir(dev_dir)) != NULL) { + if (!strncmp(dir->d_name, CHIP_DEV_PREFIX, len)) { + num_chips++; + } + } + closedir(dev_dir); + } else { + syslog(LOG_ERR, "[GPIOD_INTERFACE]: opendir() error"); + return -1; + } + + /* Assume opendir() error. */ + return num_chips; +} diff -Nru mraa-1.9.0/src/initio/initio.c mraa-2.0.0/src/initio/initio.c --- mraa-1.9.0/src/initio/initio.c 1970-01-01 00:00:00.000000000 +0000 +++ mraa-2.0.0/src/initio/initio.c 2018-09-06 12:34:41.000000000 +0000 @@ -0,0 +1,890 @@ +/* + * 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) +{ + char* lendptr; + long val = strtol(intStr, &lendptr, base); + + /* Test for no-conversion */ + if (intStr == lendptr) { + return MRAA_ERROR_UNSPECIFIED; + } + + /* Test for overflow/underflow for a long int */ + if (errno == ERANGE || val > INT_MAX || val < INT_MIN) { + *value = 0; + return MRAA_ERROR_UNSPECIFIED; + } + + if (str_end) { + *str_end = lendptr; + } + + *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, const char* proto_full) +{ + if (!proto || (n <= 1) || (!proto_full)) { + 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' from '%s'", bus, proto_full); + } + } else { + syslog(LOG_ERR, "parse_uart_ow: invalid uart_ow bus number '%s' from '%s'", proto[1], proto_full); + } + + return dev; +} + +static mraa_uart_context +parse_uart(char** proto, size_t n, const char* proto_full) +{ + if (!proto || (n <= 1) || (!proto_full)) { + 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' from '%s'", uart, proto_full); + return NULL; + } else { + if (++idx == n) { + return dev; + } + } + } else { + syslog(LOG_ERR, "parse_uart: invalid uart index '%s' from '%s'", proto[idx], proto_full); + return NULL; + } + + /* Check for baudrate. */ + unsigned int baudrate = -1; + if (proto[idx] && (mraa_atoi_x(proto[idx], NULL, (int*) &baudrate, 0) == MRAA_SUCCESS)) { + if (mraa_uart_set_baudrate(dev, baudrate) != MRAA_SUCCESS) { + syslog(LOG_ERR, "parse_uart: could not set uart baudrate '%d' from '%s'", baudrate, proto_full); + mraa_uart_stop(dev); + return NULL; + } else { + if (++idx == n) { + return dev; + } + } + } else { + syslog(LOG_ERR, "parse_uart: invalid uart baudrate '%s' from '%s'", proto[idx], proto_full); + } + + /* Check for mode - [int] bytesize, [mraa_uart_parity_t] parity, [int] stopbits. */ + char* end = NULL; + + /* 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' from '%s'", bytesize, proto_full); + 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 '%s' from '%s'", end, proto_full); + 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' from '%s'", bytesize, proto_full); + 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 '%s' from '%s'", proto[idx], proto_full); + mraa_uart_stop(dev); + return NULL; + } + + return dev; +} + +static mraa_spi_context +parse_spi(char** proto, size_t n, const char* proto_full) +{ + if (!proto || (n <= 1) || (!proto_full)) { + 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' from '%s'", bus, proto_full); + return NULL; + } else { + if (++idx == n) { + return dev; + } + } + } else { + syslog(LOG_ERR, "parse_spi: invalid spi bus number '%s' from '%s'", proto[idx], proto_full); + 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' from '%s'", proto[idx], proto_full); + 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' from '%s'", frequency, proto_full); + mraa_spi_stop(dev); + return NULL; + } + } else { + syslog(LOG_ERR, "parse_spi: invalid spi frequency '%s' from '%s'", proto[idx], proto_full); + } + + return dev; +} + +static mraa_pwm_context +parse_pwm(char** proto, size_t n, const char* proto_full) +{ + if (!proto || (n <= 1) || (!proto_full)) { + 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; +} + +#if !defined(PERIPHERALMAN) +static mraa_iio_context +parse_iio(char** proto, size_t n, const char* proto_full) +{ + if (!proto || (n <= 1) || (!proto_full)) { + 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' from '%s'", device, proto_full); + } + } else { + syslog(LOG_ERR, "parse_iio: invalid iio device number '%s' from '%s'", proto[1], proto_full); + } + + return dev; +} +#endif + +static mraa_i2c_context +parse_i2c(char** proto, size_t n, const char* proto_full) +{ + if (!proto || (n <= 1) || (!proto_full)) { + 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' from '%s'", bus, proto_full); + return NULL; + } else { + if (++idx == n) + return dev; + } + } else { + syslog(LOG_ERR, "parse_i2c: invalid i2c bus number '%s' from '%s'", proto[idx], proto_full); + 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 '0x%02x' from '%s'", address, proto_full); + 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' from '%s'", proto[idx], proto_full); + mraa_i2c_stop(dev); + return NULL; + } + } + + return dev; +} + +static mraa_aio_context +parse_aio(char** proto, size_t n, const char* proto_full) +{ + if (!proto || (n <= 1) || (!proto_full)) { + 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' from '%s'", aio_num, proto_full); + return NULL; + } else { + if (++idx == n) { + return dev; + } + } + } else { + syslog(LOG_ERR, "parse_aio: failed to parse '%s' as integer from '%s'", proto[idx], proto_full); + 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 bits '%d' from '%s'", num_bits, proto_full); + mraa_aio_close(dev); + return NULL; + } + } else { + syslog(LOG_ERR, "parse_aio: invalid aio bit number '%s' from '%s'", proto[idx], proto_full); + mraa_aio_close(dev); + return NULL; + } + + return dev; +} + +static mraa_gpio_context +parse_gpio(char** proto, size_t n, const char* proto_full) +{ + if (!proto || (n <= 1) || (!proto_full)) { + 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' from '%s'", gpio_num, proto_full); + return NULL; + } + } else { + syslog(LOG_ERR, "parse_gpio: invalid gpio number '%s' from '%s'", proto[idx], proto_full); + 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' from '%s'", proto[idx], proto_full); + 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' from '%s'", G_DIR_OUT, proto_full); + 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' from '%s'", + gpio_num, value, proto_full); + 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' from '%s'", proto[idx], proto_full); + 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' from '%s'", proto[idx], proto_full); + 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' from '%s'", proto[idx], proto_full); + 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' from '%s'", proto[idx], proto_full); + 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, str_descs[i]); + if (!dev) { + syslog(LOG_ERR, "mraa_io_init: error parsing aio init string '%s'", str_descs[i]); + status = MRAA_ERROR_INVALID_HANDLE; + free(new_desc); + } + + 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; + free(new_desc); + } 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, str_descs[i]); + if (!dev) { + syslog(LOG_ERR, "mraa_io_init: error parsing gpio init string '%s'", str_descs[i]); + status = MRAA_ERROR_INVALID_HANDLE; + free(new_desc); + } + + 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; + free(new_desc); + } else { + new_desc->gpios[new_desc->n_gpio++] = dev; + } + } + } +#if !defined(PERIPHERALMAN) + 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, str_descs[i]); + if (!dev) { + syslog(LOG_ERR, "mraa_io_init: error parsing iio init string '%s'", str_descs[i]); + status = MRAA_ERROR_INVALID_HANDLE; + free(new_desc); + } + + 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; + free(new_desc); + } else { + new_desc->iios[new_desc->n_iio++] = dev; + } + } + } +#endif + 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, str_descs[i]); + if (!dev) { + syslog(LOG_ERR, "mraa_io_init: error parsing i2c init string '%s'", str_descs[i]); + status = MRAA_ERROR_INVALID_HANDLE; + free(new_desc); + } + + 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; + free(new_desc); + } 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, str_descs[i]); + if (!dev) { + syslog(LOG_ERR, "mraa_io_init: error parsing pwm init string '%s'", str_descs[i]); + 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; + free(new_desc); + } 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, str_descs[i]); + if (!dev) { + syslog(LOG_ERR, "mraa_io_init: error parsing spi init string '%s'", str_descs[i]); + status = MRAA_ERROR_INVALID_HANDLE; + free(new_desc); + } + + 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; + free(new_desc); + } 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, str_descs[i]); + if (!dev) { + syslog(LOG_ERR, "mraa_io_init: error parsing uart init string '%s'", str_descs[i]); + status = MRAA_ERROR_INVALID_HANDLE; + free(new_desc); + } + + 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; + free(new_desc); + } 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, str_descs[i]); + if (!dev) { + syslog(LOG_ERR, "mraa_io_init: error parsing uart_ow init string '%s'", str_descs[i]); + status = MRAA_ERROR_INVALID_HANDLE; + free(new_desc); + } + + 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; + free(new_desc); + } 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; + free(new_desc); + } 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 ((status == MRAA_SUCCESS) && (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); + } + +#if !defined(PERIPHERALMAN) + for (int i = 0; i < desc->n_iio; ++i) { + mraa_iio_close(desc->iios[i]); + } + if (desc->n_iio) { + free(desc->iios); + } +#endif + + 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 -Nru mraa-1.9.0/src/led/led.c mraa-2.0.0/src/led/led.c --- mraa-1.9.0/src/led/led.c 2018-02-15 23:08:49.000000000 +0000 +++ mraa-2.0.0/src/led/led.c 2018-09-06 12:34:41.000000000 +0000 @@ -127,7 +127,48 @@ } mraa_led_context -mraa_led_init(const char* led) +mraa_led_init(int index) +{ + mraa_led_context dev = NULL; + char directory[MAX_SIZE]; + struct stat dir; + + if (plat == NULL) { + syslog(LOG_ERR, "led: init: platform not initialised"); + return NULL; + } + + if (plat->led_dev_count == 0) { + syslog(LOG_ERR, "led: init: no led device defined in platform"); + return NULL; + } + + if (index < 0) { + syslog(LOG_ERR, "led: init: led index cannot be negative"); + return NULL; + } + + if (index >= plat->led_dev_count) { + syslog(LOG_ERR, "led: init: requested led above led device count"); + return NULL; + } + + dev = mraa_led_init_internal((char*) plat->led_dev[index].name); + if (dev == NULL) { + return NULL; + } + + snprintf(directory, MAX_SIZE, "%s/%s", SYSFS_CLASS_LED, dev->led_name); + if (stat(directory, &dir) == 0 && S_ISDIR(dir.st_mode)) { + syslog(LOG_NOTICE, "led: init: current user doesn't have access rights for using LED %s", dev->led_name); + } + strncpy(dev->led_path, (const char*) directory, sizeof(directory)); + + return dev; +} + +mraa_led_context +mraa_led_init_raw(const char* led) { mraa_led_context dev = NULL; char directory[MAX_SIZE]; diff -Nru mraa-1.9.0/src/mraa.c mraa-2.0.0/src/mraa.c --- mraa-1.9.0/src/mraa.c 2018-02-15 23:08:49.000000000 +0000 +++ mraa-2.0.0/src/mraa.c 2018-09-06 12:34:41.000000000 +0000 @@ -29,6 +29,7 @@ #endif #include +#include #include #include #include @@ -45,7 +46,7 @@ #include #include #include - +#include #if defined(IMRAA) #include @@ -57,6 +58,7 @@ #include "firmata/firmata_mraa.h" #include "grovepi/grovepi.h" #include "gpio.h" +#include "gpio/gpio_chardev.h" #include "version.h" #include "i2c.h" #include "pwm.h" @@ -98,6 +100,26 @@ return MRAA_ERROR_INVALID_PARAMETER; } +mraa_boolean_t mraa_is_kernel_chardev_interface_compatible() +{ + if (mraa_get_number_of_gpio_chips() <= 0) { + syslog(LOG_NOTICE, "gpio: platform supports chardev but kernel doesn't, falling back to sysfs"); + return 0; + } + + return 1; +} + +mraa_boolean_t mraa_is_platform_chardev_interface_capable() +{ + if (plat->chardev_capable) { + return mraa_is_kernel_chardev_interface_compatible(); + } + + syslog(LOG_NOTICE, "gpio: platform doesn't support chardev, falling back to sysfs"); + return 0; +} + /** * Whilst the actual mraa init function is now called imraa_init, it's only * callable externally if IMRAA is enabled @@ -174,18 +196,21 @@ } #if defined(USBPLAT) - // Now detect sub platform, note this is not an else since we could be in - // an error case and fall through to MRAA_ERROR_PLATFORM_NOT_INITIALISED - if (plat != NULL) { - mraa_platform_t usb_platform_type = mraa_usb_platform_extender(plat); - // if we have no known platform just replace usb platform with platform - if (plat->platform_type == MRAA_UNKNOWN_PLATFORM && usb_platform_type != MRAA_UNKNOWN_PLATFORM) { - plat->platform_type = usb_platform_type; - } - } - if (plat == NULL) { - printf("mraa: FATAL error, failed to initialise platform\n"); - return MRAA_ERROR_PLATFORM_NOT_INITIALISED; + syslog(LOG_NOTICE, "Searching for USB plaform extender libraries..."); + /* If a usb platform lib is present, attempt to load and look for + * necessary symbols for adding extended I/O */ + void* usblib = dlopen("libmraa-platform-ft4222.so", RTLD_LAZY); + if (usblib) + { + syslog(LOG_NOTICE, "Found USB platform extender library: libmraa-platform-ft4222.so"); + syslog(LOG_NOTICE, "Detecting FT4222 subplatforms..."); + fptr_add_platform_extender add_ft4222_platform = + (fptr_add_platform_extender)dlsym(usblib, "mraa_usb_platform_extender"); + + /* If this method exists, call it to add a subplatform */ + syslog(LOG_NOTICE, "Detecting FT4222 subplatforms complete, found %i subplatform/s", + ((add_ft4222_platform != NULL) && (add_ft4222_platform(plat) == MRAA_SUCCESS)) + ? 1 : 0); } #endif @@ -218,6 +243,11 @@ return MRAA_ERROR_NO_RESOURCES; } + plat->chardev_capable = mraa_is_platform_chardev_interface_capable(); + if (plat->chardev_capable) { + syslog(LOG_NOTICE, "gpio: support for chardev interface is activated"); + } + syslog(LOG_NOTICE, "libmraa initialised for platform '%s' of type %d", mraa_get_platform_name(), mraa_get_platform_type()); return MRAA_SUCCESS; } @@ -247,7 +277,8 @@ free(plat->adv_func); } mraa_board_t* sub_plat = plat->sub_platform; - if (sub_plat != NULL) { + /* No alloc's in an FTDI_FT4222 platform structure */ + if ((sub_plat != NULL) && (sub_plat->platform_type != MRAA_FTDI_FT4222)) { if (sub_plat->pins != NULL) { free(sub_plat->pins); } @@ -256,21 +287,27 @@ } free(sub_plat); } -#if defined(JSONPLAT) if (plat->platform_type == MRAA_JSON_PLATFORM) { // Free the platform name free(plat->platform_name); plat->platform_name = NULL; + } - int i = 0; - // Free the UART device path + int i = 0; + /* Free the UART device path. Note, some platforms dynamically + * allocate space for device_path, others use #defines or consts, + * which means this has to be handled differently per platform + */ + if ((plat->platform_type == MRAA_JSON_PLATFORM) || + (plat->platform_type == MRAA_UP2) || + (plat->platform_type == MRAA_IEI_TANK)) { for (i = 0; i < plat->uart_dev_count; i++) { if (plat->uart_dev[i].device_path != NULL) { free(plat->uart_dev[i].device_path); } } } -#endif + free(plat); plat = NULL; @@ -754,7 +791,7 @@ } int -mraa_get_uart_count(void) +mraa_get_uart_count() { if (plat == NULL) { return -1; @@ -763,7 +800,7 @@ } int -mraa_get_spi_count(void) +mraa_get_spi_bus_count() { if (plat == NULL) { return -1; @@ -772,7 +809,7 @@ } int -mraa_get_pwm_count(void) +mraa_get_pwm_count() { if (plat == NULL) { return -1; @@ -781,7 +818,7 @@ } int -mraa_get_gpio_count(void) +mraa_get_gpio_count() { if (plat == NULL) { return -1; @@ -790,7 +827,7 @@ } int -mraa_get_aio_count(void) +mraa_get_aio_count() { if (plat == NULL) { return -1; @@ -880,7 +917,11 @@ return -1; } - for (i = 0; i < plat->gpio_count; i++) { + for (i = 0; i < plat->phy_pin_count; i++) { + // Skip non GPIO pins + if (!(plat->pins[i].capabilities.gpio)) + continue; + if (plat->pins[i].name != NULL && strncmp(pin_name, plat->pins[i].name, strlen(plat->pins[i].name) + 1) == 0) { return i; @@ -1109,6 +1150,34 @@ } } +mraa_result_t +mraa_find_uart_bus_pci(const char* pci_dev_path, char** dev_name) +{ + char path[PATH_MAX]; + const int max_allowable_len = 16; + snprintf(path, PATH_MAX - 1, "%s", pci_dev_path); + if (!mraa_file_exist(path)) { + return MRAA_ERROR_INVALID_PARAMETER; + } + + struct dirent** namelist; + int n = scandir(path, &namelist, NULL, alphasort); + if (n <= 0) { + syslog(LOG_ERR, "Failed to find expected UART bus: %s", strerror(errno)); + return MRAA_ERROR_INVALID_RESOURCE; + } + + *dev_name = (char*) malloc(sizeof(char) * max_allowable_len); + + snprintf(*dev_name, max_allowable_len, "/dev/%s", namelist[n - 1]->d_name); + while (n--) { + free(namelist[n]); + } + free(namelist); + syslog(LOG_INFO, "UART device: %s selected for initialization", *dev_name); + return MRAA_SUCCESS; +} + static int mraa_count_i2c_files(const char* path, const struct stat* sb, int flag, struct FTW* ftwb) { diff -Nru mraa-1.9.0/src/spi/spi.c mraa-2.0.0/src/spi/spi.c --- mraa-1.9.0/src/spi/spi.c 2018-02-15 23:08:49.000000000 +0000 +++ mraa-2.0.0/src/spi/spi.c 2018-09-06 12:34:41.000000000 +0000 @@ -256,9 +256,12 @@ int speed = 0; dev->clock = hz; if (ioctl(dev->devfd, SPI_IOC_RD_MAX_SPEED_HZ, &speed) != -1) { - if (speed < hz) { - dev->clock = speed; - syslog(LOG_WARNING, "spi: Selected speed reduced to max allowed speed"); + if (speed < hz) { + // We wanted to never go higher than SPI_IOC_RD_MAX_SPEED_HZ but it + // seems a bunch of drivers don't have this set to the actual max + // so we only complain about it + // dev->clock = speed; + syslog(LOG_NOTICE, "spi: Selected speed (%d Hz) is higher than the kernel max allowed speed (%lu Hz)", hz, SPI_IOC_RD_MAX_SPEED_HZ); } } return MRAA_SUCCESS; diff -Nru mraa-1.9.0/src/usb/CMakeLists.txt mraa-2.0.0/src/usb/CMakeLists.txt --- mraa-1.9.0/src/usb/CMakeLists.txt 2018-02-15 23:08:49.000000000 +0000 +++ mraa-2.0.0/src/usb/CMakeLists.txt 2018-09-06 12:34:41.000000000 +0000 @@ -1,12 +1 @@ -set (mraa_LIB_USB_SRCS_NOAUTO ${PROJECT_SOURCE_DIR}/src/usb/usb.c) - -if (FTDI4222) - message (INFO " - FTDI4222") - set (mraa_LIB_USB_SRCS_NOAUTO ${mraa_LIB_USB_SRCS_NOAUTO} - ${PROJECT_SOURCE_DIR}/src/usb/ftdi_ft4222.c - ) -endif () - -set (mraa_LIB_PLAT_SRCS_NOAUTO ${mraa_LIB_PLAT_SRCS_NOAUTO} - ${mraa_LIB_USB_SRCS_NOAUTO} PARENT_SCOPE) - +add_subdirectory(ft4222) diff -Nru mraa-1.9.0/src/usb/ft4222/CMakeLists.txt mraa-2.0.0/src/usb/ft4222/CMakeLists.txt --- mraa-1.9.0/src/usb/ft4222/CMakeLists.txt 1970-01-01 00:00:00.000000000 +0000 +++ mraa-2.0.0/src/usb/ft4222/CMakeLists.txt 2018-09-06 12:34:41.000000000 +0000 @@ -0,0 +1,19 @@ +if (FTDI4222) + set(target_name mraa-platform-ft4222) + add_library(${target_name} SHARED ftdi_ft4222.cxx ftdi_ft4222.hpp) + target_link_libraries(${target_name} ${LIBFT4222_LIBRARIES}) + install(TARGETS ${target_name} DESTINATION ${LIB_INSTALL_DIR}) + + set_target_properties( + ${target_name} + PROPERTIES + SOVERSION ${mraa_VERSION_MAJOR} + VERSION ${mraa_VERSION_STRING} + ) + if (MSYS) + # Under MSYS we have to put our generated DLL into bin, otherwise it's not picked up + install(TARGETS ${target_name} DESTINATION ${CMAKE_INSTALL_BINDIR}) + else () + install(TARGETS ${target_name} DESTINATION ${LIB_INSTALL_DIR}) + endif () +endif() diff -Nru mraa-1.9.0/src/usb/ft4222/ftdi_ft4222.cxx mraa-2.0.0/src/usb/ft4222/ftdi_ft4222.cxx --- mraa-1.9.0/src/usb/ft4222/ftdi_ft4222.cxx 1970-01-01 00:00:00.000000000 +0000 +++ mraa-2.0.0/src/usb/ft4222/ftdi_ft4222.cxx 2018-09-06 12:34:41.000000000 +0000 @@ -0,0 +1,1451 @@ +/* + * Author: Henry Bruce + * Copyright (c) 2015 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 "ftdi_ft4222.hpp" +#include "ftd2xx.h" +#include "libft4222.h" +#include "linux/i2c-dev.h" +#include "types.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace ft4222 +{ +#define gpioPinsPerFt4222 4 + +/* These devices have configurable addresses which leave it up to makers of + * development expander boards to either set these addresses or provide a means + * to set them (jumpers or solder). The dev boards for both the PCA9555 and + * PCA9672 have a slave address of 010 0xxx (where xxx is configurable). + */ +#define PCA9672_ADDR 0x20 +#define PCA9555_ADDR 0x27 +#define PCA9555_INPUT_REG 0 +#define PCA9555_OUTPUT_REG 2 +#define PCA9555_POLARITY_REG 4 +#define PCA9555_DIRECTION_REG 6 +#define PCA9545_ADDR 0x70 +#define PCA9672_PINS 8 +#define PCA9555_PINS 16 +#define PCA9545_BUSSES 4 +#define GPIO_PORT_IO_RESET GPIO_PORT2 +#define GPIO_PORT_IO_INT GPIO_PORT3 +#define MAX_IO_EXPANDER_PINS PCA9555_PINS + +/* GPIO expander types */ +typedef enum { IO_EXP_NONE, IO_EXP_PCA9672, IO_EXP_PCA9555 } ft4222_io_exp_type; + +/* GPIO types */ +typedef enum { + GPIO_TYPE_BUILTIN, + GPIO_TYPE_PCA9672, + GPIO_TYPE_PCA9555, + GPIO_TYPE_UNKNOWN = 99 +} ft4222_gpio_type; + +/* GPIO expander interrupt monitor */ +struct gpio_expander_intmon { + pthread_t thread; + pthread_mutex_t mutex; + mraa_boolean_t should_stop; + mraa_boolean_t is_interrupt_detected[MAX_IO_EXPANDER_PINS]; + int num_active_pins; +}; + +/* At present, no c++11 in mraa, so create a lock guard */ +class lock_guard +{ + public: + lock_guard(pthread_mutex_t& mtx) : _mtx(mtx) + { + if (pthread_mutex_lock(&_mtx)) + syslog(LOG_ERR, "FT4222 error creating lock on mutex"); + } + virtual ~lock_guard() + { + if (pthread_mutex_unlock(&_mtx)) + syslog(LOG_ERR, "FT4222 error creating lock on mutex"); + } + + private: + pthread_mutex_t& _mtx; +}; + +/* Each FT4222 device is represented by 1 Ftdi_4222_Shim instance */ +class Ftdi_4222_Shim +{ + public: + Ftdi_4222_Shim(); + + virtual ~Ftdi_4222_Shim(); + + static mraa_board_t* init_and_setup_mraa_board(); + + bool init_next_free_ftdi4222_device(); + bool setup_io(); + bool init_ftdi_gpios(); + int ft4222_detect_i2c_switch(); + + uint32_t ftdi_device_id; + uint8_t pca9672DirectionMask; + union { + uint16_t word; + uint8_t bytes[2]; + } pca9555OutputValue; + union { + uint16_t word; + uint8_t bytes[2]; + } pca9555DirectionValue; + + gpio_expander_intmon gpio_mon; + std::vector pinDirection; + + FT_HANDLE h_gpio; + FT_HANDLE h_i2c; + FT_HANDLE h_spi; + mraa_i2c_mode_t mraa_i2c_mode; + uint32_t ft4222_i2c_speed(); + pthread_mutex_t mtx_ft4222; + int cur_i2c_bus; + ft4222_io_exp_type exp_type; + + private: + /** + * Function detects known I2C I/O expanders and returns the number of GPIO pins + * on expander + */ + int _detect_io_expander(); + + /* Collection to store the board info for 1 FT4222 device */ + mraa_board_t _board; + /* Collection to store pin info for 1 FT4222 device */ + std::vector _pins; + /* Struct to store the function table info for 1 FT4222 device */ + mraa_adv_func_t _adv_func_table; +}; + +Ftdi_4222_Shim::Ftdi_4222_Shim() +: ftdi_device_id(0), pca9672DirectionMask(0), gpio_mon(), pinDirection(4, GPIO_INPUT), h_gpio(NULL), + h_i2c(NULL), h_spi(NULL), mraa_i2c_mode(MRAA_I2C_FAST), cur_i2c_bus(0), exp_type(IO_EXP_NONE), + _board(), _adv_func_table() +{ + pca9555OutputValue.word = 0; + pca9555DirectionValue.word = 0; + + /* Initialize mutexes */ + pthread_mutexattr_t attr_rec; + pthread_mutexattr_init(&attr_rec); + pthread_mutexattr_settype(&attr_rec, PTHREAD_MUTEX_RECURSIVE); + if (pthread_mutex_init(&mtx_ft4222, &attr_rec) != 0) { + syslog(LOG_ERR, "Failed to setup FT HW device mutex for FT4222 access"); + throw std::runtime_error("Failed to setup FT HW device mutex for FT4222 access"); + } +} + +Ftdi_4222_Shim::~Ftdi_4222_Shim() +{ + if (ftdi_device_id) + syslog(LOG_NOTICE, "Closing FTDI FT4222 device id: 0x%08x", ftdi_device_id); + + if (h_gpio) + FT4222_UnInitialize(h_gpio); + if (h_i2c) + FT4222_UnInitialize(h_i2c); + if (h_spi) + FT4222_UnInitialize(h_spi); + + if (h_gpio) + FT_Close(h_gpio); + if (h_i2c) + FT_Close(h_i2c); + if (h_spi) + FT_Close(h_spi); +} + +/* Global collections for handling multiple shims */ +std::vector _ftdi_shims; +/* Provide a map of i2c bus index to shim pointer */ +std::map _i2c_bus_to_shim; +/* Provide a map of gpio bus index to shim pointer */ +std::map _gpio_pin_to_shim; + +uint32_t +Ftdi_4222_Shim::ft4222_i2c_speed() +{ + static std::map mode2kHz; + mode2kHz[MRAA_I2C_STD] = 100; + mode2kHz[MRAA_I2C_FAST] = 400; + mode2kHz[MRAA_I2C_HIGH] = 3400; + return mode2kHz[mraa_i2c_mode]; +} + +Ftdi_4222_Shim* +ShimFromI2cBus(int bus) +{ + std::map::iterator it = _i2c_bus_to_shim.find(bus); + if (it == _i2c_bus_to_shim.end()) { + std::ostringstream oss; + oss << "{"; + for (std::map::const_iterator it = _i2c_bus_to_shim.begin(); + it != _i2c_bus_to_shim.end();) { + oss << it->first; + if (++it != _i2c_bus_to_shim.end()) + oss << ", "; + } + oss << "}"; + syslog(LOG_ERR, "Ftdi_4222_Shim lookup failed for I2C bus: %d, valid busses are: %s", bus, + oss.str().c_str()); + return NULL; + } + + return it->second; +} + +Ftdi_4222_Shim* +ShimFromGpioPin(int pin) +{ + std::map::iterator it = _gpio_pin_to_shim.find(pin); + if (it == _gpio_pin_to_shim.end()) { + std::ostringstream oss; + oss << "{"; + for (std::map::const_iterator it = _gpio_pin_to_shim.begin(); + it != _gpio_pin_to_shim.end();) { + oss << it->first; + if (++it != _gpio_pin_to_shim.end()) + oss << ", "; + } + oss << "}"; + syslog(LOG_ERR, "Ftdi_4222_Shim lookup failed for pin: %d, valid pins are: %s", pin, + oss.str().c_str()); + return NULL; + } + + return it->second; +} + +mraa_board_t* +Ftdi_4222_Shim::init_and_setup_mraa_board() +{ + /* The Ftdi_4222_Shim constructor can throw */ + try { + /* Add a shim object to the collection */ + _ftdi_shims.push_back(Ftdi_4222_Shim()); + } catch (...) { + syslog(LOG_ERR, "Failed to create an Ftdi_4222_Shim instance..."); + return NULL; + } + + /* Attempt to initialize an FTDI4222 device and setup I/O for use by mraa */ + if (_ftdi_shims.back().init_next_free_ftdi4222_device() && _ftdi_shims.back().setup_io()) { + return &_ftdi_shims.back()._board; + } else { + _ftdi_shims.pop_back(); + return NULL; + } +} + + +void +ft4222_sleep_ms(unsigned long mseconds) +{ + struct timespec sleepTime = {}; + // Number of seconds + sleepTime.tv_sec = mseconds / 1000; + // Convert fractional seconds to nanoseconds + sleepTime.tv_nsec = (mseconds % 1000) * 1000000; + // Iterate nanosleep in a loop until the total sleep time is the original + // value of the seconds parameter + while ((nanosleep(&sleepTime, &sleepTime) != 0) && (errno == EINTR)) + ; +} + + +bool +Ftdi_4222_Shim::init_next_free_ftdi4222_device() +{ + DWORD numDevs = 0; + + if (FT_CreateDeviceInfoList(&numDevs) != FT_OK) { + syslog(LOG_ERR, "FT_CreateDeviceInfoList failed"); + return false; + } + syslog(LOG_NOTICE, "FT_GetDeviceInfoList returned %d devices", numDevs); + + FT_DEVICE_LIST_INFO_NODE devInfo[numDevs]; + if (FT_GetDeviceInfoList(&devInfo[0], &numDevs) != FT_OK) { + syslog(LOG_ERR, "FT_GetDeviceInfoList failed"); + return false; + } + + int first_4222_ndx = -1; + int ftdi_mode = -1; + /* Look for FT_DEVICE_4222H_0 devices. Print out all devices found. */ + for (DWORD i = 0; i < numDevs; i++) { + /* Log info for debugging */ + syslog(LOG_NOTICE, " FTDI ndx: %02d id: 0x%08x %s description: '%s'", i, devInfo[i].ID, + (devInfo[i].Flags & 0x2) ? "High-speed USB" : "Full-speed USB", &devInfo[i].Description[0]); + + /* If this FTDI device ID is already assigned to an Ftdi_4222_Shim, + * then log and skip */ + for (std::vector::const_iterator it = _ftdi_shims.begin(); + (it != _ftdi_shims.end()) && ((*it).ftdi_device_id != 0); ++it) { + if ((*it).ftdi_device_id == devInfo[i].ID) { + syslog(LOG_NOTICE, " FTDI ndx: %02d id: 0x%08x already initialized, skipping...", + i, devInfo[i].ID); + continue; + } + } + + /* FTDI_4222 mode 3 provides 2 devices */ + if ((first_4222_ndx == -1) && (devInfo[i].Type == FT_DEVICE_4222H_0) && + ((i + 1 < numDevs) && (devInfo[i].ID == devInfo[i + 1].ID))) { + first_4222_ndx = i; + ftdi_mode = 3; + } + /* FTDI_4222 mode 0 provides 1 device */ + else if ((first_4222_ndx == -1) && (devInfo[i].Type == FT_DEVICE_4222H_0)) { + first_4222_ndx = i; + ftdi_mode = 0; + } + } + + /* Was a usable 4222 found? */ + if (first_4222_ndx == -1) { + syslog(LOG_ERR, "No FT4222 (mode 0 or 3) devices found."); + return false; + } + + syslog(LOG_NOTICE, "FTDI 4222 device found at ndx: %02d, mode %d (%s)", first_4222_ndx, ftdi_mode, + ftdi_mode == 0 ? "SPI/I2C" : ftdi_mode == 3 ? "SPI/I2C and GPIO" : "Unknown mode"); + + /* Both modes provide a SPI/I2C at the first ndx */ + syslog(LOG_NOTICE, "FTDI ndx: %02d initializing as SPI/I2C", first_4222_ndx); + + /* Setup I2c */ + if (devInfo[first_4222_ndx].LocId == 0) { + syslog(LOG_ERR, "No I2C controller for FTDI_4222 device"); + return false; + } + + if (FT_OpenEx(reinterpret_cast(devInfo[first_4222_ndx].LocId), FT_OPEN_BY_LOCATION, &h_i2c) != FT_OK) { + syslog(LOG_NOTICE, "FTDI ndx: %02d initializing as SPI/I2C device - FAILED to open", first_4222_ndx + 1); + return false; + } + + // Tell the FT4222 to be an I2C Master by default on init. + if (FT4222_I2CMaster_Init(h_i2c, ft4222_i2c_speed()) != FT4222_OK) { + syslog(LOG_NOTICE, "FTDI ndx: %02d initializing as SPI/I2C device - FAILED to " + "initialize", + first_4222_ndx + 1); + return false; + } + + if (FT4222_I2CMaster_Reset(h_i2c) != FT4222_OK) { + syslog(LOG_NOTICE, "FTDI ndx: %02d initializing as SPI/I2C device - FAILED to reset", + first_4222_ndx + 1); + return false; + } + + /* Mode 3 adds 1 GPIO device, setup GPIO */ + if (ftdi_mode == 3) { + syslog(LOG_NOTICE, "FTDI ndx: %02d initializing as GPIO device", first_4222_ndx + 1); + + DWORD locationIdGpio = devInfo[first_4222_ndx + 1].LocId; + if (locationIdGpio == 0) { + syslog(LOG_ERR, "No GPIO controller for FTDI_4222 device"); + return false; + } + + if (FT_OpenEx((PVOID)(uintptr_t) locationIdGpio, FT_OPEN_BY_LOCATION, &h_gpio) != FT_OK) { + syslog(LOG_NOTICE, "FTDI ndx: %02d initializing as GPIO device - FAILED to open", + first_4222_ndx + 1); + return false; + } + + if (!init_ftdi_gpios()) { + syslog(LOG_NOTICE, "FTDI ndx: %02d initializing as GPIO device - FAILED to initialize", + first_4222_ndx + 1); + return false; + } + } + + /* Save off this FTDI device ID */ + ftdi_device_id = devInfo[first_4222_ndx].ID; + + syslog(LOG_NOTICE, "FTDI FT4222 device initialization completed successfully"); + return true; +} + +int +ft4222_i2c_read_internal(Ftdi_4222_Shim& shim, uint8_t addr, uint8_t* data, int length) +{ + uint16 bytesRead = 0; + uint8 controllerStatus = 0; + + /* If a read fails, check the I2C controller status, reset the controller. + * + * In some cases a master read will return FT4222_OK but leaves the bus in + * an error state. + * */ + FT4222_STATUS sts_rd = FT4222_I2CMaster_Read(shim.h_i2c, addr, data, length, &bytesRead); + + if ((sts_rd != FT4222_OK) || ((FT4222_I2CMaster_GetStatus(shim.h_i2c, &controllerStatus) != FT4222_OK) || + (controllerStatus & 0x2))) { + FT4222_I2CMaster_GetStatus(shim.h_i2c, &controllerStatus); + + syslog(LOG_ERR, "FT4222_I2CMaster_Read failed for address 0x%02x with code 0x%02x I2C " + "controller status: 0x%02x", + addr, sts_rd, controllerStatus); + FT4222_I2CMaster_Reset(shim.h_i2c); + return 0; + } + + return bytesRead; +} + +int +ft4222_i2c_write_internal(Ftdi_4222_Shim& shim, uint8_t addr, uint8_t* data, int bytesToWrite) +{ + uint16 bytesWritten = 0; + uint8 controllerStatus; + + /* If a write fails, check the I2C controller status, reset the controller, + * return 0? */ + if (FT4222_I2CMaster_Write(shim.h_i2c, addr, data, bytesToWrite, &bytesWritten) != FT4222_OK) { + FT4222_I2CMaster_GetStatus(shim.h_i2c, &controllerStatus); + + syslog(LOG_ERR, "FT4222_I2CMaster_Write failed address %#02x. Code %d", addr, controllerStatus); + FT4222_I2CMaster_Reset(shim.h_i2c); + bytesWritten = 0; + } + + if (bytesWritten != bytesToWrite) + syslog(LOG_ERR, "FT4222_I2CMaster_Write wrote %u of %u bytes.", bytesWritten, bytesToWrite); + + return bytesWritten; +} +mraa_result_t +ft4222_i2c_select_bus(int bus) +{ + Ftdi_4222_Shim* shim = ShimFromI2cBus(bus); + if (!shim) + return MRAA_ERROR_NO_RESOURCES; + + if (bus > 0 && bus != shim->cur_i2c_bus) { + syslog(LOG_NOTICE, "ft4222_i2c_select_bus switching to bus %d", bus); + uint8_t data; + if (bus == 0) + data = 0; + else + data = 1 << (bus - 1); + + if (ft4222_i2c_write_internal(*shim, PCA9545_ADDR, &data, 1) == 1) + shim->cur_i2c_bus = bus; + else + return MRAA_ERROR_UNSPECIFIED; + } + return MRAA_SUCCESS; +} + +int +ft4222_i2c_context_read(mraa_i2c_context dev, uint8_t* data, int length) +{ + Ftdi_4222_Shim* shim = ShimFromI2cBus(dev->busnum); + if (!shim) + return -1; + + int bytes_read = 0; + if (ft4222_i2c_select_bus(dev->busnum) == MRAA_SUCCESS) + bytes_read = ft4222_i2c_read_internal(*shim, dev->addr, data, length); + return bytes_read; +} + +int +ft4222_i2c_context_write(mraa_i2c_context dev, uint8_t* data, int length) +{ + Ftdi_4222_Shim* shim = ShimFromI2cBus(dev->busnum); + if (!shim) + return -1; + + int bytes_written = 0; + if (ft4222_i2c_select_bus(dev->busnum) == MRAA_SUCCESS) + bytes_written = ft4222_i2c_write_internal(*shim, dev->addr, data, length); + return bytes_written; +} + +int +Ftdi_4222_Shim::_detect_io_expander() +{ + uint8_t data = 0; + if (ft4222_i2c_read_internal(*this, PCA9672_ADDR, &data, 1) == 1) { + syslog(LOG_ERR, "Detected I/O expander: PCA9672 with %d I/O pins", PCA9672_PINS); + exp_type = IO_EXP_PCA9672; + return PCA9672_PINS; + } else { + uint8_t reg = PCA9555_INPUT_REG; + ft4222_i2c_write_internal(*this, PCA9555_ADDR, ®, 1); + if (ft4222_i2c_read_internal(*this, PCA9555_ADDR, &data, 1) == 1) { + syslog(LOG_ERR, "Detected I/O expander: PCA9555 with %d I/O pins", PCA9555_PINS); + exp_type = IO_EXP_PCA9555; + reg = PCA9555_OUTPUT_REG; + + ft4222_i2c_write_internal(*this, PCA9555_ADDR, ®, 1); + ft4222_i2c_read_internal(*this, PCA9555_ADDR, &pca9555OutputValue.bytes[0], 2); + + reg = PCA9555_DIRECTION_REG; + + ft4222_i2c_write_internal(*this, PCA9555_ADDR, ®, 1); + ft4222_i2c_read_internal(*this, PCA9555_ADDR, &pca9555DirectionValue.bytes[0], 2); + return PCA9555_PINS; + } + } + exp_type = IO_EXP_NONE; + return 0; +} + +ft4222_gpio_type +ft4222_get_gpio_type(int pin) +{ + Ftdi_4222_Shim* shim = ShimFromGpioPin(pin); + if (!shim) + return GPIO_TYPE_UNKNOWN; + + if (pin < gpioPinsPerFt4222) { + return GPIO_TYPE_BUILTIN; + } else + switch (shim->exp_type) { + case IO_EXP_PCA9672: + return GPIO_TYPE_PCA9672; + case GPIO_TYPE_PCA9555: + return GPIO_TYPE_PCA9555; + default: + return GPIO_TYPE_UNKNOWN; + } +} + +mraa_result_t +ftdi_ft4222_set_internal_gpio_dir(Ftdi_4222_Shim& shim, int physical_pin, GPIO_Dir direction) +{ + /* Update the direction for this pin */ + shim.pinDirection[physical_pin] = direction; + + if (!shim.init_ftdi_gpios()) + return MRAA_ERROR_UNSPECIFIED; + + return MRAA_SUCCESS; +} + +mraa_result_t +ft4222_gpio_set_pca9672_dir(mraa_gpio_context dev, mraa_gpio_dir_t dir) +{ + Ftdi_4222_Shim* shim = ShimFromGpioPin(dev->phy_pin); + if (!shim) + return MRAA_ERROR_UNSPECIFIED; + + uint8_t mask = 1 << dev->phy_pin; + switch (dir) { + case MRAA_GPIO_IN: { + shim->pca9672DirectionMask |= mask; + int bytes_written = + ft4222_i2c_write_internal(*shim, PCA9672_ADDR, &shim->pca9672DirectionMask, 1); + return bytes_written == 1 ? MRAA_SUCCESS : MRAA_ERROR_UNSPECIFIED; + } + case MRAA_GPIO_OUT: { + shim->pca9672DirectionMask &= (~mask); + return MRAA_SUCCESS; + } + default: + return MRAA_ERROR_UNSPECIFIED; + } +} + + +mraa_result_t +ft4222_gpio_set_pca9555_dir(mraa_gpio_context dev, mraa_gpio_dir_t dir) +{ + Ftdi_4222_Shim* shim = ShimFromGpioPin(dev->phy_pin); + if (!shim) + return MRAA_ERROR_UNSPECIFIED; + + uint16_t mask = 1 << (dev->phy_pin - gpioPinsPerFt4222); + switch (dir) { + case MRAA_GPIO_IN: + shim->pca9555DirectionValue.word |= mask; + break; + case MRAA_GPIO_OUT: + shim->pca9555DirectionValue.word &= (~mask); + break; + default: { + syslog(LOG_ERR, "Invalid gpio direction: 0x%08x", dir); + return MRAA_ERROR_UNSPECIFIED; + } + } + uint8_t buf[3] = { PCA9555_DIRECTION_REG, shim->pca9555DirectionValue.bytes[0], + shim->pca9555DirectionValue.bytes[1] }; + + int bytes_written = ft4222_i2c_write_internal(*shim, PCA9555_ADDR, &buf[0], sizeof(buf)); + return bytes_written == sizeof(buf) ? MRAA_SUCCESS : MRAA_ERROR_UNSPECIFIED; +} + +mraa_result_t +ftdi_ft4222_set_internal_gpio_trigger(int pin, GPIO_Trigger trigger) +{ + Ftdi_4222_Shim* shim = ShimFromGpioPin(pin); + if (!shim) + return MRAA_ERROR_NO_RESOURCES; + + FT4222_STATUS ft4222Status = + FT4222_GPIO_SetInputTrigger(shim->h_gpio, static_cast(pin), trigger); + if (ft4222Status == FT4222_OK) + return MRAA_SUCCESS; + else { + syslog(LOG_ERR, "FT4222_GPIO_SetInputTrigger failed with FT4222_STATUS: 0x%04x", ft4222Status); + return MRAA_ERROR_UNSPECIFIED; + } +} + +// Function detects known I2C switches and returns the number of busses. +// On startup switch is disabled so default bus will be integrated i2c bus. +int +Ftdi_4222_Shim::ft4222_detect_i2c_switch() +{ + uint8_t data = 0; + if (ft4222_i2c_read_internal(*this, PCA9545_ADDR, &data, 1) == 1) { + data = 0; + return ft4222_i2c_write_internal(*this, PCA9545_ADDR, &data, 1) == 1 ? PCA9545_BUSSES : 0; + } + return 0; +} + +/******************* I2C functions *******************/ + +mraa_result_t +i2c_init_bus_replace(mraa_i2c_context dev) +{ + Ftdi_4222_Shim* shim = ShimFromI2cBus(dev->busnum); + if (!shim) + return MRAA_ERROR_NO_RESOURCES; + + lock_guard lock(shim->mtx_ft4222); + + // Tell the FT4222 to be an I2C Master. + FT4222_STATUS ft4222Status = FT4222_I2CMaster_Init(shim->h_i2c, shim->ft4222_i2c_speed()); + if (FT4222_OK != ft4222Status) { + syslog(LOG_ERR, "FT4222_I2CMaster_Init failed (error %d)!", ft4222Status); + return MRAA_ERROR_NO_RESOURCES; + } + + // Reset the I2CM registers to a known state. + ft4222Status = FT4222_I2CMaster_Reset(shim->h_i2c); + if (FT4222_OK != ft4222Status) { + syslog(LOG_ERR, "FT4222_I2CMaster_Reset failed (error %d)!", ft4222Status); + return MRAA_ERROR_NO_RESOURCES; + } + + syslog(LOG_NOTICE, "I2C interface enabled GPIO0 and GPIO1 will be unavailable."); + dev->handle = shim->h_i2c; + + // Don't use file descriptors + dev->fh = -1; + + // Advertise minimal i2c support as per + // https://www.kernel.org/doc/Documentation/i2c/functionality + dev->funcs = I2C_FUNC_I2C; + return MRAA_SUCCESS; +} + +mraa_result_t +i2c_set_frequency_replace(mraa_i2c_context dev, mraa_i2c_mode_t mode) +{ + Ftdi_4222_Shim* shim = ShimFromI2cBus(dev->busnum); + if (!shim) + return MRAA_ERROR_NO_RESOURCES; + + lock_guard lock(shim->mtx_ft4222); + + /* Save off this speed */ + shim->mraa_i2c_mode = mode; + + return FT4222_I2CMaster_Init(shim->h_i2c, shim->ft4222_i2c_speed()) == FT4222_OK ? MRAA_SUCCESS : MRAA_ERROR_UNSPECIFIED; +} + +mraa_result_t +i2c_address_replace(mraa_i2c_context dev, uint8_t addr) +{ + dev->addr = (int) addr; + return MRAA_SUCCESS; +} + +int +i2c_read_replace(mraa_i2c_context dev, uint8_t* data, int length) +{ + Ftdi_4222_Shim* shim = ShimFromI2cBus(dev->busnum); + if (!shim) + return -1; + + lock_guard lock(shim->mtx_ft4222); + + int bytes_read = ft4222_i2c_read_internal(*shim, dev->addr, data, length); + + return bytes_read; +} + +int +i2c_read_byte_replace(mraa_i2c_context dev) +{ + Ftdi_4222_Shim* shim = ShimFromI2cBus(dev->busnum); + if (!shim) + return -1; + + lock_guard lock(shim->mtx_ft4222); + + uint8_t data = 0; + int bytes_read = ft4222_i2c_context_read(dev, &data, 1); + return bytes_read == 1 ? data : -1; +} + +int +i2c_read_byte_data_replace(mraa_i2c_context dev, uint8_t command) +{ + Ftdi_4222_Shim* shim = ShimFromI2cBus(dev->busnum); + if (!shim) + return -1; + + lock_guard lock(shim->mtx_ft4222); + + uint8_t data; + int bytes_read = 0; + + uint16 bytesWritten = ft4222_i2c_context_write(dev, &command, 1); + + if (bytesWritten == 1) + bytes_read = ft4222_i2c_context_read(dev, &data, 1); + + if (bytes_read == 1) { + return (int) data; + } + return -1; +} + +int +i2c_read_word_data_replace(mraa_i2c_context dev, uint8_t command) +{ + Ftdi_4222_Shim* shim = ShimFromI2cBus(dev->busnum); + if (!shim) + return -1; + + lock_guard lock(shim->mtx_ft4222); + + union { + uint8_t bytes[2]; + uint16_t word; + } buf = {}; + int bytes_read = 0; + + int bytes_written = ft4222_i2c_context_write(dev, &command, 1); + if (bytes_written == 1) + bytes_read = ft4222_i2c_context_read(dev, &buf.bytes[0], 2); + + if (bytes_read == 2) + return (int) buf.word; + + return -1; +} + +int +i2c_read_bytes_data_replace(mraa_i2c_context dev, uint8_t command, uint8_t* data, int length) +{ + Ftdi_4222_Shim* shim = ShimFromI2cBus(dev->busnum); + if (!shim) + return -1; + + lock_guard lock(shim->mtx_ft4222); + + int bytes_read = 0; + int bytes_written = ft4222_i2c_context_write(dev, &command, 1); + if (bytes_written == 1) + bytes_read = ft4222_i2c_context_read(dev, data, length); + return bytes_read; +} + +mraa_result_t +i2c_write_replace(mraa_i2c_context dev, const uint8_t* data, int bytesToWrite) +{ + Ftdi_4222_Shim* shim = ShimFromI2cBus(dev->busnum); + if (!shim) + return MRAA_ERROR_NO_RESOURCES; + + lock_guard lock(shim->mtx_ft4222); + uint16 bytesWritten = ft4222_i2c_context_write(dev, (uint8_t*) data, bytesToWrite); + return bytesToWrite == bytesWritten ? MRAA_SUCCESS : MRAA_ERROR_INVALID_HANDLE; +} + +/* No mutex needed */ +mraa_result_t +i2c_write_byte_replace(mraa_i2c_context dev, uint8_t data) +{ + mraa_result_t status = i2c_write_replace(dev, &data, 1); + return status; +} + +/* No mutex needed */ +mraa_result_t +i2c_write_byte_data_replace(mraa_i2c_context dev, const uint8_t data, const uint8_t command) +{ + uint8_t buf[2] = { command, data }; + mraa_result_t status = i2c_write_replace(dev, &buf[0], 2); + return status; +} + +/* No mutex needed */ +mraa_result_t +i2c_write_word_data_replace(mraa_i2c_context dev, const uint16_t data, const uint8_t command) +{ + uint8_t buf[3] = { command, (uint8_t) data, (uint8_t)(data >> 8) }; + mraa_result_t status = i2c_write_replace(dev, &buf[0], 3); + return status; +} + +mraa_result_t i2c_stop_replace(mraa_i2c_context /*dev*/) +{ + return MRAA_SUCCESS; +} + +// /******************* GPIO functions *******************/ +// +mraa_result_t +gpio_init_internal_replace(mraa_gpio_context dev, int pin) +{ + Ftdi_4222_Shim* shim = ShimFromGpioPin(dev->phy_pin); + if (!shim) + return MRAA_ERROR_NO_RESOURCES; + + lock_guard lock(shim->mtx_ft4222); + + /* Keep the subplatform index as pin. Example: 516 */ + /* And the phy_pin as the local index to pin. Example: 516 - 512 = 4 */ + dev->pin = pin; + dev->phy_pin = pin & (~MRAA_SUB_PLATFORM_MASK); + + if (pin < 2) { + syslog(LOG_NOTICE, "Closing I2C interface to enable GPIO%d", pin); + + /* Replace with call to SPI init when SPI is fully implemented */ + FT4222_STATUS ft4222Status = + FT4222_SPIMaster_Init(shim->h_gpio, SPI_IO_SINGLE, CLK_DIV_4, CLK_IDLE_HIGH, CLK_LEADING, 0x01); + if (FT4222_OK != ft4222Status) { + syslog(LOG_ERR, "Failed to close I2C interface and start SPI (error %d)!", ft4222Status); + return MRAA_ERROR_NO_RESOURCES; + } + } + return MRAA_SUCCESS; +} + +mraa_result_t gpio_mode_replace(mraa_gpio_context /*dev*/, mraa_gpio_mode_t /*mode*/) +{ + return MRAA_ERROR_FEATURE_NOT_IMPLEMENTED; +} + +mraa_result_t +gpio_edge_mode_replace(mraa_gpio_context dev, mraa_gpio_edge_t mode) +{ + Ftdi_4222_Shim* shim = ShimFromGpioPin(dev->phy_pin); + if (!shim) + return MRAA_ERROR_NO_RESOURCES; + + lock_guard lock(shim->mtx_ft4222); + + mraa_result_t result = MRAA_SUCCESS; + + switch (ft4222_get_gpio_type(dev->phy_pin)) { + case GPIO_TYPE_BUILTIN: + switch (mode) { + case MRAA_GPIO_EDGE_NONE: + case MRAA_GPIO_EDGE_BOTH: + result = ftdi_ft4222_set_internal_gpio_trigger( + dev->phy_pin, static_cast(GPIO_TRIGGER_RISING | GPIO_TRIGGER_FALLING)); + break; + case MRAA_GPIO_EDGE_RISING: + result = ftdi_ft4222_set_internal_gpio_trigger(dev->phy_pin, GPIO_TRIGGER_RISING); + break; + case MRAA_GPIO_EDGE_FALLING: + result = ftdi_ft4222_set_internal_gpio_trigger(dev->phy_pin, GPIO_TRIGGER_FALLING); + break; + default: + result = MRAA_ERROR_FEATURE_NOT_IMPLEMENTED; + break; + } + break; + case GPIO_TYPE_PCA9672: + case GPIO_TYPE_PCA9555: + break; + default: + result = MRAA_ERROR_INVALID_RESOURCE; + break; + } + + return result; +} + +mraa_result_t +ft4222_i2c_read_io_expander(Ftdi_4222_Shim& shim, uint16_t* value) +{ + int bytes_read = 0; + uint8_t reg = PCA9555_INPUT_REG; + + switch (shim.exp_type) { + case IO_EXP_PCA9672: + bytes_read = ft4222_i2c_read_internal(shim, PCA9672_ADDR, (uint8_t*) value, 1); + break; + case GPIO_TYPE_PCA9555: + if (ft4222_i2c_write_internal(shim, PCA9555_ADDR, ®, 1) == 1) + bytes_read = ft4222_i2c_read_internal(shim, PCA9555_ADDR, (uint8_t*) value, 2); + break; + default:; + } + return bytes_read > 0 ? MRAA_SUCCESS : MRAA_ERROR_UNSPECIFIED; +} + +int +gpio_read_replace(mraa_gpio_context dev) +{ + Ftdi_4222_Shim* shim = ShimFromGpioPin(dev->phy_pin); + if (!shim) + return -1; + + lock_guard lock(shim->mtx_ft4222); + + switch (ft4222_get_gpio_type(dev->phy_pin)) { + case GPIO_TYPE_BUILTIN: { + BOOL value; + FT4222_STATUS ft4222Status = + FT4222_GPIO_Read(shim->h_gpio, static_cast(dev->phy_pin), &value); + if (FT4222_OK != ft4222Status) { + syslog(LOG_ERR, "FT4222_GPIO_Read failed (error %d)!", ft4222Status); + return -1; + } + return value; + } + case GPIO_TYPE_PCA9672: + case GPIO_TYPE_PCA9555: { + uint16_t mask = 1 << (dev->phy_pin - gpioPinsPerFt4222); + uint16_t value; + mraa_result_t res = ft4222_i2c_read_io_expander(*shim, &value); + return res == MRAA_SUCCESS ? (value & mask) == mask : -1; + } + default: + return -1; + } +} + +mraa_result_t +gpio_write_replace_wrapper(mraa_gpio_context dev, int write_value, bool require_atomic = true) +{ + Ftdi_4222_Shim* shim = ShimFromGpioPin(dev->phy_pin); + if (!shim) + return MRAA_ERROR_NO_RESOURCES; + + if (require_atomic) + pthread_mutex_lock(&shim->mtx_ft4222); + + mraa_result_t result = MRAA_SUCCESS; + + switch (ft4222_get_gpio_type(dev->phy_pin)) { + case GPIO_TYPE_BUILTIN: { + FT4222_STATUS ft4222Status = + FT4222_GPIO_Write(shim->h_gpio, static_cast(dev->phy_pin), write_value); + if (FT4222_OK != ft4222Status) { + syslog(LOG_ERR, "FT4222_GPIO_Write to pin %i failed (error %d)!", + dev->phy_pin, + ft4222Status); + result = MRAA_ERROR_UNSPECIFIED; + } + } break; + case GPIO_TYPE_PCA9672: { + uint8_t mask = 1 << dev->phy_pin; + uint8_t value; + int bytes_written = 0; + int bytes_read = ft4222_i2c_read_internal(*shim, PCA9672_ADDR, &value, 1); + if (bytes_read == 1) { + if (write_value == 1) + value = value | mask | shim->pca9672DirectionMask; + else + value &= (~mask); + bytes_written = ft4222_i2c_write_internal(*shim, PCA9672_ADDR, &value, 1); + } + result = bytes_written == 1 ? MRAA_SUCCESS : MRAA_ERROR_UNSPECIFIED; + } break; + case GPIO_TYPE_PCA9555: { + uint16_t mask = 1 << (dev->phy_pin - gpioPinsPerFt4222); + if (write_value) + shim->pca9555OutputValue.word |= mask; + else + shim->pca9555OutputValue.word &= (~mask); + uint8_t buf[3] = { PCA9555_OUTPUT_REG, shim->pca9555OutputValue.bytes[0], + shim->pca9555OutputValue.bytes[1] }; + int bytes_written = ft4222_i2c_write_internal(*shim, PCA9555_ADDR, &buf[0], sizeof(buf)); + result = bytes_written == sizeof(buf) ? MRAA_SUCCESS : MRAA_ERROR_UNSPECIFIED; + } break; + default: + result = MRAA_ERROR_INVALID_RESOURCE; + break; + } + + if (require_atomic) + pthread_mutex_unlock(&shim->mtx_ft4222); + + return result; +} + +mraa_result_t +gpio_write_replace(mraa_gpio_context dev, int write_value) +{ + Ftdi_4222_Shim* shim = ShimFromGpioPin(dev->phy_pin); + if (!shim) + return MRAA_ERROR_NO_RESOURCES; + + lock_guard lock(shim->mtx_ft4222); + + /* Default to an atomic gpio_write_replace call */ + return gpio_write_replace_wrapper(dev, write_value); +} + +mraa_result_t +gpio_dir_replace(mraa_gpio_context dev, mraa_gpio_dir_t dir) +{ + Ftdi_4222_Shim* shim = ShimFromGpioPin(dev->phy_pin); + if (!shim) + return MRAA_ERROR_NO_RESOURCES; + + lock_guard lock(shim->mtx_ft4222); + + switch (ft4222_get_gpio_type(dev->phy_pin)) { + case GPIO_TYPE_BUILTIN: + switch (dir) { + case MRAA_GPIO_IN: + return ftdi_ft4222_set_internal_gpio_dir(*shim, dev->phy_pin, GPIO_INPUT); + case MRAA_GPIO_OUT: + return ftdi_ft4222_set_internal_gpio_dir(*shim, dev->phy_pin, GPIO_OUTPUT); + case MRAA_GPIO_OUT_HIGH: + if (ftdi_ft4222_set_internal_gpio_dir(*shim, dev->phy_pin, GPIO_OUTPUT) != MRAA_SUCCESS) + return MRAA_ERROR_UNSPECIFIED; + return gpio_write_replace_wrapper(dev, 1, false); + case MRAA_GPIO_OUT_LOW: + if (ftdi_ft4222_set_internal_gpio_dir(*shim, dev->phy_pin, GPIO_OUTPUT) != MRAA_SUCCESS) + return MRAA_ERROR_UNSPECIFIED; + return gpio_write_replace_wrapper(dev, 0, false); + default: + return MRAA_ERROR_INVALID_PARAMETER; + } + case GPIO_TYPE_PCA9672: + switch (dir) { + case MRAA_GPIO_IN: + case MRAA_GPIO_OUT: + return ft4222_gpio_set_pca9672_dir(dev, dir); + case MRAA_GPIO_OUT_HIGH: + if (ft4222_gpio_set_pca9672_dir(dev, dir) != MRAA_SUCCESS) + return MRAA_ERROR_UNSPECIFIED; + return gpio_write_replace_wrapper(dev, 1, false); + case MRAA_GPIO_OUT_LOW: + if (ft4222_gpio_set_pca9672_dir(dev, dir) != MRAA_SUCCESS) + return MRAA_ERROR_UNSPECIFIED; + return gpio_write_replace_wrapper(dev, 0, false); + default: + return MRAA_ERROR_INVALID_PARAMETER; + } + case GPIO_TYPE_PCA9555: + switch (dir) { + case MRAA_GPIO_IN: + case MRAA_GPIO_OUT: + return ft4222_gpio_set_pca9555_dir(dev, dir); + case MRAA_GPIO_OUT_HIGH: + if (ft4222_gpio_set_pca9555_dir(dev, dir) != MRAA_SUCCESS) + return MRAA_ERROR_UNSPECIFIED; + return gpio_write_replace_wrapper(dev, 1, false); + case MRAA_GPIO_OUT_LOW: + if (ft4222_gpio_set_pca9555_dir(dev, dir) != MRAA_SUCCESS) + return MRAA_ERROR_UNSPECIFIED; + return gpio_write_replace_wrapper(dev, 0, false); + default: + return MRAA_ERROR_INVALID_PARAMETER; + } + default: + return MRAA_ERROR_INVALID_RESOURCE; + } +} + +mraa_boolean_t +ft4222_has_internal_gpio_triggered(Ftdi_4222_Shim& shim, int physical_pin) +{ + uint16 num_events = 0; + FT4222_GPIO_GetTriggerStatus(shim.h_gpio, static_cast(physical_pin), &num_events); + + if (num_events > 0) { + int i; + uint16 num_events_read; + GPIO_Trigger event; + for (i = 0; i < num_events; ++i) { + FT4222_GPIO_ReadTriggerQueue(shim.h_gpio, static_cast(physical_pin), &event, + 1, &num_events_read); + } + return TRUE; + } else + return FALSE; +} + +// INT pin of i2c PCA9672 GPIO expander is connected to FT4222 GPIO #3 +// We use INT to detect any expander GPIO level change +void* +ft4222_gpio_monitor(void* arg) +{ + Ftdi_4222_Shim* shim = static_cast(arg); + + uint16_t prev_value = 0; + ft4222_i2c_read_io_expander(*shim, &prev_value); + while (!shim->gpio_mon.should_stop) { + { + lock_guard lock(shim->mtx_ft4222); + if (ft4222_has_internal_gpio_triggered(*shim, GPIO_PORT_IO_INT)) { + uint16_t value; + if (ft4222_i2c_read_io_expander(*shim, &value) == MRAA_SUCCESS) { + uint16_t change_value = prev_value ^ value; + int i; + for (i = 0; i < MAX_IO_EXPANDER_PINS; ++i) { + uint16_t mask = 1 << i; + shim->gpio_mon.is_interrupt_detected[i] = (change_value & mask); + } + prev_value = value; + } + } + } + ft4222_sleep_ms(10); + } + return NULL; +} + +void +ft4222_gpio_monitor_add_pin(Ftdi_4222_Shim& shim) +{ + if (shim.gpio_mon.num_active_pins == 0) { + pthread_mutexattr_t attr_rec; + pthread_mutexattr_init(&attr_rec); + pthread_mutexattr_settype(&attr_rec, PTHREAD_MUTEX_RECURSIVE); + if (pthread_mutex_init(&shim.gpio_mon.mutex, &attr_rec) != 0) { + syslog(LOG_ERR, "Failed to setup GPIO monitor mutex for FT4222 access"); + throw std::runtime_error("Failed to setup GPIO monitor mutex for FT4222 access"); + } + + pthread_create(&shim.gpio_mon.thread, NULL, ft4222_gpio_monitor, &shim); + } + shim.gpio_mon.num_active_pins++; +} + +void +ft4222_gpio_monitor_remove_pin(Ftdi_4222_Shim& shim) +{ + shim.gpio_mon.num_active_pins--; + if (shim.gpio_mon.num_active_pins == 0) { + shim.gpio_mon.should_stop = TRUE; + pthread_join(shim.gpio_mon.thread, NULL); + pthread_mutex_destroy(&shim.gpio_mon.mutex); + } +} + +mraa_boolean_t +ft4222_gpio_monitor_is_interrupt_detected(Ftdi_4222_Shim& shim, int pin) +{ + mraa_boolean_t is_interrupt_detected = FALSE; + if (shim.gpio_mon.is_interrupt_detected[pin]) { + shim.gpio_mon.is_interrupt_detected[pin] = FALSE; + is_interrupt_detected = TRUE; + } + return is_interrupt_detected; +} + +mraa_result_t +gpio_interrupt_handler_init_replace(mraa_gpio_context dev) +{ + while (dev->isr_thread_terminating) { + ft4222_sleep_ms(10); + } + + Ftdi_4222_Shim* shim = ShimFromGpioPin(dev->phy_pin); + if (!shim) + return MRAA_ERROR_NO_RESOURCES; + + lock_guard lock(shim->mtx_ft4222); + + std::string extra; + switch (ft4222_get_gpio_type(dev->phy_pin)) { + case GPIO_TYPE_BUILTIN: + /* Make sure this pin is an input */ + // ftdi_ft4222_set_internal_gpio_dir(*shim, dev->phy_pin, GPIO_INPUT); + extra += "(FT4222 GPIO pin)"; + break; + case GPIO_TYPE_PCA9672: + case GPIO_TYPE_PCA9555: + /* Make sure pin is an input */ + ftdi_ft4222_set_internal_gpio_dir(*shim, GPIO_PORT_IO_INT, GPIO_INPUT); + ftdi_ft4222_set_internal_gpio_trigger(GPIO_PORT_IO_INT, GPIO_TRIGGER_FALLING); + ft4222_gpio_monitor_add_pin(*shim); + extra += "(FT4222 expander GPIO pin)"; + break; + default: + return MRAA_ERROR_INVALID_RESOURCE; + } + syslog(LOG_NOTICE, "ISR added for pin: %d physical_pin: %d %s", dev->pin, dev->phy_pin, extra.c_str()); + + return MRAA_SUCCESS; +} + +/* This method is running in a cancelable thread which can go away at any time, + * likewise, the isr_thread_terminating check might never happen and the GPIO + * monitor can have problems - not sure of the best fix for this... most likely + * the best fix would be to NOT support the I/O expanders. */ +mraa_result_t +gpio_wait_interrupt_replace(mraa_gpio_context dev) +{ + + Ftdi_4222_Shim* shim = ShimFromGpioPin(dev->phy_pin); + if (!shim) + return MRAA_ERROR_NO_RESOURCES; + + + mraa_boolean_t interrupt_detected = FALSE; + ft4222_gpio_type gpio_type = GPIO_TYPE_BUILTIN; + + { + lock_guard lock(shim->mtx_ft4222); + gpio_type = ft4222_get_gpio_type(dev->phy_pin); + } + + while (!dev->isr_thread_terminating && !interrupt_detected) { + + switch (gpio_type) { + case GPIO_TYPE_BUILTIN: { + lock_guard lock(shim->mtx_ft4222); + interrupt_detected = ft4222_has_internal_gpio_triggered(*shim, dev->phy_pin); + } break; + case GPIO_TYPE_PCA9672: + case GPIO_TYPE_PCA9555: { + lock_guard lock(shim->mtx_ft4222); + /* Expander pin indexing starts past the FT4222 GPIO pins */ + interrupt_detected = + ft4222_gpio_monitor_is_interrupt_detected(*shim, dev->phy_pin - gpioPinsPerFt4222); + } break; + default:; + } + ft4222_sleep_ms(10); + } + if (dev->isr_thread_terminating) { + lock_guard lock(shim->mtx_ft4222); + ft4222_gpio_monitor_remove_pin(*shim); + } + + return MRAA_SUCCESS; +} + +void +ft4222_populate_i2c_func_table(mraa_adv_func_t* func_table) +{ + func_table->i2c_init_bus_replace = &i2c_init_bus_replace; + func_table->i2c_set_frequency_replace = &i2c_set_frequency_replace; + func_table->i2c_address_replace = &i2c_address_replace; + func_table->i2c_read_replace = &i2c_read_replace; + func_table->i2c_read_byte_replace = &i2c_read_byte_replace; + func_table->i2c_read_byte_data_replace = &i2c_read_byte_data_replace; + func_table->i2c_read_word_data_replace = &i2c_read_word_data_replace; + func_table->i2c_read_bytes_data_replace = &i2c_read_bytes_data_replace; + func_table->i2c_write_replace = &i2c_write_replace; // Used in 3 places + func_table->i2c_write_byte_replace = &i2c_write_byte_replace; // No mutex needed + func_table->i2c_write_byte_data_replace = &i2c_write_byte_data_replace; + func_table->i2c_write_word_data_replace = &i2c_write_word_data_replace; + func_table->i2c_stop_replace = &i2c_stop_replace; +} + +void +ft4222_populate_gpio_func_table(mraa_adv_func_t* func_table) +{ + func_table->gpio_init_internal_replace = &gpio_init_internal_replace; + func_table->gpio_mode_replace = &gpio_mode_replace; + func_table->gpio_edge_mode_replace = &gpio_edge_mode_replace; + func_table->gpio_dir_replace = &gpio_dir_replace; + func_table->gpio_read_replace = &gpio_read_replace; + func_table->gpio_write_replace = &gpio_write_replace; // 6 + func_table->gpio_interrupt_handler_init_replace = &gpio_interrupt_handler_init_replace; + func_table->gpio_wait_interrupt_replace = &gpio_wait_interrupt_replace; +} + +/* Store mraa_board_t subplatform allocated by this library */ +char ftdi_4222_platform_name[] = "FTDI FT4222"; +bool +Ftdi_4222_Shim::setup_io() +{ + int numI2cGpioExpanderPins = _detect_io_expander(); + int numUsbGpio = gpioPinsPerFt4222 + numI2cGpioExpanderPins; + int numI2cBusses = 1 + ft4222_detect_i2c_switch(); + int numUsbPins = numUsbGpio + 2 * (numI2cBusses - 1); // Add SDA and SCL for each i2c switch bus + mraa_pincapabilities_t pinCapsI2c = (mraa_pincapabilities_t){ 1, 0, 0, 0, 0, 1, 0, 0 }; + mraa_pincapabilities_t pinCapsI2cGpio = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 1, 0, 0 }; + mraa_pincapabilities_t pinCapsGpio = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }; + + _board.platform_name = &ftdi_4222_platform_name[0]; + _board.platform_type = MRAA_FTDI_FT4222; + _board.phy_pin_count = numUsbPins; + _board.gpio_count = numUsbGpio; + + int bus = 0; + _board.i2c_bus_count = numI2cBusses; + _board.def_i2c_bus = bus; + _board.i2c_bus[bus].bus_id = bus; + + /* Save off an I2C bus-to-shim value */ + _i2c_bus_to_shim[bus] = this; + + // I2c pins (these are virtual, entries are required to configure i2c layer) + // We currently assume that GPIO 0/1 are reserved for i2c operation + _pins.push_back(mraa_pininfo_t()); + strncpy(&_pins.back().name[0], "IGPIO0/SCL0", MRAA_PIN_NAME_SIZE); + _pins.back().capabilities = pinCapsI2cGpio; + _pins.back().gpio.pinmap = 512 + _pins.size() - 1; + _pins.back().gpio.mux_total = 0; + _pins.back().i2c.mux_total = 0; + _board.i2c_bus[bus].scl = _pins.size() - 1; + /* Save off a GPIO ndx-to-shim value */ + _gpio_pin_to_shim[_pins.size() - 1] = this; + + _pins.push_back(mraa_pininfo_t()); + strncpy(&_pins.back().name[0], "IGPIO1/SDA0", MRAA_PIN_NAME_SIZE); + _pins.back().capabilities = pinCapsI2cGpio; + _pins.back().gpio.pinmap = 512 + _pins.size() - 1; + _pins.back().gpio.mux_total = 0; + _pins.back().i2c.mux_total = 0; + _board.i2c_bus[bus].sda = _pins.size() - 1; + /* Save off a GPIO ndx-to-shim value */ + _gpio_pin_to_shim[_pins.size() - 1] = this; + + // FTDI4222 gpio + _pins.push_back(mraa_pininfo_t()); + strncpy(&_pins.back().name[0], "INT-GPIO2", MRAA_PIN_NAME_SIZE); + _pins.back().capabilities = pinCapsGpio; + _pins.back().gpio.pinmap = 512 + _pins.size() - 1; + _pins.back().gpio.mux_total = 0; + /* Save off a GPIO ndx-to-shim value */ + _gpio_pin_to_shim[_pins.size() - 1] = this; + + _pins.push_back(mraa_pininfo_t()); + strncpy(&_pins.back().name[0], "INT-GPIO3", MRAA_PIN_NAME_SIZE); + _pins.back().capabilities = pinCapsGpio; + _pins.back().gpio.pinmap = 512 + _pins.size() - 1; + _pins.back().gpio.mux_total = 0; + /* Save off a GPIO ndx-to-shim value */ + _gpio_pin_to_shim[_pins.size() - 1] = this; + + + // Virtual gpio pins on i2c I/O expander. + for (int i = 0; i < numI2cGpioExpanderPins; ++i) { + _pins.push_back(mraa_pininfo_t()); + snprintf(&_pins.back().name[0], MRAA_PIN_NAME_SIZE, "EXP-GPIO%d", i); + _pins.back().capabilities = pinCapsGpio; + _pins.back().gpio.pinmap = 512 + _pins.size() - 1; + _pins.back().gpio.mux_total = 0; + /* Save off a GPIO ndx-to-shim value */ + _gpio_pin_to_shim[_pins.size() - 1] = this; + } + + // Now add any extra i2c buses behind i2c switch + for (bus = 1; bus < numI2cBusses; ++bus) { + _board.i2c_bus[bus].bus_id = bus; + _pins.back().i2c.mux_total = 0; + snprintf(&_pins.back().name[0], MRAA_PIN_NAME_SIZE, "SDA%d", bus); + _pins.back().capabilities = pinCapsI2c; + _board.i2c_bus[bus].sda = _pins.size() - 1; + + _pins.push_back(mraa_pininfo_t()); + snprintf(&_pins.back().name[0], MRAA_PIN_NAME_SIZE, "SCL%d", bus); + _pins.back().capabilities = pinCapsI2c; + _pins.back().i2c.mux_total = 0; + _board.i2c_bus[bus].scl = _pins.size() - 1; + + _pins.push_back(mraa_pininfo_t()); + } + /* The board pins points to the shim pins vector */ + _board.pins = &_pins[0]; + + _board.adv_func = &_adv_func_table; + + ft4222_populate_i2c_func_table(_board.adv_func); + ft4222_populate_gpio_func_table(_board.adv_func); + + /* Success, return the sub platform */ + return true; +} + +bool +Ftdi_4222_Shim::init_ftdi_gpios() +{ + /* Setting the direction requires a re-init, which means the + * previous resources should also be un-initialized first */ + if (h_gpio) + FT4222_UnInitialize(h_gpio); + + /* Use GPIO2 as GPIO (not suspend output) */ + return (FT4222_SetSuspendOut(h_gpio, 0) == FT4222_OK) && + /* Use GPIO3 as GPIO (not interrupt for I/O expander) */ + (FT4222_SetWakeUpInterrupt(h_gpio, 0) == FT4222_OK) && + (FT4222_GPIO_Init(h_gpio, &pinDirection[0]) == FT4222_OK); +} + +} /* namespace ft4222 */ + +/* One C method exposed for loading a platform */ +mraa_result_t +mraa_usb_platform_extender(mraa_board_t* board) +{ + /* If no board provided return unknown */ + if (board == NULL) + return MRAA_ERROR_PLATFORM_NOT_INITIALISED; + + /* Attempt to initialize an FT4222 shim and assign it as a sub-platform */ + board->sub_platform = ft4222::Ftdi_4222_Shim::init_and_setup_mraa_board(); + + /* No sub-platform returned, drop out */ + if (board->sub_platform == NULL) + return MRAA_ERROR_PLATFORM_NOT_INITIALISED; + + syslog(LOG_NOTICE, "Added subplatform of type: %s", board->sub_platform->platform_name); + + return MRAA_SUCCESS; +} diff -Nru mraa-1.9.0/src/usb/ft4222/ftdi_ft4222.hpp mraa-2.0.0/src/usb/ft4222/ftdi_ft4222.hpp --- mraa-1.9.0/src/usb/ft4222/ftdi_ft4222.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mraa-2.0.0/src/usb/ft4222/ftdi_ft4222.hpp 2018-09-06 12:34:41.000000000 +0000 @@ -0,0 +1,50 @@ +#ifndef _EXPORT_USERS_NECK_MRAA_FT4222_SRC_USB_FT4222_FTDI_FT4222_HPP +#define _EXPORT_USERS_NECK_MRAA_FT4222_SRC_USB_FT4222_FTDI_FT4222_HPP + +/* + * Author: Henry Bruce + * Copyright (c) 2015 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" { + +#include +#include "mraa_internal.h" + +/** + * Attempt to initialize a mraa_board_t for a UMFT4222EV module + * + * @param board Pointer to valid board structure. If a mraa_board_t + * is initialized, it will be added to board->sub_platform + * + * @return MRAA_SUCCESS if a valid subplaform has been initialized, + * otherwise return MRAA_ERROR_PLATFORM_NOT_INITIALISED + */ +mraa_result_t mraa_usb_platform_extender(mraa_board_t* board); + +} +#endif + +#endif diff -Nru mraa-1.9.0/src/usb/ftdi_ft4222.c mraa-2.0.0/src/usb/ftdi_ft4222.c --- mraa-1.9.0/src/usb/ftdi_ft4222.c 2018-02-15 23:08:49.000000000 +0000 +++ mraa-2.0.0/src/usb/ftdi_ft4222.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1134 +0,0 @@ -/* - * Author: Henry Bruce - * Copyright (c) 2015 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 "linux/i2c-dev.h" -#include "common.h" -#include "ftd2xx.h" -#include "libft4222.h" -#include "usb/ftdi_ft4222.h" - -#define PLATFORM_NAME "FTDI FT4222" -#define I2CM_ERROR(status) (((status) &0x02) != 0) -#define PCA9672_ADDR 0x20 -#define PCA9555_ADDR 0x27 -#define PCA9555_INPUT_REG 0 -#define PCA9555_OUTPUT_REG 2 -#define PCA9555_POLARITY_REG 4 -#define PCA9555_DIRECTION_REG 6 -#define PCA9545_ADDR 0x70 -#define PCA9672_PINS 8 -#define PCA9555_PINS 16 -#define PCA9545_BUSSES 4 -#define GPIO_PORT_IO_RESET GPIO_PORT2 -#define GPIO_PORT_IO_INT GPIO_PORT3 -#define MAX_IO_EXPANDER_PINS PCA9555_PINS - -typedef enum {IO_EXP_NONE, IO_EXP_PCA9672, IO_EXP_PCA9555} ft4222_io_exp_type; -typedef enum {GPIO_TYPE_BUILTIN, GPIO_TYPE_PCA9672, GPIO_TYPE_PCA9555, GPIO_TYPE_UNKNOWN=99} ft4222_gpio_type; - -static pthread_mutex_t ft4222_lock; -static FT_HANDLE ftHandleGpio = (FT_HANDLE) NULL; //GPIO Handle -static FT_HANDLE ftHandleI2c = (FT_HANDLE) NULL; //I2C/SPI Handle -static FT_HANDLE ftHandleSpi = (FT_HANDLE) NULL; //I2C/SPI Handle -static GPIO_Dir pinDirection[] = {GPIO_OUTPUT, GPIO_OUTPUT, GPIO_OUTPUT, GPIO_OUTPUT}; -static uint8_t pca9672DirectionMask = 0; -static uint16_t pca9555OutputValue = 0; -static uint16_t pca9555DirectionValue = 0; -static int bus_speed = 400; -static int numFt4222GpioPins = 4; -static int numI2cGpioExpanderPins = 8; -static int numI2cSwitchBusses = 4; -static int currentI2cBus = 0; -static ft4222_io_exp_type gpio_expander_chip; -static mraa_boolean_t libft4222_load_success = TRUE; - -FT_STATUS (*dl_FT_GetDeviceInfoList)(FT_DEVICE_LIST_INFO_NODE*, LPDWORD); -FT_STATUS (*dl_FT_CreateDeviceInfoList)(LPDWORD); -FT_STATUS (*dl_FT_OpenEx)(PVOID, DWORD, FT_HANDLE*); -FT4222_STATUS (*dl_FT4222_GetVersion)(FT_HANDLE, FT4222_Version*); -FT4222_STATUS (*dl_FT4222_I2CMaster_Write)(FT_HANDLE, uint16, uint8*, uint16, uint16*); -FT4222_STATUS (*dl_FT4222_I2CMaster_Reset)(FT_HANDLE); -FT4222_STATUS (*dl_FT4222_I2CMaster_Read)(FT_HANDLE, uint16, uint8*, uint16, uint16*); -FT4222_STATUS (*dl_FT4222_I2CMaster_Init)(FT_HANDLE, uint32); -FT4222_STATUS (*dl_FT4222_I2CMaster_GetStatus)(FT_HANDLE, uint8*); -FT4222_STATUS (*dl_FT4222_GPIO_Init)(FT_HANDLE, GPIO_Dir[4]); -FT4222_STATUS (*dl_FT4222_GPIO_GetTriggerStatus)(FT_HANDLE, GPIO_Port, uint16*); -FT4222_STATUS (*dl_FT4222_GPIO_ReadTriggerQueue)(FT_HANDLE, GPIO_Port, GPIO_Trigger*, uint16, uint16*); -FT4222_STATUS (*dl_FT4222_GPIO_Read)(FT_HANDLE, GPIO_Port, BOOL*); -FT4222_STATUS (*dl_FT4222_GPIO_SetInputTrigger)(FT_HANDLE, GPIO_Port, GPIO_Trigger); -FT4222_STATUS (*dl_FT4222_GPIO_Write)(FT_HANDLE, GPIO_Port, BOOL); -FT4222_STATUS (*dl_FT4222_SetWakeUpInterrupt)(FT_HANDLE, BOOL); -FT4222_STATUS (*dl_FT4222_SetSuspendOut)(FT_HANDLE, BOOL); -FT4222_STATUS (*dl_FT4222_SPIMaster_Init)(FT_HANDLE, FT4222_SPIMode, FT4222_SPIClock, FT4222_SPICPOL, FT4222_SPICPHA, uint8); - -static void -mraa_ftdi_ft4222_sleep_ms(unsigned long mseconds) -{ - struct timespec sleepTime; - - sleepTime.tv_sec = mseconds / 1000; // Number of seconds - sleepTime.tv_nsec = (mseconds % 1000) * 1000000; // Convert fractional seconds to nanoseconds - - // Iterate nanosleep in a loop until the total sleep time is the original - // value of the seconds parameter - while ((nanosleep(&sleepTime, &sleepTime) != 0) && (errno == EINTR)) - ; -} - -static unsigned int -mraa_ftdi_ft4222_get_tick_count_ms() -{ - static unsigned int startTick = 0; - unsigned int ticks; - struct timeval now; - gettimeofday(&now, NULL); - ticks = now.tv_sec * 1000; - ticks += now.tv_usec / 1000; - if (startTick == 0) - startTick = ticks; - return ticks - startTick; -} - -void * -mraa_ftdi_ft4222_dlsym(const char *symbol) -{ - void *func = dlsym(libft4222_lib, symbol); - if (func == NULL) { - syslog(LOG_ERR, "%s", dlerror()); - libft4222_load_success = FALSE; - } - return func; -} - - -mraa_result_t -mraa_ftdi_ft4222_init() -{ - mraa_result_t mraaStatus = MRAA_ERROR_NO_RESOURCES; - FT_DEVICE_LIST_INFO_NODE* devInfo = NULL; - FT_STATUS ftStatus; - DWORD numDevs = 0; - int i; - int retCode = 0; - - dl_FT_GetDeviceInfoList = mraa_ftdi_ft4222_dlsym("FT_GetDeviceInfoList"); - dl_FT_CreateDeviceInfoList = mraa_ftdi_ft4222_dlsym("FT_CreateDeviceInfoList"); - dl_FT4222_GetVersion = mraa_ftdi_ft4222_dlsym("FT4222_GetVersion"); - dl_FT4222_I2CMaster_Write = mraa_ftdi_ft4222_dlsym("FT4222_I2CMaster_Write"); - dl_FT4222_I2CMaster_Reset = mraa_ftdi_ft4222_dlsym("FT4222_I2CMaster_Reset"); - dl_FT4222_I2CMaster_Read = mraa_ftdi_ft4222_dlsym("FT4222_I2CMaster_Read"); - dl_FT4222_I2CMaster_Init = mraa_ftdi_ft4222_dlsym("FT4222_I2CMaster_Init"); - dl_FT4222_I2CMaster_GetStatus = mraa_ftdi_ft4222_dlsym("FT4222_I2CMaster_GetStatus"); - dl_FT4222_GPIO_Init = mraa_ftdi_ft4222_dlsym("FT4222_GPIO_Init"); - dl_FT4222_GPIO_GetTriggerStatus = mraa_ftdi_ft4222_dlsym("FT4222_GPIO_GetTriggerStatus"); - dl_FT4222_GPIO_ReadTriggerQueue = mraa_ftdi_ft4222_dlsym("FT4222_GPIO_ReadTriggerQueue"); - dl_FT4222_GPIO_Read = mraa_ftdi_ft4222_dlsym("FT4222_GPIO_Read"); - dl_FT4222_GPIO_SetInputTrigger = mraa_ftdi_ft4222_dlsym("FT4222_GPIO_SetInputTrigger"); - dl_FT4222_GPIO_Write = mraa_ftdi_ft4222_dlsym("FT4222_GPIO_Write"); - dl_FT4222_SetWakeUpInterrupt = mraa_ftdi_ft4222_dlsym("FT4222_SetWakeUpInterrupt"); - dl_FT4222_SetSuspendOut = mraa_ftdi_ft4222_dlsym("FT4222_SetSuspendOut"); - dl_FT4222_SPIMaster_Init = mraa_ftdi_ft4222_dlsym("FT4222_SPIMaster_Init"); - dl_FT_OpenEx = mraa_ftdi_ft4222_dlsym("FT_OpenEx"); - - if (!libft4222_load_success) { - syslog(LOG_ERR, "Failed to find all symbols for FTDI4222 support"); - goto init_exit; - } - - ftStatus = dl_FT_CreateDeviceInfoList(&numDevs); - if (ftStatus != FT_OK) { - syslog(LOG_ERR, "FT_CreateDeviceInfoList failed: error code %d\n", ftStatus); - goto init_exit; - } - - devInfo = calloc((size_t) numDevs, sizeof(FT_DEVICE_LIST_INFO_NODE)); - if (devInfo == NULL) { - syslog(LOG_ERR, "FT4222 allocation failure.\n"); - goto init_exit; - } - - ftStatus = dl_FT_GetDeviceInfoList(devInfo, &numDevs); - syslog(LOG_NOTICE, "FT_GetDeviceInfoList returned %d devices\n", numDevs); - if (ftStatus != FT_OK) { - syslog(LOG_ERR, "FT_GetDeviceInfoList failed (error code %d)\n", (int) ftStatus); - goto init_exit; - } - if (numDevs < 2) { - syslog(LOG_ERR, "No FT4222 devices connected.\n"); - goto init_exit; - } - if(numDevs > 2) { - syslog(LOG_ERR, "CNFMODE not supported. Valid modes are 0 or 3.\n"); - goto init_exit; - } - - // FIXME: Assumes just one physical FTDI device present - DWORD locationIdI2c = 0; - DWORD locationIdGpio = 0; - if (devInfo[0].Type == FT_DEVICE_4222H_0) - locationIdI2c = devInfo[0].LocId; - if (devInfo[1].Type == FT_DEVICE_4222H_0) - locationIdGpio = devInfo[1].LocId; - - if (locationIdI2c == 0) { - syslog(LOG_ERR, "FT_GetDeviceInfoList contains no I2C controllers\n"); - goto init_exit; - } - - if (locationIdGpio == 0) { - syslog(LOG_ERR, "FT_GetDeviceInfoList contains no GPIO controllers\n"); - goto init_exit; - } - - ftStatus = dl_FT_OpenEx((PVOID)(uintptr_t) locationIdI2c, FT_OPEN_BY_LOCATION, &ftHandleI2c); - if (ftStatus != FT_OK) { - syslog(LOG_ERR, "FT_OpenEx failed (error %d)\n", (int) ftStatus); - goto init_exit; - } - - ftStatus = dl_FT_OpenEx((PVOID)(uintptr_t) locationIdGpio, FT_OPEN_BY_LOCATION, &ftHandleGpio); - if (ftStatus != FT_OK) { - syslog(LOG_ERR, "FT_OpenEx failed (error %d)\n", (int) ftStatus); - goto init_exit; - } - - dl_FT4222_SetSuspendOut(ftHandleGpio, 0); - dl_FT4222_SetWakeUpInterrupt(ftHandleGpio, 0); - ftStatus = dl_FT4222_GPIO_Init(ftHandleGpio, pinDirection); - if (ftStatus != FT_OK) { - syslog(LOG_ERR, "FT4222_GPIO_Init failed (error %d)\n", (int) ftStatus); - mraaStatus = MRAA_ERROR_NO_RESOURCES; - goto init_exit; - } - - // Tell the FT4222 to be an I2C Master by default on init. - FT4222_STATUS ft4222Status = dl_FT4222_I2CMaster_Init(ftHandleI2c, bus_speed); - if (FT4222_OK != ft4222Status) { - syslog(LOG_ERR, "FT4222_I2CMaster_Init failed (error %d)!\n", ft4222Status); - goto init_exit; - } - - ft4222Status = dl_FT4222_I2CMaster_Reset(ftHandleI2c); - if (FT4222_OK != ft4222Status) { - syslog(LOG_ERR, "FT4222_I2CMaster_Reset failed (error %d)!\n", ft4222Status); - goto init_exit; - } - - mraaStatus = MRAA_SUCCESS; - -init_exit: - if (devInfo != NULL) - free(devInfo); - if (mraaStatus == MRAA_SUCCESS) - syslog(LOG_NOTICE, "mraa_ftdi_ft4222_init completed successfully\n"); - return mraaStatus; -} - - -mraa_result_t -mraa_ftdi_ft4222_get_version(unsigned int* versionChip, unsigned int* versionLib) -{ - if (ftHandleI2c != NULL) { - FT4222_Version ft4222Version; - FT4222_STATUS ft4222Status = dl_FT4222_GetVersion(ftHandleI2c, &ft4222Version); - if (FT4222_OK == ft4222Status) { - *versionChip = (unsigned int) ft4222Version.chipVersion; - *versionLib = (unsigned int) ft4222Version.dllVersion; - syslog(LOG_NOTICE, "FT4222_GetVersion %08X %08X\n", *versionChip, *versionLib); - return MRAA_SUCCESS; - } else { - syslog(LOG_ERR, "FT4222_GetVersion failed (error %d)\n", (int) ft4222Status); - return MRAA_ERROR_NO_RESOURCES; - } - } else { - syslog(LOG_ERR, "Bad FT4222 handle\n"); - return MRAA_ERROR_INVALID_HANDLE; - } -} - - -/******************* Private I2C functions *******************/ - -static void -mraa_ftdi_ft4222_i2c_log(char* msg, uint8_t addr, const uint8_t* data, int length) -{ - char buf[256]; - int pos = sprintf(buf, "%s: %#02x ", msg, addr); - int i = 0; - pos += sprintf(&buf[pos], "{"); - for (i = 0; i < length; ++i) - pos += sprintf(&buf[pos], "%#02x ", data[i]); - pos += sprintf(&buf[pos], "}"); - syslog(LOG_NOTICE, "%s", buf); -} - - -static int -mraa_ftdi_ft4222_i2c_read_internal(FT_HANDLE handle, uint8_t addr, uint8_t* data, int length) -{ - uint16 bytesRead = 0; - uint8 controllerStatus; - FT4222_STATUS ft4222Status = dl_FT4222_I2CMaster_Read(handle, addr, data, length, &bytesRead); - // mraa_ftdi_ft4222_i2c_log("FT4222_I2CMaster_Read", addr, data, length); - ft4222Status = dl_FT4222_I2CMaster_GetStatus(ftHandleI2c, &controllerStatus); - if (FT4222_OK != ft4222Status || I2CM_ERROR(controllerStatus)) { - syslog(LOG_ERR, "FT4222_I2CMaster_Read failed for address %#02x. Code %d", addr, controllerStatus); - dl_FT4222_I2CMaster_Reset(handle); - return 0; - } - // syslog(LOG_NOTICE, "FT4222_I2CMaster_Read completed"); - return bytesRead; -} - -static int -mraa_ftdi_ft4222_i2c_write_internal(FT_HANDLE handle, uint8_t addr, const uint8_t* data, int bytesToWrite) -{ - uint16 bytesWritten = 0; - uint8 controllerStatus; - // mraa_ftdi_ft4222_i2c_log("FT4222_I2CMaster_Write", addr, data, bytesToWrite); - FT4222_STATUS ft4222Status = dl_FT4222_I2CMaster_Write(handle, addr, (uint8_t*) data, bytesToWrite, &bytesWritten); - ft4222Status = dl_FT4222_I2CMaster_GetStatus(ftHandleI2c, &controllerStatus); - if (FT4222_OK != ft4222Status || I2CM_ERROR(controllerStatus)) { - syslog(LOG_ERR, "FT4222_I2CMaster_Write failed address %#02x\n", addr); - dl_FT4222_I2CMaster_Reset(handle); - return 0; - } - if (bytesWritten != bytesToWrite) - syslog(LOG_ERR, "FT4222_I2CMaster_Write wrote %u of %u bytes.\n", bytesWritten, bytesToWrite); - - // syslog(LOG_NOTICE, "FT4222_I2CMaster_Write completed"); - return bytesWritten; -} - - -// Function detects known I2C I/O expanders and returns the number of GPIO pins on expander -static int -mraa_ftdi_ft4222_detect_io_expander() -{ - uint8_t data; - if (mraa_ftdi_ft4222_i2c_read_internal(ftHandleI2c, PCA9672_ADDR, &data, 1) == 1) { - gpio_expander_chip = IO_EXP_PCA9672; - return PCA9672_PINS; - } else { - uint8_t reg = PCA9555_INPUT_REG; - mraa_ftdi_ft4222_i2c_write_internal(ftHandleI2c, PCA9555_ADDR, ®, 1); - if (mraa_ftdi_ft4222_i2c_read_internal(ftHandleI2c, PCA9555_ADDR, &data, 1) == 1) { - gpio_expander_chip = IO_EXP_PCA9555; - reg = PCA9555_OUTPUT_REG; - mraa_ftdi_ft4222_i2c_write_internal(ftHandleI2c, PCA9555_ADDR, ®, 1); - mraa_ftdi_ft4222_i2c_read_internal(ftHandleI2c, PCA9555_ADDR, (uint8_t*)&pca9555OutputValue, 2); - reg = PCA9555_DIRECTION_REG; - mraa_ftdi_ft4222_i2c_write_internal(ftHandleI2c, PCA9555_ADDR, ®, 1); - mraa_ftdi_ft4222_i2c_read_internal(ftHandleI2c, PCA9555_ADDR, (uint8_t*)&pca9555DirectionValue, 2); - return PCA9555_PINS; - } - } - gpio_expander_chip = IO_EXP_NONE; - return 0; -} - - -static ft4222_gpio_type -mraa_ftdi_ft4222_get_gpio_type(int pin) -{ - if (pin < numFt4222GpioPins) { - return GPIO_TYPE_BUILTIN; - } else switch (gpio_expander_chip) { - case IO_EXP_PCA9672: - return GPIO_TYPE_PCA9672; - case GPIO_TYPE_PCA9555: - return GPIO_TYPE_PCA9555; - default: - return GPIO_TYPE_UNKNOWN; - } -} - - -static mraa_result_t -ftdi_ft4222_set_internal_gpio_dir(int pin, GPIO_Dir direction) -{ - pinDirection[pin] = direction; - if (dl_FT4222_GPIO_Init(ftHandleGpio, pinDirection) != FT4222_OK) - return MRAA_ERROR_UNSPECIFIED; - else - return MRAA_SUCCESS; -} - - -static mraa_result_t -mraa_ftdi_ft4222_gpio_set_pca9672_dir(int pin, mraa_gpio_dir_t dir) -{ - uint8_t mask = 1 << pin; - switch (dir) { - case MRAA_GPIO_IN: - pca9672DirectionMask |= mask; - int bytes_written = mraa_ftdi_ft4222_i2c_write_internal(ftHandleI2c, PCA9672_ADDR, &pca9672DirectionMask, 1); - return bytes_written == 1 ? MRAA_SUCCESS : MRAA_ERROR_UNSPECIFIED; - case MRAA_GPIO_OUT: - pca9672DirectionMask &= (~mask); - return MRAA_SUCCESS; - default: - return MRAA_ERROR_UNSPECIFIED; - } -} - - -static mraa_result_t -mraa_ftdi_ft4222_gpio_set_pca9555_dir(int pin, mraa_gpio_dir_t dir) -{ - uint16_t mask = 1 << pin; - switch (dir) { - case MRAA_GPIO_IN: - pca9555DirectionValue |= mask; - break; - case MRAA_GPIO_OUT: - pca9555DirectionValue &= (~mask); - break; - default: - return MRAA_ERROR_UNSPECIFIED; - } - uint8_t buf[3]; - buf[0] = PCA9555_DIRECTION_REG; - buf[1] = (uint8_t)(pca9555DirectionValue & 0xFF); - buf[2] = (uint8_t)(pca9555DirectionValue >> 8); - pthread_mutex_lock(&ft4222_lock); - int bytes_written = mraa_ftdi_ft4222_i2c_write_internal(ftHandleI2c, PCA9555_ADDR, buf, sizeof(buf)); - pthread_mutex_unlock(&ft4222_lock); - return bytes_written == sizeof(buf) ? MRAA_SUCCESS : MRAA_ERROR_UNSPECIFIED; -} - - - -static mraa_result_t -ftdi_ft4222_set_internal_gpio_trigger(int pin, GPIO_Trigger trigger) -{ - FT4222_STATUS ft4222Status = dl_FT4222_GPIO_SetInputTrigger(ftHandleGpio, pin, trigger); - if (ft4222Status == FT4222_OK) - return MRAA_SUCCESS; - else - return MRAA_ERROR_UNSPECIFIED; -} - - - - -// Function detects known I2C switches and returns the number of busses. -// On startup switch is disabled so default bus will be integrated i2c bus. -static int -mraa_ftdi_ft4222_detect_i2c_switch() -{ - uint8_t data; - if(mraa_ftdi_ft4222_i2c_read_internal(ftHandleI2c, PCA9545_ADDR, &data, 1) == 1) { - data = 0; - return mraa_ftdi_ft4222_i2c_write_internal(ftHandleI2c, PCA9545_ADDR, &data, 1) == 1 ? PCA9545_BUSSES : 0; - } - return 0; -} - - -static mraa_result_t -mraa_ftdi_ft4222_i2c_select_bus(int bus) -{ - if (bus > 0 && bus != currentI2cBus) { - syslog(LOG_NOTICE, "mraa_ftdi_ft4222_i2c_select_bus switching to bus %d", bus); - uint8_t data; - if (bus == 0) - data = 0; - else - data = 1 << (bus-1); - if (mraa_ftdi_ft4222_i2c_write_internal(ftHandleI2c, PCA9545_ADDR, &data, 1) == 1) - currentI2cBus = bus; - else - return MRAA_ERROR_UNSPECIFIED; - } - return MRAA_SUCCESS; -} - -static int -mraa_ftdi_ft4222_i2c_context_read(mraa_i2c_context dev, uint8_t* data, int length) -{ - int bytes_read = 0; - if (mraa_ftdi_ft4222_i2c_select_bus(dev->busnum) == MRAA_SUCCESS) - bytes_read = mraa_ftdi_ft4222_i2c_read_internal(dev->handle, dev->addr, data, length); - return bytes_read; -} - -static int -mraa_ftdi_ft4222_i2c_context_write(mraa_i2c_context dev, uint8_t* data, int length) -{ - int bytes_written = 0; - if (mraa_ftdi_ft4222_i2c_select_bus(dev->busnum) == MRAA_SUCCESS) - bytes_written = mraa_ftdi_ft4222_i2c_write_internal(dev->handle, dev->addr, data, length); - return bytes_written; -} - - - -/******************* I2C functions *******************/ - -static mraa_result_t -mraa_ftdi_ft4222_i2c_init_bus_replace(mraa_i2c_context dev) -{ - // Tell the FT4222 to be an I2C Master. - FT4222_STATUS ft4222Status = dl_FT4222_I2CMaster_Init(ftHandleI2c, bus_speed); - if (FT4222_OK != ft4222Status) { - syslog(LOG_ERR, "FT4222_I2CMaster_Init failed (error %d)!\n", ft4222Status); - return MRAA_ERROR_NO_RESOURCES; - } - - // Reset the I2CM registers to a known state. - ft4222Status = dl_FT4222_I2CMaster_Reset(ftHandleI2c); - if (FT4222_OK != ft4222Status) { - syslog(LOG_ERR, "FT4222_I2CMaster_Reset failed (error %d)!\n", ft4222Status); - return MRAA_ERROR_NO_RESOURCES; - } - - syslog(LOG_NOTICE, "I2C interface enabled GPIO0 and GPIO1 will be unavailable.\n"); - dev->handle = ftHandleI2c; - dev->fh = -1; // We don't use file descriptors - dev->funcs = I2C_FUNC_I2C; // Advertise minimal i2c support as per - // https://www.kernel.org/doc/Documentation/i2c/functionality - return MRAA_SUCCESS; -} - - -static mraa_result_t -mraa_ftdi_ft4222_i2c_frequency(mraa_i2c_context dev, mraa_i2c_mode_t mode) -{ - switch (mode) { - case MRAA_I2C_STD: /**< up to 100Khz */ - bus_speed = 100; - break; - MRAA_I2C_FAST: /**< up to 400Khz */ - bus_speed = 400; - break; - MRAA_I2C_HIGH: /**< up to 3.4Mhz */ - bus_speed = 3400; - break; - } - return dl_FT4222_I2CMaster_Init(ftHandleI2c, bus_speed) == FT4222_OK ? MRAA_SUCCESS : MRAA_ERROR_NO_RESOURCES; -} - - -static mraa_result_t -mraa_ftdi_ft4222_i2c_address(mraa_i2c_context dev, uint8_t addr) -{ - dev->addr = (int) addr; - return MRAA_SUCCESS; -} - - -static int -mraa_ftdi_ft4222_i2c_read(mraa_i2c_context dev, uint8_t* data, int length) -{ - pthread_mutex_lock(&ft4222_lock); - int bytes_read = mraa_ftdi_ft4222_i2c_read_internal(dev->handle, dev->addr, data, length); - pthread_mutex_unlock(&ft4222_lock); - return bytes_read; -} - -static int -mraa_ftdi_ft4222_i2c_read_byte(mraa_i2c_context dev) -{ - uint8_t data; - pthread_mutex_lock(&ft4222_lock); - int bytes_read = mraa_ftdi_ft4222_i2c_context_read(dev, &data, 1); - pthread_mutex_unlock(&ft4222_lock); - return bytes_read == 1 ? data : -1; -} - -static int -mraa_ftdi_ft4222_i2c_read_byte_data(mraa_i2c_context dev, uint8_t command) -{ - uint8_t data; - int bytes_read = 0; - pthread_mutex_lock(&ft4222_lock); - uint16 bytesWritten = mraa_ftdi_ft4222_i2c_context_write(dev, &command, 1); - if (bytesWritten == 1) - bytes_read = mraa_ftdi_ft4222_i2c_context_read(dev, &data, 1); - pthread_mutex_unlock(&ft4222_lock); - if (bytes_read == 1) { - return (int) data; - } - return -1; -} - -static int -mraa_ftdi_ft4222_i2c_read_word_data(mraa_i2c_context dev, uint8_t command) -{ - uint8_t buf[2]; - uint16_t data; - int bytes_read = 0; - pthread_mutex_lock(&ft4222_lock); - int bytes_written = mraa_ftdi_ft4222_i2c_context_write(dev, &command, 1); - if (bytes_written == 1) - bytes_read = mraa_ftdi_ft4222_i2c_context_read(dev, buf, 2); - pthread_mutex_unlock(&ft4222_lock); - if (bytes_read == 2) { - return (int) data; - } - return -1; -} - -static int -mraa_ftdi_ft4222_i2c_read_bytes_data(mraa_i2c_context dev, uint8_t command, uint8_t* data, int length) -{ - int bytes_read = 0; - pthread_mutex_lock(&ft4222_lock); - int bytes_written = mraa_ftdi_ft4222_i2c_context_write(dev, &command, 1); - if (bytes_written == 1) - bytes_read = mraa_ftdi_ft4222_i2c_context_read(dev, data, length); - pthread_mutex_unlock(&ft4222_lock); - return bytes_read; -} - -static mraa_result_t -mraa_ftdi_ft4222_i2c_write(mraa_i2c_context dev, const uint8_t* data, int bytesToWrite) -{ - pthread_mutex_lock(&ft4222_lock); - uint16 bytesWritten = mraa_ftdi_ft4222_i2c_context_write(dev, (uint8_t*)data, bytesToWrite); - pthread_mutex_unlock(&ft4222_lock); - return bytesToWrite == bytesWritten ? MRAA_SUCCESS : MRAA_ERROR_INVALID_HANDLE; -} - - -static mraa_result_t -mraa_ftdi_ft4222_i2c_write_byte(mraa_i2c_context dev, uint8_t data) -{ - mraa_result_t status = mraa_ftdi_ft4222_i2c_write(dev, &data, 1); - return status; -} - -static mraa_result_t -mraa_ftdi_ft4222_i2c_write_byte_data(mraa_i2c_context dev, const uint8_t data, const uint8_t command) -{ - uint8_t buf[2]; - buf[0] = command; - buf[1] = data; - mraa_result_t status = mraa_ftdi_ft4222_i2c_write(dev, buf, 2); - return status; -} - -static mraa_result_t -mraa_ftdi_ft4222_i2c_write_word_data(mraa_i2c_context dev, const uint16_t data, const uint8_t command) -{ - uint8_t buf[3]; - buf[0] = command; - buf[1] = (uint8_t) data; - buf[2] = (uint8_t)(data >> 8); - mraa_result_t status = mraa_ftdi_ft4222_i2c_write(dev, buf, 3); - return status; -} - -static mraa_result_t -mraa_ftdi_ft4222_i2c_stop(mraa_i2c_context dev) -{ - return MRAA_SUCCESS; -} - -/******************* GPIO functions *******************/ - -static mraa_result_t -mraa_ftdi_ft4222_gpio_init_internal_replace(mraa_gpio_context dev, int pin) -{ - dev->phy_pin = (pin < numFt4222GpioPins) ? pin : pin - numFt4222GpioPins; - if (pin < 2) { - syslog(LOG_NOTICE, "Closing I2C interface to enable GPIO%d\n", pin); - - /* Replace with call to SPI init when SPI is fully implemented */ - FT4222_STATUS ft4222Status = dl_FT4222_SPIMaster_Init(ftHandleSpi, SPI_IO_SINGLE, CLK_DIV_4, CLK_IDLE_HIGH, CLK_LEADING, 0x01); - if (FT4222_OK != ft4222Status){ - syslog(LOG_ERR, "Failed to close I2C interface and start SPI (error %d)!\n", ft4222Status); - return MRAA_ERROR_NO_RESOURCES; - } - } - return MRAA_SUCCESS; -} - -static mraa_result_t -mraa_ftdi_ft4222_gpio_mode_replace(mraa_gpio_context dev, mraa_gpio_mode_t mode) -{ - return MRAA_ERROR_FEATURE_NOT_IMPLEMENTED; -} - -static mraa_result_t -mraa_ftdi_ft4222_gpio_edge_mode_replace(mraa_gpio_context dev, mraa_gpio_edge_t mode) -{ - switch (mraa_ftdi_ft4222_get_gpio_type(dev->pin)) { - case GPIO_TYPE_BUILTIN: - switch (mode) { - case MRAA_GPIO_EDGE_NONE: - return ftdi_ft4222_set_internal_gpio_trigger(dev->pin, 0); - case MRAA_GPIO_EDGE_BOTH: - return ftdi_ft4222_set_internal_gpio_trigger(dev->pin, GPIO_TRIGGER_RISING | GPIO_TRIGGER_FALLING); - case MRAA_GPIO_EDGE_RISING: - return ftdi_ft4222_set_internal_gpio_trigger(dev->pin, GPIO_TRIGGER_RISING); - case MRAA_GPIO_EDGE_FALLING: - return ftdi_ft4222_set_internal_gpio_trigger(dev->pin, GPIO_TRIGGER_FALLING); - default: - return MRAA_ERROR_FEATURE_NOT_IMPLEMENTED; - } - break; - case GPIO_TYPE_PCA9672: - case GPIO_TYPE_PCA9555: - return MRAA_SUCCESS; - default: - return MRAA_ERROR_INVALID_RESOURCE; - } - -} - -static mraa_result_t -mraa_ftdi_ft4222_i2c_read_io_expander(uint16_t* value) -{ - int bytes_read = 0; - uint8_t reg = PCA9555_INPUT_REG; - pthread_mutex_lock(&ft4222_lock); - switch (gpio_expander_chip) { - case IO_EXP_PCA9672: - bytes_read = mraa_ftdi_ft4222_i2c_read_internal(ftHandleI2c, PCA9672_ADDR, (uint8_t*)value, 1); - break; - case GPIO_TYPE_PCA9555: - if (mraa_ftdi_ft4222_i2c_write_internal(ftHandleI2c, PCA9555_ADDR, ®, 1) == 1) - bytes_read = mraa_ftdi_ft4222_i2c_read_internal(ftHandleI2c, PCA9555_ADDR, (uint8_t*)value, 2); - break; - default:; - } - pthread_mutex_unlock(&ft4222_lock); - return bytes_read > 0 ? MRAA_SUCCESS : MRAA_ERROR_UNSPECIFIED; -} - -static int -mraa_ftdi_ft4222_gpio_read_replace(mraa_gpio_context dev) -{ - switch (mraa_ftdi_ft4222_get_gpio_type(dev->pin)) { - case GPIO_TYPE_BUILTIN: - { - BOOL value; - FT4222_STATUS ft4222Status = dl_FT4222_GPIO_Read(ftHandleGpio, dev->phy_pin, &value); - if (FT4222_OK != ft4222Status) { - syslog(LOG_ERR, "FT4222_GPIO_Read failed (error %d)!\n", ft4222Status); - return -1; - } - return value; - } - case GPIO_TYPE_PCA9672: - case GPIO_TYPE_PCA9555: - { - uint16_t mask = 1 << dev->phy_pin; - uint16_t value; - mraa_result_t res = mraa_ftdi_ft4222_i2c_read_io_expander(&value); - return res == MRAA_SUCCESS ? (value & mask) == mask : -1; - } - default: - return -1; - } -} - - -static mraa_result_t -mraa_ftdi_ft4222_gpio_write_replace(mraa_gpio_context dev, int write_value) -{ - switch (mraa_ftdi_ft4222_get_gpio_type(dev->pin)) { - case GPIO_TYPE_BUILTIN: - { - FT4222_STATUS ft4222Status = dl_FT4222_GPIO_Write(ftHandleGpio, dev->phy_pin, write_value); - if (FT4222_OK != ft4222Status) { - syslog(LOG_ERR, "FT4222_GPIO_Write failed (error %d)!\n", ft4222Status); - return MRAA_ERROR_UNSPECIFIED; - } - return MRAA_SUCCESS; - } - case GPIO_TYPE_PCA9672: - { - uint8_t mask = 1 << dev->phy_pin; - uint8_t value; - int bytes_written = 0; - pthread_mutex_lock(&ft4222_lock); - int bytes_read = mraa_ftdi_ft4222_i2c_read_internal(ftHandleI2c, PCA9672_ADDR, &value, 1); - if (bytes_read == 1) { - if (write_value == 1) - value = value | mask | pca9672DirectionMask; - else - value &= (~mask); - bytes_written = mraa_ftdi_ft4222_i2c_write_internal(ftHandleI2c, PCA9672_ADDR, &value, 1); - } - pthread_mutex_unlock(&ft4222_lock); - return bytes_written == 1 ? MRAA_SUCCESS : MRAA_ERROR_UNSPECIFIED; - } - case GPIO_TYPE_PCA9555: - { - uint16_t mask = 1 << dev->phy_pin; - if (write_value) - pca9555OutputValue |= mask; - else - pca9555OutputValue &= (~mask); - uint8_t buf[3]; - buf[0] = PCA9555_OUTPUT_REG; - buf[1] = (uint8_t)(pca9555OutputValue & 0xFF); - buf[2] = (uint8_t)(pca9555OutputValue >> 8); - pthread_mutex_lock(&ft4222_lock); - int bytes_written = mraa_ftdi_ft4222_i2c_write_internal(ftHandleI2c, PCA9555_ADDR, buf, sizeof(buf)); - pthread_mutex_unlock(&ft4222_lock); - return bytes_written == sizeof(buf) ? MRAA_SUCCESS : MRAA_ERROR_UNSPECIFIED; - } - default: - return MRAA_ERROR_INVALID_RESOURCE; - } -} - - -static mraa_result_t -mraa_ftdi_ft4222_gpio_dir_replace(mraa_gpio_context dev, mraa_gpio_dir_t dir) -{ - switch (mraa_ftdi_ft4222_get_gpio_type(dev->pin)) { - case GPIO_TYPE_BUILTIN: - switch (dir) { - case MRAA_GPIO_IN: - return ftdi_ft4222_set_internal_gpio_dir(dev->phy_pin, GPIO_INPUT); - case MRAA_GPIO_OUT: - return ftdi_ft4222_set_internal_gpio_dir(dev->phy_pin, GPIO_OUTPUT); - case MRAA_GPIO_OUT_HIGH: - if (ftdi_ft4222_set_internal_gpio_dir(dev->phy_pin, GPIO_OUTPUT) != MRAA_SUCCESS) - return MRAA_ERROR_UNSPECIFIED; - return mraa_ftdi_ft4222_gpio_write_replace(dev, 1); - case MRAA_GPIO_OUT_LOW: - if (ftdi_ft4222_set_internal_gpio_dir(dev->phy_pin, GPIO_OUTPUT) != MRAA_SUCCESS) - return MRAA_ERROR_UNSPECIFIED; - return mraa_ftdi_ft4222_gpio_write_replace(dev, 0); - default: - return MRAA_ERROR_INVALID_PARAMETER; - } - case GPIO_TYPE_PCA9672: - switch (dir) { - case MRAA_GPIO_IN: - case MRAA_GPIO_OUT: - return mraa_ftdi_ft4222_gpio_set_pca9672_dir(dev->phy_pin, dir); - case MRAA_GPIO_OUT_HIGH: - if (mraa_ftdi_ft4222_gpio_set_pca9672_dir(dev->phy_pin, dir) != MRAA_SUCCESS) - return MRAA_ERROR_UNSPECIFIED; - return mraa_ftdi_ft4222_gpio_write_replace(dev, 1); - case MRAA_GPIO_OUT_LOW: - if (mraa_ftdi_ft4222_gpio_set_pca9672_dir(dev->phy_pin, dir) != MRAA_SUCCESS) - return MRAA_ERROR_UNSPECIFIED; - return mraa_ftdi_ft4222_gpio_write_replace(dev, 0); - default: - return MRAA_ERROR_INVALID_PARAMETER; - } - case GPIO_TYPE_PCA9555: - switch (dir) { - case MRAA_GPIO_IN: - case MRAA_GPIO_OUT: - return mraa_ftdi_ft4222_gpio_set_pca9555_dir(dev->phy_pin, dir); - case MRAA_GPIO_OUT_HIGH: - if (mraa_ftdi_ft4222_gpio_set_pca9555_dir(dev->phy_pin, dir) != MRAA_SUCCESS) - return MRAA_ERROR_UNSPECIFIED; - return mraa_ftdi_ft4222_gpio_write_replace(dev, 1); - case MRAA_GPIO_OUT_LOW: - if (mraa_ftdi_ft4222_gpio_set_pca9555_dir(dev->phy_pin, dir) != MRAA_SUCCESS) - return MRAA_ERROR_UNSPECIFIED; - return mraa_ftdi_ft4222_gpio_write_replace(dev, 0); - default: - return MRAA_ERROR_INVALID_PARAMETER; - } - default: - return MRAA_ERROR_INVALID_RESOURCE; - } -} - -static mraa_boolean_t -mraa_ftdi_ft4222_has_internal_gpio_triggered(int pin) -{ - uint16 num_events = 0; - FT4222_STATUS ft4222Status = dl_FT4222_GPIO_GetTriggerStatus(ftHandleGpio, pin, &num_events); - if (num_events > 0) { - int i; - uint16 num_events_read; - GPIO_Trigger event; - for (i = 0; i < num_events; ++i) - dl_FT4222_GPIO_ReadTriggerQueue(ftHandleGpio, pin, &event, 1, &num_events_read); - return TRUE; - } else - return FALSE; -} - -static struct { - pthread_t thread; - pthread_mutex_t mutex; - mraa_boolean_t should_stop; - mraa_boolean_t is_interrupt_detected[MAX_IO_EXPANDER_PINS]; - int num_active_pins; -} gpio_monitor = {0}; - -// INT pin of i2c PCA9672 GPIO expander is connected to FT4222 GPIO #3 -// We use INT to detect any expander GPIO level change -static void* -mraa_ftdi_ft4222_gpio_monitor(void *arg) -{ - uint16_t prev_value = 0; - mraa_ftdi_ft4222_i2c_read_io_expander(&prev_value); - while (!gpio_monitor.should_stop) { - mraa_boolean_t gpio_activity_detected = mraa_ftdi_ft4222_has_internal_gpio_triggered(GPIO_PORT_IO_INT); - if (gpio_activity_detected) { - uint16_t value; - if (mraa_ftdi_ft4222_i2c_read_io_expander(&value) == MRAA_SUCCESS) { - uint16_t change_value = prev_value ^ value; - int i; - pthread_mutex_lock(&gpio_monitor.mutex); - for (i = 0; i < MAX_IO_EXPANDER_PINS; ++i) { - uint16_t mask = 1 << i; - gpio_monitor.is_interrupt_detected[i] = change_value & mask ? 1 : 0; - } - pthread_mutex_unlock(&gpio_monitor.mutex); - prev_value = value; - } - } - mraa_ftdi_ft4222_sleep_ms(20); - } -} - - -static void -mraa_ftdi_ft4222_gpio_monitor_add_pin(int pin) -{ - if (gpio_monitor.num_active_pins == 0) { - pthread_mutex_init(&gpio_monitor.mutex, NULL); - pthread_create(&gpio_monitor.thread, NULL, mraa_ftdi_ft4222_gpio_monitor, NULL); - } - pthread_mutex_lock(&gpio_monitor.mutex); - gpio_monitor.num_active_pins++; - pthread_mutex_unlock(&gpio_monitor.mutex); -} - - -static void -mraa_ftdi_ft4222_gpio_monitor_remove_pin(int pin) -{ - pthread_mutex_lock(&gpio_monitor.mutex); - gpio_monitor.num_active_pins--; - if (gpio_monitor.num_active_pins == 0) { - pthread_mutex_unlock(&gpio_monitor.mutex); - gpio_monitor.should_stop = TRUE; - pthread_join(gpio_monitor.thread, NULL); - pthread_mutex_destroy(&gpio_monitor.mutex); - } else - pthread_mutex_unlock(&gpio_monitor.mutex); -} - - -static mraa_boolean_t -mraa_ftdi_ft4222_gpio_monitor_is_interrupt_detected(int pin) -{ - mraa_boolean_t is_interrupt_detected = FALSE; - pthread_mutex_lock(&gpio_monitor.mutex); - if (gpio_monitor.is_interrupt_detected[pin]) { - gpio_monitor.is_interrupt_detected[pin] = FALSE; - is_interrupt_detected = TRUE; - } - pthread_mutex_unlock(&gpio_monitor.mutex); - return is_interrupt_detected; -} - -static mraa_result_t -mraa_ftdi_ft4222_gpio_interrupt_handler_init_replace(mraa_gpio_context dev) -{ - switch (mraa_ftdi_ft4222_get_gpio_type(dev->pin)) { - case GPIO_TYPE_BUILTIN: - mraa_ftdi_ft4222_has_internal_gpio_triggered(dev->phy_pin); - break; - case GPIO_TYPE_PCA9672: - case GPIO_TYPE_PCA9555: - ftdi_ft4222_set_internal_gpio_dir(GPIO_PORT_IO_INT, GPIO_INPUT); - ftdi_ft4222_set_internal_gpio_trigger(GPIO_PORT_IO_INT, GPIO_TRIGGER_FALLING); - mraa_ftdi_ft4222_has_internal_gpio_triggered(GPIO_PORT_IO_INT); - mraa_ftdi_ft4222_gpio_monitor_add_pin(dev->phy_pin); - break; - } - return MRAA_SUCCESS; -} - -static mraa_result_t -mraa_ftdi_ft4222_gpio_wait_interrupt_replace(mraa_gpio_context dev) -{ - int prev_level = mraa_ftdi_ft4222_gpio_read_replace(dev); - ft4222_gpio_type gpio_type = mraa_ftdi_ft4222_get_gpio_type(dev->pin); - mraa_boolean_t interrupt_detected = FALSE; - - while (!dev->isr_thread_terminating && !interrupt_detected) { - switch (gpio_type) { - case GPIO_TYPE_BUILTIN: - interrupt_detected = mraa_ftdi_ft4222_has_internal_gpio_triggered(dev->phy_pin); - break; - case GPIO_TYPE_PCA9672: - case GPIO_TYPE_PCA9555: - interrupt_detected = mraa_ftdi_ft4222_gpio_monitor_is_interrupt_detected(dev->phy_pin); - break; - default:; - } - if (!interrupt_detected) - mraa_ftdi_ft4222_sleep_ms(20); - } - if (dev->isr_thread_terminating) - mraa_ftdi_ft4222_gpio_monitor_remove_pin(dev->phy_pin); - return MRAA_SUCCESS; -} - -static void -mraa_ftdi_ft4222_populate_i2c_func_table(mraa_adv_func_t* func_table) -{ - func_table->i2c_init_bus_replace = &mraa_ftdi_ft4222_i2c_init_bus_replace; - func_table->i2c_set_frequency_replace = &mraa_ftdi_ft4222_i2c_frequency; - func_table->i2c_address_replace = &mraa_ftdi_ft4222_i2c_address; - func_table->i2c_read_replace = &mraa_ftdi_ft4222_i2c_read; - func_table->i2c_read_byte_replace = &mraa_ftdi_ft4222_i2c_read_byte; - func_table->i2c_read_byte_data_replace = &mraa_ftdi_ft4222_i2c_read_byte_data; - func_table->i2c_read_word_data_replace = &mraa_ftdi_ft4222_i2c_read_word_data; - func_table->i2c_read_bytes_data_replace = &mraa_ftdi_ft4222_i2c_read_bytes_data; - func_table->i2c_write_replace = &mraa_ftdi_ft4222_i2c_write; - func_table->i2c_write_byte_replace = &mraa_ftdi_ft4222_i2c_write_byte; - func_table->i2c_write_byte_data_replace = &mraa_ftdi_ft4222_i2c_write_byte_data; - func_table->i2c_write_word_data_replace = &mraa_ftdi_ft4222_i2c_write_word_data; - func_table->i2c_stop_replace = &mraa_ftdi_ft4222_i2c_stop; -} - -static void -mraa_ftdi_ft4222_populate_gpio_func_table(mraa_adv_func_t* func_table) -{ - func_table->gpio_init_internal_replace = &mraa_ftdi_ft4222_gpio_init_internal_replace; - func_table->gpio_mode_replace = &mraa_ftdi_ft4222_gpio_mode_replace; - func_table->gpio_edge_mode_replace = &mraa_ftdi_ft4222_gpio_edge_mode_replace; - func_table->gpio_dir_replace = &mraa_ftdi_ft4222_gpio_dir_replace; - func_table->gpio_read_replace = &mraa_ftdi_ft4222_gpio_read_replace; - func_table->gpio_write_replace = &mraa_ftdi_ft4222_gpio_write_replace; - func_table->gpio_interrupt_handler_init_replace = &mraa_ftdi_ft4222_gpio_interrupt_handler_init_replace; - func_table->gpio_wait_interrupt_replace = &mraa_ftdi_ft4222_gpio_wait_interrupt_replace; -} - - -mraa_board_t* -mraa_ftdi_ft4222() -{ - mraa_board_t* sub_plat = (mraa_board_t*) calloc(1, sizeof(mraa_board_t)); - if (sub_plat == NULL) - return NULL; - numI2cGpioExpanderPins = mraa_ftdi_ft4222_detect_io_expander(); - int pinIndex = 0; - int numUsbGpio = numFt4222GpioPins + numI2cGpioExpanderPins; - int numI2cBusses = 1 + mraa_ftdi_ft4222_detect_i2c_switch(); - int numUsbPins = numUsbGpio + 2 * (numI2cBusses-1); // Add SDA and SCL for each i2c switch bus - mraa_pincapabilities_t pinCapsI2c = (mraa_pincapabilities_t){ 1, 0, 0, 0, 0, 1, 0, 0 }; - mraa_pincapabilities_t pinCapsI2cGpio = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 1, 0, 0 }; - mraa_pincapabilities_t pinCapsGpio = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }; - - sub_plat->platform_name = PLATFORM_NAME; - sub_plat->phy_pin_count = numUsbPins; - sub_plat->gpio_count = numUsbGpio; - mraa_pininfo_t* pins = (mraa_pininfo_t*) calloc(numUsbPins,sizeof(mraa_pininfo_t)); - if (pins == NULL) { - return NULL; - } - sub_plat->pins = pins; - - int bus = 0; - sub_plat->i2c_bus_count = numI2cBusses; - sub_plat->def_i2c_bus = bus; - sub_plat->i2c_bus[bus].bus_id = bus; - - // I2c pins (these are virtual, entries are required to configure i2c layer) - // We currently assume that GPIO 0/1 are reserved for i2c operation - strncpy(sub_plat->pins[pinIndex].name, "IGPIO0/SCL0", MRAA_PIN_NAME_SIZE); - sub_plat->pins[pinIndex].capabilities = pinCapsI2cGpio; - sub_plat->pins[pinIndex].gpio.pinmap = pinIndex; - sub_plat->pins[pinIndex].gpio.mux_total = 0; - sub_plat->pins[pinIndex].i2c.mux_total = 0; - sub_plat->i2c_bus[bus].scl = pinIndex; - pinIndex++; - strncpy(sub_plat->pins[pinIndex].name, "IGPIO1/SDA0", MRAA_PIN_NAME_SIZE); - sub_plat->pins[pinIndex].capabilities = pinCapsI2cGpio; - sub_plat->pins[pinIndex].gpio.pinmap = pinIndex; - sub_plat->pins[pinIndex].gpio.mux_total = 0; - sub_plat->pins[pinIndex].i2c.mux_total = 0; - sub_plat->i2c_bus[bus].sda = pinIndex; - pinIndex++; - - // FTDI4222 gpio - strncpy(sub_plat->pins[pinIndex].name, "INT-GPIO2", MRAA_PIN_NAME_SIZE); - sub_plat->pins[pinIndex].capabilities = pinCapsGpio; - sub_plat->pins[pinIndex].gpio.pinmap = pinIndex; - sub_plat->pins[pinIndex].gpio.mux_total = 0; - pinIndex++; - strncpy(sub_plat->pins[pinIndex].name, "INT-GPIO3", MRAA_PIN_NAME_SIZE); - sub_plat->pins[pinIndex].capabilities = pinCapsGpio; - sub_plat->pins[pinIndex].gpio.pinmap = pinIndex; - sub_plat->pins[pinIndex].gpio.mux_total = 0; - pinIndex++; - - // Virtual gpio pins on i2c I/O expander. - int i; - for (i = 0; i < numI2cGpioExpanderPins; ++i) { - snprintf(sub_plat->pins[pinIndex].name, MRAA_PIN_NAME_SIZE, "EXP-GPIO%d", i); - sub_plat->pins[pinIndex].capabilities = pinCapsGpio; - sub_plat->pins[pinIndex].gpio.pinmap = pinIndex; - sub_plat->pins[pinIndex].gpio.mux_total = 0; - pinIndex++; - } - - // Now add any extra i2c busses behind i2c switch - for (bus = 1; bus < numI2cBusses; ++bus) { - sub_plat->i2c_bus[bus].bus_id = bus; - sub_plat->pins[pinIndex].i2c.mux_total = 0; - snprintf(sub_plat->pins[pinIndex].name, MRAA_PIN_NAME_SIZE, "SDA%d", bus); - sub_plat->pins[pinIndex].capabilities = pinCapsI2c; - sub_plat->i2c_bus[bus].sda = pinIndex; - pinIndex++; - snprintf(sub_plat->pins[pinIndex].name, MRAA_PIN_NAME_SIZE, "SCL%d", bus); - sub_plat->pins[pinIndex].capabilities = pinCapsI2c; - sub_plat->pins[pinIndex].i2c.mux_total = 0; - sub_plat->i2c_bus[bus].scl = pinIndex; - pinIndex++; - } - - // Set override functions - mraa_adv_func_t* func_table = (mraa_adv_func_t*) calloc(1, sizeof(mraa_adv_func_t)); - if (func_table == NULL) { - return NULL; - } - mraa_ftdi_ft4222_populate_i2c_func_table(func_table); - mraa_ftdi_ft4222_populate_gpio_func_table(func_table); - - sub_plat->adv_func = func_table; - - if (pthread_mutex_init(&ft4222_lock, NULL) != 0) { - syslog(LOG_ERR, "Could not create mutex for FT4222 access"); - return NULL; - } - - return sub_plat; -} - diff -Nru mraa-1.9.0/src/usb/usb.c mraa-2.0.0/src/usb/usb.c --- mraa-1.9.0/src/usb/usb.c 2018-02-15 23:08:49.000000000 +0000 +++ mraa-2.0.0/src/usb/usb.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,70 +0,0 @@ -/* - * Author: Henry Bruce - * Copyright (c) 2015 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 "mraa_internal.h" -#ifdef FTDI4222 -#include "usb/ftdi_ft4222.h" -#endif - - -mraa_platform_t -mraa_usb_platform_extender(mraa_board_t* board) -{ - mraa_board_t* sub_plat = NULL; - mraa_platform_t platform_type = MRAA_UNKNOWN_PLATFORM; - -#ifdef FTDI4222 - libft4222_lib = dlopen("libft4222.so", RTLD_LAZY); - if (!libft4222_lib) { - syslog(LOG_WARNING, "libft4222.so not found, skipping"); - } else { - if (mraa_ftdi_ft4222_init() == MRAA_SUCCESS) { - unsigned int versionChip, versionLib; - if (mraa_ftdi_ft4222_get_version(&versionChip, &versionLib) == MRAA_SUCCESS) { - // TODO: Add ft4222 version checks - platform_type = MRAA_FTDI_FT4222; - } - } - } -#endif - switch (platform_type) { -#ifdef FTDI4222 - case MRAA_FTDI_FT4222: - sub_plat = mraa_ftdi_ft4222(); - break; -#endif - default: - // this is not an error but more that we didn't find a USB platform extender we recognise - syslog(LOG_DEBUG, "Unknown USB Platform Extender, currently not supported by MRAA"); - } - - if (sub_plat != NULL) { - sub_plat->platform_type = platform_type; - board->sub_platform = sub_plat; - } - return platform_type; -} diff -Nru mraa-1.9.0/src/x86/iei_tank.c mraa-2.0.0/src/x86/iei_tank.c --- mraa-1.9.0/src/x86/iei_tank.c 1970-01-01 00:00:00.000000000 +0000 +++ mraa-2.0.0/src/x86/iei_tank.c 2018-09-06 12:34:41.000000000 +0000 @@ -0,0 +1,168 @@ +/* + * Author: Mihai Tudor Panu + * 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 "common.h" +#include "x86/iei_tank.h" + +#define PLATFORM_NAME "IEI Tank" + +mraa_board_t* +mraa_iei_tank() +{ + mraa_board_t* b = (mraa_board_t*) calloc(1, sizeof(mraa_board_t)); + if (b == NULL) { + return NULL; + } + + b->platform_name = PLATFORM_NAME; + b->phy_pin_count = MRAA_IEI_TANK_PINCOUNT; + b->chardev_capable = 1; + + b->adv_func = (mraa_adv_func_t*) calloc(1, sizeof(mraa_adv_func_t)); + if (b->adv_func == NULL) { + goto error; + } + + b->pins = (mraa_pininfo_t*) calloc(MRAA_IEI_TANK_PINCOUNT,sizeof(mraa_pininfo_t)); + if (b->pins == NULL) { + free(b->adv_func); + goto error; + } + + // Maps the DB9 DIO connector + strncpy(b->pins[0].name, "DIN0", 8); + b->pins[0].capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }; + b->pins[0].gpio.pinmap = 4; + b->pins[0].gpio.mux_total = 0; + b->pins[0].gpio.gpio_chip = 0; + b->pins[0].gpio.gpio_line = 4; + strncpy(b->pins[1].name, "DOUT0", 8); + b->pins[1].capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }; + b->pins[1].gpio.pinmap = 0; + b->pins[1].gpio.mux_total = 0; + b->pins[1].gpio.gpio_chip = 0; + b->pins[1].gpio.gpio_line = 0; + strncpy(b->pins[2].name, "DIN1", 8); + b->pins[2].capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }; + b->pins[2].gpio.pinmap = 11; + b->pins[2].gpio.mux_total = 0; + b->pins[2].gpio.gpio_chip = 1; + b->pins[2].gpio.gpio_line = 1; + strncpy(b->pins[3].name, "DOUT1", 8); + b->pins[3].capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }; + b->pins[3].gpio.pinmap = 1; + b->pins[3].gpio.mux_total = 0; + b->pins[3].gpio.gpio_chip = 0; + b->pins[3].gpio.gpio_line = 1; + strncpy(b->pins[4].name, "DIN2", 8); + b->pins[4].capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }; + b->pins[4].gpio.pinmap = 12; + b->pins[4].gpio.mux_total = 0; + b->pins[4].gpio.gpio_chip = 1; + b->pins[4].gpio.gpio_line = 2; + strncpy(b->pins[5].name, "DOUT2", 8); + b->pins[5].capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }; + b->pins[5].gpio.pinmap = 2; + b->pins[5].gpio.mux_total = 0; + b->pins[5].gpio.gpio_chip = 0; + b->pins[5].gpio.gpio_line = 2; + strncpy(b->pins[6].name, "DIN3", 8); + b->pins[6].capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }; + b->pins[6].gpio.pinmap = 13; + b->pins[6].gpio.mux_total = 0; + b->pins[6].gpio.gpio_chip = 1; + b->pins[6].gpio.gpio_line = 3; + strncpy(b->pins[7].name, "DOUT3", 8); + b->pins[7].capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }; + b->pins[7].gpio.pinmap = 3; + b->pins[7].gpio.mux_total = 0; + b->pins[7].gpio.gpio_chip = 0; + b->pins[7].gpio.gpio_line = 3; + strncpy(b->pins[8].name, "5V", 8); + b->pins[8].capabilities = (mraa_pincapabilities_t){ 1, 0, 0, 0, 0, 0, 0, 0 }; + + // Maps the 6 uart ports + b->uart_dev_count = 6; + b->def_uart_dev = 0; + if (mraa_find_uart_bus_pci("/sys/devices/pnp0/00:03/tty", + &(b->uart_dev[0].device_path)) != MRAA_SUCCESS) { + syslog(LOG_WARNING, "Unable to initialize COM1"); + b->uart_dev_count--; + } else { + b->uart_dev[0].name = "COM1"; + b->uart_dev[0].index = 0; + } + if (mraa_find_uart_bus_pci("/sys/devices/pnp0/00:04/tty", + &(b->uart_dev[1].device_path)) != MRAA_SUCCESS) { + syslog(LOG_WARNING, "Unable to initialize COM2"); + b->uart_dev_count--; + } else { + b->uart_dev[1].name = "COM2"; + b->uart_dev[1].index = 1; + } + if (mraa_find_uart_bus_pci("/sys/devices/pnp0/00:05/tty", + &(b->uart_dev[2].device_path)) != MRAA_SUCCESS) { + syslog(LOG_WARNING, "Unable to initialize COM3"); + b->uart_dev_count--; + } else { + b->uart_dev[2].name = "COM3"; + b->uart_dev[2].index = 2; + } + if (mraa_find_uart_bus_pci("/sys/devices/pnp0/00:06/tty", + &(b->uart_dev[3].device_path)) != MRAA_SUCCESS) { + syslog(LOG_WARNING, "Unable to initialize COM4"); + b->uart_dev_count--; + } else { + b->uart_dev[3].name = "COM4"; + b->uart_dev[3].index = 3; + } + if (mraa_find_uart_bus_pci("/sys/devices/pnp0/00:07/tty", + &(b->uart_dev[4].device_path)) != MRAA_SUCCESS) { + syslog(LOG_WARNING, "Unable to initialize COM5"); + b->uart_dev_count--; + } else { + b->uart_dev[4].name = "COM5"; + b->uart_dev[4].index = 4; + } + if (mraa_find_uart_bus_pci("/sys/devices/pnp0/00:08/tty", + &(b->uart_dev[5].device_path)) != MRAA_SUCCESS) { + syslog(LOG_WARNING, "Unable to initialize COM6"); + b->uart_dev_count--; + } else { + b->uart_dev[5].name = "COM6"; + b->uart_dev[5].index = 5; + } + + return b; +error: + syslog(LOG_CRIT, "iei-tank: Platform failed to initialize"); + free(b); + return NULL; +} diff -Nru mraa-1.9.0/src/x86/intel_joule_expansion.c mraa-2.0.0/src/x86/intel_joule_expansion.c --- mraa-1.9.0/src/x86/intel_joule_expansion.c 2018-02-15 23:08:49.000000000 +0000 +++ mraa-2.0.0/src/x86/intel_joule_expansion.c 2018-09-06 12:34:41.000000000 +0000 @@ -43,6 +43,7 @@ b->platform_name = PLATFORM_NAME; b->phy_pin_count = MRAA_INTEL_JOULE_EXPANSION_PINCOUNT; + b->chardev_capable = 1; b->aio_count = 0; b->adc_raw = 0; b->adc_supported = 0; @@ -160,12 +161,16 @@ b->pins[pos].capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }; b->pins[pos].gpio.pinmap = 451; b->pins[pos].gpio.mux_total = 0; + b->pins[pos].gpio.gpio_chip = 0; + b->pins[pos].gpio.gpio_line = 22; pos++; strncpy(b->pins[pos].name, "SPP1RX", 8); b->pins[pos].capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 1, 0, 0, 0 }; b->pins[pos].gpio.pinmap = 421; b->pins[pos].gpio.mux_total = 0; + b->pins[pos].gpio.gpio_chip = 1; + b->pins[pos].gpio.gpio_line = 64; pos++; strncpy(b->pins[pos].name, "PMICRST", 8); @@ -179,18 +184,24 @@ b->pins[pos].capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 1, 0, 0, 0 }; b->pins[pos].gpio.pinmap = 422; b->pins[pos].gpio.mux_total = 0; + b->pins[pos].gpio.gpio_chip = 1; + b->pins[pos].gpio.gpio_line = 65; pos++; strncpy(b->pins[pos].name, "19.2mhz", 8); b->pins[pos].capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }; b->pins[pos].gpio.pinmap = 356; b->pins[pos].gpio.mux_total = 0; + b->pins[pos].gpio.gpio_chip = 2; + b->pins[pos].gpio.gpio_line = 41; pos++; strncpy(b->pins[pos].name, "SPP1FS0", 8); b->pins[pos].capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 1, 0, 0, 0 }; b->pins[pos].gpio.pinmap = 417; b->pins[pos].gpio.mux_total = 0; + b->pins[pos].gpio.gpio_chip = 1; + b->pins[pos].gpio.gpio_line = 60; pos++; strncpy(b->pins[pos].name, "UART0TX", 8); @@ -200,12 +211,16 @@ b->pins[pos].uart.pinmap = 0; b->pins[pos].uart.parent_id = 0; b->pins[pos].uart.mux_total = 0; + b->pins[pos].gpio.gpio_chip = 0; + b->pins[pos].gpio.gpio_line = 39; pos++; strncpy(b->pins[pos].name, "SPP1FS2", 8); b->pins[pos].capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 1, 0, 0, 0 }; b->pins[pos].gpio.pinmap = 419; b->pins[pos].gpio.mux_total = 0; + b->pins[pos].gpio.gpio_chip = 1; + b->pins[pos].gpio.gpio_line = 62; pos++; strncpy(b->pins[pos].name, "PWRGD", 8); @@ -220,6 +235,8 @@ b->pins[pos].capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 1, 0, 0, 0 }; b->pins[pos].gpio.pinmap = 416; b->pins[pos].gpio.mux_total = 0; + b->pins[pos].gpio.gpio_chip = 1; + b->pins[pos].gpio.gpio_line = 59; pos++; strncpy(b->pins[pos].name, "I2C0SDA", 8); @@ -234,6 +251,8 @@ b->pins[pos].capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }; b->pins[pos].gpio.pinmap = 381; b->pins[pos].gpio.mux_total = 0; + b->pins[pos].gpio.gpio_chip = 1; + b->pins[pos].gpio.gpio_line = 24; pos++; strncpy(b->pins[pos].name, "I2C0SCL", 8); @@ -248,6 +267,10 @@ b->pins[pos].capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }; b->pins[pos].gpio.pinmap = 382; b->pins[pos].gpio.mux_total = 0; + b->pins[pos].gpio.gpio_chip = 1; + b->pins[pos].gpio.gpio_line = 24; + b->pins[pos].gpio.gpio_chip = 1; + b->pins[pos].gpio.gpio_line = 25; pos++; strncpy(b->pins[pos].name, "II0SDA", 8); @@ -262,6 +285,8 @@ b->pins[pos].capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }; b->pins[pos].gpio.pinmap = 380; b->pins[pos].gpio.mux_total = 0; + b->pins[pos].gpio.gpio_chip = 1; + b->pins[pos].gpio.gpio_line = 23; pos++; strncpy(b->pins[pos].name, "IIC0SCL", 8); @@ -276,6 +301,8 @@ b->pins[pos].capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }; b->pins[pos].gpio.pinmap = 379; b->pins[pos].gpio.mux_total = 0; + b->pins[pos].gpio.gpio_chip = 1; + b->pins[pos].gpio.gpio_line = 22; pos++; strncpy(b->pins[pos].name, "IIC1SDA", 8); @@ -291,6 +318,8 @@ b->pins[pos].capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }; b->pins[pos].gpio.pinmap = 378; b->pins[pos].gpio.mux_total = 0; + b->pins[pos].gpio.gpio_chip = 1; + b->pins[pos].gpio.gpio_line = 21; pos++; strncpy(b->pins[pos].name, "IIC1SCL", 8); @@ -308,12 +337,16 @@ b->pins[pos].uart.pinmap = 0; b->pins[pos].uart.parent_id = 0; b->pins[pos].uart.mux_total = 0; + b->pins[pos].gpio.gpio_chip = 0; + b->pins[pos].gpio.gpio_line = 43; pos++; strncpy(b->pins[pos].name, "ISH_IO6", 8); b->pins[pos].capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }; b->pins[pos].gpio.pinmap = 343; b->pins[pos].gpio.mux_total = 0; + b->pins[pos].gpio.gpio_chip = 2; + b->pins[pos].gpio.gpio_line = 28; pos++; strncpy(b->pins[pos].name, "UART1RX", 8); @@ -323,12 +356,16 @@ b->pins[pos].uart.pinmap = 0; b->pins[pos].uart.parent_id = 0; b->pins[pos].uart.mux_total = 0; + b->pins[pos].gpio.gpio_chip = 0; + b->pins[pos].gpio.gpio_line = 42; pos++; strncpy(b->pins[pos].name, "ISH_IO5", 8); b->pins[pos].capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }; b->pins[pos].gpio.pinmap = 342; b->pins[pos].gpio.mux_total = 0; + b->pins[pos].gpio.gpio_chip = 2; + b->pins[pos].gpio.gpio_line = 27; pos++; strncpy(b->pins[pos].name, "PWM0", 8); @@ -338,12 +375,16 @@ b->pins[pos].pwm.pinmap = 0; b->pins[pos].pwm.parent_id = 0; b->pins[pos].pwm.mux_total = 0; + b->pins[pos].gpio.gpio_chip = 0; + b->pins[pos].gpio.gpio_line = 34; pos++; strncpy(b->pins[pos].name, "ISH_IO4", 8); b->pins[pos].capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }; b->pins[pos].gpio.pinmap = 341; b->pins[pos].gpio.mux_total = 0; + b->pins[pos].gpio.gpio_chip = 2; + b->pins[pos].gpio.gpio_line = 26; pos++; strncpy(b->pins[pos].name, "PWM1", 8); @@ -353,6 +394,8 @@ b->pins[pos].pwm.pinmap = 1; b->pins[pos].pwm.parent_id = 0; b->pins[pos].pwm.mux_total = 0; + b->pins[pos].gpio.gpio_chip = 0; + b->pins[pos].gpio.gpio_line = 35; pos++; strncpy(b->pins[pos].name, "ISH_IO3", 8); @@ -360,6 +403,8 @@ // High level will be V1P8 - VBE on MBT3904D b->pins[pos].gpio.pinmap = 340; b->pins[pos].gpio.mux_total = 0; + b->pins[pos].gpio.gpio_chip = 2; + b->pins[pos].gpio.gpio_line = 25; pos++; // pin 30 @@ -370,6 +415,8 @@ b->pins[pos].pwm.pinmap = 2; b->pins[pos].pwm.parent_id = 0; b->pins[pos].pwm.mux_total = 0; + b->pins[pos].gpio.gpio_chip = 0; + b->pins[pos].gpio.gpio_line = 36; pos++; strncpy(b->pins[pos].name, "ISH_IO2", 8); @@ -377,6 +424,8 @@ // High level will be V1P8 - VBE on MBT3904D b->pins[pos].gpio.pinmap = 339; b->pins[pos].gpio.mux_total = 0; + b->pins[pos].gpio.gpio_chip = 2; + b->pins[pos].gpio.gpio_line = 24; pos++; strncpy(b->pins[pos].name, "PWM3", 8); @@ -386,6 +435,8 @@ b->pins[pos].pwm.pinmap = 3; b->pins[pos].pwm.parent_id = 0; b->pins[pos].pwm.mux_total = 0; + b->pins[pos].gpio.gpio_chip = 0; + b->pins[pos].gpio.gpio_line = 37; pos++; strncpy(b->pins[pos].name, "ISH_IO1", 8); @@ -393,6 +444,8 @@ // High level will be V1P8 - VBE on MBT3904D b->pins[pos].gpio.pinmap = 338; b->pins[pos].gpio.mux_total = 0; + b->pins[pos].gpio.gpio_chip = 2; + b->pins[pos].gpio.gpio_line = 23; pos++; strncpy(b->pins[pos].name, "1.8V", 8); @@ -404,6 +457,8 @@ // High level will be V1P8 - VBE on MBT3904D b->pins[pos].gpio.pinmap = 337; b->pins[pos].gpio.mux_total = 0; + b->pins[pos].gpio.gpio_chip = 2; + b->pins[pos].gpio.gpio_line = 22; pos++; strncpy(b->pins[pos].name, "GND", 8); @@ -473,6 +528,8 @@ b->pins[pos].capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }; b->pins[pos].gpio.pinmap = 456; b->pins[pos].gpio.mux_total = 0; + b->pins[pos].gpio.gpio_chip = 0; + b->pins[pos].gpio.gpio_line = 27; pos++; strncpy(b->pins[pos].name, "1.8V", 8); @@ -483,6 +540,8 @@ b->pins[pos].capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }; b->pins[pos].gpio.pinmap = 270; b->pins[pos].gpio.mux_total = 0; + b->pins[pos].gpio.gpio_chip = 4; + b->pins[pos].gpio.gpio_line = 6; pos++; strncpy(b->pins[pos].name, "GND", 8); @@ -493,6 +552,8 @@ b->pins[pos].capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }; b->pins[pos].gpio.pinmap = 271; b->pins[pos].gpio.mux_total = 0; + b->pins[pos].gpio.gpio_chip = 4; + b->pins[pos].gpio.gpio_line = 7; pos++; strncpy(b->pins[pos].name, "CAMERA", 8); @@ -503,6 +564,8 @@ b->pins[pos].capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }; b->pins[pos].gpio.pinmap = 272; b->pins[pos].gpio.mux_total = 0; + b->pins[pos].gpio.gpio_chip = 4; + b->pins[pos].gpio.gpio_line = 8; pos++; strncpy(b->pins[pos].name, "CAMERA", 8); @@ -513,6 +576,8 @@ b->pins[pos].capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 1, 0, 0, 0 }; b->pins[pos].gpio.pinmap = 411; b->pins[pos].gpio.mux_total = 0; + b->pins[pos].gpio.gpio_chip = 1; + b->pins[pos].gpio.gpio_line = 54; pos++; // pin 60 @@ -524,6 +589,8 @@ b->pins[pos].capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 1, 0, 0, 0 }; b->pins[pos].gpio.pinmap = 412; b->pins[pos].gpio.mux_total = 0; + b->pins[pos].gpio.gpio_chip = 1; + b->pins[pos].gpio.gpio_line = 55; pos++; strncpy(b->pins[pos].name, "SPI_DAT", 8); @@ -536,30 +603,40 @@ b->pins[pos].capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 1, 0, 0, 0 }; b->pins[pos].gpio.pinmap = 413; b->pins[pos].gpio.mux_total = 0; + b->pins[pos].gpio.gpio_chip = 1; + b->pins[pos].gpio.gpio_line = 56; pos++; strncpy(b->pins[pos].name, "SPICLKB", 8); b->pins[pos].capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }; b->pins[pos].gpio.pinmap = 384; b->pins[pos].gpio.mux_total = 0; + b->pins[pos].gpio.gpio_chip = 1; + b->pins[pos].gpio.gpio_line = 27; pos++; strncpy(b->pins[pos].name, "SPP0CLK", 8); b->pins[pos].capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 1, 0, 0, 0 }; b->pins[pos].gpio.pinmap = 410; b->pins[pos].gpio.mux_total = 0; + b->pins[pos].gpio.gpio_chip = 1; + b->pins[pos].gpio.gpio_line = 53; pos++; strncpy(b->pins[pos].name, "SPICLKA", 8); b->pins[pos].capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }; b->pins[pos].gpio.pinmap = 383; b->pins[pos].gpio.mux_total = 0; + b->pins[pos].gpio.gpio_chip = 1; + b->pins[pos].gpio.gpio_line = 26; pos++; strncpy(b->pins[pos].name, "SPP0TX", 8); b->pins[pos].capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 1, 0, 0, 0 }; b->pins[pos].gpio.pinmap = 414; b->pins[pos].gpio.mux_total = 0; + b->pins[pos].gpio.gpio_chip = 1; + b->pins[pos].gpio.gpio_line = 57; pos++; strncpy(b->pins[pos].name, "UART0RX", 8); @@ -569,12 +646,16 @@ b->pins[pos].uart.pinmap = 0; b->pins[pos].uart.parent_id = 0; b->pins[pos].uart.mux_total = 0; + b->pins[pos].gpio.gpio_chip = 0; + b->pins[pos].gpio.gpio_line = 38; pos++; strncpy(b->pins[pos].name, "SPP0RX", 8); b->pins[pos].capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 1, 0, 0, 0 }; b->pins[pos].gpio.pinmap = 415; b->pins[pos].gpio.mux_total = 0; + b->pins[pos].gpio.gpio_chip = 1; + b->pins[pos].gpio.gpio_line = 58; pos++; // pin 70 @@ -585,6 +666,8 @@ b->pins[pos].uart.pinmap = 0; b->pins[pos].uart.parent_id = 0; b->pins[pos].uart.mux_total = 0; + b->pins[pos].gpio.gpio_chip = 0; + b->pins[pos].gpio.gpio_line = 40; pos++; strncpy(b->pins[pos].name, "I2C1SDA", 8); @@ -602,6 +685,8 @@ b->pins[pos].uart.pinmap = 0; b->pins[pos].uart.parent_id = 0; b->pins[pos].uart.mux_total = 0; + b->pins[pos].gpio.gpio_chip = 0; + b->pins[pos].gpio.gpio_line = 41; pos++; strncpy(b->pins[pos].name, "I2C1SCL", 8); @@ -619,6 +704,8 @@ b->pins[pos].uart.pinmap = 0; b->pins[pos].uart.parent_id = 0; b->pins[pos].uart.mux_total = 0; + b->pins[pos].gpio.gpio_chip = 0; + b->pins[pos].gpio.gpio_line = 51; pos++; strncpy(b->pins[pos].name, "I2C2SDA", 8); @@ -636,6 +723,8 @@ b->pins[pos].uart.pinmap = 0; b->pins[pos].uart.parent_id = 0; b->pins[pos].uart.mux_total = 0; + b->pins[pos].gpio.gpio_chip = 0; + b->pins[pos].gpio.gpio_line = 50; pos++; strncpy(b->pins[pos].name, "I2C2SCL", 8); @@ -653,12 +742,16 @@ b->pins[pos].uart.pinmap = 0; b->pins[pos].uart.parent_id = 0; b->pins[pos].uart.mux_total = 0; + b->pins[pos].gpio.gpio_chip = 0; + b->pins[pos].gpio.gpio_line = 52; pos++; strncpy(b->pins[pos].name, "RTC_CLK", 8); b->pins[pos].capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }; b->pins[pos].gpio.pinmap = 367; b->pins[pos].gpio.mux_total = 0; + b->pins[pos].gpio.gpio_chip = 1; + b->pins[pos].gpio.gpio_line = 10; pos++; // pin 80 @@ -668,6 +761,8 @@ b->pins[pos].uart.pinmap = 0; b->pins[pos].uart.parent_id = 0; b->pins[pos].uart.mux_total = 0; + b->pins[pos].gpio.gpio_chip = 0; + b->pins[pos].gpio.gpio_line = 53; pos++; while (pos != 100) { @@ -679,24 +774,32 @@ b->pins[pos].capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }; b->pins[pos].gpio.pinmap = 337; b->pins[pos].gpio.mux_total = 0; + b->pins[pos].gpio.gpio_chip = 2; + b->pins[pos].gpio.gpio_line = 22; pos++; strncpy(b->pins[pos].name, "LED101", 8); b->pins[pos].capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }; b->pins[pos].gpio.pinmap = 338; b->pins[pos].gpio.mux_total = 0; + b->pins[pos].gpio.gpio_chip = 2; + b->pins[pos].gpio.gpio_line = 23; pos++; strncpy(b->pins[pos].name, "LED102", 8); b->pins[pos].capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }; b->pins[pos].gpio.pinmap = 339; b->pins[pos].gpio.mux_total = 0; + b->pins[pos].gpio.gpio_chip = 2; + b->pins[pos].gpio.gpio_line = 24; pos++; strncpy(b->pins[pos].name, "LED103", 8); b->pins[pos].capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }; b->pins[pos].gpio.pinmap = 340; b->pins[pos].gpio.mux_total = 0; + b->pins[pos].gpio.gpio_chip = 2; + b->pins[pos].gpio.gpio_line = 25; pos++; strncpy(b->pins[pos].name, "LEDBT", 8); @@ -711,6 +814,14 @@ b->pins[pos].gpio.mux_total = 0; pos++; + strncpy(b->pins[pos].name, "GPBTN", 8); + b->pins[pos].capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }; + b->pins[pos].gpio.pinmap = 446; + b->pins[pos].gpio.mux_total = 0; + b->pins[pos].gpio.gpio_chip = 0; + b->pins[pos].gpio.gpio_line = 17; + pos++; + return b; error: diff -Nru mraa-1.9.0/src/x86/intel_minnow_byt_compatible.c mraa-2.0.0/src/x86/intel_minnow_byt_compatible.c --- mraa-1.9.0/src/x86/intel_minnow_byt_compatible.c 2018-02-15 23:08:49.000000000 +0000 +++ mraa-2.0.0/src/x86/intel_minnow_byt_compatible.c 2018-09-06 12:34:41.000000000 +0000 @@ -38,7 +38,7 @@ int arch_nr_gpios_adjust = 0x100; mraa_result_t -mraa_intel_minnowboard_set_pininfo(mraa_board_t* board, int mraa_index, char* name, mraa_pincapabilities_t caps, int sysfs_pin) +mraa_intel_minnowboard_set_pininfo(mraa_board_t* board, int mraa_index, char* name, mraa_pincapabilities_t caps, int sysfs_pin, int chip, int line) { if (mraa_index < board->phy_pin_count) { // adjust mraa_index for ARCH_NR_GPIOS value @@ -48,6 +48,8 @@ if (caps.gpio) { pin_info->gpio.pinmap = sysfs_pin | arch_nr_gpios_adjust; pin_info->gpio.mux_total = 0; + pin_info->gpio.gpio_chip = chip; + pin_info->gpio.gpio_line = line; } if (caps.i2c) { pin_info->i2c.pinmap = 1; @@ -102,6 +104,7 @@ b->platform_version = "Ax"; b->gpio_count = b->phy_pin_count = MRAA_INTEL_MINNOW_MAX_PINCOUNT; } + b->chardev_capable = 1; b->pins = (mraa_pininfo_t*) calloc((size_t) b->phy_pin_count, sizeof(mraa_pininfo_t)); if (b->pins == NULL) { @@ -131,39 +134,39 @@ arch_nr_gpios_adjust = 0; } - mraa_intel_minnowboard_set_pininfo(b, 0, "INVALID", (mraa_pincapabilities_t){ 0, 0, 0, 0, 0, 0, 0, 0 }, -1); - mraa_intel_minnowboard_set_pininfo(b, 1, "GND", (mraa_pincapabilities_t){ 0, 0, 0, 0, 0, 0, 0, 0 }, -1); - mraa_intel_minnowboard_set_pininfo(b, 2, "GND", (mraa_pincapabilities_t){ 0, 0, 0, 0, 0, 0, 0, 0 }, -1); - mraa_intel_minnowboard_set_pininfo(b, 3, "5v", (mraa_pincapabilities_t){ 0, 0, 0, 0, 0, 0, 0, 0 }, -1); - mraa_intel_minnowboard_set_pininfo(b, 4, "3.3v", (mraa_pincapabilities_t){ 1, 0, 0, 0, 0, 0, 0, 0 }, -1); - mraa_intel_minnowboard_set_pininfo(b, 5, "SPI_CS", (mraa_pincapabilities_t){ 1, 0, 0, 0, 1, 0, 0, 0 }, 220); - mraa_intel_minnowboard_set_pininfo(b, 6, "UART1TX", (mraa_pincapabilities_t){ 1, 0, 0, 0, 0, 0, 0, 1 }, 225); - mraa_intel_minnowboard_set_pininfo(b, 7, "SPIMISO", (mraa_pincapabilities_t){ 1, 0, 0, 0, 1, 0, 0, 0 }, 221); - mraa_intel_minnowboard_set_pininfo(b, 8, "UART1RX", (mraa_pincapabilities_t){ 1, 0, 0, 0, 0, 0, 0, 1 }, 224); - mraa_intel_minnowboard_set_pininfo(b, 9, "SPIMOSI", (mraa_pincapabilities_t){ 1, 0, 0, 0, 1, 0, 0, 0 }, 222); - mraa_intel_minnowboard_set_pininfo(b, 10, "UART1CT", (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }, 227); - mraa_intel_minnowboard_set_pininfo(b, 11, "SPI_CLK", (mraa_pincapabilities_t){ 1, 0, 0, 0, 1, 0, 0, 0 }, 223); - mraa_intel_minnowboard_set_pininfo(b, 12, "UART1RT", (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }, 226); - mraa_intel_minnowboard_set_pininfo(b, 13, "I2C_SCL", (mraa_pincapabilities_t){ 1, 0, 0, 0, 0, 1, 0, 0 }, 243); - mraa_intel_minnowboard_set_pininfo(b, 14, "I2S_CLK", (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }, 216); - mraa_intel_minnowboard_set_pininfo(b, 15, "I2C_SDA", (mraa_pincapabilities_t){ 1, 0, 0, 0, 0, 1, 0, 0 }, 242); - mraa_intel_minnowboard_set_pininfo(b, 16, "I2S_FRM", (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }, 217); - mraa_intel_minnowboard_set_pininfo(b, 17, "UART2TX", (mraa_pincapabilities_t){ 1, 0, 0, 0, 0, 0, 0, 1 }, 229); - mraa_intel_minnowboard_set_pininfo(b, 18, "I2S_DO", (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }, 219); - mraa_intel_minnowboard_set_pininfo(b, 19, "UART2RX", (mraa_pincapabilities_t){ 1, 0, 0, 0, 0, 0, 0, 1 }, 228); - mraa_intel_minnowboard_set_pininfo(b, 20, "I2S_DI", (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }, 218); - mraa_intel_minnowboard_set_pininfo(b, 21, "S5_0", (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }, 82); + mraa_intel_minnowboard_set_pininfo(b, 0, "INVALID", (mraa_pincapabilities_t){ 0, 0, 0, 0, 0, 0, 0, 0 }, -1, -1, -1); + mraa_intel_minnowboard_set_pininfo(b, 1, "GND", (mraa_pincapabilities_t){ 0, 0, 0, 0, 0, 0, 0, 0 }, -1, -1, -1); + mraa_intel_minnowboard_set_pininfo(b, 2, "GND", (mraa_pincapabilities_t){ 0, 0, 0, 0, 0, 0, 0, 0 }, -1, -1, -1); + mraa_intel_minnowboard_set_pininfo(b, 3, "5v", (mraa_pincapabilities_t){ 0, 0, 0, 0, 0, 0, 0, 0 }, -1, -1, -1); + mraa_intel_minnowboard_set_pininfo(b, 4, "3.3v", (mraa_pincapabilities_t){ 0, 0, 0, 0, 0, 0, 0, 0 }, -1, -1, -1); + mraa_intel_minnowboard_set_pininfo(b, 5, "SPI_CS", (mraa_pincapabilities_t){ 1, 0, 0, 0, 1, 0, 0, 0 }, 220, 0, 66); + mraa_intel_minnowboard_set_pininfo(b, 6, "UART1TX", (mraa_pincapabilities_t){ 1, 0, 0, 0, 0, 0, 0, 1 }, 225, 0, 71); + mraa_intel_minnowboard_set_pininfo(b, 7, "SPIMISO", (mraa_pincapabilities_t){ 1, 0, 0, 0, 1, 0, 0, 0 }, 221, 0, 67); + mraa_intel_minnowboard_set_pininfo(b, 8, "UART1RX", (mraa_pincapabilities_t){ 1, 0, 0, 0, 0, 0, 0, 1 }, 224, 0, 70); + mraa_intel_minnowboard_set_pininfo(b, 9, "SPIMOSI", (mraa_pincapabilities_t){ 1, 0, 0, 0, 1, 0, 0, 0 }, 222, 0, 68); + mraa_intel_minnowboard_set_pininfo(b, 10, "UART1CT", (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }, 227, 0, 73); + mraa_intel_minnowboard_set_pininfo(b, 11, "SPI_CLK", (mraa_pincapabilities_t){ 1, 0, 0, 0, 1, 0, 0, 0 }, 223, 0, 69); + mraa_intel_minnowboard_set_pininfo(b, 12, "UART1RT", (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }, 226, 0, 72); + mraa_intel_minnowboard_set_pininfo(b, 13, "I2C_SCL", (mraa_pincapabilities_t){ 1, 0, 0, 0, 0, 1, 0, 0 }, 243, 0, 89); + mraa_intel_minnowboard_set_pininfo(b, 14, "I2S_CLK", (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }, 216, 0, 62); + mraa_intel_minnowboard_set_pininfo(b, 15, "I2C_SDA", (mraa_pincapabilities_t){ 1, 0, 0, 0, 0, 1, 0, 0 }, 242, 0, 88); + mraa_intel_minnowboard_set_pininfo(b, 16, "I2S_FRM", (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }, 217, 0, 63); + mraa_intel_minnowboard_set_pininfo(b, 17, "UART2TX", (mraa_pincapabilities_t){ 1, 0, 0, 0, 0, 0, 0, 1 }, 229, 0, 75); + mraa_intel_minnowboard_set_pininfo(b, 18, "I2S_DO", (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }, 219, 0, 65); + mraa_intel_minnowboard_set_pininfo(b, 19, "UART2RX", (mraa_pincapabilities_t){ 1, 0, 0, 0, 0, 0, 0, 1 }, 228, 0, 74); + mraa_intel_minnowboard_set_pininfo(b, 20, "I2S_DI", (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }, 218, 0, 64); + mraa_intel_minnowboard_set_pininfo(b, 21, "S5_0", (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }, 82, 2, 0); mraa_intel_minnowboard_set_pininfo(b, 22, "PWM0", (mraa_pincapabilities_t){ 1, 0, 1, 0, 0, 0, 0, 0 }, - 248); // Assume BIOS configured for PWM - mraa_intel_minnowboard_set_pininfo(b, 23, "S5_1", (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }, 83); + 248, 0, 94); // Assume BIOS configured for PWM + mraa_intel_minnowboard_set_pininfo(b, 23, "S5_1", (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }, 83, 2, 1); mraa_intel_minnowboard_set_pininfo(b, 24, "PWM1", (mraa_pincapabilities_t){ 1, 0, 1, 0, 0, 0, 0, 0 }, - 249); // Assume BIOS configured for PWM - mraa_intel_minnowboard_set_pininfo(b, 25, "S5_4", (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }, 84); + 249, 0, 95); // Assume BIOS configured for PWM + mraa_intel_minnowboard_set_pininfo(b, 25, "S5_4", (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }, 84, 2, 2); if (turbot) { - mraa_intel_minnowboard_set_pininfo(b, 26, "I2S_MCLK", (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }, 253); - mraa_intel_minnowboard_set_pininfo(b, 27, "S5_22", (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }, 104); + mraa_intel_minnowboard_set_pininfo(b, 26, "I2S_MCLK", (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }, 253, 0, 99); + mraa_intel_minnowboard_set_pininfo(b, 27, "D2_LED", (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }, 104, 2, 22); } else { - mraa_intel_minnowboard_set_pininfo(b, 26, "IBL8254", (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }, 208); + mraa_intel_minnowboard_set_pininfo(b, 26, "IBL8254", (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }, 208, 0, 54); } // Set number of i2c adaptors usable from userspace diff -Nru mraa-1.9.0/src/x86/up2.c mraa-2.0.0/src/x86/up2.c --- mraa-1.9.0/src/x86/up2.c 2018-02-15 23:08:49.000000000 +0000 +++ mraa-2.0.0/src/x86/up2.c 2018-09-06 12:34:41.000000000 +0000 @@ -53,7 +53,7 @@ // utility function to setup pin mapping of boards static mraa_result_t mraa_up2_set_pininfo(mraa_board_t* board, int mraa_index, char* name, - mraa_pincapabilities_t caps, int sysfs_pin) + mraa_pincapabilities_t caps, int sysfs_pin, int chip, int line) { if (mraa_index < board->phy_pin_count) { mraa_pininfo_t* pin_info = &board->pins[mraa_index]; @@ -62,6 +62,8 @@ if (caps.gpio) { pin_info->gpio.pinmap = sysfs_pin; pin_info->gpio.mux_total = 0; + pin_info->gpio.gpio_chip = chip; + pin_info->gpio.gpio_line = line; } if (caps.pwm) { pin_info->pwm.parent_id = 0; @@ -116,6 +118,7 @@ b->platform_version = PLATFORM_VERSION; b->phy_pin_count = MRAA_UP2_PINCOUNT; b->gpio_count = MRAA_UP2_GPIOCOUNT; + b->chardev_capable = 1; b->pins = (mraa_pininfo_t*) malloc(sizeof(mraa_pininfo_t) * MRAA_UP2_PINCOUNT); if (b->pins == NULL) { @@ -128,47 +131,47 @@ goto error; } - mraa_up2_set_pininfo(b, 0, "INVALID", (mraa_pincapabilities_t) {0, 0, 0, 0, 0, 0, 0, 0}, -1); - mraa_up2_set_pininfo(b, 1, "3.3v", (mraa_pincapabilities_t) {0, 0, 0, 0, 0, 0, 0, 0}, -1); - mraa_up2_set_pininfo(b, 2, "5v", (mraa_pincapabilities_t) {0, 0, 0, 0, 0, 0, 0, 0}, -1); - mraa_up2_set_pininfo(b, 3, "I2C_SDA", (mraa_pincapabilities_t) {1, 1, 0, 0, 0, 1, 0, 0}, MRAA_UP2_NORTH_BASE + 28); - mraa_up2_set_pininfo(b, 4, "5v", (mraa_pincapabilities_t) {0, 0, 0, 0, 0, 0, 0, 0}, -1); - mraa_up2_set_pininfo(b, 5, "I2C_SCL", (mraa_pincapabilities_t) {1, 1, 0, 0, 0, 1, 0, 0}, MRAA_UP2_NORTH_BASE + 29); - mraa_up2_set_pininfo(b, 6, "GND", (mraa_pincapabilities_t) {0, 0, 0, 0, 0, 0, 0, 0}, -1); - mraa_up2_set_pininfo(b, 7, "GPIO4", (mraa_pincapabilities_t) {1, 1, 0, 0, 0, 0, 0, 0}, MRAA_UP2_NORTHWEST_BASE + 76); - mraa_up2_set_pininfo(b, 8, "UART_TX", (mraa_pincapabilities_t) {1, 1, 0, 0, 0, 0, 0, 1}, MRAA_UP2_NORTH_BASE + 43); - mraa_up2_set_pininfo(b, 9, "GND", (mraa_pincapabilities_t) {0, 0, 0, 0, 0, 0, 0, 0}, -1); - mraa_up2_set_pininfo(b, 10, "UART_RX", (mraa_pincapabilities_t) {1, 1, 0, 0, 0, 0, 0, 1}, MRAA_UP2_NORTH_BASE + 42); - mraa_up2_set_pininfo(b, 11, "UART_RTS", (mraa_pincapabilities_t) {1, 1, 0, 0, 0, 0, 0, 1}, MRAA_UP2_NORTH_BASE + 44); - mraa_up2_set_pininfo(b, 12, "I2S_CLK", (mraa_pincapabilities_t) {1, 1, 0, 0, 0, 0, 0, 0}, MRAA_UP2_WEST_BASE + 16); - mraa_up2_set_pininfo(b, 13, "GPIO27", (mraa_pincapabilities_t) {1, 1, 0, 0, 0, 0, 0, 0}, MRAA_UP2_NORTHWEST_BASE + 75); - mraa_up2_set_pininfo(b, 14, "GND", (mraa_pincapabilities_t) {0, 0, 0, 0, 0, 0, 0, 0}, -1); - mraa_up2_set_pininfo(b, 15, "GPIO22", (mraa_pincapabilities_t) {1, 1, 0, 0, 0, 0, 0, 0}, MRAA_UP2_NORTHWEST_BASE + 74); - mraa_up2_set_pininfo(b, 16, "PWM3", (mraa_pincapabilities_t) {1, 1, 1, 0, 0, 0, 0, 0}, MRAA_UP2_NORTH_BASE + 37); - mraa_up2_set_pininfo(b, 17, "3.3v", (mraa_pincapabilities_t) {0, 0, 0, 0, 0, 0, 0, 0}, -1); - mraa_up2_set_pininfo(b, 18, "GPIO24", (mraa_pincapabilities_t) {1, 1, 0, 0, 0, 0, 0, 0}, MRAA_UP2_NORTHWEST_BASE + 48); - mraa_up2_set_pininfo(b, 19, "SPI0_MOSI", (mraa_pincapabilities_t) {1, 1, 0, 0, 1, 0, 0, 0}, MRAA_UP2_NORTHWEST_BASE + 65); - mraa_up2_set_pininfo(b, 20, "GND", (mraa_pincapabilities_t) {0, 0, 0, 0, 0, 0, 0, 0}, -1); - mraa_up2_set_pininfo(b, 21, "SPI0_MISO", (mraa_pincapabilities_t) {1, 1, 0, 0, 1, 0, 0, 0}, MRAA_UP2_NORTHWEST_BASE + 64); - mraa_up2_set_pininfo(b, 22, "GPIO25", (mraa_pincapabilities_t) {1, 1, 0, 0, 0, 0, 0, 0}, MRAA_UP2_NORTHWEST_BASE + 45); - mraa_up2_set_pininfo(b, 23, "SPI0_CLK", (mraa_pincapabilities_t) {1, 1, 0, 0, 1, 0, 0, 0}, MRAA_UP2_NORTHWEST_BASE + 61); - mraa_up2_set_pininfo(b, 24, "SPI0_CS0", (mraa_pincapabilities_t) {1, 1, 0, 0, 1, 0, 0, 0}, MRAA_UP2_NORTHWEST_BASE + 62); - mraa_up2_set_pininfo(b, 25, "GND", (mraa_pincapabilities_t) {0, 0, 0, 0, 0, 0, 0, 0}, -1); - mraa_up2_set_pininfo(b, 26, "SPI0_CS1", (mraa_pincapabilities_t) {1, 1, 0, 0, 1, 0, 0, 0}, MRAA_UP2_NORTHWEST_BASE + 63); - mraa_up2_set_pininfo(b, 27, "ID_SD", (mraa_pincapabilities_t) {1, 1, 0, 0, 0, 1, 0, 0}, MRAA_UP2_NORTH_BASE + 30); - mraa_up2_set_pininfo(b, 28, "ID_SC", (mraa_pincapabilities_t) {1, 1, 0, 0, 0, 1, 0, 0}, MRAA_UP2_NORTH_BASE + 31); - mraa_up2_set_pininfo(b, 29, "GPIO5", (mraa_pincapabilities_t) {1, 1, 0, 0, 0, 0, 0, 0}, MRAA_UP2_NORTHWEST_BASE + 73); - mraa_up2_set_pininfo(b, 30, "GND", (mraa_pincapabilities_t) {0, 0, 0, 0, 0, 0, 0, 0}, -1); - mraa_up2_set_pininfo(b, 31, "GPIO6", (mraa_pincapabilities_t) {1, 1, 0, 0, 0, 0, 0, 0}, MRAA_UP2_NORTHWEST_BASE + 47); - mraa_up2_set_pininfo(b, 32, "PWM0", (mraa_pincapabilities_t) {1, 1, 1, 0, 0, 0, 0, 0}, MRAA_UP2_NORTH_BASE + 34); - mraa_up2_set_pininfo(b, 33, "PWM1", (mraa_pincapabilities_t) {1, 1, 1, 0, 0, 0, 0, 0}, MRAA_UP2_NORTH_BASE + 35); - mraa_up2_set_pininfo(b, 34, "GND", (mraa_pincapabilities_t) {0, 0, 0, 0, 0, 0, 0, 0}, -1); - mraa_up2_set_pininfo(b, 35, "I2S_FRM", (mraa_pincapabilities_t) {1, 1, 0, 0, 0, 0, 0, 0}, MRAA_UP2_WEST_BASE + 17); - mraa_up2_set_pininfo(b, 36, "UART_CTS", (mraa_pincapabilities_t) {1, 1, 0, 0, 0, 0, 0, 1}, MRAA_UP2_NORTH_BASE + 45); - mraa_up2_set_pininfo(b, 37, "GPIO26", (mraa_pincapabilities_t) {1, 1, 0, 0, 0, 0, 0, 0}, MRAA_UP2_NORTHWEST_BASE + 46); - mraa_up2_set_pininfo(b, 38, "I2S_DIN", (mraa_pincapabilities_t) {1, 1, 0, 0, 0, 0, 0, 0}, MRAA_UP2_WEST_BASE + 18); - mraa_up2_set_pininfo(b, 39, "GND", (mraa_pincapabilities_t) {0, 0, 0, 0, 0, 0, 0, 0}, -1); - mraa_up2_set_pininfo(b, 40, "I2S_DOUT", (mraa_pincapabilities_t) {1, 1, 0, 0, 0, 0, 0, 0}, MRAA_UP2_WEST_BASE + 19); + mraa_up2_set_pininfo(b, 0, "INVALID", (mraa_pincapabilities_t) {0, 0, 0, 0, 0, 0, 0, 0}, -1, -1, -1); + mraa_up2_set_pininfo(b, 1, "3.3v", (mraa_pincapabilities_t) {0, 0, 0, 0, 0, 0, 0, 0}, -1, -1, -1); + mraa_up2_set_pininfo(b, 2, "5v", (mraa_pincapabilities_t) {0, 0, 0, 0, 0, 0, 0, 0}, -1, -1, -1); + mraa_up2_set_pininfo(b, 3, "I2C_SDA", (mraa_pincapabilities_t) {1, 1, 0, 0, 0, 1, 0, 0}, MRAA_UP2_NORTH_BASE + 28, 0, 28); + mraa_up2_set_pininfo(b, 4, "5v", (mraa_pincapabilities_t) {0, 0, 0, 0, 0, 0, 0, 0}, -1, -1, -1); + mraa_up2_set_pininfo(b, 5, "I2C_SCL", (mraa_pincapabilities_t) {1, 1, 0, 0, 0, 1, 0, 0}, MRAA_UP2_NORTH_BASE + 29, 0, 29); + mraa_up2_set_pininfo(b, 6, "GND", (mraa_pincapabilities_t) {0, 0, 0, 0, 0, 0, 0, 0}, -1, -1, -1); + mraa_up2_set_pininfo(b, 7, "GPIO4", (mraa_pincapabilities_t) {1, 1, 0, 0, 0, 0, 0, 0}, MRAA_UP2_NORTHWEST_BASE + 76, 1, 76); + mraa_up2_set_pininfo(b, 8, "UART_TX", (mraa_pincapabilities_t) {1, 1, 0, 0, 0, 0, 0, 1}, MRAA_UP2_NORTH_BASE + 43, 0, 43); + mraa_up2_set_pininfo(b, 9, "GND", (mraa_pincapabilities_t) {0, 0, 0, 0, 0, 0, 0, 0}, -1, -1, -1); + mraa_up2_set_pininfo(b, 10, "UART_RX", (mraa_pincapabilities_t) {1, 1, 0, 0, 0, 0, 0, 1}, MRAA_UP2_NORTH_BASE + 42, 0, 42); + mraa_up2_set_pininfo(b, 11, "UART_RTS", (mraa_pincapabilities_t) {1, 1, 0, 0, 0, 0, 0, 1}, MRAA_UP2_NORTH_BASE + 44, 0, 44); + mraa_up2_set_pininfo(b, 12, "I2S_CLK", (mraa_pincapabilities_t) {1, 1, 0, 0, 0, 0, 0, 0}, MRAA_UP2_WEST_BASE + 16, 2, 16); + mraa_up2_set_pininfo(b, 13, "GPIO27", (mraa_pincapabilities_t) {1, 1, 0, 0, 0, 0, 0, 0}, MRAA_UP2_NORTHWEST_BASE + 75, 1, 75); + mraa_up2_set_pininfo(b, 14, "GND", (mraa_pincapabilities_t) {0, 0, 0, 0, 0, 0, 0, 0}, -1, -1, -1); + mraa_up2_set_pininfo(b, 15, "GPIO22", (mraa_pincapabilities_t) {1, 1, 0, 0, 0, 0, 0, 0}, MRAA_UP2_NORTHWEST_BASE + 74, 1, 74); + mraa_up2_set_pininfo(b, 16, "PWM3", (mraa_pincapabilities_t) {1, 1, 1, 0, 0, 0, 0, 0}, MRAA_UP2_NORTH_BASE + 37, 0, 37); + mraa_up2_set_pininfo(b, 17, "3.3v", (mraa_pincapabilities_t) {0, 0, 0, 0, 0, 0, 0, 0}, -1, -1, -1); + mraa_up2_set_pininfo(b, 18, "GPIO24", (mraa_pincapabilities_t) {1, 1, 0, 0, 0, 0, 0, 0}, MRAA_UP2_NORTHWEST_BASE + 48, 1, 48); + mraa_up2_set_pininfo(b, 19, "SPI0_MOSI", (mraa_pincapabilities_t) {1, 1, 0, 0, 1, 0, 0, 0}, MRAA_UP2_NORTHWEST_BASE + 65, 1, 65); + mraa_up2_set_pininfo(b, 20, "GND", (mraa_pincapabilities_t) {0, 0, 0, 0, 0, 0, 0, 0}, -1, -1, -1); + mraa_up2_set_pininfo(b, 21, "SPI0_MISO", (mraa_pincapabilities_t) {1, 1, 0, 0, 1, 0, 0, 0}, MRAA_UP2_NORTHWEST_BASE + 64, 1, 64); + mraa_up2_set_pininfo(b, 22, "GPIO25", (mraa_pincapabilities_t) {1, 1, 0, 0, 0, 0, 0, 0}, MRAA_UP2_NORTHWEST_BASE + 45, 1, 45); + mraa_up2_set_pininfo(b, 23, "SPI0_CLK", (mraa_pincapabilities_t) {1, 1, 0, 0, 1, 0, 0, 0}, MRAA_UP2_NORTHWEST_BASE + 61, 1, 61); + mraa_up2_set_pininfo(b, 24, "SPI0_CS0", (mraa_pincapabilities_t) {1, 1, 0, 0, 1, 0, 0, 0}, MRAA_UP2_NORTHWEST_BASE + 62, 1, 62); + mraa_up2_set_pininfo(b, 25, "GND", (mraa_pincapabilities_t) {0, 0, 0, 0, 0, 0, 0, 0}, -1, -1, -1); + mraa_up2_set_pininfo(b, 26, "SPI0_CS1", (mraa_pincapabilities_t) {1, 1, 0, 0, 1, 0, 0, 0}, MRAA_UP2_NORTHWEST_BASE + 63, 1, 63); + mraa_up2_set_pininfo(b, 27, "ID_SD", (mraa_pincapabilities_t) {1, 1, 0, 0, 0, 1, 0, 0}, MRAA_UP2_NORTH_BASE + 30, 0, 30); + mraa_up2_set_pininfo(b, 28, "ID_SC", (mraa_pincapabilities_t) {1, 1, 0, 0, 0, 1, 0, 0}, MRAA_UP2_NORTH_BASE + 31, 0, 31); + mraa_up2_set_pininfo(b, 29, "GPIO5", (mraa_pincapabilities_t) {1, 1, 0, 0, 0, 0, 0, 0}, MRAA_UP2_NORTHWEST_BASE + 73, 1, 73); + mraa_up2_set_pininfo(b, 30, "GND", (mraa_pincapabilities_t) {0, 0, 0, 0, 0, 0, 0, 0}, -1, -1, -1); + mraa_up2_set_pininfo(b, 31, "GPIO6", (mraa_pincapabilities_t) {1, 1, 0, 0, 0, 0, 0, 0}, MRAA_UP2_NORTHWEST_BASE + 47, 1, 47); + mraa_up2_set_pininfo(b, 32, "PWM0", (mraa_pincapabilities_t) {1, 1, 1, 0, 0, 0, 0, 0}, MRAA_UP2_NORTH_BASE + 34, 0, 34); + mraa_up2_set_pininfo(b, 33, "PWM1", (mraa_pincapabilities_t) {1, 1, 1, 0, 0, 0, 0, 0}, MRAA_UP2_NORTH_BASE + 35, 0, 35); + mraa_up2_set_pininfo(b, 34, "GND", (mraa_pincapabilities_t) {0, 0, 0, 0, 0, 0, 0, 0}, -1, -1, -1); + mraa_up2_set_pininfo(b, 35, "I2S_FRM", (mraa_pincapabilities_t) {1, 1, 0, 0, 0, 0, 0, 0}, MRAA_UP2_WEST_BASE + 17, 2, 17); + mraa_up2_set_pininfo(b, 36, "UART_CTS", (mraa_pincapabilities_t) {1, 1, 0, 0, 0, 0, 0, 1}, MRAA_UP2_NORTH_BASE + 45, 0, 45); + mraa_up2_set_pininfo(b, 37, "GPIO26", (mraa_pincapabilities_t) {1, 1, 0, 0, 0, 0, 0, 0}, MRAA_UP2_NORTHWEST_BASE + 46, 1, 46); + mraa_up2_set_pininfo(b, 38, "I2S_DIN", (mraa_pincapabilities_t) {1, 1, 0, 0, 0, 0, 0, 0}, MRAA_UP2_WEST_BASE + 18, 2, 18); + mraa_up2_set_pininfo(b, 39, "GND", (mraa_pincapabilities_t) {0, 0, 0, 0, 0, 0, 0, 0}, -1, -1, -1); + mraa_up2_set_pininfo(b, 40, "I2S_DOUT", (mraa_pincapabilities_t) {1, 1, 0, 0, 0, 0, 0, 0}, MRAA_UP2_WEST_BASE + 19, 2, 19); b->i2c_bus_count = 0; b->def_i2c_bus = 0; @@ -239,7 +242,11 @@ // Configure UART b->uart_dev_count = 0; b->def_uart_dev = 0; - b->uart_dev[0].device_path = "/dev/ttyS1"; + // setting up a default path + if (mraa_find_uart_bus_pci("/sys/bus/pci/devices/0000:00:18.1/dw-apb-uart.9/tty/", + &(b->uart_dev[0].device_path)) != MRAA_SUCCESS) { + goto error; + } // Configure UART #1 (default) mraa_up2_get_pin_index(b, "UART_RX", &(b->uart_dev[0].rx)); diff -Nru mraa-1.9.0/src/x86/x86.c mraa-2.0.0/src/x86/x86.c --- mraa-1.9.0/src/x86/x86.c 2018-02-15 23:08:49.000000000 +0000 +++ mraa-2.0.0/src/x86/x86.c 2018-09-06 12:34:41.000000000 +0000 @@ -39,6 +39,7 @@ #include "x86/up.h" #include "x86/up2.h" #include "x86/intel_joule_expansion.h" +#include "x86/iei_tank.h" mraa_platform_t mraa_x86_platform() @@ -102,6 +103,9 @@ } else if (strncasecmp(line, "SDS", strlen("SDS") + 1) == 0) { platform_type = MRAA_INTEL_JOULE_EXPANSION; plat = mraa_joule_expansion_board(); + } else if ((strncasecmp(line, "SAF3", strlen("SAF3") + 1) == 0) ) { + platform_type = MRAA_IEI_TANK; + plat = mraa_iei_tank(); } else { syslog(LOG_ERR, "Platform not supported, not initialising"); platform_type = MRAA_UNKNOWN_PLATFORM; diff -Nru mraa-1.9.0/tests/CMakeLists.txt mraa-2.0.0/tests/CMakeLists.txt --- mraa-1.9.0/tests/CMakeLists.txt 2018-02-15 23:08:49.000000000 +0000 +++ mraa-2.0.0/tests/CMakeLists.txt 2018-09-06 12:34:41.000000000 +0000 @@ -36,3 +36,6 @@ message (STATUS "Could not run tests since python interpreter or python bindings not built") endif () endif () + +# Add mraa unit tests +add_subdirectory(unit) diff -Nru mraa-1.9.0/tests/unit/api/api_common_hpp_unit.cxx mraa-2.0.0/tests/unit/api/api_common_hpp_unit.cxx --- mraa-1.9.0/tests/unit/api/api_common_hpp_unit.cxx 1970-01-01 00:00:00.000000000 +0000 +++ mraa-2.0.0/tests/unit/api/api_common_hpp_unit.cxx 2018-09-06 12:34:41.000000000 +0000 @@ -0,0 +1,99 @@ +/* + * Author: Noel Eck + * 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 "gtest/gtest.h" +#include "mraa.hpp" + +/* MRAA API common test fixture */ +class api_common_hpp_unit : public ::testing::Test +{ + protected: + /* One-time setup logic if needed */ + api_common_hpp_unit() {} + + /* One-time tear-down logic if needed */ + virtual ~api_common_hpp_unit() {} + + /* Per-test setup logic if needed */ + virtual void SetUp() {} + + /* Per-test tear-down logic if needed */ + virtual void TearDown() {} +}; + +/* Test the C++ exposed common methods */ +TEST_F(api_common_hpp_unit, test_libmraa_common_methods) +{ + ASSERT_EQ(mraa::SUCCESS, mraa::init()); + + /* Test log level settings */ + for (int lvl = 0; lvl <= 7;lvl++) + ASSERT_EQ(mraa::SUCCESS, mraa::setLogLevel(lvl)) << "Set loglevel: " << lvl; + ASSERT_EQ(mraa::ERROR_INVALID_PARAMETER, mraa::setLogLevel(8)); + + /* Mock platform tests */ + if (mraa::getPlatformType() == mraa::MOCK_PLATFORM) + { + /* Pin 0 is a valid pin */ + ASSERT_TRUE(mraa::pinModeTest(0, mraa::PIN_VALID)); + + /* Pin 0 is a GPIO */ + ASSERT_TRUE(mraa::pinModeTest(0, mraa::PIN_GPIO)); + + /* Mock platform defaults to 12 bits */ + ASSERT_EQ(12, mraa::adcRawBits()); + + /* Raw bits get shifted to supported bits */ + ASSERT_EQ(10, mraa::adcSupportedBits()); + + /* Check the mock platform name */ + ASSERT_EQ("MRAA mock platform", mraa::getPlatformName()); + + /* No versioning for the mock platform */ + ASSERT_EQ("", mraa::getPlatformVersion(0)); + + /* Currently 10 pins in the mock platform */ + ASSERT_EQ(10, mraa::getPinCount()); + + /* Test the other pin/bus counts for the mock platform */ + /* Missing equivalent C++ methods */ + //EXPECT_EQ(1, mraa_get_aio_count()); + //EXPECT_EQ(1, mraa_get_gpio_count()); + EXPECT_EQ(1, mraa::getI2cBusCount()); + EXPECT_EQ(0, mraa::getI2cBusId(0)); + //EXPECT_EQ(0, mraa_get_pwm_count()); + //EXPECT_EQ(1, mraa_get_spi_bus_count()); + EXPECT_EQ(1, mraa::getUartCount()); + + /* Test pin to name method/s */ + ASSERT_EQ("GPIO0", mraa::getPinName(0)); + + /* Test the lookup method/s */ + ASSERT_EQ(0, mraa::getGpioLookup("GPIO0")); + + /* MOCK does NOT have a subplatform */ + ASSERT_FALSE(mraa::hasSubPlatform()); + } +} diff -Nru mraa-1.9.0/tests/unit/api/api_common_h_unit.cxx mraa-2.0.0/tests/unit/api/api_common_h_unit.cxx --- mraa-1.9.0/tests/unit/api/api_common_h_unit.cxx 1970-01-01 00:00:00.000000000 +0000 +++ mraa-2.0.0/tests/unit/api/api_common_h_unit.cxx 2018-09-06 12:34:41.000000000 +0000 @@ -0,0 +1,118 @@ +/* + * Author: Noel Eck + * 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 "gtest/gtest.h" +#include "mraa/common.h" +#include "include/mraa_internal_types.h" + +/* MRAA API common test fixture */ +class api_common_h_unit : public ::testing::Test +{ + protected: + /* One-time setup logic if needed */ + api_common_h_unit() {} + + /* One-time tear-down logic if needed */ + virtual ~api_common_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 mraa_init */ +TEST_F(api_common_h_unit, test_libmraa_init_doa) +{ + ASSERT_EQ(MRAA_SUCCESS, mraa_init()); +} + +/* Test for a basic mraa init/deinit */ +TEST_F(api_common_h_unit, test_libmraa_init_deinit) +{ + ASSERT_EQ(MRAA_SUCCESS, mraa_init()); + mraa_deinit(); +} + +/* Test the C exposed common methods */ +TEST_F(api_common_h_unit, test_libmraa_common_methods) +{ + ASSERT_EQ(MRAA_SUCCESS, mraa_init()); + + /* Test log level settings */ + for (int lvl = 0; lvl <= 7;lvl++) + ASSERT_EQ(MRAA_SUCCESS, mraa_set_log_level(lvl)) << "Set loglevel: " << lvl; + ASSERT_EQ(MRAA_ERROR_INVALID_PARAMETER, mraa_set_log_level(8)); + + /* Mock platform tests */ + if (mraa_get_platform_type() == MRAA_MOCK_PLATFORM) + { + /* Pin 0 is a valid pin */ + ASSERT_TRUE(mraa_pin_mode_test(0, MRAA_PIN_VALID)); + + /* Pin 0 is a GPIO */ + ASSERT_TRUE(mraa_pin_mode_test(0, MRAA_PIN_GPIO)); + + /* Mock platform defaults to 12 bits */ + ASSERT_EQ(12, mraa_adc_raw_bits()); + + /* Which better equal the bitsize for platform 0 */ + ASSERT_EQ(mraa_get_platform_adc_raw_bits(0), mraa_adc_raw_bits()); + + /* Raw bits get shifted to supported bits */ + ASSERT_EQ(10, mraa_adc_supported_bits()); + + /* Check the mock platform name */ + ASSERT_STREQ("MRAA mock platform", mraa_get_platform_name()); + + /* No versioning for the mock platform */ + ASSERT_STREQ(NULL, mraa_get_platform_version(0)); + + /* Currently 10 pins in the mock platform */ + ASSERT_EQ(10, mraa_get_pin_count()); + + /* Test the other pin/bus counts for the mock platform */ + EXPECT_EQ(1, mraa_get_aio_count()); + EXPECT_EQ(1, mraa_get_gpio_count()); + EXPECT_EQ(1, mraa_get_i2c_bus_count()); + EXPECT_EQ(0, mraa_get_i2c_bus_id(0)); + EXPECT_EQ(0, mraa_get_pwm_count()); + EXPECT_EQ(1, mraa_get_spi_bus_count()); + EXPECT_EQ(1, mraa_get_uart_count()); + + /* Test pin to name method/s */ + ASSERT_STREQ("GPIO0", mraa_get_pin_name(0)); + + /* Test the lookup method/s */ + ASSERT_EQ(0, mraa_gpio_lookup("GPIO0")); + + /* MOCK does NOT have a subplatform */ + ASSERT_FALSE(mraa_has_sub_platform()); + } + + /* Set the priority of this process */ + //EXPECT_EQ(40, mraa_set_priority(40)); +} diff -Nru mraa-1.9.0/tests/unit/api/mraa_initio_hpp_unit.cxx mraa-2.0.0/tests/unit/api/mraa_initio_hpp_unit.cxx --- mraa-1.9.0/tests/unit/api/mraa_initio_hpp_unit.cxx 1970-01-01 00:00:00.000000000 +0000 +++ mraa-2.0.0/tests/unit/api/mraa_initio_hpp_unit.cxx 2018-09-06 12:34:41.000000000 +0000 @@ -0,0 +1,47 @@ +/* + * 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.hpp" +#include "gtest/gtest.h" +#include +#include + + +/* MRAA IO INIT hpp test fixture */ +class mraa_initio_hpp_unit : public ::testing::Test +{ +}; + +/* Test for an invalid AIO init. */ +TEST_F(mraa_initio_hpp_unit, test_aio_init_invalid) +{ + ASSERT_THROW(mraa::MraaIo io("a:bogus:10"), std::runtime_error); +} + +/* Test for a valid AIO init. */ +TEST_F(mraa_initio_hpp_unit, test_aio_init_valid) +{ + mraa::MraaIo io("a:0:10"); + ASSERT_EQ(1, io.aios.size()); +} diff -Nru mraa-1.9.0/tests/unit/api/mraa_initio_h_unit.cxx mraa-2.0.0/tests/unit/api/mraa_initio_h_unit.cxx --- mraa-1.9.0/tests/unit/api/mraa_initio_h_unit.cxx 1970-01-01 00:00:00.000000000 +0000 +++ mraa-2.0.0/tests/unit/api/mraa_initio_h_unit.cxx 2018-09-06 12:34:41.000000000 +0000 @@ -0,0 +1,172 @@ +/* + * 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 +{ +}; + +/* Test for an invalid AIO init. */ +TEST_F(mraa_initio_h_unit, test_aio_init_invalid) +{ + mraa_io_descriptor* desc; + ASSERT_EQ(MRAA_ERROR_INVALID_HANDLE, mraa_io_init("a:bogus:10", &desc)); +} + +/* Test for a valid AIO init. */ +TEST_F(mraa_initio_h_unit, test_aio_init_valid) +{ + mraa_io_descriptor* desc; + ASSERT_EQ(MRAA_SUCCESS, mraa_io_init("a:0:10", &desc)); + ASSERT_EQ(MRAA_SUCCESS, mraa_io_close(desc)); +} + +/* Test for an invalid GPIO init. */ +TEST_F(mraa_initio_h_unit, test_gpio_init_invalid) +{ + mraa_io_descriptor* desc; + ASSERT_EQ(MRAA_ERROR_INVALID_HANDLE, mraa_io_init("g:0:34", &desc)); +} + +/* Test for a valid GPIO init. */ +TEST_F(mraa_initio_h_unit, test_gpio_init_valid) +{ + mraa_io_descriptor* desc; + ASSERT_EQ(MRAA_SUCCESS, mraa_io_init("g:0:1", &desc)); + ASSERT_EQ(MRAA_SUCCESS, mraa_io_close(desc)); +} + +/* 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); +} diff -Nru mraa-1.9.0/tests/unit/CMakeLists.txt mraa-2.0.0/tests/unit/CMakeLists.txt --- mraa-1.9.0/tests/unit/CMakeLists.txt 1970-01-01 00:00:00.000000000 +0000 +++ mraa-2.0.0/tests/unit/CMakeLists.txt 2018-09-06 12:34:41.000000000 +0000 @@ -0,0 +1,60 @@ +# Use the IN_LIST operator if available (for gtest) +if(POLICY CMP0057) + cmake_policy(SET CMP0057 NEW) +endif() + +# For now, Google Test is NOT required */ +find_package(GTest) + +# If not found, print a status message and return +if(NOT GTEST_FOUND) + message(STATUS "Install Google Test to enable additional unit testing") + return () +endif() + +# Unit tests - C common header methods +add_executable(test_unit_common_h api/api_common_h_unit.cxx) +target_link_libraries(test_unit_common_h ${GTEST_BOTH_LIBRARIES} mraa) +target_include_directories(test_unit_common_h + PRIVATE "${CMAKE_SOURCE_DIR}" "${CMAKE_SOURCE_DIR}/api" "${CMAKE_SOURCE_DIR}/api/mraa") +gtest_add_tests(test_unit_common_h "" api/api_common_h_unit.cxx) +list(APPEND GTEST_UNIT_TEST_TARGETS test_unit_common_h) + +# Unit tests - C++ common header methods +add_executable(test_unit_common_hpp api/api_common_hpp_unit.cxx) +target_link_libraries(test_unit_common_hpp ${GTEST_BOTH_LIBRARIES} mraa) +target_include_directories(test_unit_common_hpp PRIVATE "${CMAKE_SOURCE_DIR}/api") +gtest_add_tests(test_unit_common_hpp "" api/api_common_hpp_unit.cxx) +list(APPEND GTEST_UNIT_TEST_TARGETS test_unit_common_hpp) + +if (FTDI4222 AND USBPLAT) + # Unit tests - Test platform extenders (as much as possible) + add_executable(test_unit_ftdi4222 platform_extender/platform_extender.cxx) + target_link_libraries(test_unit_ftdi4222 ${GTEST_BOTH_LIBRARIES} mraa-platform-ft4222 dl) + target_include_directories(test_unit_ftdi4222 PRIVATE "${PROJECT_SOURCE_DIR}/api" + "${PROJECT_SOURCE_DIR}/api/mraa" + "${PROJECT_SOURCE_DIR}/include") + gtest_add_tests(test_unit_ftdi4222 "" platform_extender/platform_extender.cxx) + list(APPEND GTEST_UNIT_TEST_TARGETS test_unit_ftdi4222) +endif () + +# Unit tests - test C initio header methods on MOCK platform only +if (DETECTED_ARCH STREQUAL "MOCK") + add_executable(test_unit_ioinit_h api/mraa_initio_h_unit.cxx) + target_link_libraries(test_unit_ioinit_h ${GTEST_BOTH_LIBRARIES} mraa) + target_include_directories(test_unit_ioinit_h PRIVATE "${CMAKE_SOURCE_DIR}/api") + gtest_add_tests(test_unit_ioinit_h "" api/mraa_initio_h_unit.cxx) + list(APPEND GTEST_UNIT_TEST_TARGETS test_unit_ioinit_h) + + add_executable(test_unit_ioinit_hpp api/mraa_initio_hpp_unit.cxx) + target_link_libraries(test_unit_ioinit_hpp ${GTEST_BOTH_LIBRARIES} mraa) + target_include_directories(test_unit_ioinit_hpp PRIVATE "${CMAKE_SOURCE_DIR}/api") + gtest_add_tests(test_unit_ioinit_hpp "" api/mraa_initio_hpp_unit.cxx) + list(APPEND GTEST_UNIT_TEST_TARGETS test_unit_ioinit_hpp) + + # The initio C++ header requires c++11 + use_cxx_11(test_unit_ioinit_hpp) +endif() + +# Add a target for all unit tests +add_custom_target(test_unit_all ALL DEPENDS ${GTEST_UNIT_TEST_TARGETS}) diff -Nru mraa-1.9.0/tests/unit/platform_extender/platform_extender.cxx mraa-2.0.0/tests/unit/platform_extender/platform_extender.cxx --- mraa-1.9.0/tests/unit/platform_extender/platform_extender.cxx 1970-01-01 00:00:00.000000000 +0000 +++ mraa-2.0.0/tests/unit/platform_extender/platform_extender.cxx 2018-09-06 12:34:41.000000000 +0000 @@ -0,0 +1,56 @@ +/* + * Author: Noel Eck + * 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 "gtest/gtest.h" +#include "mraa/common.h" +#include "mraa_internal_types.h" + +/* MRAA test fixture */ +class plaform_extender : public ::testing::Test {}; + +/* Not much to test w/o hw - test a no-init case. + * Note, w/o a link to libmraa, this binary does NOT initialize mraa + * with the loader constructor attribute. This is intended. */ +TEST_F(plaform_extender, test_no_init) +{ + mraa_board_t plat = {}; + + void* usblib = dlopen("libmraa-platform-ft4222.so", RTLD_LAZY); + ASSERT_NE((void*)NULL, usblib) + << "Failed to load libmraa-platform-ft4222.so, reason (" << dlerror() + << ")"; + + fptr_add_platform_extender add_ft4222_platform = + (fptr_add_platform_extender)dlsym(usblib, "mraa_usb_platform_extender"); + + ASSERT_NE((void*)NULL, add_ft4222_platform) << "Symbol 'add_ft4222_platform' " + << "does not exist in libmraa-platform-ft4222.so"; + + ASSERT_EQ(MRAA_ERROR_PLATFORM_NOT_INITIALISED, add_ft4222_platform(&plat)) + << "Initialization returned a valid platform. Make sure no Ft4222 " + << "device is connected"; +} diff -Nru mraa-1.9.0/.travis.yml mraa-2.0.0/.travis.yml --- mraa-1.9.0/.travis.yml 2018-02-15 23:08:49.000000000 +0000 +++ mraa-2.0.0/.travis.yml 2018-09-06 12:34:41.000000000 +0000 @@ -14,9 +14,14 @@ jobs: fast_finish: true - allow_failures: - - env: TARGET=ipk include: + - &run-with-clang-minimal + stage: Clang 3.8 - minimal mock platform + env: TARGET=minimal + before_script: docker-compose pull ${TARGET} + script: + - export CC=clang-3.8 CXX=clang++-3.8 + - BUILDARCH=MOCK docker-compose run ${TARGET} - &run-with-clang stage: Clang 3.8 env: TARGET=python2 @@ -94,8 +99,4 @@ - <<: *run-additional-jobs env: TARGET=ftdi4442 - <<: *run-additional-jobs - env: TARGET=ipk - - <<: *run-additional-jobs - env: TARGET=rpm - - <<: *run-additional-jobs env: TARGET=sonar-scan