Private
Public Access
2
0

firmata: initial work

Signed-off-by: Brendan Le Foll <brendan.le.foll@intel.com>
This commit is contained in:
Brendan Le Foll
2016-03-07 14:49:42 +00:00
parent f2cbe1c68d
commit 78caa990f1
17 changed files with 1586 additions and 34 deletions

View File

@@ -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
}

View File

@@ -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());
}
}

View File

@@ -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 */

View File

@@ -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 =

111
include/firmata/firmata.h Normal file
View File

@@ -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);

View File

@@ -0,0 +1,38 @@
/*
* Author: Brendan Le Foll <brendan.le.foll@intel.com>
* 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

51
include/firmata/serial.h Normal file
View File

@@ -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 <stdint.h>
#include <termios.h>
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);

35
include/firmata/servo.h Normal file
View File

@@ -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);

View File

@@ -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);

View File

@@ -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

View File

@@ -1,7 +1,7 @@
/*
* Author: Nandkishor Sonar
* Author: Brendan Le Foll <brendan.le.foll@intel.com>
* 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;

View File

@@ -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 ()

341
src/firmata/firmata.c Normal file
View File

@@ -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 <string.h>
#include <stdlib.h>
#include <stdio.h>
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);
}

507
src/firmata/firmata_mraa.c Normal file
View File

@@ -0,0 +1,507 @@
/*
* Author: Brendan Le Foll <brendan.le.foll@intel.com>
* 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 <stdlib.h>
#include <string.h>
#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;
}

340
src/firmata/serial.c Normal file
View File

@@ -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 <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/select.h>
#include <termios.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <linux/serial.h>
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);
}

55
src/firmata/servo.c Normal file
View File

@@ -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 <stdlib.h>
#include <stdio.h>
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));
}

View File

@@ -42,6 +42,7 @@
#include <stdio.h>
#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;
}