diff --git a/api/mraa/common.h b/api/mraa/common.h index c0467ba..290f758 100644 --- a/api/mraa/common.h +++ b/api/mraa/common.h @@ -44,6 +44,7 @@ if (res != MRAA_SUCCESS) \ return res;} while(0) + /** @file * * This file defines the basic shared values for libmraa @@ -306,6 +307,16 @@ mraa_result_t mraa_remove_subplatform(mraa_platform_t subplatformtype); */ void* mraa_init_io(const char* desc); +/** + * Instantiate an unknown board using a json file + * + * @param Path to the json file, relative to the folder the program + * was initially run in or a direct path + * + * @return mraa_result indicating success + */ +mraa_result_t mraa_init_json_platform(const char* path); + #ifdef __cplusplus } #endif diff --git a/api/mraa/common.hpp b/api/mraa/common.hpp index 29894d3..16fd21b 100644 --- a/api/mraa/common.hpp +++ b/api/mraa/common.hpp @@ -327,4 +327,18 @@ initIo(std::string desc) return new T(mraa_init_io(desc.c_str())); } +/** + * Instantiate an unknown board using a json file + * + * @param Path to the json file, relative to the folder the program + * was initially run in or a direct path + * + * @return Result indicating success + */ +inline Result +initJsonPlatform(std::string path) +{ + return (Result) mraa_init_json_platform(path.c_str()); +} + } diff --git a/include/mraa_internal.h b/include/mraa_internal.h index 05e42dc..b50e4ba 100644 --- a/include/mraa_internal.h +++ b/include/mraa_internal.h @@ -37,6 +37,7 @@ extern "C" { #include "mraa_lang_func.h" extern mraa_board_t* plat; +extern char* platform_name; extern mraa_iio_info_t* plat_iio; extern mraa_lang_func_t* lang_func; diff --git a/include/mraa_internal_types.h b/include/mraa_internal_types.h index 9e6d54b..1f914e7 100644 --- a/include/mraa_internal_types.h +++ b/include/mraa_internal_types.h @@ -40,6 +40,46 @@ #define MRAA_IO_SETUP_FAILURE -2 #define MRAA_NO_SUCH_IO -1 +// Json platform keys +#define INDEX_KEY "index" +#define NAME_KEY "name" +#define PIN_COUNT_KEY "pin_count" +#define GPIO_COUNT_KEY "gpio_count" +#define AIO_COUNT_KEY "aio_count" +#define SPI_COUNT_KEY "spi_count" +#define I2C_COUNT_KEY "i2c_count" +#define UART_COUNT_KEY "uart_count" +#define PWMDEFAULT_KEY "pwmDefPeriod" +#define PWMMAX_KEY "pwmMaxPeriod" +#define PWMMIN_KEY "pwmMinPeriod" +#define LABEL_KEY "label" +#define DEFAULT_KEY "default" +#define INVALID_KEY "invalid" +#define SCLPIN_KEY "sclpin" +#define SDAPIN_KEY "sdapin" +#define CHIP_ID_KEY "chipID" +#define RAW_PIN_KEY "rawpin" +#define RXPIN_KEY "rx" +#define TXPIN_KEY "tx" +#define UART_PATH_KEY "path" +#define CLOCK_KEY "clock" +#define MISO_KEY "miso" +#define MOSI_KEY "mosi" +#define CS_KEY "chipselect" +#define PIN_KEY "pin" +#define IO_KEY "layout" +#define PLATFORM_KEY "platform" + +// 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 MRAA_JSONPLAT_ENV_VAR "MRAA_JSON_PLATFORM" + #ifdef FIRMATA struct _firmata { /*@*/ diff --git a/src/json/jsonplatform.c b/src/json/jsonplatform.c new file mode 100644 index 0000000..bed3910 --- /dev/null +++ b/src/json/jsonplatform.c @@ -0,0 +1,716 @@ +/* + * Author: Houman Brinjcargorabi + * Copyright (c) 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. + */ + +#include +#include +#include +#include + + +#include +#include +#include + +#include "mraa_internal.h" + +typedef mraa_result_t (*init_plat_func_t)(json_object*, mraa_board_t*, int); + +mraa_result_t +mraa_init_json_platform_get_pin(json_object* jobj, const char* io, const char* key, int index, int* pin) +{ + json_object* jobj_temp = NULL; + if (json_object_object_get_ex(jobj, key, &jobj_temp)) { + if (!json_object_is_type(jobj_temp, json_type_int)) { + syslog(LOG_ERR, "init_json_platform: %s %s at position: %d is not an int", io, key, index); + return MRAA_ERROR_INVALID_RESOURCE; + } + *pin = (unsigned int) json_object_get_int(jobj_temp); + return MRAA_SUCCESS; + } + syslog(LOG_ERR, "init_json_platform: No %s specified for %s at position: %d", key, io, index); + return MRAA_ERROR_NO_DATA_AVAILABLE; +} + +mraa_result_t +mraa_init_json_platform_get_index(json_object* jobj, const char* io, const char* key, int index, int* pos, int upper) +{ + json_object* jobj_temp = NULL; + if (json_object_object_get_ex(jobj, key, &jobj_temp)) { + if (!json_object_is_type(jobj_temp, json_type_int)) { + syslog(LOG_ERR, "init_json_platform: %s index at position: %d not an int", io, index); + return MRAA_ERROR_INVALID_RESOURCE; + } + + *pos = (int) json_object_get_int(jobj_temp); + if (*pos < 0 || *pos > upper) { + syslog(LOG_ERR, + "init_json_platform: %s %s at position: %d, gave: %d which was out of range", io, + key, index, *pos); + return MRAA_ERROR_INVALID_RESOURCE; + } + return MRAA_SUCCESS; + } + syslog(LOG_ERR, "init_json_platform: An %s was not found for the %s", key, io); + return MRAA_ERROR_NO_DATA_AVAILABLE; +} + +mraa_result_t +mraa_init_json_platform_platform(json_object* jobj_platform, mraa_board_t* board, int index) +{ + json_object* jobj_temp = NULL; + const char* temp_string = NULL; + int temp_count = 0; + int length = 0; + mraa_result_t ret = MRAA_SUCCESS; + + // Set the platform name + if (json_object_object_get_ex(jobj_platform, NAME_KEY, &jobj_temp)) { + if (!json_object_is_type(jobj_temp, json_type_string)) { + syslog(LOG_ERR, "init_json_platform: Platform name not a string"); + return MRAA_ERROR_NO_RESOURCES; + } + temp_string = json_object_get_string(jobj_temp); + if (temp_string == NULL || (length = strlen(temp_string)) == 0) { + syslog(LOG_ERR, "init_json_platform: Empty string provided for \"%s\" key in platform", NAME_KEY); + return MRAA_ERROR_NO_DATA_AVAILABLE; + } + board->platform_name = (char*) calloc(length, sizeof(char)); + strncpy(board->platform_name, temp_string, length); + } else { + syslog(LOG_ERR, "init_json_platform: No \"%s\" key in platform", NAME_KEY); + return MRAA_ERROR_NO_DATA_AVAILABLE; + } + + // Get the physical pincount + ret = mraa_init_json_platform_get_pin(jobj_platform, PLATFORM_KEY, PIN_COUNT_KEY, index, + &(board->phy_pin_count)); + if (ret != MRAA_SUCCESS) { + return ret; + } + + // Setup the pins + board->pins = (mraa_pininfo_t*) calloc(board->phy_pin_count, sizeof(mraa_pininfo_t)); + if (board->pins == NULL) { + syslog(LOG_ERR, "init_json_platform: Unable to allocate space for the pins"); + return MRAA_ERROR_INVALID_RESOURCE; + } + + // set the inital counts to -1 so we know if they don't exist + board->gpio_count = -1; + board->aio_count = -1; + board->uart_dev_count = -1; + board->i2c_bus_count = -1; + board->spi_bus_count = -1; + + // Check to see if they've provided a GPIO count + ret = mraa_init_json_platform_get_index(jobj_platform, PLATFORM_KEY, GPIO_COUNT_KEY, index, + &(board->gpio_count), board->phy_pin_count); + if (ret != MRAA_SUCCESS && ret != MRAA_ERROR_NO_DATA_AVAILABLE) { + return ret; + } + + // Check to see if they've provided a AIO count + ret = mraa_init_json_platform_get_index(jobj_platform, PLATFORM_KEY, AIO_COUNT_KEY, index, + &(board->aio_count), board->phy_pin_count); + if (ret != MRAA_SUCCESS && ret != MRAA_ERROR_NO_DATA_AVAILABLE) { + return ret; + } + + // Check to see if they've provided a UART count + ret = mraa_init_json_platform_get_index(jobj_platform, PLATFORM_KEY, UART_COUNT_KEY, index, + &(board->uart_dev_count), 6); + if (ret != MRAA_SUCCESS && ret != MRAA_ERROR_NO_DATA_AVAILABLE) { + return ret; + } + // Check to see if they've provided a I2C count + ret = mraa_init_json_platform_get_index(jobj_platform, PLATFORM_KEY, I2C_COUNT_KEY, index, + &(board->i2c_bus_count), 12); + if (ret != MRAA_SUCCESS && ret != MRAA_ERROR_NO_DATA_AVAILABLE) { + return ret; + } + // Check to see if they've provided a SPI count + ret = mraa_init_json_platform_get_index(jobj_platform, PLATFORM_KEY, SPI_COUNT_KEY, index, + &(board->spi_bus_count), 12); + if (ret != MRAA_SUCCESS && ret != MRAA_ERROR_NO_DATA_AVAILABLE) { + return ret; + } + + // Set the PWM default numbers + board->pwm_default_period = -1; + board->pwm_max_period = -1; + board->pwm_min_period = -1; + + // Setup the PWM rates if they exist + ret = mraa_init_json_platform_get_pin(jobj_platform, PLATFORM_KEY, PWMDEFAULT_KEY, index, + &(board->pwm_default_period)); + if (ret != MRAA_SUCCESS && ret != MRAA_ERROR_NO_DATA_AVAILABLE) { + return ret; + } + ret = mraa_init_json_platform_get_pin(jobj_platform, PLATFORM_KEY, PWMMAX_KEY, index, + &(board->pwm_max_period)); + if (ret != MRAA_SUCCESS && ret != MRAA_ERROR_NO_DATA_AVAILABLE) { + return ret; + } + ret = mraa_init_json_platform_get_pin(jobj_platform, PLATFORM_KEY, PWMMIN_KEY, index, + &(board->pwm_min_period)); + if (ret != MRAA_SUCCESS && ret != MRAA_ERROR_NO_DATA_AVAILABLE) { + return ret; + } + + // A hacky logical xor to ensure the value's have all been set or none should have been set + // Here we infer that IF A != B and B != C then A == C since they're working on binary values + if (((board->pwm_default_period == -1) != (board->pwm_max_period == -1)) || + ((board->pwm_min_period == -1) != (board->pwm_max_period == -1))) { + syslog(LOG_ERR, "init_json_platform: One of more PWM settings missing in the platform" + "configuration"); + return MRAA_ERROR_INVALID_RESOURCE; + } + // Set our platform type + board->platform_type = MRAA_JSON_PLATFORM; + board->adv_func = (mraa_adv_func_t*) calloc(1, sizeof(mraa_adv_func_t)); + return MRAA_SUCCESS; +} + +mraa_result_t +mraa_init_json_platform_io(json_object* jobj_io, mraa_board_t* board, int index) +{ + const char* temp_string = NULL; + json_object* jobj_temp = NULL; + int pos = 0; + int invalid = 0; + pos = index; + + // set the label for the IO + if (json_object_object_get_ex(jobj_io, LABEL_KEY, &jobj_temp)) { + if (!json_object_is_type(jobj_temp, json_type_string)) { + syslog(LOG_ERR, "init_json_platform: IO label at position: %d not a string", index); + return MRAA_ERROR_NO_RESOURCES; + } + temp_string = json_object_get_string(jobj_temp); + // set the gpio label + strncpy(board->pins[pos].name, temp_string, 8); + } else { + syslog(LOG_ERR, "init_json_platform: No IO Label"); + return MRAA_ERROR_INVALID_RESOURCE; + } + if (json_object_object_get_ex(jobj_io, INVALID_KEY, &jobj_temp)) { + if (!json_object_is_type(jobj_temp, json_type_boolean)) { + syslog(LOG_ERR, "init_json_platform: Default I2C device key has an incorrect value"); + return MRAA_ERROR_INVALID_RESOURCE; + } + invalid = json_object_get_boolean(jobj_temp); + } + if (invalid) { + board->pins[pos].capabilites = (mraa_pincapabilities_t){ 0, 0, 0, 0, 0, 0, 0, 0 }; + } else { + board->pins[pos].capabilites = (mraa_pincapabilities_t){ 1, 0, 0, 0, 0, 0, 0, 0 }; + } + return MRAA_SUCCESS; +} + +mraa_result_t +mraa_init_json_platform_gpio(json_object* jobj_gpio, mraa_board_t* board, int index) +{ + int pos = 0; + mraa_result_t ret = MRAA_SUCCESS; + + // Get the gpio index + ret = mraa_init_json_platform_get_index(jobj_gpio, GPIO_KEY, INDEX_KEY, index, &pos, + board->phy_pin_count - 1); + if (ret != MRAA_SUCCESS) { + return ret; + } + // Get the gpio sysfs pin; + ret = mraa_init_json_platform_get_pin(jobj_gpio, GPIO_KEY, RAW_PIN_KEY, index, + &(board->pins[pos].gpio.pinmap)); + if (ret != MRAA_SUCCESS) { + return ret; + } + board->pins[pos].capabilites.gpio = 1; + return MRAA_SUCCESS; +} + +mraa_result_t +mraa_init_json_platform_aio(json_object* jobj_aio, mraa_board_t* board, int index) +{ + int pos = 0; + mraa_result_t ret = MRAA_SUCCESS; + + // Get the gpio index + ret = mraa_init_json_platform_get_index(jobj_aio, AIO_KEY, INDEX_KEY, index, &pos, board->phy_pin_count - 1); + if (ret != MRAA_SUCCESS) { + return ret; + } + + // Get the gpio sysfs pin; + ret = mraa_init_json_platform_get_pin(jobj_aio, AIO_KEY, RAW_PIN_KEY, index, + &(board->pins[pos].aio.pinmap)); + if (ret != MRAA_SUCCESS) { + return ret; + } + + board->pins[pos].capabilites.aio = 1; + return MRAA_SUCCESS; +} + +mraa_result_t +mraa_init_json_platform_i2c(json_object* jobj_i2c, mraa_board_t* board, int index) +{ + int pos = 0; + int pin = 0; + int sysfs_pin = 0; + mraa_result_t ret = MRAA_SUCCESS; + json_object* jobj_temp = NULL; + + // Get the I2C bus array index + ret = mraa_init_json_platform_get_index(jobj_i2c, I2C_KEY, INDEX_KEY, index, &pos, board->i2c_bus_count - 1); + if (ret != MRAA_SUCCESS) { + return ret; + } + // Get the sysfs pin + ret = mraa_init_json_platform_get_pin(jobj_i2c, I2C_KEY, RAW_PIN_KEY, index, &sysfs_pin); + if (ret != MRAA_SUCCESS) { + return ret; + } + // Setup the sda pin + ret = mraa_init_json_platform_get_index(jobj_i2c, I2C_KEY, SDAPIN_KEY, index, &pin, + board->phy_pin_count - 1); + if (ret == MRAA_ERROR_NO_DATA_AVAILABLE) { + board->i2c_bus[pos].sda = -1; + } else if (ret == MRAA_SUCCESS) { + board->pins[pin].capabilites.i2c = 1; + board->pins[pin].i2c.pinmap = sysfs_pin; + board->i2c_bus[pos].sda = pin; + } else { + return ret; + } + // Setup the scl pin + ret = mraa_init_json_platform_get_index(jobj_i2c, I2C_KEY, SCLPIN_KEY, index, &pin, + board->phy_pin_count - 1); + if (ret == MRAA_ERROR_NO_DATA_AVAILABLE) { + board->i2c_bus[pos].scl = -1; + } else if (ret == MRAA_SUCCESS) { + board->pins[pin].capabilites.i2c = 1; + board->pins[pin].i2c.pinmap = sysfs_pin; + board->i2c_bus[pos].scl = pin; + } else { + return ret; + } + + board->i2c_bus[pos].bus_id = pos; + + // check to see if this i2c is the default one + if (json_object_object_get_ex(jobj_i2c, DEFAULT_KEY, &jobj_temp)) { + if (!json_object_is_type(jobj_temp, json_type_boolean)) { + syslog(LOG_ERR, "init_json_platform: Default I2C device key has an incorrect value"); + return MRAA_ERROR_INVALID_RESOURCE; + } + if (json_object_get_boolean(jobj_temp)) { + board->def_i2c_bus = pos; + } + } + return MRAA_SUCCESS; +} + +mraa_result_t +mraa_init_json_platform_pwm(json_object* jobj_pwm, mraa_board_t* board, int index) +{ + int pos = 0; + int parent_id = 0; + int sysfs_pin = 0; + mraa_result_t ret = MRAA_SUCCESS; + + // Get the index into the physical pin array + ret = mraa_init_json_platform_get_index(jobj_pwm, PWM_KEY, INDEX_KEY, index, &pos, board->phy_pin_count - 1); + if (ret != MRAA_SUCCESS) { + return ret; + } + // Get the parent id + ret = mraa_init_json_platform_get_pin(jobj_pwm, PWM_KEY, CHIP_ID_KEY, index, &parent_id); + if (ret != MRAA_SUCCESS) { + return ret; + } + // Get the sysfs pin + ret = mraa_init_json_platform_get_pin(jobj_pwm, PWM_KEY, RAW_PIN_KEY, index, &sysfs_pin); + if (ret != MRAA_SUCCESS) { + return ret; + } + + board->pins[pos].capabilites.pwm = 1; + board->pins[pos].pwm.pinmap = sysfs_pin; + board->pins[pos].pwm.parent_id = parent_id; + return ret; +} + +mraa_result_t +mraa_init_json_platform_spi(json_object* jobj_spi, mraa_board_t* board, int index) +{ + int pos = 0; + int pin = 0; + int parent_id = 0; + json_object* jobj_temp = NULL; + mraa_result_t ret = MRAA_SUCCESS; + + // Get the index into the physical pin array + ret = mraa_init_json_platform_get_index(jobj_spi, SPI_KEY, INDEX_KEY, index, &pos, board->spi_bus_count - 1); + if (ret != MRAA_SUCCESS) { + return ret; + } + + // Get the parent id + ret = mraa_init_json_platform_get_pin(jobj_spi, SPI_KEY, CHIP_ID_KEY, index, &parent_id); + if (ret != MRAA_SUCCESS) { + return ret; + } + + // Setup the clock pin + ret = mraa_init_json_platform_get_index(jobj_spi, SPI_KEY, CLOCK_KEY, index, &pin, board->phy_pin_count - 1); + if (ret == MRAA_ERROR_NO_DATA_AVAILABLE) { + board->spi_bus[pos].sclk = -1; + } else if (ret == MRAA_SUCCESS) { + board->pins[pin].capabilites.spi = 1; + board->pins[pin].spi.parent_id = parent_id; + board->spi_bus[pos].sclk = pin; + } else { + return ret; + } + // Setup the MISO pin + ret = mraa_init_json_platform_get_index(jobj_spi, SPI_KEY, MISO_KEY, index, &pin, board->phy_pin_count - 1); + if (ret == MRAA_ERROR_NO_DATA_AVAILABLE) { + board->spi_bus[pos].miso = -1; + } else if (ret == MRAA_SUCCESS) { + board->pins[pin].capabilites.spi = 1; + board->pins[pin].spi.parent_id = parent_id; + board->spi_bus[pos].miso = pin; + } else { + return ret; + } + // Setup the MOSI pin + ret = mraa_init_json_platform_get_index(jobj_spi, SPI_KEY, MOSI_KEY, index, &pin, board->phy_pin_count - 1); + if (ret == MRAA_ERROR_NO_DATA_AVAILABLE) { + board->spi_bus[pos].mosi = -1; + } else if (ret == MRAA_SUCCESS) { + board->pins[pin].capabilites.spi = 1; + board->pins[pin].spi.parent_id = parent_id; + board->spi_bus[pos].mosi = pin; + } else { + return ret; + } + // Setup the CS pin + ret = mraa_init_json_platform_get_index(jobj_spi, SPI_KEY, CS_KEY, index, &pin, board->phy_pin_count - 1); + if (ret == MRAA_ERROR_NO_DATA_AVAILABLE) { + board->spi_bus[pos].cs = -1; + } else if (ret == MRAA_SUCCESS) { + board->pins[pin].capabilites.spi = 1; + board->pins[pin].spi.parent_id = parent_id; + board->spi_bus[pos].cs = pin; + } else { + return ret; + } + // check to see if this SPI is the default one + if (json_object_object_get_ex(jobj_spi, DEFAULT_KEY, &jobj_temp)) { + if (!json_object_is_type(jobj_temp, json_type_boolean)) { + syslog(LOG_ERR, "init_json_platform: Default I2C device key has an incorrect value"); + return MRAA_ERROR_INVALID_RESOURCE; + } + if (json_object_get_boolean(jobj_temp)) { + board->def_spi_bus = pos; + } + } + return ret; +} + +mraa_result_t +mraa_init_json_platform_uart(json_object* jobj_uart, mraa_board_t* board, int index) +{ + json_object* jobj_temp = NULL; + mraa_result_t ret = MRAA_SUCCESS; + int pos = 0; + int pin = 0; + int sysfs_pin = 0; + int parent_id = 0; + int length = 0; + const char* temp_string = NULL; + + // Get the index into the uart bus + ret = mraa_init_json_platform_get_index(jobj_uart, UART_KEY, INDEX_KEY, index, &pos, + board->uart_dev_count - 1); + if (ret != MRAA_SUCCESS) { + return ret; + } + + // Get the parent id + ret = mraa_init_json_platform_get_pin(jobj_uart, UART_KEY, CHIP_ID_KEY, index, &parent_id); + if (ret != MRAA_SUCCESS) { + return ret; + } + // Get the sysfs pin + ret = mraa_init_json_platform_get_pin(jobj_uart, UART_KEY, RAW_PIN_KEY, index, &sysfs_pin); + if (ret != MRAA_SUCCESS) { + return ret; + } + + // Setup the rx pin + ret = mraa_init_json_platform_get_index(jobj_uart, UART_KEY, RXPIN_KEY, index, &pin, + board->phy_pin_count - 1); + if (ret == MRAA_ERROR_NO_DATA_AVAILABLE) { + board->uart_dev[pos].rx = -1; + } else if (ret == MRAA_SUCCESS) { + board->pins[pin].capabilites.uart = 1; + board->pins[pin].uart.pinmap = sysfs_pin; + board->pins[pin].uart.parent_id = parent_id; + board->uart_dev[pos].rx = pin; + } else { + return ret; + } + + // Setup the TX pin + ret = mraa_init_json_platform_get_index(jobj_uart, UART_KEY, TXPIN_KEY, index, &pin, + board->phy_pin_count - 1); + if (ret == MRAA_ERROR_NO_DATA_AVAILABLE) { + board->uart_dev[pos].tx = -1; + } else if (ret == MRAA_SUCCESS) { + board->pins[pin].capabilites.uart = 1; + board->pins[pin].uart.pinmap = sysfs_pin; + board->pins[pin].uart.parent_id = parent_id; + board->uart_dev[pos].tx = pin; + } else { + return ret; + } + + // Setup the path + if (json_object_object_get_ex(jobj_uart, UART_PATH_KEY, &jobj_temp)) { + if (!json_object_is_type(jobj_temp, json_type_string)) { + syslog(LOG_ERR, "init_json_platform: UART Path at index: %d was not a string", index); + return MRAA_ERROR_NO_RESOURCES; + } + temp_string = json_object_get_string(jobj_temp); + if (temp_string == NULL || (length = strlen(temp_string)) == 0) { + syslog(LOG_ERR, "init_json_platform: UART Path at index: %d was empty", index); + return MRAA_ERROR_NO_DATA_AVAILABLE; + } + board->uart_dev[pos].device_path = (char*) calloc(length, sizeof(char)); + strncpy(board->uart_dev[pos].device_path, temp_string, length); + } else { + syslog(LOG_ERR, "init_json_platform: UART config at index: %d needs a path", index); + return MRAA_ERROR_NO_DATA_AVAILABLE; + } + + // If this element is supposed to be default set it. + if (json_object_object_get_ex(jobj_uart, DEFAULT_KEY, &jobj_temp)) { + if (!json_object_is_type(jobj_temp, json_type_boolean)) { + syslog(LOG_ERR, "init_json_platform: Default UART device key has an incorrect value"); + return MRAA_ERROR_INVALID_RESOURCE; + } + if (json_object_get_boolean(jobj_temp)) { + board->def_uart_dev = pos; + } + } + return MRAA_SUCCESS; +} + +mraa_result_t +mraa_init_json_platform_loop(json_object* jobj_platform, const char* obj_key, mraa_board_t* board, init_plat_func_t func) +{ + mraa_result_t ret = MRAA_SUCCESS; + int i = 0, array_length = 0; + json_object *jobj_temp = NULL, *jobj_io = NULL; + if (json_object_object_get_ex(jobj_platform, obj_key, &jobj_temp)) { + array_length = json_object_array_length(jobj_temp); + for (i = 0; i < array_length; i++) { + // Get the json object at position i + jobj_io = json_object_array_get_idx(jobj_temp, i); + // Check to see it's the right type + if (!json_object_is_type(jobj_io, json_type_object)) { + syslog(LOG_ERR, "init_json_platform: One of more of the elements in the \"%s\" " + "array where not JSON objects", + obj_key); + return MRAA_ERROR_INVALID_RESOURCE; + } + ret = (*func)(jobj_io, board, i); + if (ret != MRAA_SUCCESS) { + return ret; + } + } + } else { + syslog(LOG_ERR, "init_json_platform: No \"%s\" info found in json file", obj_key); + ret = MRAA_ERROR_NO_DATA_AVAILABLE; + } + return ret; +} + +mraa_result_t +mraa_init_json_platform_size_check(json_object* jobj_platform, + const char* obj_key, + mraa_board_t* board, + init_plat_func_t func, + int range) +{ + json_object* jobj_temp = NULL; + mraa_result_t ret = MRAA_SUCCESS; + int array_length = 0; + if (json_object_object_get_ex(jobj_platform, obj_key, &jobj_temp)) { + // Make sure the value for the key is an array + if (!json_object_is_type(jobj_temp, json_type_array)) { + syslog(LOG_ERR, "init_json_platform: json key \"%s\" should be an array", obj_key); + return MRAA_ERROR_INVALID_RESOURCE; + } + // make sure we don't have more than our range + array_length = json_object_array_length(jobj_temp); + if (array_length > range) { + syslog(LOG_ERR, + "init_json_platform: The size of the %s array given was %d, max was: %d", + obj_key, array_length, range); + return MRAA_ERROR_INVALID_RESOURCE; + } + ret = mraa_init_json_platform_loop(jobj_platform, obj_key, board, func); + if (ret != MRAA_SUCCESS) { + return ret; + } + return MRAA_SUCCESS; + } + syslog(LOG_NOTICE, "init_json_platform: %s wasn't found in the json file", obj_key); + return MRAA_ERROR_NO_DATA_AVAILABLE; +} + +mraa_result_t +mraa_init_json_platform(const char* platform_json) +{ + mraa_result_t ret = MRAA_SUCCESS; + char* buffer = NULL; + struct stat st; + int file_lock = 0, array_length = 0, i = 0; + json_object *jobj_platform = NULL, *jobj_temp = NULL; + mraa_board_t* board = NULL; + + // Try to lock the file for use + if ((file_lock = open(platform_json, O_RDONLY)) == -1) { + syslog(LOG_ERR, "init_json_platform: Failed to open platform file"); + return MRAA_ERROR_INVALID_RESOURCE; + } + + if (fstat(file_lock, &st) != 0 || (!S_ISREG(st.st_mode))) { + syslog(LOG_ERR, "init_json_platform: Failed to retrieve information about a file or the " + "file specified is not actually a file"); + close(file_lock); + return MRAA_ERROR_INVALID_RESOURCE; + } + + buffer = mmap(0, st.st_size, PROT_READ, MAP_SHARED, file_lock, 0); + close(file_lock); + if (buffer == MAP_FAILED) { + syslog(LOG_ERR, "init_json_platform: Failed to read platform file"); + return MRAA_ERROR_INVALID_RESOURCE; + } + + // Parse the json file + jobj_platform = json_tokener_parse(buffer); + // Allocate some memory for the board information + board = (mraa_board_t*) calloc(1, sizeof(mraa_board_t)); + if (board == NULL) { + munmap(buffer, st.st_size); + return MRAA_ERROR_INVALID_HANDLE; + } + + // Call our helper to go through and init our board for the "Platform" data + ret = mraa_init_json_platform_loop(jobj_platform, PLATFORM_KEY, board, mraa_init_json_platform_platform); + if (ret != MRAA_SUCCESS) { + goto unsuccessful; + } + + // Setup the IO's with their labels + ret = mraa_init_json_platform_size_check(jobj_platform, IO_KEY, board, + mraa_init_json_platform_io, board->phy_pin_count); + if (ret != MRAA_SUCCESS) { + goto unsuccessful; + } + + // Setup GPIO + ret = mraa_init_json_platform_size_check(jobj_platform, GPIO_KEY, board, + mraa_init_json_platform_gpio, board->phy_pin_count); + if (ret != MRAA_SUCCESS) { + goto unsuccessful; + } + + // Setup AIO + ret = mraa_init_json_platform_size_check(jobj_platform, AIO_KEY, board, + mraa_init_json_platform_aio, board->phy_pin_count); + if (ret != MRAA_SUCCESS && ret != MRAA_ERROR_NO_DATA_AVAILABLE) { + goto unsuccessful; + } + + // Setup SPI + ret = mraa_init_json_platform_size_check(jobj_platform, SPI_KEY, board, + mraa_init_json_platform_spi, board->spi_bus_count); + if (ret != MRAA_SUCCESS && ret != MRAA_ERROR_NO_DATA_AVAILABLE) { + goto unsuccessful; + } + + // Setup I2C + ret = mraa_init_json_platform_size_check(jobj_platform, I2C_KEY, board, + mraa_init_json_platform_i2c, board->i2c_bus_count); + if (ret != MRAA_SUCCESS && ret != MRAA_ERROR_NO_DATA_AVAILABLE) { + goto unsuccessful; + } + + // Setup UART + ret = mraa_init_json_platform_size_check(jobj_platform, UART_KEY, board, + mraa_init_json_platform_uart, board->uart_dev_count); + if (ret != MRAA_SUCCESS && ret != MRAA_ERROR_NO_DATA_AVAILABLE) { + for (i = 0; i < board->uart_dev_count; i++) { + if (board->uart_dev[i].device_path != NULL) { + free(plat->uart_dev[i].device_path); + } + } + goto unsuccessful; + } + + // Setup PWM + ret = mraa_init_json_platform_size_check(jobj_platform, PWM_KEY, board, + mraa_init_json_platform_pwm, board->phy_pin_count); + if (ret != MRAA_SUCCESS && ret != MRAA_ERROR_NO_DATA_AVAILABLE) { + goto unsuccessful; + } + + // Free the old empty platform + free(plat); + // Set the new one in it's place + plat = board; + platform_name = plat->platform_name; + + // We made it to the end without anything going wrong, just cleanup + ret = MRAA_SUCCESS; + syslog(LOG_NOTICE, "init_json_platform: Platform %s initialised via json", platform_name); + goto cleanup; + +unsuccessful: + free(board->platform_name); + free(board->pins); + free(board->adv_func); + free(board); +cleanup: + json_object_put(jobj_platform); + munmap(buffer, st.st_size); + return ret; +} diff --git a/src/mraa.c b/src/mraa.c index e42b734..e159b3f 100644 --- a/src/mraa.c +++ b/src/mraa.c @@ -40,9 +40,11 @@ #include #include #include +#include #include #include + #if defined(IMRAA) #include #include @@ -59,13 +61,14 @@ #include "spi.h" #include "uart.h" - #define IIO_DEVICE_WILDCARD "iio:device*" + + mraa_board_t* plat = NULL; mraa_iio_info_t* plat_iio = NULL; mraa_lang_func_t* lang_func = NULL; -static char* platform_name = NULL; +char* platform_name = NULL; static char* platform_long_name = NULL; static int num_i2c_devices = 0; @@ -99,7 +102,9 @@ imraa_init() if (plat != NULL) { return MRAA_SUCCESS; } - + char* env_var; + mraa_result_t ret; + mraa_platform_t platform_type = MRAA_NULL_PLATFORM; uid_t proc_euid = geteuid(); struct passwd* proc_user = getpwuid(proc_euid); @@ -113,19 +118,34 @@ imraa_init() syslog(LOG_NOTICE, "libmraa version %s initialised by user '%s' with EUID %d", mraa_get_version(), (proc_user != NULL) ? proc_user->pw_name : "", proc_euid); - mraa_platform_t platform_type; + // Check to see if the enviroment variable has been set + env_var = getenv(MRAA_JSONPLAT_ENV_VAR); + if (env_var != NULL) { + // We only care about success, the init will write to syslog if things went wrong + switch ((ret = mraa_init_json_platform(env_var))) { + case MRAA_SUCCESS: + platform_type = plat->platform_type; + break; + default: + syslog(LOG_NOTICE, "libmraa was unable to initialise a platform from json"); + } + } + + // Not an else because if the env var didn't load what we wanted maybe we can still load something + if (platform_type == MRAA_NULL_PLATFORM) { #if defined(X86PLAT) - // Use runtime x86 platform detection - platform_type = mraa_x86_platform(); + // Use runtime x86 platform detection + platform_type = mraa_x86_platform(); #elif defined(ARMPLAT) - // Use runtime ARM platform detection - platform_type = mraa_arm_platform(); + // Use runtime ARM platform detection + platform_type = mraa_arm_platform(); #elif defined(MOCKPLAT) - // Use mock platform - platform_type = mraa_mock_platform(); + // Use mock platform + platform_type = mraa_mock_platform(); #else #error mraa_ARCH NOTHING #endif + } if (plat != NULL) { plat->platform_type = platform_type; @@ -206,6 +226,7 @@ mraa_init() void mraa_deinit() { + int i = 0; if (plat != NULL) { if (plat->pins != NULL) { free(plat->pins); @@ -217,6 +238,19 @@ mraa_deinit() } free(sub_plat); } +#if defined(JSONPLAT) + if (plat->platform_type == MRAA_JSON_PLATFORM) { + // Free the platform name + free(plat->platform_name); + + // Free the UART device path + 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); } @@ -1235,3 +1269,12 @@ mraa_init_io(const char* desc) syslog(LOG_ERR, "mraa_init_io: Invalid IO type given."); return NULL; } + + +#ifndef JSONPLAT +mraa_result_t +mraa_init_json_platform(const char* desc) +{ + return MRAA_ERROR_FEATURE_NOT_SUPPORTED; +} +#endif