diff --git a/api/mraa/common.h b/api/mraa/common.h index 1880852..3a894c6 100644 --- a/api/mraa/common.h +++ b/api/mraa/common.h @@ -274,7 +274,10 @@ int mraa_get_sub_platform_id(int pin_or_bus_index); */ int mraa_get_sub_platform_index(int pin_or_bus_id); - +/** + * + */ +mraa_result_t mraa_add_subplatform(mraa_platform_t subplatformtype, const char* uart_dev); #ifdef __cplusplus } diff --git a/api/mraa/common.hpp b/api/mraa/common.hpp index 65202b1..397254d 100644 --- a/api/mraa/common.hpp +++ b/api/mraa/common.hpp @@ -288,4 +288,19 @@ getDefaultI2cBus(int platform_offset=MRAA_MAIN_PLATFORM_OFFSET) { return mraa_get_default_i2c_bus(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") + * @return Result of operation + */ +inline Result +addSubplatform(Platform subplatformtype, std::string uart_dev) +{ + return (Result) mraa_add_subplatform((mraa_platform_t) subplatformtype, uart_dev.c_str()); +} + } diff --git a/api/mraa/types.h b/api/mraa/types.h index 36f2e27..c01ec00 100644 --- a/api/mraa/types.h +++ b/api/mraa/types.h @@ -54,6 +54,9 @@ typedef enum { // USB platform extenders start at 256 MRAA_FTDI_FT4222 = 256, /**< FTDI FT4222 USB to i2c bridge */ + // contains bit 9 so is subplatform + MRAA_GENERIC_FIRMATA = 1280, /**< Firmata uart platform/bridge */ + 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 */ diff --git a/api/mraa/types.hpp b/api/mraa/types.hpp index be37b9a..75bff11 100644 --- a/api/mraa/types.hpp +++ b/api/mraa/types.hpp @@ -47,13 +47,13 @@ typedef enum { BEAGLEBONE = 6, /**< The different BeagleBone Black Modes B/C */ BANANA = 7, /**< Allwinner A20 based Banana Pi and Banana Pro */ INTEL_NUC5 = 8, /**< The Intel 5th generations Broadwell NUCs */ - 96BOARDS = 9, /**< Linaro 96boards */ + A96BOARDS = 9, /**< Linaro 96boards, A prefix for 'ARM' since not allowed numerical */ INTEL_SOFIA_3GR = 10, /**< The Intel SoFIA 3GR */ INTEL_CHERRYHILLS = 11, /**< The Intel Braswell Cherryhills */ FTDI_FT4222 = 256, /**< FTDI FT4222 USB to i2c bridge */ - FIRMATA = 1024, /**< Firmata uart platform/bridge */ + GENERIC_FIRMATA = 1280, /**< Firmata uart platform/bridge */ NULL_PLATFORM = 98, UNKNOWN_PLATFORM = diff --git a/include/firmata/firmata.h b/include/firmata/firmata.h new file mode 100644 index 0000000..41f7c32 --- /dev/null +++ b/include/firmata/firmata.h @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2016 Intel Corporation + * Copyright (c) 2015 Jules Dourlens (jdourlens@gmail.com) + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#pragma once + +#include "serial.h" + +#define MODE_INPUT 0x00 +#define MODE_OUTPUT 0x01 +#define MODE_ANALOG 0x02 +#define MODE_PWM 0x03 +#define MODE_SERVO 0x04 +#define MODE_SHIFT 0x05 +#define MODE_I2C 0x06 + +#define LOW 0 +#define HIGH 1 + +#define FIRMATA_START_SYSEX 0xF0 // start a MIDI Sysex message +#define FIRMATA_END_SYSEX 0xF7 // end a MIDI Sysex message +#define FIRMATA_PIN_MODE_QUERY 0x72 // ask for current and supported pin modes +#define FIRMATA_PIN_MODE_RESPONSE 0x73 // reply with current and supported pin modes +#define FIRMATA_PIN_STATE_QUERY 0x6D +#define FIRMATA_PIN_STATE_RESPONSE 0x6E +#define FIRMATA_CAPABILITY_QUERY 0x6B +#define FIRMATA_CAPABILITY_RESPONSE 0x6C +#define FIRMATA_ANALOG_MAPPING_QUERY 0x69 +#define FIRMATA_ANALOG_MAPPING_RESPONSE 0x6A + +#define FIRMATA_DIGITAL_MESSAGE 0x90 // send data for a digital pin +#define FIRMATA_ANALOG_MESSAGE 0xE0 // send data for an analog pin (or PWM) +#define FIRMATA_ANALOG_MESSAGE 0xE0 // send data for an analog pin (or PWM) +#define FIRMATA_REPORT_ANALOG 0xC0 // enable analog input by pin # +#define FIRMATA_REPORT_DIGITAL 0xD0 // enable digital input by port pair + +#define FIRMATA_I2C_CONFIG 0x78 +#define FIRMATA_I2C_REPLY 0x77 +#define FIRMATA_I2C_REQUEST 0x76 + +#define I2C_MODE_WRITE 0x00 +#define I2C_MODE_READ 0x01 +#define I2C_CONTINUOUSREAD 0x02 +#define I2C_STOP_READING 0x03 + +#define FIRMATA_SET_PIN_MODE 0xF4 // set a pin to INPUT/OUTPUT/PWM/etc + +#define FIRMATA_REPORT_VERSION 0xF9 // report protocol version +#define FIRMATA_SYSTEM_RESET 0xFF // reset from MIDI + +#define FIRMATA_START_SYSEX 0xF0 // start a MIDI Sysex message +#define FIRMATA_END_SYSEX 0xF7 // end a MIDI Sysex message + +// extended command set using sysex (0-127/0x00-0x7F) +/* 0x00-0x0F reserved for custom commands */ +#define FIRMATA_SERVO_CONFIG 0x70 // set max angle, minPulse, maxPulse, freq +#define FIRMATA_STRING 0x71 // a string message with 14-bits per char +#define FIRMATA_REPORT_FIRMWARE 0x79 // report name and version of the firmware +#define FIRMATA_SYSEX_NON_REALTIME 0x7E // MIDI Reserved for non-realtime messages +#define FIRMATA_SYSEX_REALTIME 0x7F // MIDI Reserved for realtime messages + +#define FIRMATA_MSG_LEN 1024 + +typedef struct s_pin { + uint8_t mode; + uint8_t analog_channel; + uint64_t supported_modes; + uint32_t value; +} t_pin; + +typedef struct s_firmata { + t_serial* serial; + t_pin pins[128]; + int i2cmsg[256][256]; + int parse_command_len; + int parse_count; + uint8_t parse_buff[FIRMATA_MSG_LEN]; + int isReady; + char firmware[140]; +} t_firmata; + +t_firmata* firmata_new(const char* name); +void firmata_initPins(t_firmata* firmata); +int firmata_askFirmware(t_firmata* firmata); +int firmata_pinMode(t_firmata* firmata, int pin, int mode); +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); +void firmata_parse(t_firmata* firmata, const uint8_t* buf, int len); +void firmata_endParse(t_firmata* firmata); diff --git a/include/firmata/firmata_mraa.h b/include/firmata/firmata_mraa.h new file mode 100644 index 0000000..a80d73a --- /dev/null +++ b/include/firmata/firmata_mraa.h @@ -0,0 +1,38 @@ +/* + * 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 + +#ifdef __cplusplus +extern "C" { +#endif + +#include "mraa_internal.h" + +mraa_platform_t mraa_firmata_platform(mraa_board_t* board, const char* uart_dev); + + +#ifdef __cplusplus +} +#endif diff --git a/include/firmata/serial.h b/include/firmata/serial.h new file mode 100644 index 0000000..e35e273 --- /dev/null +++ b/include/firmata/serial.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2016 Intel Corporation + * Copyright (c) 2015 Jules Dourlens (jdourlens@gmail.com) + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#pragma once + +#include +#include + +typedef struct s_serial { + int port_is_open; + const char* port_name; + int baud_rate; + char* error_msg; + + int port_fd; + struct termios settings_orig; + struct termios settings; + int tx; + int rx; +} t_serial; + +t_serial* serial_new(); +int serial_open(t_serial* serial, const char* name); +int serial_setBaud(t_serial* serial, int baud); +int serial_read(t_serial* serial, void* ptr, int count); +int serial_write(t_serial* serial, void* ptr, int len); +int serial_waitInput(t_serial* serial, int msec); +int serial_discardInput(t_serial* serial); +void serial_flushOutput(t_serial* serial); +int serial_setControl(t_serial* serial, int dtr, int rts); diff --git a/include/firmata/servo.h b/include/firmata/servo.h new file mode 100644 index 0000000..5f11681 --- /dev/null +++ b/include/firmata/servo.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2016 Intel Corporation + * Copyright (c) 2015 Jules Dourlens (jdourlens@gmail.com) + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#pragma once + +#include "firmata.h" + +typedef struct s_servo { + t_firmata* firmata; + int pin; +} t_servo; + +t_servo* servo_attach(t_firmata* firmata, int pin); +int servo_write(t_servo* servo, int value); diff --git a/include/mraa_adv_func.h b/include/mraa_adv_func.h index b33fc36..79430cd 100644 --- a/include/mraa_adv_func.h +++ b/include/mraa_adv_func.h @@ -73,6 +73,8 @@ typedef struct { mraa_result_t (*i2c_write_word_data_replace) (mraa_i2c_context dev, const uint16_t data, const uint8_t command); mraa_result_t (*i2c_stop_replace) (mraa_i2c_context dev); + mraa_result_t (*aio_init_internal_replace) (mraa_aio_context dev, int pin); + mraa_result_t (*aio_read_replace) (mraa_aio_context dev); mraa_result_t (*aio_get_valid_fp) (mraa_aio_context dev); mraa_result_t (*aio_init_pre) (unsigned int aio); mraa_result_t (*aio_init_post) (mraa_aio_context dev); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 30b4d46..d8110c2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -106,6 +106,11 @@ if (USBPLAT) add_subdirectory(usb) endif () +if (FIRMATA) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DFIRMATA=1") + add_subdirectory (firmata) +endif () + set (mraa_LIB_SRCS ${mraa_LIB_PLAT_SRCS_NOAUTO} # autogenerated version file diff --git a/src/aio/aio.c b/src/aio/aio.c index 32b794f..92aa9f4 100644 --- a/src/aio/aio.c +++ b/src/aio/aio.c @@ -1,7 +1,7 @@ /* * Author: Nandkishor Sonar * Author: Brendan Le Foll - * Copyright (c) 2014, 2015 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 @@ -56,7 +56,7 @@ aio_get_valid_fp(mraa_aio_context dev) } static mraa_aio_context -mraa_aio_init_internal(mraa_adv_func_t* func_table) +mraa_aio_init_internal(mraa_adv_func_t* func_table, int aio) { mraa_aio_context dev = calloc(1, sizeof(struct _aio)); if (dev == NULL) { @@ -64,6 +64,20 @@ mraa_aio_init_internal(mraa_adv_func_t* func_table) } dev->advance_func = func_table; + if (IS_FUNC_DEFINED(dev, aio_init_internal_replace)) { + if (dev->advance_func->aio_init_internal_replace(dev, aio) == MRAA_SUCCESS) { + return dev; + } + free(dev); + return NULL; + } + + // Open valid analog input file and get the pointer. + if (MRAA_SUCCESS != aio_get_valid_fp(dev)) { + free(dev); + return NULL; + } + return dev; } @@ -83,16 +97,37 @@ mraa_aio_init(unsigned int aio) syslog(LOG_ERR, "aio: Sub platform Not Initialised"); return NULL; } - pin = mraa_get_sub_platform_index(aio); + aio = mraa_get_sub_platform_index(aio); + } + + // aio are always past the gpio_count in the pin array + pin = aio + board->gpio_count; + + if (pin < 0 || pin >= board->phy_pin_count) { + syslog(LOG_ERR, "aio: pin %i beyond platform definition", pin); + return NULL; + } + if (aio > board->aio_count) { + syslog(LOG_ERR, "aio: requested channel out of range"); + return NULL; + } + if (board->pins[pin].capabilites.aio != 1) { + syslog(LOG_ERR, "aio: pin %i not capable of aio", pin); + return NULL; + } + if (board->pins[pin].aio.mux_total > 0) { + if (mraa_setup_mux_mapped(board->pins[pin].aio) != MRAA_SUCCESS) { + syslog(LOG_ERR, "aio: unable to setup multiplexers for pin"); + return NULL; + } } // Create ADC device connected to specified channel - mraa_aio_context dev = mraa_aio_init_internal(board->adv_func); + mraa_aio_context dev = mraa_aio_init_internal(board->adv_func, aio); if (dev == NULL) { syslog(LOG_ERR, "aio: Insufficient memory for specified input channel %d", aio); return NULL; } - pin = aio + board->gpio_count; dev->channel = board->pins[pin].aio.pinmap; dev->value_bit = DEFAULT_BITS; @@ -103,32 +138,6 @@ mraa_aio_init(unsigned int aio) return NULL; } } - if (aio > board->aio_count) { - syslog(LOG_ERR, "aio: requested channel out of range"); - free(dev); - return NULL; - } - - if (board->pins[pin].capabilites.aio != 1) { - syslog(LOG_ERR, "aio: pin uncapable of aio"); - free(dev); - return NULL; - } - - if (board->pins[pin].aio.mux_total > 0) { - if (mraa_setup_mux_mapped(board->pins[pin].aio) != MRAA_SUCCESS) { - free(dev); - syslog(LOG_ERR, "aio: unable to setup multiplexers for pin"); - return NULL; - } - } - - // Open valid analog input file and get the pointer. - if (MRAA_SUCCESS != aio_get_valid_fp(dev)) { - free(dev); - return NULL; - } - raw_bits = mraa_adc_raw_bits(); if (IS_FUNC_DEFINED(dev, aio_init_post)) { mraa_result_t ret = dev->advance_func->aio_init_post(dev); @@ -138,12 +147,18 @@ mraa_aio_init(unsigned int aio) } } + raw_bits = mraa_adc_raw_bits(); + return dev; } unsigned int mraa_aio_read(mraa_aio_context dev) { + if (IS_FUNC_DEFINED(dev, aio_read_replace)) { + return dev->advance_func->aio_read_replace(dev); + } + char buffer[17]; unsigned int shifter_value = 0; diff --git a/src/firmata/CMakeLists.txt b/src/firmata/CMakeLists.txt new file mode 100644 index 0000000..540a1af --- /dev/null +++ b/src/firmata/CMakeLists.txt @@ -0,0 +1,11 @@ +if (FIRMATA) + message (STATUS "INFO - Adding firmata backend support") + set (mraa_LIB_PLAT_SRCS_NOAUTO ${mraa_LIB_PLAT_SRCS_NOAUTO} + ${PROJECT_SOURCE_DIR}/src/firmata/firmata.c + ${PROJECT_SOURCE_DIR}/src/firmata/servo.c + ${PROJECT_SOURCE_DIR}/src/firmata/serial.c + ${PROJECT_SOURCE_DIR}/src/firmata/firmata_mraa.c + PARENT_SCOPE + ) + message (${mraa_LIB_PLAT_SRCS_NOAUTO}) +endif () diff --git a/src/firmata/firmata.c b/src/firmata/firmata.c new file mode 100644 index 0000000..16b887c --- /dev/null +++ b/src/firmata/firmata.c @@ -0,0 +1,341 @@ +/* + * Copyright (c) 2016 Intel Corporation + * Copyright (c) 2015 Jules Dourlens (jdourlens@gmail.com) + * + * 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 "firmata/serial.h" +#include "firmata/firmata.h" + +#include +#include +#include + +t_firmata* +firmata_new(const char* name) +{ + t_firmata* res; + + printf("Opening device at: %s\n", name); + res = malloc(sizeof(t_firmata)); + if (!res) { + perror("firmata_new::Failed malloc"); + return (NULL); + } + memset(res, 0, sizeof(*res)); + res->serial = serial_new(); + if (!res->serial) { + perror("firmata_new::Failed malloc"); + return (NULL); + } + serial_open(res->serial, name); + firmata_initPins(res); + serial_setBaud(res->serial, 57600); + firmata_askFirmware(res); + printf("Device opened at: %s\n", name); + return (res); +} + +int +firmata_pull(t_firmata* firmata) +{ + uint8_t buff[FIRMATA_MSG_LEN]; + int r; + + r = serial_waitInput(firmata->serial, 40); + if (r > 0) { + r = serial_read(firmata->serial, buff, sizeof(buff)); + if (r < 0) { + return (0); + } + if (r > 0) { + firmata_parse(firmata, buff, r); + return (r); + } + } else if (r < 0) { + return (r); + } +} + +void +firmata_parse(t_firmata* firmata, const uint8_t* buf, int len) +{ + const uint8_t* p; + const uint8_t* end; + + p = buf; + end = p + len; + for (p = buf; p < end; p++) { + uint8_t msn = *p & 0xF0; + if (msn == 0xE0 || msn == 0x90 || *p == 0xF9) { + firmata->parse_command_len = 3; + firmata->parse_count = 0; + } else if (msn == 0xC0 || msn == 0xD0) { + firmata->parse_command_len = 2; + firmata->parse_count = 0; + } else if (*p == FIRMATA_START_SYSEX) { + firmata->parse_count = 0; + firmata->parse_command_len = sizeof(firmata->parse_buff); + } else if (*p == FIRMATA_END_SYSEX) { + firmata->parse_command_len = firmata->parse_count + 1; + } else if (*p & 0x80) { + firmata->parse_command_len = 1; + firmata->parse_count = 0; + } + if (firmata->parse_count < (int) sizeof(firmata->parse_buff)) { + firmata->parse_buff[firmata->parse_count] = (uint8_t)(*p); + firmata->parse_count++; + } + if (firmata->parse_count == firmata->parse_command_len) { + firmata_endParse(firmata); + firmata->parse_count = 0; + firmata->parse_command_len = 0; + } + } +} + +void +firmata_endParse(t_firmata* firmata) +{ + uint8_t cmd = (firmata->parse_buff[0] & 0xF0); + int pin; + + if (cmd == 0xE0 && firmata->parse_count == 3) { + int analog_ch = (firmata->parse_buff[0] & 0x0F); + int analog_val = firmata->parse_buff[1] | (firmata->parse_buff[2] << 7); + for (pin = 0; pin < 128; pin++) { + if (firmata->pins[pin].analog_channel == analog_ch) { + firmata->pins[pin].value = analog_val; + return; + } + } + return; + } + if (cmd == 0x90 && firmata->parse_count == 3) { + int port_num = (firmata->parse_buff[0] & 0x0F); + int port_val = firmata->parse_buff[1] | (firmata->parse_buff[2] << 7); + int pin = port_num * 8; + int mask; + for (mask = 1; mask & 0xFF; mask <<= 1, pin++) { + if (firmata->pins[pin].mode == MODE_INPUT) { + uint32_t val = (port_val & mask) ? 1 : 0; + firmata->pins[pin].value = val; + } + } + return; + } + if (firmata->parse_buff[0] == FIRMATA_START_SYSEX && + firmata->parse_buff[firmata->parse_count - 1] == FIRMATA_END_SYSEX) { + if (firmata->parse_buff[1] == FIRMATA_REPORT_FIRMWARE) { + int len = 0; + int i; + for (i = 4; i < firmata->parse_count - 2; i += 2) { + firmata->firmware[len++] = + (firmata->parse_buff[i] & 0x7F) | ((firmata->parse_buff[i + 1] & 0x7F) << 7); + } + firmata->firmware[len++] = '-'; + firmata->firmware[len++] = firmata->parse_buff[2] + '0'; + firmata->firmware[len++] = '.'; + firmata->firmware[len++] = firmata->parse_buff[3] + '0'; + firmata->firmware[len++] = 0; + printf("Name :: %s\n", firmata->firmware); + // query the board's capabilities only after hearing the + // REPORT_FIRMWARE message. For boards that reset when + // the port open (eg, Arduino with reset=DTR), they are + // not ready to communicate for some time, so the only + // way to reliably query their capabilities is to wait + // until the REPORT_FIRMWARE message is heard. + uint8_t buf[80]; + len = 0; + buf[len++] = FIRMATA_START_SYSEX; + buf[len++] = FIRMATA_ANALOG_MAPPING_QUERY; // read analog to pin # info + buf[len++] = FIRMATA_END_SYSEX; + buf[len++] = FIRMATA_START_SYSEX; + buf[len++] = FIRMATA_CAPABILITY_QUERY; // read capabilities + buf[len++] = FIRMATA_END_SYSEX; + for (i = 0; i < 16; i++) { + buf[len++] = 0xC0 | i; // report analog + buf[len++] = 1; + buf[len++] = 0xD0 | i; // report digital + buf[len++] = 1; + } + firmata->isReady = 1; + serial_write(firmata->serial, buf, len); + } else if (firmata->parse_buff[1] == FIRMATA_CAPABILITY_RESPONSE) { + int pin, i, n; + for (pin = 0; pin < 128; pin++) { + firmata->pins[pin].supported_modes = 0; + } + for (i = 2, n = 0, pin = 0; i < firmata->parse_count; i++) { + if (firmata->parse_buff[i] == 127) { + pin++; + n = 0; + continue; + } + if (n == 0) { + // first byte is supported mode + firmata->pins[pin].supported_modes |= (1 << firmata->parse_buff[i]); + } + n = n ^ 1; + } + // send a state query for for every pin with any modes + for (pin = 0; pin < 128; pin++) { + uint8_t buf[512]; + int len = 0; + if (firmata->pins[pin].supported_modes) { + buf[len++] = FIRMATA_START_SYSEX; + buf[len++] = FIRMATA_PIN_STATE_QUERY; + buf[len++] = pin; + buf[len++] = FIRMATA_END_SYSEX; + } + serial_write(firmata->serial, buf, len); + } + } else if (firmata->parse_buff[1] == FIRMATA_ANALOG_MAPPING_RESPONSE) { + int pin = 0; + int i; + for (i = 2; i < firmata->parse_count - 1; i++) { + firmata->pins[pin].analog_channel = firmata->parse_buff[i]; + pin++; + } + return; + } else if (firmata->parse_buff[1] == FIRMATA_PIN_STATE_RESPONSE && firmata->parse_count >= 6) { + int pin = firmata->parse_buff[2]; + firmata->pins[pin].mode = firmata->parse_buff[3]; + firmata->pins[pin].value = firmata->parse_buff[4]; + if (firmata->parse_count > 6) + firmata->pins[pin].value |= (firmata->parse_buff[5] << 7); + if (firmata->parse_count > 7) + firmata->pins[pin].value |= (firmata->parse_buff[6] << 14); + } 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); + int reg = (firmata->parse_buff[4] & 0x7f) | ((firmata->parse_buff[5] & 0x7f) << 7); + 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);; + i = i+2; + } + printf("i2c reply is %d\n", firmata->i2cmsg[addr][reg]); + } + return; + } +} + +void +firmata_initPins(t_firmata* firmata) +{ + int i; + + firmata->parse_count = 0; + firmata->parse_command_len = 0; + firmata->isReady = 0; + for (i = 0; i < 128; i++) { + firmata->pins[i].mode = 255; + firmata->pins[i].analog_channel = 127; + firmata->pins[i].supported_modes = 0; + firmata->pins[i].value = 0; + } +} + +int +firmata_askFirmware(t_firmata* firmata) +{ + uint8_t buf[3]; + int res; + + buf[0] = FIRMATA_START_SYSEX; + buf[1] = FIRMATA_REPORT_FIRMWARE; // read firmata name & version + buf[2] = FIRMATA_END_SYSEX; + res = serial_write(firmata->serial, buf, 3); + return (res); +} + +int +firmata_pinMode(t_firmata* firmata, int pin, int mode) +{ + int res; + uint8_t buff[4]; + + firmata->pins[pin].mode = mode; + buff[0] = FIRMATA_SET_PIN_MODE; + buff[1] = pin; + buff[2] = mode; + printf("Setting pinMode at: %i with value: %i\n", pin, mode); + res = serial_write(firmata->serial, buff, 3); + return (res); +} + +int +firmata_analogWrite(t_firmata* firmata, int pin, int value) +{ + int res; + + uint8_t buff[3]; + printf("Writting analogWrite at: %i with value: %i\n", pin, value); + buff[0] = 0xE0 | pin; + buff[1] = value & 0x7F; + buff[2] = (value >> 7) & 0x7F; + res = serial_write(firmata->serial, buff, 3); + return (res); +} + +int +firmata_analogRead(t_firmata *firmata, int pin) +{ + int res; + int value = 1; + uint8_t buff[2]; + printf("Writting analogRead at: %i\n", pin); + buff[0] = FIRMATA_REPORT_ANALOG | pin; + buff[1] = value; + printf("192 == %d, pinval == %d, pin %d", buff[0], buff[1], pin); + res = serial_write(firmata->serial, buff, 2); + return res; +} + +int +firmata_digitalWrite(t_firmata* firmata, int pin, int value) +{ + int i; + int res; + uint8_t buff[4]; + + if (pin < 0 || pin > 127) + return (0); + firmata->pins[pin].value = value; + int port_num = pin / 8; + int port_val = 0; + for (i = 0; i < 8; i++) { + int p = port_num * 8 + i; + if (firmata->pins[p].mode == MODE_OUTPUT || firmata->pins[p].mode == MODE_INPUT) { + if (firmata->pins[p].value) { + port_val |= (1 << i); + } + } + } + printf("Writting digitalWrite at: %i with value: %i\n", pin, value); + buff[0] = FIRMATA_DIGITAL_MESSAGE | port_num; + buff[1] = port_val & 0x7F; + buff[2] = (port_val >> 7) & 0x7F; + res = serial_write(firmata->serial, buff, 3); + return (res); +} diff --git a/src/firmata/firmata_mraa.c b/src/firmata/firmata_mraa.c new file mode 100644 index 0000000..e6f9ed6 --- /dev/null +++ b/src/firmata/firmata_mraa.c @@ -0,0 +1,507 @@ +/* + * 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 + +#include "mraa_internal.h" +#include "firmata/firmata_mraa.h" +#include "firmata/firmata.h" +#include "firmata/serial.h" + +static t_firmata* firmata_dev; +static pthread_t thread_id; + +static mraa_result_t +mraa_firmata_i2c_init_bus_replace(mraa_i2c_context dev) +{ + int delay = 1; // this should be either 1 or 0, I don't know :) + uint8_t buff[4]; + printf("i2c init\n"); + buff[0] = FIRMATA_START_SYSEX; + buff[1] = FIRMATA_I2C_CONFIG; + buff[2] = delay & 0xFF, (delay >> 8) & 0xFF; + buff[3] = FIRMATA_END_SYSEX; + serial_write(firmata_dev->serial, buff, 4); + + return MRAA_SUCCESS; +} + +static mraa_result_t +mraa_firmata_i2c_address(mraa_i2c_context dev, uint8_t addr) +{ + // only thing needed and it's already done + //dev->addr = (int) addr; + + return MRAA_SUCCESS; +} + +static mraa_result_t +mraa_firmata_i2c_frequency(mraa_i2c_context dev, mraa_i2c_mode_t mode) +{ + return MRAA_ERROR_FEATURE_NOT_IMPLEMENTED; +} + +static mraa_result_t +mraa_firmata_send_i2c_read_req(mraa_i2c_context dev, int length) +{ + 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; + buffer[3] = I2C_MODE_READ << 3; + + // number of bytes + buffer[4] = length & 0x7f; + buffer[5] = (length >> 7) & 0x7f; + buffer[6] = FIRMATA_END_SYSEX; + + if (serial_write(firmata_dev->serial, buffer, 7) != 7) { + free(buffer); + return MRAA_ERROR_INVALID_RESOURCE; + } + + // this needs a lock :) + memset(&firmata_dev->i2cmsg[dev->addr][0], -1, sizeof(int)*length); + + free(buffer); + return MRAA_SUCCESS; +} + +static mraa_result_t +mraa_firmata_send_i2c_read_cont_req(mraa_i2c_context dev, uint8_t command, int length) +{ + 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; + buffer[3] = I2C_MODE_READ << 3; + + // register to read from + buffer[4] = command & 0x7f; + buffer[5] = (command >> 7) & 0x7f; + // number of bytes + buffer[6] = length & 0x7f; + buffer[7] = (length >> 7) & 0x7f; + buffer[8] = FIRMATA_END_SYSEX; + + if (serial_write(firmata_dev->serial, buffer, 9) != 9) { + free(buffer); + return MRAA_ERROR_INVALID_RESOURCE; + } + + // this needs a lock :) + memset(&firmata_dev->i2cmsg[dev->addr][command], -1, sizeof(int)*length); + + free(buffer); + return MRAA_SUCCESS; +} + +static uint8_t +mraa_firmata_i2c_read_byte(mraa_i2c_context dev) +{ + if (mraa_firmata_send_i2c_read_req(dev, 1) == MRAA_SUCCESS) { + while (firmata_dev->i2cmsg[dev->addr][0] == -1) { + usleep(500); + } + return firmata_dev->i2cmsg[dev->addr][0]; + } +} + +static uint16_t +mraa_firmata_i2c_read_word_data(mraa_i2c_context dev, uint8_t command) +{ + if (mraa_firmata_send_i2c_read_cont_req(dev, command, 2) == MRAA_SUCCESS) { + while (firmata_dev->i2cmsg[dev->addr][command] == -1) { + usleep(500); + } + + uint8_t* rawdata[2]; + rawdata[0] = firmata_dev->i2cmsg[dev->addr][command]; + rawdata[1] = firmata_dev->i2cmsg[dev->addr][command+1]; + uint16_t data = (uint16_t) rawdata; + uint8_t high = (data & 0xFF00) >> 8; + data = (data << 8) & 0xFF00; + data |= high; + + return data; + } + return 0; +} + +static int +mraa_firmata_i2c_read_bytes_data(mraa_i2c_context dev, uint8_t command, uint8_t* data, int length) +{ + if (mraa_firmata_send_i2c_read_cont_req(dev, command, length) == MRAA_SUCCESS) { + while (firmata_dev->i2cmsg[dev->addr][command] == -1) { + usleep(500); + } + + memcpy(data, &firmata_dev->i2cmsg[dev->addr][command], sizeof(int)*length); + return length; + } + return 0; +} + +static int +mraa_firmata_i2c_read(mraa_i2c_context dev, uint8_t* data, int length) +{ + if (mraa_firmata_send_i2c_read_req(dev, length) == MRAA_SUCCESS) { + while (firmata_dev->i2cmsg[dev->addr][0] == -1) { + usleep(500); + } + int i = 0; + for (i = 0; i < length; i++) { + data[i] = firmata_dev->i2cmsg[dev->addr][i]; + } + return length; + } +} + +static uint8_t +mraa_firmata_i2c_read_byte_data(mraa_i2c_context dev, uint8_t command) +{ + if (mraa_firmata_send_i2c_read_cont_req(dev, command, 1) == MRAA_SUCCESS) { + while (firmata_dev->i2cmsg[dev->addr][command] == -1) { + usleep(500); + } + + return firmata_dev->i2cmsg[dev->addr][command]; + } + + return 0; +} + +static mraa_result_t +mraa_firmata_i2c_write(mraa_i2c_context dev, const uint8_t* data, int bytesToWrite) +{ + // 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); + int i = 0; + int ii = 4; + buffer[0] = FIRMATA_START_SYSEX; + buffer[1] = FIRMATA_I2C_REQUEST; + buffer[2] = dev->addr; + buffer[3] = I2C_MODE_WRITE << 3; + // we need to write until FIRMATA_END_SYSEX + for (i; i < (buffer_size-1); i++) { + buffer[ii] = data[i] & 0x7F; + buffer[ii+1] = (data[i] >> 7) & 0x7f; + ii = ii+2; + } + buffer[buffer_size-1] = FIRMATA_END_SYSEX; + serial_write(firmata_dev->serial, buffer, buffer_size); + return MRAA_SUCCESS; +} + +static mraa_result_t +mraa_firmata_i2c_write_byte(mraa_i2c_context dev, uint8_t data) +{ + uint8_t* buffer = calloc(7, 0); + buffer[0] = FIRMATA_START_SYSEX; + buffer[1] = FIRMATA_I2C_REQUEST; + buffer[2] = dev->addr; + buffer[3] = I2C_MODE_WRITE << 3; + buffer[4] = data & 0x7F; + buffer[5] = (data >> 7) & 0x7F; + buffer[6] = FIRMATA_END_SYSEX; + serial_write(firmata_dev->serial, buffer, 7); + return MRAA_SUCCESS; +} + +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); + buffer[0] = FIRMATA_START_SYSEX; + buffer[1] = FIRMATA_I2C_REQUEST; + buffer[2] = dev->addr; + buffer[3] = I2C_MODE_WRITE << 3; + buffer[4] = command & 0x7F; + buffer[5] = (command >> 7) & 0x7F; + buffer[6] = data & 0x7F; + buffer[7] = (data >> 7) & 0x7F; + buffer[8] = FIRMATA_END_SYSEX; + serial_write(firmata_dev->serial, buffer, 9); + return MRAA_SUCCESS; +} + +static mraa_result_t +mraa_firmata_i2c_write_word_data(mraa_i2c_context dev, const uint16_t data, const uint8_t command) +{ + return MRAA_ERROR_FEATURE_NOT_IMPLEMENTED; +} + +static mraa_result_t +mraa_firmata_i2c_stop(mraa_i2c_context dev) +{ + return MRAA_SUCCESS; +} + +static unsigned int +mraa_firmata_aio_read(mraa_aio_context dev) +{ + // careful, whilst you need to enable '0' for A0 you then need to read 14 + // in t_firmata because well that makes sense doesn't it... + return (unsigned int) firmata_dev->pins[dev->channel].value; +} + +static mraa_result_t +mraa_firmata_aio_init_internal_replace(mraa_aio_context dev, int aio) +{ + // firmata considers A0 pin0 as well as actual pin0 :/ + firmata_pinMode(firmata_dev, aio, MODE_ANALOG); + // register for updates on that ADC channel + firmata_analogRead(firmata_dev, aio); + + return MRAA_SUCCESS; +} + +static mraa_result_t +mraa_firmata_gpio_init_internal_replace(mraa_gpio_context dev, int pin) +{ + dev->pin = pin; + dev->phy_pin = pin; + + return MRAA_SUCCESS; +} + +static mraa_result_t +mraa_firmata_gpio_mode_replace(mraa_gpio_context dev, mraa_gpio_mode_t mode) +{ + return MRAA_ERROR_FEATURE_NOT_IMPLEMENTED; +} + +static int +mraa_firmata_gpio_read_replace(mraa_gpio_context dev) +{ + return firmata_dev->pins[dev->pin].value; +} + +static mraa_result_t +mraa_firmata_gpio_write_replace(mraa_gpio_context dev, int write_value) +{ + if (write_value == 0) { + firmata_digitalWrite(firmata_dev, dev->phy_pin, LOW); + } else { + firmata_digitalWrite(firmata_dev, dev->phy_pin, HIGH); + } + + return MRAA_SUCCESS; +} + +static mraa_result_t +mraa_firmata_gpio_dir_replace(mraa_gpio_context dev, mraa_gpio_dir_t dir) +{ + switch (dir) { + case MRAA_GPIO_IN: + firmata_pinMode(firmata_dev, dev->phy_pin, MODE_INPUT); + break; + case MRAA_GPIO_OUT: + firmata_pinMode(firmata_dev, dev->phy_pin, MODE_OUTPUT); + break; + case MRAA_GPIO_OUT_LOW: + firmata_pinMode(firmata_dev, dev->phy_pin, MODE_OUTPUT); + firmata_digitalWrite(firmata_dev, dev->phy_pin, LOW); + break; + case MRAA_GPIO_OUT_HIGH: + firmata_pinMode(firmata_dev, dev->phy_pin, MODE_OUTPUT); + firmata_digitalWrite(firmata_dev, dev->phy_pin, HIGH); + break; + default: + return MRAA_ERROR_INVALID_PARAMETER; + } + return MRAA_SUCCESS; +} + +static void +mraa_firmata_pull_handler(void) +{ + while(1) { + firmata_pull(firmata_dev); + usleep(100); + } +} + +mraa_board_t* +mraa_firmata_init(const char* uart_dev) +{ + 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 this isn't working then we have an issue with our uart + while (!firmata_dev->isReady) { + firmata_pull(firmata_dev); + } + + pthread_create(&thread_id, NULL, mraa_firmata_pull_handler, NULL); + + b->platform_name = "firmata"; + // do we support 2.5? Or are we more 2.3? + // or should we return the flashed sketch name? + b->platform_version = firmata_dev->firmware; + b->gpio_count = 14; + b->aio_count = 6; + b->adc_supported = 10; + b->phy_pin_count = 20; + b->i2c_bus_count = 1; + b->def_i2c_bus = 0; + b->i2c_bus[0].bus_id = 0; + + b->pins = (mraa_pininfo_t*) calloc(b->phy_pin_count, sizeof(mraa_pininfo_t)); + if (b->pins == NULL) { + free(b); + return NULL; + } + + strncpy(b->pins[0].name, "IO0", 8); + b->pins[0].capabilites = (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].capabilites = (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].capabilites = (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].capabilites = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }; + b->pins[3].gpio.pinmap = 3; + strncpy(b->pins[4].name, "IO4", 8); + b->pins[4].capabilites = (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].capabilites = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }; + b->pins[5].gpio.pinmap = 5; + strncpy(b->pins[6].name, "IO6", 8); + b->pins[6].capabilites = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }; + b->pins[6].gpio.pinmap = 6; + strncpy(b->pins[7].name, "IO7", 8); + b->pins[7].capabilites = (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].capabilites = (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].capabilites = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }; + b->pins[9].gpio.pinmap = 9; + strncpy(b->pins[10].name, "IO10", 8); + b->pins[10].capabilites = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }; + b->pins[10].gpio.pinmap = 10; + strncpy(b->pins[11].name, "IO11", 8); + b->pins[11].capabilites = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }; + b->pins[11].gpio.pinmap = 11; + strncpy(b->pins[12].name, "IO12", 8); + b->pins[12].capabilites = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }; + b->pins[12].gpio.pinmap = 12; + strncpy(b->pins[13].name, "IO13", 8); + b->pins[13].capabilites = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 }; + b->pins[13].gpio.pinmap = 13; + strncpy(b->pins[10].name, "A0", 8); + b->pins[14].capabilites = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 1, 0 }; + b->pins[14].gpio.pinmap = 14; + b->pins[14].aio.pinmap = 14; + strncpy(b->pins[11].name, "A1", 8); + b->pins[15].capabilites = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 1, 0 }; + b->pins[15].gpio.pinmap = 15; + b->pins[15].aio.pinmap = 15; + strncpy(b->pins[12].name, "A2", 8); + b->pins[16].capabilites = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 1, 0 }; + b->pins[16].gpio.pinmap = 16; + b->pins[16].aio.pinmap = 16; + strncpy(b->pins[13].name, "A3", 8); + b->pins[17].capabilites = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 1, 0 }; + b->pins[17].gpio.pinmap = 17; + b->pins[17].aio.pinmap = 17; + strncpy(b->pins[13].name, "A4", 8); + b->pins[18].capabilites = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 1, 0 }; + b->pins[18].gpio.pinmap = 18; + b->pins[18].aio.pinmap = 18; + strncpy(b->pins[13].name, "A5", 8); + b->pins[19].capabilites = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 1, 0 }; + b->pins[19].gpio.pinmap = 19; + b->pins[19].aio.pinmap = 19; + + 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 NULL; + } + + b->adv_func->gpio_init_internal_replace = &mraa_firmata_gpio_init_internal_replace; + b->adv_func->gpio_mode_replace = &mraa_firmata_gpio_mode_replace; + b->adv_func->gpio_dir_replace = &mraa_firmata_gpio_dir_replace; + b->adv_func->gpio_read_replace = &mraa_firmata_gpio_read_replace; + b->adv_func->gpio_write_replace = &mraa_firmata_gpio_write_replace; + + b->adv_func->aio_init_internal_replace = &mraa_firmata_aio_init_internal_replace; + b->adv_func->aio_read_replace = &mraa_firmata_aio_read; + + b->adv_func->i2c_init_bus_replace = &mraa_firmata_i2c_init_bus_replace; + b->adv_func->i2c_set_frequency_replace = &mraa_firmata_i2c_frequency; + b->adv_func->i2c_address_replace = &mraa_firmata_i2c_address; + b->adv_func->i2c_read_replace = &mraa_firmata_i2c_read; + b->adv_func->i2c_read_byte_replace = &mraa_firmata_i2c_read_byte; + b->adv_func->i2c_read_byte_data_replace = &mraa_firmata_i2c_read_byte_data; + b->adv_func->i2c_read_word_data_replace = &mraa_firmata_i2c_read_word_data; + b->adv_func->i2c_read_bytes_data_replace = &mraa_firmata_i2c_read_bytes_data; + b->adv_func->i2c_write_replace = &mraa_firmata_i2c_write; + b->adv_func->i2c_write_byte_replace = &mraa_firmata_i2c_write_byte; + b->adv_func->i2c_write_byte_data_replace = &mraa_firmata_i2c_write_byte_data; + b->adv_func->i2c_write_word_data_replace = &mraa_firmata_i2c_write_word_data; + b->adv_func->i2c_stop_replace = &mraa_firmata_i2c_stop; + + return b; +} + +mraa_platform_t +mraa_firmata_platform(mraa_board_t* board, const char* uart_dev) +{ + /** + * Firmata boards are not something we can detect so we just trust the user + * to initialise them themselves and is the only platform type not to be + * initialised from mraa_init(). Good luck! + */ + mraa_board_t* sub_plat = NULL; + + sub_plat = mraa_firmata_init(uart_dev); + if (sub_plat != NULL) { + sub_plat->platform_type = MRAA_GENERIC_FIRMATA; + board->sub_platform = sub_plat; + return sub_plat->platform_type; + } + + return MRAA_NULL_PLATFORM; +} diff --git a/src/firmata/serial.c b/src/firmata/serial.c new file mode 100644 index 0000000..ee61ce6 --- /dev/null +++ b/src/firmata/serial.c @@ -0,0 +1,340 @@ +/* + * Copyright (c) 2016 Intel Corporation + * Copyright (c) 2015 Jules Dourlens (jdourlens@gmail.com) + * + * 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 "firmata/serial.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +t_serial* +serial_new() +{ + t_serial* res; + + res = malloc(sizeof(t_serial)); + if (!res) { + return (NULL); + } + res->port_is_open = 0; + res->baud_rate = 57600; + res->tx = 0; + res->rx = 0; + return (res); +} + +int +serial_open(t_serial* serial, const char* name) +{ + struct serial_struct kernel_serial_settings; + int bits; + + serial->port_fd = open(name, O_RDWR | O_NOCTTY | O_NONBLOCK); + if (serial->port_fd < 0) { + if (errno == EACCES) { + perror("Unable to access, insufficient permission"); + } else if (errno == EISDIR) { + perror("Unable to open, Object is a directory, not a serial port"); + } else if (errno == ENODEV || errno == ENXIO) { + perror("Unable to open, Serial port hardware not installed"); + } else if (errno == ENOENT) { + perror("Unable to open, Device name does not exist"); + } else { + perror("Unable to open: Unknown error."); + } + return (-1); + } + memset(&(serial->settings), 0, sizeof(struct termios)); +#if 0 + if (ioctl(serial->port_fd, TIOCMGET, &bits) < 0) { + close(serial->port_fd); + perror("Unable to query serial port signals"); + return (-1); + } + bits &= ~(TIOCM_DTR | TIOCM_RTS); + if (ioctl(serial->port_fd, TIOCMSET, &bits) < 0) { + close(serial->port_fd); + perror("Unable to control serial port signals"); + return (-1); + } + if (tcgetattr(serial->port_fd, &(serial->settings_orig)) != 0) { + close(serial->port_fd); + perror("Unable to query serial port settings (perhaps not a serial port)"); + return (-1); + } + memset(&(serial->settings), 0, sizeof(struct termios)); + serial->settings.c_iflag = IGNBRK | IGNPAR; + serial->settings.c_cflag = CS8 | CREAD | HUPCL | CLOCAL; + serial_setBaud(serial, serial->baud_rate); + if (ioctl(serial->port_fd, TIOCGSERIAL, &kernel_serial_settings) == 0) { + kernel_serial_settings.flags |= ASYNC_LOW_LATENCY; + ioctl(serial->port_fd, TIOCSSERIAL, &kernel_serial_settings); + } + tcflush(serial->port_fd, TCIFLUSH); +#endif + serial->port_name = name; + serial->port_is_open = 1; + return 0; +} + +int +serial_setBaud(t_serial* serial, int baud) +{ + speed_t spd; + switch (baud) { + case 230400: + spd = B230400; + break; + case 115200: + spd = B115200; + break; + case 57600: + spd = B57600; + break; + case 38400: + spd = B38400; + break; + case 19200: + spd = B19200; + break; + case 9600: + spd = B9600; + break; + case 4800: + spd = B4800; + break; + case 2400: + spd = B2400; + break; + case 1800: + spd = B1800; + break; + case 1200: + spd = B1200; + break; + case 600: + spd = B600; + break; + case 300: + spd = B300; + break; + case 200: + spd = B200; + break; + case 150: + spd = B150; + break; + case 134: + spd = B134; + break; + case 110: + spd = B110; + break; + case 75: + spd = B75; + break; + case 50: + spd = B50; + break; +#ifdef B460800 + case 460800: + spd = B460800; + break; +#endif +#ifdef B500000 + case 500000: + spd = B500000; + break; +#endif +#ifdef B576000 + case 576000: + spd = B576000; + break; +#endif +#ifdef B921600 + case 921600: + spd = B921600; + break; +#endif +#ifdef B1000000 + case 1000000: + spd = B1000000; + break; +#endif +#ifdef B1152000 + case 1152000: + spd = B1152000; + break; +#endif +#ifdef B1500000 + case 1500000: + spd = B1500000; + break; +#endif +#ifdef B2000000 + case 2000000: + spd = B2000000; + break; +#endif +#ifdef B2500000 + case 2500000: + spd = B2500000; + break; +#endif +#ifdef B3000000 + case 3000000: + spd = B3000000; + break; +#endif +#ifdef B3500000 + case 3500000: + spd = B3500000; + break; +#endif +#ifdef B4000000 + case 4000000: + spd = B4000000; + break; +#endif +#ifdef B7200 + case 7200: + spd = B7200; + break; +#endif +#ifdef B14400 + case 14400: + spd = B14400; + break; +#endif +#ifdef B28800 + case 28800: + spd = B28800; + break; +#endif +#ifdef B76800 + case 76800: + spd = B76800; + break; +#endif + default: { + return -1; + } + } + cfsetospeed(&(serial->settings), spd); + cfsetispeed(&(serial->settings), spd); + if (tcsetattr(serial->port_fd, TCSANOW, &(serial->settings)) < 0) + return (-1); + return (0); +} + +int +serial_read(t_serial* serial, void* ptr, int count) +{ + int n, bits; + + if (!serial->port_is_open) + return (-1); + if (count <= 0) + return (0); + n = read(serial->port_fd, ptr, count); + if (n < 0 && (errno == EAGAIN || errno == EINTR)) + return (0); + if (n == 0 && ioctl(serial->port_fd, TIOCMGET, &bits) < 0) + return (-99); + serial->rx += n; + return (n); +} + +int +serial_write(t_serial* serial, void* ptr, int len) +{ + //printf("Write %d\n", len); + write(serial->port_fd, (const char *)ptr, len); + return (len); +} + +int +serial_waitInput(t_serial* serial, int msec) +{ + if (!serial->port_is_open) + return -1; + fd_set rfds; + struct timeval tv; + tv.tv_sec = msec / 1000; + tv.tv_usec = (msec % 1000) * 1000; + FD_ZERO(&rfds); + FD_SET(serial->port_fd, &rfds); + return (select(serial->port_fd + 1, &rfds, NULL, NULL, &tv)); +} + +int +serial_discardInput(t_serial* serial) +{ + if (!serial->port_is_open) + return; + // does this really work properly (and is it thread safe) on Linux?? + tcflush(serial->port_fd, TCIFLUSH); +} + +void +serial_flushOutput(t_serial* serial) +{ + if (!serial->port_is_open) + return; + tcdrain(serial->port_fd); +} + +int +serial_setControl(t_serial* serial, int dtr, int rts) +{ + if (!serial->port_is_open) + return -1; + int bits; + if (ioctl(serial->port_fd, TIOCMGET, &bits) < 0) + return -1; + if (dtr == 1) { + bits |= TIOCM_DTR; + } else if (dtr == 0) { + bits &= ~TIOCM_DTR; + } + if (rts == 1) { + bits |= TIOCM_RTS; + } else if (rts == 0) { + bits &= ~TIOCM_RTS; + } + if (ioctl(serial->port_fd, TIOCMSET, &bits) < 0) + return -1; + ; + return (0); +} diff --git a/src/firmata/servo.c b/src/firmata/servo.c new file mode 100644 index 0000000..5ec54b6 --- /dev/null +++ b/src/firmata/servo.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2016 Intel Corporation + * Copyright (c) 2015 Jules Dourlens (jdourlens@gmail.com) + * + * 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 "firmata/servo.h" + +#include +#include + +t_servo* +servo_attach(t_firmata* firmata, int pin) +{ + t_servo* res; + + if (!firmata || !firmata->isReady) { + perror("servo_new::Firmata is not ready"); + return (NULL); + } + res = malloc(sizeof(t_servo)); + if (!res) { + perror("servo_new::malloc failed"); + return (NULL); + } + res->firmata = firmata; + res->pin = pin; + firmata_pinMode(res->firmata, pin, MODE_SERVO); + + return res; +} + +int +servo_write(t_servo* servo, int value) +{ + return (firmata_analogWrite(servo->firmata, servo->pin, value)); +} diff --git a/src/mraa.c b/src/mraa.c index 3260e70..77b4bf6 100644 --- a/src/mraa.c +++ b/src/mraa.c @@ -42,6 +42,7 @@ #include #include "mraa_internal.h" +#include "firmata/firmata_mraa.h" #include "gpio.h" #include "version.h" @@ -141,6 +142,10 @@ mraa_init() } #endif +#if defined(FIRMATA) + // look for USB id 8087:0aba -> genuino/arduino 101 +#endif + // Look for IIO devices mraa_iio_detect(); @@ -941,3 +946,18 @@ mraa_get_iio_device_count() { return plat_iio->iio_device_count; } + +mraa_result_t +mraa_add_subplatform(mraa_platform_t subplatformtype, const char* uart_dev) +{ +#ifdef FIRMATA + if (subplatformtype == MRAA_GENERIC_FIRMATA) { + if (mraa_firmata_platform(plat, uart_dev) == MRAA_GENERIC_FIRMATA) { + syslog(LOG_NOTICE, "mraa: Added firmata subplatform"); + return MRAA_SUCCESS; + } + } +#endif + + return MRAA_ERROR_INVALID_PARAMETER; +}