diff --git a/CMakeLists.txt b/CMakeLists.txt index fcf1bf2b3..0c46a2bb4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -130,6 +130,7 @@ option (BUILDSWIGNODE "Build swig node modules." ON) option (BUILDSWIGJAVA "Build Java API." OFF) option (USBPLAT "Detection USB platform." OFF) option (FIRMATA "Add Firmata support to mraa." OFF) +option (FIRMATABLE "Add Firmata BLE support to mraa." OFF) option (ONEWIRE "Add Onewire support to mraa." ON) option (JSONPLAT "Add Platform loading via a json file." ON) option (IMRAA "Add Imraa support to mraa." OFF) diff --git a/api/mraa/types.h b/api/mraa/types.h index 9c129b609..ba37c576a 100644 --- a/api/mraa/types.h +++ b/api/mraa/types.h @@ -57,6 +57,8 @@ typedef enum { // contains bit 9 so is subplatform MRAA_GENERIC_FIRMATA = 1280, /**< Firmata uart platform/bridge */ + MRAA_BLE_FIRMATA_BY_NAME = 1281, /**< Firmata ble platform by name */ + MRAA_BLE_FIRMATA_BY_ADDRESS = 1282, /**< Firmata ble platform by address*/ MRAA_MOCK_PLATFORM = 96, /**< Mock platform, which requires no real hardware */ MRAA_JSON_PLATFORM = 97, /**< User initialised platform from json*/ diff --git a/api/mraa/types.hpp b/api/mraa/types.hpp index 4aa50a8c4..ca6aff0b9 100644 --- a/api/mraa/types.hpp +++ b/api/mraa/types.hpp @@ -56,6 +56,8 @@ typedef enum { FTDI_FT4222 = 256, /**< FTDI FT4222 USB to i2c bridge */ GENERIC_FIRMATA = 1280, /**< Firmata uart platform/bridge */ + BLE_FIRMATA_BY_NAME = 1281, /**< Firmata ble platform by name */ + BLE_FIRMATA_BY_ADDRESS = 1282, /**< Firmata ble platform by address */ NULL_PLATFORM = 98, UNKNOWN_PLATFORM = diff --git a/examples/python/aio_ble.py b/examples/python/aio_ble.py new file mode 100644 index 000000000..f99295ef2 --- /dev/null +++ b/examples/python/aio_ble.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +# Author: Brendan Le Foll +# Copyright (c) 2014 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 +import time + +print (mraa.getVersion()) +mraa.addSubplatform(mraa.BLE_FIRMATA_BY_NAME, "FIRMATA") + +try: + x = mraa.Aio(0+512) + for i in range(50): + print (x.read()) + print ("%.5f" % x.readFloat()) + time.sleep(1) +except: + print ("Are you sure you have an ADC?") diff --git a/examples/python/hello_gpio_ble.py b/examples/python/hello_gpio_ble.py new file mode 100644 index 000000000..fc88efcd4 --- /dev/null +++ b/examples/python/hello_gpio_ble.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python + +# Author: Thomas Ingleby +# Copyright (c) 2014 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 +import time + +print (mraa.getVersion()) +mraa.addSubplatform(mraa.BLE_FIRMATA_BY_NAME, "FIRMATA") +x = mraa.Gpio(13 + 512) +x.dir(mraa.DIR_OUT) +print "Blinking" +for i in range(5): + x.write(1) + time.sleep(1) + x.write(0) + time.sleep(1) diff --git a/examples/python/rgblcd_ble.py b/examples/python/rgblcd_ble.py new file mode 100644 index 000000000..670fd3940 --- /dev/null +++ b/examples/python/rgblcd_ble.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +# Author: Brendan Le Foll +# Copyright (c) 2014 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 + +mraa.addSubplatform(mraa.BLE_FIRMATA_BY_NAME, "FIRMATA") + +# This example will change the LCD backlight on the Grove-LCD RGB backlight +# to a nice shade of purple +x = mraa.I2c(512+0) +x.address(0x62) + +# initialise device +x.writeReg(0, 0) +x.writeReg(1, 0) + +# sent RGB color data +x.writeReg(0x08, 0xAA) +x.writeReg(0x04, 255) +x.writeReg(0x02, 255) diff --git a/include/firmata/firmata.h b/include/firmata/firmata.h index 4ef4bf0bb..a24159402 100644 --- a/include/firmata/firmata.h +++ b/include/firmata/firmata.h @@ -27,6 +27,9 @@ #include #include "uart.h" +#ifdef FIRMATABLE +#include "firmata_ble.h" +#endif #define MODE_INPUT 0x00 #define MODE_OUTPUT 0x01 @@ -92,6 +95,9 @@ typedef struct s_pin { typedef struct s_firmata { mraa_uart_context uart; +#ifdef FIRMATABLE + lb_bl_device* bl_dev; +#endif t_pin pins[128]; int i2cmsg[256][256]; int parse_command_len; @@ -105,6 +111,7 @@ typedef struct s_firmata { } t_firmata; t_firmata* firmata_new(const char* name); +t_firmata* firmata_ble_new(const char* name, mraa_platform_t type); void firmata_initPins(t_firmata* firmata); int firmata_askFirmware(t_firmata* firmata); int firmata_pinMode(t_firmata* firmata, int pin, int mode); @@ -112,6 +119,8 @@ int firmata_digitalWrite(t_firmata* firmata, int pin, int value); int firmata_analogWrite(t_firmata* firmata, int pin, int value); int firmata_analogRead(t_firmata* firmata, int pin); int firmata_pull(t_firmata* firmata); +int firmata_write_internal(t_firmata* firmata_dev, const char* buf, size_t len); void firmata_parse(t_firmata* firmata, const uint8_t* buf, int len); void firmata_endParse(t_firmata* firmata); void firmata_close(t_firmata* firmata); +void firmata_ble_close(t_firmata* firmata); diff --git a/include/firmata/firmata_ble.h b/include/firmata/firmata_ble.h new file mode 100644 index 000000000..b11887f18 --- /dev/null +++ b/include/firmata/firmata_ble.h @@ -0,0 +1,63 @@ +/* + * Author: Shiran Ben-Melech + * 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. + */ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "mraa_internal.h" +#include "littleb.h" + +void* liblittleb_lib; + +lb_result_t (*dl_lb_init)(); +lb_result_t (*dl_lb_destroy)(); +lb_result_t (*dl_lb_context_new)(); +lb_result_t (*dl_lb_context_free)(); +lb_result_t (*dl_lb_get_bl_devices)(int); +lb_result_t (*dl_lb_connect_device)(lb_bl_device*); +lb_result_t (*dl_lb_disconnect_device)(lb_bl_device*); +lb_result_t (*dl_lb_pair_device)(lb_bl_device*); +lb_result_t (*dl_lb_unpair_device)(lb_bl_device*); +lb_result_t (*dl_lb_get_ble_characteristic_by_characteristic_path)(lb_bl_device*, const char*, lb_ble_char**); +lb_result_t (*dl_lb_get_ble_characteristic_by_uuid)(lb_bl_device*, const char*, lb_ble_char**); +lb_result_t (*dl_lb_get_ble_service_by_service_path)(lb_bl_device*, const char*, lb_ble_service**); +lb_result_t (*dl_lb_get_ble_service_by_uuid)(lb_bl_device*, const char*, lb_ble_service**); +lb_result_t (*dl_lb_get_ble_device_services)(lb_bl_device*); +lb_result_t (*dl_lb_get_device_by_device_path)(const char*, lb_bl_device**); +lb_result_t (*dl_lb_get_device_by_device_name)(const char*, lb_bl_device**); +lb_result_t (*dl_lb_get_device_by_device_address)(const char*, lb_bl_device**); +lb_result_t (*dl_lb_write_to_characteristic)(lb_bl_device*, const char*, int, uint8_t*); +lb_result_t (*dl_lb_read_from_characteristic)(lb_bl_device*, const char*, size_t*, uint8_t**); +lb_result_t (*dl_lb_register_characteristic_read_event)(lb_bl_device*, const char*, sd_bus_message_handler_t, void*); +lb_result_t (*dl_lb_parse_uart_service_message)(sd_bus_message*, const void**, size_t*); + +mraa_result_t mraa_firmata_ble_init(); + + +#ifdef __cplusplus +} +#endif diff --git a/include/firmata/firmata_mraa.h b/include/firmata/firmata_mraa.h index a80d73a32..527c2ea4b 100644 --- a/include/firmata/firmata_mraa.h +++ b/include/firmata/firmata_mraa.h @@ -30,7 +30,7 @@ extern "C" { #include "mraa_internal.h" -mraa_platform_t mraa_firmata_platform(mraa_board_t* board, const char* uart_dev); +mraa_platform_t mraa_firmata_platform(mraa_board_t* board, const char* uart_dev, mraa_platform_t type); #ifdef __cplusplus diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a505ca991..c465514e0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -7,6 +7,10 @@ set (mraa_LIB_INCLUDE_DIRS if (FIRMATA) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DFIRMATA=1") add_subdirectory (firmata) + + if (FIRMATABLE) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DFIRMATABLE=1") + endif() endif () if (ONEWIRE) @@ -255,7 +259,7 @@ if (BUILDSWIG) endif () add_library (mraa ${mraa_LIB_SRCS}) -target_link_libraries (mraa ${mraa_LIBS}) +target_link_libraries (mraa ${mraa_LIBS} dl) set_target_properties( mraa PROPERTIES diff --git a/src/firmata/CMakeLists.txt b/src/firmata/CMakeLists.txt index 8ebc4330f..be899018f 100644 --- a/src/firmata/CMakeLists.txt +++ b/src/firmata/CMakeLists.txt @@ -1,8 +1,16 @@ if (FIRMATA) message (STATUS "INFO - Adding firmata backend support") - set (mraa_LIB_SRCS_NOAUTO ${mraa_LIB_SRCS_NOAUTO} + set (mraa_firmata_LIBS ${PROJECT_SOURCE_DIR}/src/firmata/firmata.c ${PROJECT_SOURCE_DIR}/src/firmata/firmata_mraa.c - PARENT_SCOPE ) + if (FIRMATABLE) + message (STATUS "INFO - Adding firmata ble backend support") + set (mraa_firmata_LIBS ${mraa_firmata_LIBS} + ${PROJECT_SOURCE_DIR}/src/firmata/firmata_ble.c + ) + endif () + set (mraa_LIB_SRCS_NOAUTO ${mraa_LIB_SRCS_NOAUTO} ${mraa_firmata_LIBS} + PARENT_SCOPE + ) endif () diff --git a/src/firmata/firmata.c b/src/firmata/firmata.c index 68068f3ef..ecdf44e95 100644 --- a/src/firmata/firmata.c +++ b/src/firmata/firmata.c @@ -23,12 +23,53 @@ */ #include "firmata/firmata.h" +#include "firmata/firmata_ble.h" #include "mraa_internal.h" #include #include #include +static int +firmata_uart_read_handler(sd_bus_message* message, void* userdata, sd_bus_error* error) +{ + + int r, i; + size_t size = 0; + uint8_t* result = NULL; + t_firmata* firmata = (t_firmata*) userdata; + + r = dl_lb_parse_uart_service_message(message, (const void**) &result, &size); + if (r < 0) { + syslog(LOG_ERR, "ERROR: couldn't parse uart message\n"); + return -MRAA_ERROR_UNSPECIFIED; + } + + firmata_parse(firmata, result, size); + + return LB_SUCCESS; +} + +inline int +firmata_write_internal(t_firmata* firmata_dev, const char* buf, size_t len) +{ + int r = MRAA_ERROR_UNSPECIFIED; + if (firmata_dev->uart != NULL) { + mraa_uart_write(firmata_dev->uart, buf, len); + } +#ifdef FIRMATABLE + else if (firmata_dev->bl_dev != NULL) { + r = dl_lb_write_to_characteristic(firmata_dev->bl_dev, + "6e400002-b5a3-f393-e0a9-e50e24dcca9e", len, (uint8_t*) buf); + if (r < 0) { + syslog(LOG_ERR, "ERROR: lb_write_to_characteristic\n"); + return -MRAA_ERROR_UNSPECIFIED; + } + } +#endif + return MRAA_SUCCESS; +} + t_firmata* firmata_new(const char* name) { @@ -50,7 +91,7 @@ firmata_new(const char* name) if (res->uart == NULL) { syslog(LOG_ERR, "firmata: UART failed to setup"); free(res); - return NULL; + return NULL; } firmata_initPins(res); @@ -65,6 +106,131 @@ firmata_new(const char* name) return res; } +#ifdef FIRMATABLE +t_firmata* +firmata_ble_new(const char* name, mraa_platform_t type) +{ + t_firmata* res; + int ble_res = LB_ERROR_UNSPECIFIED; + + res = calloc(1, sizeof(t_firmata)); + if (!res) { + return NULL; + } + + int ret = pthread_spin_init(&res->lock, PTHREAD_PROCESS_SHARED); + if (ret != 0) { + syslog(LOG_ERR, "firmata; could not init locking"); + free(res); + return NULL; + } + + + res->bl_dev = NULL; + + ble_res = mraa_firmata_ble_init(); + if (ble_res < 0) { + syslog(LOG_ERR, "firmata: littleb failed to setup"); + free(res); + return NULL; + } + + ble_res = dl_lb_init(); + if (ble_res < 0) { + syslog(LOG_ERR, "ERROR: lb_init\n"); + free(res); + return NULL; + } + + ble_res = dl_lb_get_bl_devices(5); + if (ble_res < 0) { + syslog(LOG_ERR, "ERROR: lb_get_bl_devices\n"); + firmata_ble_close(res); + free(res); + return NULL; + } + + if (type == MRAA_BLE_FIRMATA_BY_NAME) { + ble_res = dl_lb_get_device_by_device_name(name, &res->bl_dev); + } else if (type == MRAA_BLE_FIRMATA_BY_ADDRESS) { + ble_res = dl_lb_get_device_by_device_address(name, &res->bl_dev); + } + if (ble_res < 0) { + syslog(LOG_ERR, "ERROR: Device FIRMATA not found\n"); + firmata_ble_close(res); + free(res); + return NULL; + } + + ble_res = dl_lb_connect_device(res->bl_dev); + if (ble_res < 0) { + syslog(LOG_ERR, "ERROR: lb_connect_device\n"); + firmata_ble_close(res); + free(res); + return NULL; + } + + // ble_res = lb_pair_device(res->lb_ctx, res->bl_dev); + // if (ble_res < 0) { + // syslog(LOG_ERR, "ERROR: lb_pair_device\n"); + // free(res); + // return NULL; + //} + + ble_res = dl_lb_get_ble_device_services(res->bl_dev); + if (ble_res < 0) { + syslog(LOG_ERR, "ERROR: lb_get_ble_device_services\n"); + firmata_ble_close(res); + free(res); + return NULL; + } + + ble_res = dl_lb_register_characteristic_read_event(res->bl_dev, + "6e400003-b5a3-f393-e0a9-e50e24dcca9e", + firmata_uart_read_handler, res); + if (ble_res < 0) { + syslog(LOG_ERR, "ERROR: lb_register_characteristic_read_event\n"); + firmata_ble_close(res); + free(res); + return NULL; + } + + firmata_initPins(res); + + firmata_askFirmware(res); + syslog(LOG_INFO, "firmata: Device opened at: %s", name); + + return res; +} + +void +firmata_ble_close(t_firmata* firmata) +{ + lb_result_t r = LB_ERROR_UNSPECIFIED; + + // r = lb_unpair_device(lb_ctx, firmata); + // if (r < 0) { + // syslog(LOG_ERR, "ERROR: lb_unpair_device\n"); + // exit(r); + //} + + r = dl_lb_disconnect_device(firmata->bl_dev); + if (r < 0) { + syslog(LOG_ERR, "ERROR: lb_disconnect_device\n"); + } + + r = dl_lb_context_free(); + if (r < 0) { + syslog(LOG_ERR, "ERROR: lb_context_free\n"); + } + + r = dl_lb_destroy(); + if (r < 0) { + syslog(LOG_ERR, "ERROR: lb_destroy\n"); + } +} +#endif + void firmata_close(t_firmata* firmata) { @@ -199,7 +365,7 @@ firmata_endParse(t_firmata* firmata) buf[len++] = 1; } firmata->isReady = 1; - mraa_uart_write(firmata->uart, buf, len); + firmata_write_internal(firmata, buf, len); } else if (firmata->parse_buff[1] == FIRMATA_CAPABILITY_RESPONSE) { int pin, i, n; for (pin = 0; pin < 128; pin++) { @@ -227,7 +393,7 @@ firmata_endParse(t_firmata* firmata) buf[len++] = pin; buf[len++] = FIRMATA_END_SYSEX; } - mraa_uart_write(firmata->uart, buf, len); + firmata_write_internal(firmata, buf, len); } } else if (firmata->parse_buff[1] == FIRMATA_ANALOG_MAPPING_RESPONSE) { int pin = 0; @@ -302,7 +468,7 @@ firmata_askFirmware(t_firmata* firmata) buf[0] = FIRMATA_START_SYSEX; buf[1] = FIRMATA_REPORT_FIRMWARE; // read firmata name & version buf[2] = FIRMATA_END_SYSEX; - res = mraa_uart_write(firmata->uart, buf, 3); + res = firmata_write_internal(firmata, buf, 3); return (res); } @@ -316,7 +482,7 @@ firmata_pinMode(t_firmata* firmata, int pin, int mode) buff[0] = FIRMATA_SET_PIN_MODE; buff[1] = pin; buff[2] = mode; - res = mraa_uart_write(firmata->uart, buff, 3); + res = firmata_write_internal(firmata, buff, 3); return (res); } @@ -329,19 +495,19 @@ firmata_analogWrite(t_firmata* firmata, int pin, int value) buff[0] = 0xE0 | pin; buff[1] = value & 0x7F; buff[2] = (value >> 7) & 0x7F; - res = mraa_uart_write(firmata->uart, buff, 3); + res = firmata_write_internal(firmata, buff, 3); return (res); } int -firmata_analogRead(t_firmata *firmata, int pin) +firmata_analogRead(t_firmata* firmata, int pin) { int res; int value = 1; char buff[2]; buff[0] = FIRMATA_REPORT_ANALOG | pin; buff[1] = value; - res = mraa_uart_write(firmata->uart, buff, 2); + res = firmata_write_internal(firmata, buff, 2); return res; } @@ -368,6 +534,6 @@ firmata_digitalWrite(t_firmata* firmata, int pin, int value) buff[0] = FIRMATA_DIGITAL_MESSAGE | port_num; buff[1] = port_val & 0x7F; buff[2] = (port_val >> 7) & 0x7F; - res = mraa_uart_write(firmata->uart, buff, 3); + res = firmata_write_internal(firmata, buff, 3); return (res); } diff --git a/src/firmata/firmata_ble.c b/src/firmata/firmata_ble.c new file mode 100644 index 000000000..23ab9e9ea --- /dev/null +++ b/src/firmata/firmata_ble.c @@ -0,0 +1,93 @@ +/* + * Author: Shiran Ben-Melech + * 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 "firmata.h" +#include "mraa_internal.h" +#include "firmata/firmata.h" +#include "firmata/firmata_ble.h" + +#define PLATFORM_NAME "FIRMATA_BLE" + +static mraa_boolean_t liblittleb_load_success = true; + +void * +mraa_firmata_ble_dlsym(const char *symbol) +{ + void *func = dlsym(liblittleb_lib, symbol); + if (func == NULL) { + syslog(LOG_ERR, "%s", dlerror()); + liblittleb_load_success = false; + } + return func; +} + + +mraa_result_t +mraa_firmata_ble_init() +{ + mraa_result_t mraaStatus = MRAA_ERROR_NO_RESOURCES; + + liblittleb_lib = dlopen("liblittleb.so", RTLD_LAZY); + if (!liblittleb_lib) { + syslog(LOG_WARNING, "liblittleb.so not found, skipping"); + return MRAA_ERROR_FEATURE_NOT_SUPPORTED; + } + + dl_lb_init = mraa_firmata_ble_dlsym("lb_init"); + dl_lb_destroy = mraa_firmata_ble_dlsym("lb_destroy"); + dl_lb_context_new = mraa_firmata_ble_dlsym("lb_context_new"); + dl_lb_context_free = mraa_firmata_ble_dlsym("lb_context_free"); + dl_lb_get_bl_devices = mraa_firmata_ble_dlsym("lb_get_bl_devices"); + dl_lb_connect_device = mraa_firmata_ble_dlsym("lb_connect_device"); + dl_lb_disconnect_device = mraa_firmata_ble_dlsym("lb_disconnect_device"); + dl_lb_pair_device = mraa_firmata_ble_dlsym("lb_pair_device"); + dl_lb_unpair_device = mraa_firmata_ble_dlsym("lb_unpair_device"); + dl_lb_get_ble_characteristic_by_characteristic_path = mraa_firmata_ble_dlsym("lb_get_ble_characteristic_by_characteristic_path"); + dl_lb_get_ble_characteristic_by_uuid = mraa_firmata_ble_dlsym("lb_get_ble_characteristic_by_uuid"); + dl_lb_get_ble_service_by_service_path = mraa_firmata_ble_dlsym("lb_get_ble_service_by_service_path"); + dl_lb_get_ble_service_by_uuid = mraa_firmata_ble_dlsym("lb_get_ble_service_by_uuid"); + dl_lb_get_ble_device_services = mraa_firmata_ble_dlsym("lb_get_ble_device_services"); + dl_lb_get_device_by_device_path = mraa_firmata_ble_dlsym("lb_get_device_by_device_path"); + dl_lb_get_device_by_device_name = mraa_firmata_ble_dlsym("lb_get_device_by_device_name"); + dl_lb_get_device_by_device_address = mraa_firmata_ble_dlsym("lb_get_device_by_device_address"); + dl_lb_write_to_characteristic = mraa_firmata_ble_dlsym("lb_write_to_characteristic"); + dl_lb_read_from_characteristic = mraa_firmata_ble_dlsym("lb_read_from_characteristic"); + dl_lb_register_characteristic_read_event = mraa_firmata_ble_dlsym("lb_register_characteristic_read_event"); + dl_lb_parse_uart_service_message = mraa_firmata_ble_dlsym("lb_parse_uart_service_message"); + + if (!liblittleb_load_success) { + syslog(LOG_ERR, "Failed to find all symbols for littleb support"); + goto init_exit; + } + + mraaStatus = MRAA_SUCCESS; + +init_exit: + if (mraaStatus == MRAA_SUCCESS) + syslog(LOG_NOTICE, "mraa_firmata_ble_init completed successfully\n"); + return mraaStatus; +} \ No newline at end of file diff --git a/src/firmata/firmata_mraa.c b/src/firmata/firmata_mraa.c index e3708245d..903618726 100644 --- a/src/firmata/firmata_mraa.c +++ b/src/firmata/firmata_mraa.c @@ -51,7 +51,7 @@ mraa_firmata_init(int feature) mraa_result_t mraa_firmata_write_sysex(mraa_firmata_context dev, char* msg, int length) { - return mraa_uart_write(firmata_dev->uart, msg, length); + return firmata_write_internal(firmata_dev, msg, length); } mraa_result_t @@ -59,7 +59,7 @@ mraa_firmata_response(mraa_firmata_context dev, void (*fptr)(uint8_t*, int)) { if (dev->added == 0) { struct _firmata** ptr; - ptr = realloc(firmata_dev->devs, (firmata_dev->dev_count+1) * sizeof(struct _firmata*)); + ptr = realloc(firmata_dev->devs, (firmata_dev->dev_count + 1) * sizeof(struct _firmata*)); if (ptr == NULL) { return MRAA_ERROR_NO_RESOURCES; } @@ -98,7 +98,7 @@ mraa_firmata_i2c_init_bus_replace(mraa_i2c_context dev) buff[1] = FIRMATA_I2C_CONFIG; buff[2] = delay & 0xFF, (delay >> 8) & 0xFF; buff[3] = FIRMATA_END_SYSEX; - mraa_uart_write(firmata_dev->uart, buff, 4); + firmata_write_internal(firmata_dev, buff, 4); return MRAA_SUCCESS; } @@ -135,7 +135,7 @@ mraa_firmata_send_i2c_read_req(mraa_i2c_context dev, int length) buffer[5] = (length >> 7) & 0x7f; buffer[6] = FIRMATA_END_SYSEX; - if (mraa_uart_write(firmata_dev->uart, buffer, 7) != 7) { + if (firmata_write_internal(firmata_dev, buffer, 7) != 7) { free(buffer); return MRAA_ERROR_UNSPECIFIED; } @@ -167,7 +167,7 @@ mraa_firmata_send_i2c_read_reg_req(mraa_i2c_context dev, uint8_t command, int le buffer[7] = (length >> 7) & 0x7f; buffer[8] = FIRMATA_END_SYSEX; - if (mraa_uart_write(firmata_dev->uart, buffer, 9) != 9) { + if (firmata_write_internal(firmata_dev, buffer, 9) != 9) { free(buffer); return MRAA_ERROR_UNSPECIFIED; } @@ -290,7 +290,7 @@ mraa_firmata_i2c_write(mraa_i2c_context dev, const uint8_t* data, int bytesToWri ii = ii+2; } buffer[buffer_size-1] = FIRMATA_END_SYSEX; - mraa_uart_write(firmata_dev->uart, buffer, buffer_size); + firmata_write_internal(firmata_dev, buffer, buffer_size); free(buffer); return MRAA_SUCCESS; } @@ -309,7 +309,7 @@ mraa_firmata_i2c_write_byte(mraa_i2c_context dev, uint8_t data) buffer[4] = data & 0x7F; buffer[5] = (data >> 7) & 0x7F; buffer[6] = FIRMATA_END_SYSEX; - mraa_uart_write(firmata_dev->uart, buffer, 7); + firmata_write_internal(firmata_dev, buffer, 7); free(buffer); return MRAA_SUCCESS; } @@ -330,7 +330,7 @@ mraa_firmata_i2c_write_byte_data(mraa_i2c_context dev, const uint8_t data, const buffer[6] = data & 0x7F; buffer[7] = (data >> 7) & 0x7F; buffer[8] = FIRMATA_END_SYSEX; - mraa_uart_write(firmata_dev->uart, buffer, 9); + firmata_write_internal(firmata_dev, buffer, 9); free(buffer); return MRAA_SUCCESS; } @@ -535,20 +535,21 @@ mraa_firmata_pull_handler(void* vp) } mraa_board_t* -mraa_firmata_plat_init(const char* uart_dev) +mraa_firmata_plat_init(const char* uart_dev, mraa_platform_t type) { mraa_board_t* b = (mraa_board_t*) calloc(1, sizeof(mraa_board_t)); if (b == NULL) { return NULL; } - firmata_dev = firmata_new(uart_dev); - if (firmata_dev == NULL) { - syslog(LOG_WARNING, "firmata: Failed to open uart to Firmata dev on %s", uart_dev); - fprintf(stderr, "Mraa expected to find a Firmata device on %s, is the port in use?\n", uart_dev); - free(b); - return NULL; - } + if (type == MRAA_GENERIC_FIRMATA) { + firmata_dev = firmata_new(uart_dev); + if (firmata_dev == NULL) { + syslog(LOG_WARNING, "firmata: Failed to open uart to Firmata dev on %s", uart_dev); + fprintf(stderr, "Mraa expected to find a Firmata device on %s, is the port in use?\n", uart_dev); + free(b); + return NULL; + } // if this isn't working then we have an issue with our uart int retry = 20; @@ -556,14 +557,23 @@ mraa_firmata_plat_init(const char* uart_dev) firmata_pull(firmata_dev); } - if (!retry) { - syslog(LOG_ERR, "firmata: Failed to find a valid Firmata board on %s", uart_dev); - firmata_close(firmata_dev); - free(b); - return NULL; + pthread_create(&thread_id, NULL, mraa_firmata_pull_handler, NULL); } - pthread_create(&thread_id, NULL, mraa_firmata_pull_handler, NULL); + else if (type == MRAA_BLE_FIRMATA_BY_NAME || type == MRAA_BLE_FIRMATA_BY_ADDRESS) { +#ifndef FIRMATABLE + return NULL; +#endif + firmata_dev = firmata_ble_new(uart_dev, type); + if (firmata_dev == NULL) { + syslog(LOG_WARNING, "firmata: Failed to open ble to Firmata dev on %s", uart_dev); + fprintf(stderr, "Mraa expected to find a Firmata ble device named %s, is the device " + "available?\n", + uart_dev); + free(b); + return NULL; + } + } b->platform_name = "firmata"; // do we support 2.5? Or are we more 2.3? @@ -695,7 +705,7 @@ mraa_firmata_plat_init(const char* uart_dev) } mraa_platform_t -mraa_firmata_platform(mraa_board_t* board, const char* uart_dev) +mraa_firmata_platform(mraa_board_t* board, const char* uart_dev, mraa_platform_t type) { /** * Firmata boards are not something we can detect so we just trust the user @@ -704,12 +714,12 @@ mraa_firmata_platform(mraa_board_t* board, const char* uart_dev) */ mraa_board_t* sub_plat = NULL; - sub_plat = mraa_firmata_plat_init(uart_dev); + sub_plat = mraa_firmata_plat_init(uart_dev, type); if (sub_plat != NULL) { - sub_plat->platform_type = MRAA_GENERIC_FIRMATA; + sub_plat->platform_type = type; board->sub_platform = sub_plat; return sub_plat->platform_type; } return MRAA_NULL_PLATFORM; -} +} \ No newline at end of file diff --git a/src/mraa.c b/src/mraa.c index fd957d274..6d7bcbc3f 100644 --- a/src/mraa.c +++ b/src/mraa.c @@ -1022,7 +1022,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) { @@ -1034,10 +1034,29 @@ 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) == MRAA_GENERIC_FIRMATA) { syslog(LOG_NOTICE, "mraa: Added firmata subplatform"); return MRAA_SUCCESS; } + + } else if (subplatformtype == MRAA_BLE_FIRMATA_BY_NAME) { + if (plat->sub_platform != NULL) { + return MRAA_ERROR_INVALID_PARAMETER; + } + if (mraa_firmata_platform(plat, dev, MRAA_BLE_FIRMATA_BY_NAME) == MRAA_BLE_FIRMATA_BY_NAME) { + syslog(LOG_NOTICE, "mraa: Added firmata ble subplatform by name"); + return MRAA_SUCCESS; + } + syslog(LOG_NOTICE, "mraa: Failed to add firmata ble subplatform by name"); + } else if (subplatformtype == MRAA_BLE_FIRMATA_BY_ADDRESS) { + if (plat->sub_platform != NULL) { + return MRAA_ERROR_INVALID_PARAMETER; + } + if (mraa_firmata_platform(plat, dev, MRAA_BLE_FIRMATA_BY_ADDRESS) == MRAA_BLE_FIRMATA_BY_ADDRESS) { + syslog(LOG_NOTICE, "mraa: Added firmata ble subplatform by address"); + return MRAA_SUCCESS; + } + syslog(LOG_NOTICE, "mraa: Failed to add firmata ble subplatform by address"); } #else if (subplatformtype == MRAA_GENERIC_FIRMATA) {