Private
Public Access
2
0

grovepi: grovepi subplatform support via i2c

Signed-off-by: Mihai Tudor Panu <mihai.tudor.panu@intel.com>
Signed-off-by: Brendan Le Foll <brendan.le.foll@intel.com>
This commit is contained in:
Mihai Tudor Panu
2017-09-11 07:49:57 -07:00
committed by Brendan Le Foll
parent c6b1b18a9d
commit cc55ee6314
11 changed files with 454 additions and 16 deletions

View File

@@ -50,6 +50,10 @@ USB
* [FT4222](../master/docs/ftdi_ft4222.md)
* [Firmata](../master/docs/firmata.md)
I2C
---
* [GrovePi](../master/docs/grovepi.md)
Mock
----
* [Generic simulated board](../master/docs/mock.md)

View File

@@ -360,11 +360,11 @@ int mraa_get_sub_platform_index(int pin_or_bus_id);
* Add mraa subplatform
*
* @param subplatformtype subplatform type
* @param uart_dev uart device subplatform is on
* @param dev uart device or i2c bus subplatform is on
*
* @return mraa_result_t indicating success
*/
mraa_result_t mraa_add_subplatform(mraa_platform_t subplatformtype, const char* uart_dev);
mraa_result_t mraa_add_subplatform(mraa_platform_t subplatformtype, const char* dev);
/**
* Remove a mraa subplatform

View File

@@ -412,14 +412,14 @@ getDefaultI2cBus(int platform_offset=MRAA_MAIN_PLATFORM_OFFSET)
* Add mraa subplatform
*
* @param subplatformtype the type of subplatform to add
* (e.g. MRAA_GENERIC_FIRMATA)
* @param uart_dev subplatform device string (e.g. "/dev/ttyACM0")
* (e.g. MRAA_GENERIC_FIRMATA or MRAA_GROVEPI)
* @param dev subplatform uart device string or i2c bus number (e.g. "/dev/ttyACM0" or "0")
* @return Result of operation
*/
inline Result
addSubplatform(Platform subplatformtype, std::string uart_dev)
addSubplatform(Platform subplatformtype, std::string dev)
{
return (Result) mraa_add_subplatform((mraa_platform_t) subplatformtype, uart_dev.c_str());
return (Result) mraa_add_subplatform((mraa_platform_t) subplatformtype, dev.c_str());
}
/**

View File

@@ -62,14 +62,14 @@ typedef enum {
MRAA_FTDI_FT4222 = 256, /**< FTDI FT4222 USB to i2c bridge */
// contains bit 9 so is subplatform
MRAA_GROVEPI = 1024, /**< GrovePi shield i2c bridge */
MRAA_GENERIC_FIRMATA = 1280, /**< Firmata uart platform/bridge */
MRAA_ANDROID_PERIPHERALMANAGER = 95, /**< Android Things peripheral manager platform */
MRAA_MOCK_PLATFORM = 96, /**< Mock platform, which requires no real hardware */
MRAA_JSON_PLATFORM = 97, /**< User initialised platform from json*/
MRAA_JSON_PLATFORM = 97, /**< User initialised platform from json */
MRAA_NULL_PLATFORM = 98, /**< Platform with no capabilities that hosts a sub platform */
MRAA_UNKNOWN_PLATFORM =
99 /**< An unknown platform type, typically will load INTEL_GALILEO_GEN1 */
MRAA_UNKNOWN_PLATFORM = 99 /**< An unknown platform type, typically will load INTEL_GALILEO_GEN1 */
} mraa_platform_t;
/**

View File

@@ -58,12 +58,12 @@ typedef enum {
FTDI_FT4222 = 256, /**< FTDI FT4222 USB to i2c bridge */
GROVEPI = 1024, /**< GrovePi shield i2c bridge */
GENERIC_FIRMATA = 1280, /**< Firmata uart platform/bridge */
ANDROID_PERIPHERALMANAGER = 95, /**< Android Things peripheral manager platform */
NULL_PLATFORM = 98,
UNKNOWN_PLATFORM =
99 /**< An unknown platform type, typically will load INTEL_GALILEO_GEN1 */
UNKNOWN_PLATFORM = 99 /**< An unknown platform type, typically will load INTEL_GALILEO_GEN1 */
} Platform;
/**

66
docs/grovepi.md Normal file
View File

@@ -0,0 +1,66 @@
GrovePi Shield {#grovepi}
=============================
Mraa can use a GrovePi shield as a subplatform. This means one can utilize the
shield IO as well as the IO on the carrier board. The GrovePi shield is meant
for RPi boards and compatibles such as UP and UP2. It provides convenient GrovePi
style connectors that can be used with various Grove sensors.
Communication with the shield is achieved over I2C using a custom firmware. It
provides access to extra GPIO, AIO and PWM pins.
### Using the subplatform API ###
Using the subplatform API is relatively simple, simply add '512', the platform
offset, to any IO calls.
Example:
* D3 becomes GPIO 512 + 3 = 515
* A2 becomes pin 512 + 2 = 514
Keep in mind that the I2C ports on the GrovePi shield are merely a level shifted
extension of the carrier board's I2C bus, hence I2C sensors do not require an
offset.
The API works from UPM or mraa in any of the supported languages and is compiled
with mraa by default. Multiple subplatforms are not yet supported.
### Pinout ###
For a complete diagram of the pins available on these shields please refer to
the hardware section of the [GrovePi Github repository](https://github.com/DexterInd/GrovePi).
### Simple code example ###
This piece of code fades an LED connected to D3 based on the position of a
rotary potentiometer on A2:
```c
#include <stdbool.h>
#include "mraa.h"
void main (int argc, char** argv)
{
mraa_add_subplatform(MRAA_GROVEPI, "0");
mraa_aio_context aio = mraa_aio_init(514);
mraa_pwm_context pwm = mraa_pwm_init(515);
while(true) {
mraa_pwm_write(pwm, mraa_aio_read(aio)/1023.0);
usleep(50000);
}
}
```
Note that the I2C bus number needs to be passed in as a string to
`mraa_add_subplatform`.
### Limitations & features to be added ###
Currently there is no support for ISRs or the option to query the shield's
firmware version, but these features may be added at a later point.
Theoretically GrovePi Zero shields are compatible too, however they were not
tested. Obviously, only a subset of the IO pins can be used due to the reduced
footprint of this shield.

47
include/grovepi/grovepi.h Normal file
View File

@@ -0,0 +1,47 @@
/*
* Author: Mihai Tudor Panu <mihai.tudor.panu@intel.com>
* Copyright (c) 2017 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 "i2c.h"
#include "mraa_internal.h"
#define GROVEPI_ADDRESS 0x04
#define GROVEPI_REGISTER 0x01
#define GROVEPI_GPIO_READ 0x01
#define GROVEPI_GPIO_WRITE 0x02
#define GROVEPI_AIO_READ 0x03
#define GROVEPI_PWM 0x04
#define GROVEPI_GPIO_MODE 0x05
#define GROVEPI_FIRMWARE 0x08
mraa_platform_t mraa_grovepi_platform(mraa_board_t* board, const int i2c_bus);
#ifdef __cplusplus
}
#endif

View File

@@ -4,6 +4,8 @@ set (mraa_LIB_INCLUDE_DIRS
${PROJECT_SOURCE_DIR}/include
)
add_subdirectory (grovepi)
if (FIRMATA)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DFIRMATA=1")
add_subdirectory (firmata)

View File

@@ -0,0 +1,4 @@
set (mraa_LIB_SRCS_NOAUTO ${mraa_LIB_SRCS_NOAUTO}
${PROJECT_SOURCE_DIR}/src/grovepi/grovepi.c
PARENT_SCOPE
)

296
src/grovepi/grovepi.c Normal file
View File

@@ -0,0 +1,296 @@
/*
* Author: Mihai Tudor Panu <mihai.tudor.panu@intel.com>
* Copyright (c) 2017 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 "grovepi/grovepi.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
static mraa_i2c_context grovepi_bus;
static int pwm_cache[10];
static int
mraa_grovepi_read_internal(int function, int pin)
{
uint8_t data[5];
uint8_t result[3];
data[0] = GROVEPI_REGISTER;
data[1] = function;
data[2] = pin;
data[3] = 0;
data[4] = 0;
if (mraa_i2c_write(grovepi_bus, data, 5) != MRAA_SUCCESS) {
syslog(LOG_WARNING, "grovepi: failed to write command to i2c bus /dev/i2c-%d", grovepi_bus->busnum);
return -1;
}
if (mraa_i2c_write_byte(grovepi_bus, 1) != MRAA_SUCCESS) {
syslog(LOG_WARNING, "grovepi: failed to write to i2c bus /dev/i2c-%d", grovepi_bus->busnum);
return -1;
}
if (function == GROVEPI_GPIO_READ) {
if (mraa_i2c_read(grovepi_bus, result, 1) != 1) {
syslog(LOG_WARNING, "grovepi: failed to read result from i2c bus /dev/i2c-%d", grovepi_bus->busnum);
return -1;
}
return result[0];
}
if (function == GROVEPI_AIO_READ) {
if (mraa_i2c_read(grovepi_bus, result, 3) != 3) {
syslog(LOG_WARNING, "grovepi: failed to read result from i2c bus /dev/i2c-%d", grovepi_bus->busnum);
return -1;
}
return (result[1] << 8) | result [2];
}
return -1;
}
static mraa_result_t
mraa_grovepi_write_internal(int function, int pin, int value)
{
uint8_t data[5];
data[0] = GROVEPI_REGISTER;
data[1] = function;
data[2] = pin;
data[3] = value;
data[4] = 0;
if (mraa_i2c_write(grovepi_bus, data, 5) != MRAA_SUCCESS) {
syslog(LOG_WARNING, "grovepi: failed to write command to i2c bus /dev/i2c-%d", grovepi_bus->busnum);
return MRAA_ERROR_UNSPECIFIED;
}
return MRAA_SUCCESS;
}
static mraa_result_t
mraa_grovepi_aio_init_internal_replace(mraa_aio_context dev, int aio)
{
dev->channel = aio;
return MRAA_SUCCESS;
}
static int
mraa_grovepi_aio_read_replace(mraa_aio_context dev)
{
return mraa_grovepi_read_internal(GROVEPI_AIO_READ, dev->channel);
}
static mraa_result_t
mraa_grovepi_gpio_init_internal_replace(mraa_gpio_context dev, int pin)
{
dev->pin = pin;
dev->phy_pin = pin;
return MRAA_SUCCESS;
}
static int
mraa_grovepi_gpio_read_replace(mraa_gpio_context dev)
{
return mraa_grovepi_read_internal(GROVEPI_GPIO_READ, dev->pin);
}
static mraa_result_t
mraa_grovepi_gpio_write_replace(mraa_gpio_context dev, int write_value)
{
return mraa_grovepi_write_internal(GROVEPI_GPIO_WRITE, dev->pin, write_value);
}
static mraa_result_t
mraa_grovepi_gpio_mode_replace(mraa_gpio_context dev, mraa_gpio_mode_t mode)
{
return MRAA_ERROR_FEATURE_NOT_IMPLEMENTED;
}
static mraa_result_t
mraa_grovepi_gpio_dir_replace(mraa_gpio_context dev, mraa_gpio_dir_t dir)
{
return MRAA_SUCCESS;
}
static mraa_result_t
mraa_grovepi_gpio_close_replace(mraa_gpio_context dev)
{
free(dev);
return MRAA_SUCCESS;
}
static mraa_pwm_context
mraa_grovepi_pwm_init_internal_replace(void* func_table, int pin)
{
mraa_pwm_context dev = (mraa_pwm_context) calloc(1, sizeof(struct _pwm));
if (dev == NULL) {
return NULL;
}
dev->pin = pin;
dev->chipid = 512;
dev->period = 2048000; // Locked, in ns
dev->advance_func = (mraa_adv_func_t*) func_table;
return dev;
}
static mraa_result_t
mraa_grovepi_pwm_write_replace(mraa_pwm_context dev, float percentage)
{
int value = (int)((percentage - 1) / 8000);
pwm_cache[dev->pin] = value;
return mraa_grovepi_write_internal(GROVEPI_PWM, dev->pin, value);
}
static float
mraa_grovepi_pwm_read_replace(mraa_pwm_context dev)
{
if (pwm_cache[dev->pin]) {
return (pwm_cache[dev->pin] + 1) * 8000;
}
return 0;
}
static mraa_result_t
mraa_grovepi_pwm_enable_replace(mraa_pwm_context dev, int enable)
{
if(!enable) {
return mraa_grovepi_write_internal(GROVEPI_GPIO_WRITE, dev->pin, 0);
} else {
return mraa_grovepi_write_internal(GROVEPI_PWM, dev->pin, pwm_cache[dev->pin]);
}
}
static mraa_result_t
mraa_grovepi_pwm_period_replace(mraa_pwm_context dev, int period)
{
syslog(LOG_WARNING, "You cannot set period of a PWM pin with GrovePi\n");
return MRAA_ERROR_FEATURE_NOT_IMPLEMENTED;
}
mraa_platform_t
mraa_grovepi_platform(mraa_board_t* board, const int i2c_bus)
{
mraa_board_t* b = (mraa_board_t*) calloc(1, sizeof(mraa_board_t));
if (b == NULL) {
return MRAA_NULL_PLATFORM;
}
grovepi_bus = mraa_i2c_init(i2c_bus);
if (grovepi_bus == NULL) {
syslog(LOG_WARNING, "grovepi: Failed to initialize i2c bus %d", i2c_bus);
free(b);
return MRAA_NULL_PLATFORM;
}
mraa_i2c_address(grovepi_bus, GROVEPI_ADDRESS);
b->platform_name = "grovepi";
b->platform_version = "1.2.7"; // TODO: add firmware query function
b->platform_type = MRAA_GROVEPI;
b->gpio_count = 10;
b->aio_count = 4;
b->adc_supported = 10;
b->phy_pin_count = 14;
b->pwm_min_period = 2048;
b->pwm_max_period = 2048;
b->pins = (mraa_pininfo_t*) calloc(b->phy_pin_count, sizeof(mraa_pininfo_t));
if (b->pins == NULL) {
free(b);
return MRAA_NULL_PLATFORM;
}
strncpy(b->pins[0].name, "IO0", 8);
b->pins[0].capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 };
b->pins[0].gpio.pinmap = 0;
strncpy(b->pins[1].name, "IO1", 8);
b->pins[1].capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 };
b->pins[1].gpio.pinmap = 1;
strncpy(b->pins[2].name, "IO2", 8);
b->pins[2].capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 };
b->pins[2].gpio.pinmap = 2;
strncpy(b->pins[3].name, "IO3", 8);
b->pins[3].capabilities = (mraa_pincapabilities_t){ 1, 1, 1, 0, 0, 0, 0, 0 };
b->pins[3].gpio.pinmap = 3;
strncpy(b->pins[4].name, "IO4", 8);
b->pins[4].capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 };
b->pins[4].gpio.pinmap = 4;
strncpy(b->pins[5].name, "IO5", 8);
b->pins[5].capabilities = (mraa_pincapabilities_t){ 1, 1, 1, 0, 0, 0, 0, 0 };
b->pins[5].gpio.pinmap = 5;
strncpy(b->pins[6].name, "IO6", 8);
b->pins[6].capabilities = (mraa_pincapabilities_t){ 1, 1, 1, 0, 0, 0, 0, 0 };
b->pins[6].gpio.pinmap = 6;
strncpy(b->pins[7].name, "IO7", 8);
b->pins[7].capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 };
b->pins[7].gpio.pinmap = 7;
strncpy(b->pins[8].name, "IO8", 8);
b->pins[8].capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 };
b->pins[8].gpio.pinmap = 8;
strncpy(b->pins[9].name, "IO9", 8);
b->pins[9].capabilities = (mraa_pincapabilities_t){ 1, 1, 1, 0, 0, 0, 0, 0 };
b->pins[9].gpio.pinmap = 9;
strncpy(b->pins[10].name, "A0", 8);
b->pins[10].capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 1, 0 };
b->pins[10].gpio.pinmap = 10;
b->pins[10].aio.pinmap = 0;
strncpy(b->pins[11].name, "A1", 8);
b->pins[11].capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 1, 0 };
b->pins[11].gpio.pinmap = 11;
b->pins[11].aio.pinmap = 1;
strncpy(b->pins[12].name, "A2", 8);
b->pins[12].capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 1, 0 };
b->pins[12].gpio.pinmap = 12;
b->pins[12].aio.pinmap = 2;
strncpy(b->pins[13].name, "A3", 8);
b->pins[13].capabilities = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 1, 0 };
b->pins[13].gpio.pinmap = 13;
b->pins[13].aio.pinmap = 3;
b->adv_func = (mraa_adv_func_t*) calloc(1, sizeof(mraa_adv_func_t));
if (b->adv_func == NULL) {
free(b->pins);
free(b);
return MRAA_NULL_PLATFORM;
}
b->adv_func->gpio_init_internal_replace = &mraa_grovepi_gpio_init_internal_replace;
b->adv_func->gpio_mode_replace = &mraa_grovepi_gpio_mode_replace;
b->adv_func->gpio_dir_replace = &mraa_grovepi_gpio_dir_replace;
//TODO: add interrupt support
//b->adv_func->gpio_edge_mode_replace = &mraa_grovepi_gpio_edge_mode_replace;
//b->adv_func->gpio_interrupt_handler_init_replace = &mraa_grovepi_gpio_interrupt_handler_init_replace;
//b->adv_func->gpio_wait_interrupt_replace = &mraa_grovepi_gpio_wait_interrupt_replace;
b->adv_func->gpio_read_replace = &mraa_grovepi_gpio_read_replace;
b->adv_func->gpio_write_replace = &mraa_grovepi_gpio_write_replace;
b->adv_func->gpio_close_replace = &mraa_grovepi_gpio_close_replace;
b->adv_func->aio_init_internal_replace = &mraa_grovepi_aio_init_internal_replace;
b->adv_func->aio_read_replace = &mraa_grovepi_aio_read_replace;
b->adv_func->pwm_init_internal_replace = &mraa_grovepi_pwm_init_internal_replace;
b->adv_func->pwm_write_replace = &mraa_grovepi_pwm_write_replace;
b->adv_func->pwm_read_replace = &mraa_grovepi_pwm_read_replace;
b->adv_func->pwm_enable_replace = &mraa_grovepi_pwm_enable_replace;
b->adv_func->pwm_period_replace = &mraa_grovepi_pwm_period_replace;
board->sub_platform = b;
return b->platform_type;
}

View File

@@ -55,6 +55,7 @@
#include "mraa_internal.h"
#include "firmata/firmata_mraa.h"
#include "grovepi/grovepi.h"
#include "gpio.h"
#include "version.h"
#include "i2c.h"
@@ -1268,7 +1269,7 @@ mraa_get_iio_device_count()
}
mraa_result_t
mraa_add_subplatform(mraa_platform_t subplatformtype, const char* uart_dev)
mraa_add_subplatform(mraa_platform_t subplatformtype, const char* dev)
{
#if defined(FIRMATA)
if (subplatformtype == MRAA_GENERIC_FIRMATA) {
@@ -1280,7 +1281,7 @@ mraa_add_subplatform(mraa_platform_t subplatformtype, const char* uart_dev)
syslog(LOG_NOTICE, "mraa: We don't support multiple firmata subplatforms!");
return MRAA_ERROR_FEATURE_NOT_SUPPORTED;
}
if (mraa_firmata_platform(plat, uart_dev) == MRAA_GENERIC_FIRMATA) {
if (mraa_firmata_platform(plat, dev) == MRAA_GENERIC_FIRMATA) {
syslog(LOG_NOTICE, "mraa: Added firmata subplatform");
return MRAA_SUCCESS;
}
@@ -1291,14 +1292,33 @@ mraa_add_subplatform(mraa_platform_t subplatformtype, const char* uart_dev)
}
#endif
if (subplatformtype == MRAA_GROVEPI) {
if (plat == NULL || plat->platform_type == MRAA_UNKNOWN_PLATFORM || plat->i2c_bus_count == 0) {
syslog(LOG_NOTICE, "mraa: The GrovePi shield is not supported on this platform!");
return MRAA_ERROR_FEATURE_NOT_SUPPORTED;
}
if (plat->sub_platform != NULL) {
syslog(LOG_NOTICE, "mraa: A subplatform was already added!");
return MRAA_ERROR_FEATURE_NOT_SUPPORTED;
}
int i2c_bus;
if(mraa_atoi(strdup(dev), &i2c_bus) != MRAA_SUCCESS && i2c_bus < plat->i2c_bus_count) {
syslog(LOG_NOTICE, "mraa: Cannot add GrovePi subplatform, invalid i2c bus specified");
return MRAA_ERROR_INVALID_PARAMETER;
}
if (mraa_grovepi_platform(plat, i2c_bus) == MRAA_GROVEPI) {
syslog(LOG_NOTICE, "mraa: Added GrovePi subplatform");
return MRAA_SUCCESS;
}
}
return MRAA_ERROR_INVALID_PARAMETER;
}
mraa_result_t
mraa_remove_subplatform(mraa_platform_t subplatformtype)
{
#if defined(FIRMATA)
if (subplatformtype == MRAA_GENERIC_FIRMATA) {
if (subplatformtype != MRAA_FTDI_FT4222) {
if (plat == NULL || plat->sub_platform == NULL) {
return MRAA_ERROR_INVALID_PARAMETER;
}
@@ -1307,7 +1327,6 @@ mraa_remove_subplatform(mraa_platform_t subplatformtype)
free(plat->sub_platform);
return MRAA_SUCCESS;
}
#endif
return MRAA_ERROR_INVALID_PARAMETER;
}