diff --git a/api/mraa/firmata.h b/api/mraa/firmata.h new file mode 100644 index 0000000..2ec7f8d --- /dev/null +++ b/api/mraa/firmata.h @@ -0,0 +1,101 @@ +/* + * Author: Brendan Le Foll + * 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 + +/** + * @file + * @brief Firmata IO + * + * Firmata IO lets you SYSEX messages construct and ask for a callback on a + * SYSEX messages. This is meant to provide a way to call custom firmata APIs + * especially using the Custom firmata API + * + * @snippet firmata_curie_imu.c Interesting + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "common.h" + +/** + * Opaque pointer definition to the internal struct _firmata. This context + * refers to one firmata 'extension' letting you write/return SYSEX messages + * directly + */ +typedef struct _firmata* mraa_firmata_context; + +/** + * Initialise firmata context on a feature. This feature is what will be + * listened on if you request a response callback + * + * @param firmata feature + * @return firmata context or NULL + */ +mraa_firmata_context mraa_firmata_init(int feature); + +/** + * Sends a custom SYSEX message to the firmata board. + * + * @param dev The Firmata context + * @param msg The SYSEX message + * @param length The length of the sysex message + */ +mraa_result_t mraa_firmata_write_sysex(mraa_firmata_context dev, char* msg, int length); + +/** + * Set a callback on 'feature'. This function is not thread safe and threads + * calling it need to make sure they are the only thread calling this. + * + * @param dev The Firmata context + * @param fptr Function pointer to function to be called when interupt is + * triggered, the returned buffer and length are the arguments. + * @return Result of operation + */ +mraa_result_t mraa_firmata_response(mraa_firmata_context dev, void (*fptr)(uint8_t*, int)); + +/** + * Stop getting events on feature. This is more efficient than mraa_firmata_close + * as it can be re-enabled without adding a feature + * + * @param dev The Firmata context + * @return Result of operation + */ +mraa_result_t mraa_firmata_response_stop(mraa_firmata_context dev); + +/** + * Free all firmata handle resources, this will leave an element in an array + * internally that will be skipped, avoid closing many firmata contexts often + * as there is a cost to doing this + * + * @param dev The Firmata context + * @return Result of operation + */ +mraa_result_t mraa_firmata_close(mraa_firmata_context dev); + +#ifdef __cplusplus +} +#endif diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 31d8087..3fa24b6 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -13,6 +13,8 @@ add_executable (mraa-gpio mraa-gpio.c) add_executable (mraa-i2c mraa-i2c.c) add_executable (spi_max7219 spi_max7219.c) add_executable (iio_driver iio_driver.c) +add_executable (firmata_curie_imu firmata_curie_imu.c) +add_executable (i2c_firmata i2c_firmata.c) include_directories(${PROJECT_SOURCE_DIR}/api) # FIXME Hack to access mraa internal types used by mraa-i2c @@ -34,6 +36,8 @@ target_link_libraries (mraa-gpio mraa) target_link_libraries (mraa-i2c mraa) target_link_libraries (spi_max7219 mraa) target_link_libraries (iio_driver mraa) +target_link_libraries (firmata_curie_imu mraa) +target_link_libraries (i2c_firmata mraa) add_subdirectory (c++) diff --git a/examples/firmata_curie_imu.c b/examples/firmata_curie_imu.c new file mode 100644 index 0000000..7569224 --- /dev/null +++ b/examples/firmata_curie_imu.c @@ -0,0 +1,103 @@ +/* + * Author: Brendan Le Foll + * 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 "mraa.h" +#include "mraa/firmata.h" + +#define FIRMATA_START_SYSEX 0xF0 +#define FIRMATA_END_SYSEX 0xF7 +#define FIRMATA_I2C_REPLY 0x77 +#define FIRMATA_I2C_REQUEST 0x76 +#define I2C_MODE_READ 0x01 + +void +interrupt(uint8_t* buf, int length) +{ + printf("reg read returned: %d, with buffer size %d\n", ((buf[6] & 0x7f) | ((buf[7] & 0x7f) << 7)), length); +} + +int +main() +{ + mraa_init(); + //! [Interesting] + + /** + * This example reads from a firmata device the check buffer on a BMP085 on + * 0xD0 which should return 0x55. Obviously I2C_REPLY has to be disabled in + * firmata_pull for this to work breaking all i2c support for firmata + */ + + mraa_add_subplatform(MRAA_GENERIC_FIRMATA, "/dev/ttyACM0"); + mraa_firmata_context firm = mraa_firmata_init(FIRMATA_I2C_REPLY); + if (firm == NULL) { + return EXIT_FAILURE; + } + + mraa_firmata_response(firm, interrupt); + + uint8_t* buffer = calloc(9, 0); + if (buffer == NULL) { + free(firm); + return EXIT_FAILURE; + } + buffer[0] = FIRMATA_START_SYSEX; + buffer[1] = FIRMATA_I2C_REQUEST; + buffer[2] = 0x77; + buffer[3] = I2C_MODE_READ << 3; + + // register to read from + buffer[4] = 0xD0 & 0x7f; + buffer[5] = (0xD0 >> 7) & 0x7f; + // number of bytes + buffer[6] = 1 & 0x7f; + buffer[7] = (1 >> 7) & 0x7f; + buffer[8] = FIRMATA_END_SYSEX; + + mraa_firmata_write_sysex(firm, buffer, 9); + + sleep(1); + + // stop the isr and set it again + mraa_firmata_response_stop(firm); + mraa_firmata_response(firm, interrupt); + mraa_firmata_write_sysex(firm, buffer, 9); + + sleep(1); + + // close everything and try again + mraa_firmata_close(firm); + firm = mraa_firmata_init(FIRMATA_I2C_REPLY); + mraa_firmata_response(firm, interrupt); + mraa_firmata_write_sysex(firm, buffer, 9); + + sleep(10); + + mraa_firmata_close(firm); + //! [Interesting] + + return EXIT_SUCCESS; +} diff --git a/examples/i2c_firmata.c b/examples/i2c_firmata.c new file mode 100644 index 0000000..e072ad1 --- /dev/null +++ b/examples/i2c_firmata.c @@ -0,0 +1,64 @@ +/* + * Author: Brendan Le Foll + * 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 "mraa.h" + +int +main(int argc, char** argv) +{ + mraa_init(); + mraa_add_subplatform(MRAA_GENERIC_FIRMATA, "/dev/ttyACM0"); + + mraa_i2c_context i2c; + i2c = mraa_i2c_init(0 + 512); +#if 0 + mraa_i2c_address(i2c, 0x62); + +#if 1 + uint8_t rx_tx_buf[2]; + rx_tx_buf[0] = 0x0; + rx_tx_buf[1] = 0x0; + mraa_i2c_write(i2c, rx_tx_buf, 2); +#endif + //mraa_i2c_write_byte_data(i2c, 0x0, 0x0); + mraa_i2c_write_byte_data(i2c, 0x0, 0x1); + + mraa_i2c_write_byte_data(i2c, 0xFF, 0x08); + mraa_i2c_write_byte_data(i2c, 0x00, 0x04); + mraa_i2c_write_byte_data(i2c, 0xA0, 0x02); +#else + mraa_i2c_address(i2c, 0x77); + int res = mraa_i2c_read_byte_data(i2c, 0xd0); + printf("res is 0x%x\n", res); + + uint8_t data[2]; + mraa_i2c_write_byte(i2c, 0x77); + mraa_i2c_read(i2c, data, 1); + + res = mraa_i2c_read_word_data(i2c, 0xAA); // BMP085_CAL_AC1 + printf("res is %d\n", res); +#endif + sleep(10); + +} diff --git a/include/firmata/firmata.h b/include/firmata/firmata.h index 030f57a..062a8f4 100644 --- a/include/firmata/firmata.h +++ b/include/firmata/firmata.h @@ -97,6 +97,8 @@ typedef struct s_firmata { uint8_t parse_buff[FIRMATA_MSG_LEN]; int isReady; char firmware[140]; + uint8_t dev_count; + struct _firmata** devs; } t_firmata; t_firmata* firmata_new(const char* name); diff --git a/include/mraa_internal_types.h b/include/mraa_internal_types.h index 9f6cae3..6c72cc7 100644 --- a/include/mraa_internal_types.h +++ b/include/mraa_internal_types.h @@ -1,7 +1,7 @@ /* * Author: Thomas Ingleby * Author: Brendan Le Foll - * Copyright (c) 2014 Intel Corporation. + * 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 @@ -40,6 +40,17 @@ #define MRAA_IO_SETUP_FAILURE -2 #define MRAA_NO_SUCH_IO -1 +#ifdef FIRMATA +struct _firmata { + /*@*/ + uint8_t feature; /**< the feature */ + uint8_t index; + void (* isr)(uint8_t*, int); /**< the feature response request */ + mraa_boolean_t added; /**< boolean to set if responses already set in devs array */ + /*@}*/ +}; +#endif + /** * A structure representing a gpio pin. */ diff --git a/src/firmata/firmata.c b/src/firmata/firmata.c index e9e47f9..563ecce 100644 --- a/src/firmata/firmata.c +++ b/src/firmata/firmata.c @@ -23,6 +23,7 @@ */ #include "firmata/firmata.h" +#include "mraa_internal.h" #include #include @@ -35,17 +36,17 @@ firmata_new(const char* name) mraa_result_t uart_res = MRAA_ERROR_UNSPECIFIED; printf("Opening device at: %s\n", name); - res = malloc(sizeof(t_firmata)); + res = calloc(1, sizeof(t_firmata)); if (!res) { perror("firmata_new::Failed malloc"); - return (NULL); + return NULL; } - memset(res, 0, sizeof(*res)); res->uart = mraa_uart_init_raw(name); if (res->uart == NULL) { fprintf(stderr, "UART failed to setup\n"); - return EXIT_FAILURE; + free(res); + return NULL; } firmata_initPins(res); @@ -70,15 +71,14 @@ firmata_pull(t_firmata* firmata) if (r > 0) { r = mraa_uart_read(firmata->uart, buff, sizeof(buff)); if (r < 0) { - return (0); + return 0; } if (r > 0) { firmata_parse(firmata, buff, r); - return (r); + return r; } - } else if (r < 0) { - return (r); } + return r; } void @@ -230,6 +230,8 @@ firmata_endParse(t_firmata* firmata) firmata->pins[pin].value |= (firmata->parse_buff[5] << 7); if (firmata->parse_count > 7) firmata->pins[pin].value |= (firmata->parse_buff[6] << 14); +#if 1 + // disable this to check the firmata_devs responses } else if (firmata->parse_buff[1] == FIRMATA_I2C_REPLY) { printf("got an i2c reply with count %d!!\n", firmata->parse_count); int addr = (firmata->parse_buff[2] & 0x7f) | ((firmata->parse_buff[3] & 0x7f) << 7); @@ -237,10 +239,26 @@ firmata_endParse(t_firmata* firmata) int i = 6; int ii = 0; for (ii; ii < (firmata->parse_count - 7) / 2; ii++) { - firmata->i2cmsg[addr][reg+ii] = (firmata->parse_buff[i] & 0x7f) | ((firmata->parse_buff[i+1] & 0x7f) << 7);; + firmata->i2cmsg[addr][reg+ii] = (firmata->parse_buff[i] & 0x7f) | ((firmata->parse_buff[i+1] & 0x7f) << 7); i = i+2; } printf("i2c reply is %d\n", firmata->i2cmsg[addr][reg]); +#endif + } else { + struct _firmata* devs = firmata->devs[0]; + int i = 0; + if (devs != NULL) { + for (i; i < firmata->dev_count; i++, devs++) { + if (devs != NULL) { + if (firmata->parse_buff[1] == devs->feature) { + // call func + if (devs->isr) { + devs->isr(firmata->parse_buff, firmata->parse_count); + } + } + } + } + } } return; } diff --git a/src/firmata/firmata_mraa.c b/src/firmata/firmata_mraa.c index e7355af..6ba9597 100644 --- a/src/firmata/firmata_mraa.c +++ b/src/firmata/firmata_mraa.c @@ -25,6 +25,7 @@ #include #include +#include "firmata.h" #include "mraa_internal.h" #include "firmata/firmata_mraa.h" #include "firmata/firmata.h" @@ -32,6 +33,59 @@ static t_firmata* firmata_dev; static pthread_t thread_id; +mraa_firmata_context +mraa_firmata_init(int feature) +{ + mraa_firmata_context dev = (mraa_firmata_context) calloc(1, sizeof(struct _firmata)); + if (dev == NULL) { + return NULL; + } + dev->feature = (uint8_t) feature; + dev->added = 0; + + return dev; +} + +mraa_result_t +mraa_firmata_write_sysex(mraa_firmata_context dev, char* msg, int length) +{ + return mraa_uart_write(firmata_dev->uart, msg, length); +} + +mraa_result_t +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*)); + if (ptr == NULL) { + return MRAA_ERROR_NO_RESOURCES; + } + firmata_dev->devs = ptr; + dev->index = firmata_dev->dev_count; + firmata_dev->dev_count++; + firmata_dev->devs[dev->index] = dev; + dev->added = 1; + } + dev->isr = fptr; + return MRAA_SUCCESS; +} + +mraa_result_t +mraa_firmata_response_stop(mraa_firmata_context dev) +{ + dev->isr = NULL; + return MRAA_SUCCESS; +} + +mraa_result_t +mraa_firmata_close(mraa_firmata_context dev) +{ + mraa_firmata_response_stop(dev); + free(dev); + return MRAA_SUCCESS; +} + static mraa_result_t mraa_firmata_i2c_init_bus_replace(mraa_i2c_context dev) { @@ -136,6 +190,7 @@ mraa_firmata_i2c_read_byte(mraa_i2c_context dev) } return firmata_dev->i2cmsg[dev->addr][0]; } + return 0; } static uint16_t @@ -186,6 +241,8 @@ mraa_firmata_i2c_read(mraa_i2c_context dev, uint8_t* data, int length) } return length; } + + return 0; } static uint8_t @@ -208,6 +265,9 @@ mraa_firmata_i2c_write(mraa_i2c_context dev, const uint8_t* data, int bytesToWri // buffer needs 5 bytes for firmata, and 2 bytes for every byte of data int buffer_size = (bytesToWrite*2) + 5; uint8_t* buffer = calloc(buffer_size, 0); + if (buffer == NULL) { + return MRAA_ERROR_NO_RESOURCES; + } int i = 0; int ii = 4; buffer[0] = FIRMATA_START_SYSEX; @@ -222,6 +282,7 @@ mraa_firmata_i2c_write(mraa_i2c_context dev, const uint8_t* data, int bytesToWri } buffer[buffer_size-1] = FIRMATA_END_SYSEX; mraa_uart_write(firmata_dev->uart, buffer, buffer_size); + free(buffer); return MRAA_SUCCESS; } @@ -229,6 +290,9 @@ static mraa_result_t mraa_firmata_i2c_write_byte(mraa_i2c_context dev, uint8_t data) { uint8_t* buffer = calloc(7, 0); + if (buffer == NULL) { + return MRAA_ERROR_NO_RESOURCES; + } buffer[0] = FIRMATA_START_SYSEX; buffer[1] = FIRMATA_I2C_REQUEST; buffer[2] = dev->addr; @@ -237,6 +301,7 @@ mraa_firmata_i2c_write_byte(mraa_i2c_context dev, uint8_t data) buffer[5] = (data >> 7) & 0x7F; buffer[6] = FIRMATA_END_SYSEX; mraa_uart_write(firmata_dev->uart, buffer, 7); + free(buffer); return MRAA_SUCCESS; } @@ -244,6 +309,9 @@ static mraa_result_t mraa_firmata_i2c_write_byte_data(mraa_i2c_context dev, const uint8_t data, const uint8_t command) { uint8_t* buffer = calloc(9, 0); + if (buffer == NULL) { + return MRAA_ERROR_NO_RESOURCES; + } buffer[0] = FIRMATA_START_SYSEX; buffer[1] = FIRMATA_I2C_REQUEST; buffer[2] = dev->addr; @@ -254,6 +322,7 @@ mraa_firmata_i2c_write_byte_data(mraa_i2c_context dev, const uint8_t data, const buffer[7] = (data >> 7) & 0x7F; buffer[8] = FIRMATA_END_SYSEX; mraa_uart_write(firmata_dev->uart, buffer, 9); + free(buffer); return MRAA_SUCCESS; } @@ -345,8 +414,8 @@ mraa_firmata_gpio_dir_replace(mraa_gpio_context dev, mraa_gpio_dir_t dir) return MRAA_SUCCESS; } -static void -mraa_firmata_pull_handler(void) +static void* +mraa_firmata_pull_handler(void* vp) { while(1) { firmata_pull(firmata_dev); @@ -355,7 +424,7 @@ mraa_firmata_pull_handler(void) } mraa_board_t* -mraa_firmata_init(const char* uart_dev) +mraa_firmata_plat_init(const char* uart_dev) { mraa_board_t* b = (mraa_board_t*) calloc(1, sizeof(mraa_board_t)); if (b == NULL) { @@ -499,7 +568,7 @@ mraa_firmata_platform(mraa_board_t* board, const char* uart_dev) */ mraa_board_t* sub_plat = NULL; - sub_plat = mraa_firmata_init(uart_dev); + sub_plat = mraa_firmata_plat_init(uart_dev); if (sub_plat != NULL) { sub_plat->platform_type = MRAA_GENERIC_FIRMATA; board->sub_platform = sub_plat;