added arduino, modified build

This commit is contained in:
2020-02-02 15:28:36 -08:00
parent 0189d519c6
commit 6480bc593f
3583 changed files with 1305025 additions and 247 deletions

View File

@@ -0,0 +1,3 @@
/*
* Implementation is in BLEStream.h to avoid linker issues.
*/

View File

@@ -0,0 +1,243 @@
/*
BLEStream.h
Based on BLESerial.cpp by Voita Molda
https://github.com/sandeepmistry/arduino-BLEPeripheral/blob/master/examples/serial/BLESerial.h
Last updated April 4th, 2016
*/
#ifndef _BLE_STREAM_H_
#define _BLE_STREAM_H_
#include <Arduino.h>
#if defined(_VARIANT_ARDUINO_101_X_)
#include <CurieBLE.h>
#define _MAX_ATTR_DATA_LEN_ BLE_MAX_ATTR_DATA_LEN
#else
#include <BLEPeripheral.h>
#define _MAX_ATTR_DATA_LEN_ BLE_ATTRIBUTE_MAX_VALUE_LENGTH
#endif
#define BLESTREAM_TXBUFFER_FLUSH_INTERVAL 80
#define BLESTREAM_MIN_FLUSH_INTERVAL 8 // minimum interval for flushing the TX buffer
// #define BLE_SERIAL_DEBUG
class BLEStream : public BLEPeripheral, public Stream
{
public:
BLEStream(unsigned char req = 0, unsigned char rdy = 0, unsigned char rst = 0);
void begin(...);
bool poll();
void end();
void setFlushInterval(int);
virtual int available(void);
virtual int peek(void);
virtual int read(void);
virtual void flush(void);
virtual size_t write(uint8_t byte);
using Print::write;
virtual operator bool();
private:
bool _connected;
unsigned long _flushed;
int _flushInterval;
static BLEStream* _instance;
size_t _rxHead;
size_t _rxTail;
size_t _rxCount() const;
unsigned char _rxBuffer[256];
size_t _txCount;
unsigned char _txBuffer[_MAX_ATTR_DATA_LEN_];
BLEService _uartService = BLEService("6E400001-B5A3-F393-E0A9-E50E24DCCA9E");
BLEDescriptor _uartNameDescriptor = BLEDescriptor("2901", "UART");
BLECharacteristic _rxCharacteristic = BLECharacteristic("6E400002-B5A3-F393-E0A9-E50E24DCCA9E", BLEWriteWithoutResponse, _MAX_ATTR_DATA_LEN_);
BLEDescriptor _rxNameDescriptor = BLEDescriptor("2901", "RX - Receive Data (Write)");
BLECharacteristic _txCharacteristic = BLECharacteristic("6E400003-B5A3-F393-E0A9-E50E24DCCA9E", BLENotify, _MAX_ATTR_DATA_LEN_);
BLEDescriptor _txNameDescriptor = BLEDescriptor("2901", "TX - Transfer Data (Notify)");
void _received(const unsigned char* data, size_t size);
static void _received(BLECentral& /*central*/, BLECharacteristic& rxCharacteristic);
};
/*
* BLEStream.cpp
* Copied here as a hack to avoid having to install the BLEPeripheral libarary even if it's
* not needed.
*/
BLEStream* BLEStream::_instance = NULL;
BLEStream::BLEStream(unsigned char req, unsigned char rdy, unsigned char rst) :
#if defined(_VARIANT_ARDUINO_101_X_)
BLEPeripheral()
#else
BLEPeripheral(req, rdy, rst)
#endif
{
this->_txCount = 0;
this->_rxHead = this->_rxTail = 0;
this->_flushed = 0;
this->_flushInterval = BLESTREAM_TXBUFFER_FLUSH_INTERVAL;
BLEStream::_instance = this;
addAttribute(this->_uartService);
addAttribute(this->_uartNameDescriptor);
setAdvertisedServiceUuid(this->_uartService.uuid());
addAttribute(this->_rxCharacteristic);
addAttribute(this->_rxNameDescriptor);
this->_rxCharacteristic.setEventHandler(BLEWritten, BLEStream::_received);
addAttribute(this->_txCharacteristic);
addAttribute(this->_txNameDescriptor);
}
void BLEStream::begin(...)
{
BLEPeripheral::begin();
#ifdef BLE_SERIAL_DEBUG
Serial.println(F("BLEStream::begin()"));
#endif
}
bool BLEStream::poll()
{
// BLEPeripheral::poll is called each time connected() is called
this->_connected = BLEPeripheral::connected();
if (millis() > this->_flushed + this->_flushInterval) {
flush();
}
return this->_connected;
}
void BLEStream::end()
{
this->_rxCharacteristic.setEventHandler(BLEWritten, (void(*)(BLECentral&, BLECharacteristic&))NULL);
this->_rxHead = this->_rxTail = 0;
flush();
BLEPeripheral::disconnect();
}
int BLEStream::available(void)
{
// BLEPeripheral::poll only calls delay(1) in CurieBLE so skipping it here to avoid the delay
#ifndef _VARIANT_ARDUINO_101_X_
// TODO Need to do more testing to determine if all of these calls to BLEPeripheral::poll are
// actually necessary. Seems to run fine without them, but only minimal testing so far.
BLEPeripheral::poll();
#endif
int retval = (this->_rxHead - this->_rxTail + sizeof(this->_rxBuffer)) % sizeof(this->_rxBuffer);
#ifdef BLE_SERIAL_DEBUG
if (retval > 0) {
Serial.print(F("BLEStream::available() = "));
Serial.println(retval);
}
#endif
return retval;
}
int BLEStream::peek(void)
{
#ifndef _VARIANT_ARDUINO_101_X_
BLEPeripheral::poll();
#endif
if (this->_rxTail == this->_rxHead) return -1;
uint8_t byte = this->_rxBuffer[this->_rxTail];
#ifdef BLE_SERIAL_DEBUG
Serial.print(F("BLEStream::peek() = 0x"));
Serial.println(byte, HEX);
#endif
return byte;
}
int BLEStream::read(void)
{
#ifndef _VARIANT_ARDUINO_101_X_
BLEPeripheral::poll();
#endif
if (this->_rxTail == this->_rxHead) return -1;
this->_rxTail = (this->_rxTail + 1) % sizeof(this->_rxBuffer);
uint8_t byte = this->_rxBuffer[this->_rxTail];
#ifdef BLE_SERIAL_DEBUG
Serial.print(F("BLEStream::read() = 0x"));
Serial.println(byte, HEX);
#endif
return byte;
}
void BLEStream::flush(void)
{
if (this->_txCount == 0) return;
#ifndef _VARIANT_ARDUINO_101_X_
// ensure there are available packets before sending
while(!this->_txCharacteristic.canNotify()) {
BLEPeripheral::poll();
}
#endif
this->_txCharacteristic.setValue(this->_txBuffer, this->_txCount);
this->_flushed = millis();
this->_txCount = 0;
#ifdef BLE_SERIAL_DEBUG
Serial.println(F("BLEStream::flush()"));
#endif
}
size_t BLEStream::write(uint8_t byte)
{
#ifndef _VARIANT_ARDUINO_101_X_
BLEPeripheral::poll();
#endif
if (this->_txCharacteristic.subscribed() == false) return 0;
this->_txBuffer[this->_txCount++] = byte;
if (this->_txCount == sizeof(this->_txBuffer)) flush();
#ifdef BLE_SERIAL_DEBUG
Serial.print(F("BLEStream::write( 0x"));
Serial.print(byte, HEX);
Serial.println(F(") = 1"));
#endif
return 1;
}
BLEStream::operator bool()
{
bool retval = this->_connected = BLEPeripheral::connected();
#ifdef BLE_SERIAL_DEBUG
Serial.print(F("BLEStream::operator bool() = "));
Serial.println(retval);
#endif
return retval;
}
void BLEStream::setFlushInterval(int interval)
{
if (interval > BLESTREAM_MIN_FLUSH_INTERVAL) {
this->_flushInterval = interval;
}
}
void BLEStream::_received(const unsigned char* data, size_t size)
{
for (size_t i = 0; i < size; i++) {
this->_rxHead = (this->_rxHead + 1) % sizeof(this->_rxBuffer);
this->_rxBuffer[this->_rxHead] = data[i];
}
#ifdef BLE_SERIAL_DEBUG
Serial.print(F("BLEStream::received("));
for (int i = 0; i < size; i++) Serial.print(data[i], HEX);
Serial.println(F(")"));
#endif
}
void BLEStream::_received(BLECentral& /*central*/, BLECharacteristic& rxCharacteristic)
{
BLEStream::_instance->_received(rxCharacteristic.value(), rxCharacteristic.valueLength());
}
#endif // _BLE_STREAM_H_

View File

@@ -0,0 +1,3 @@
/*
* Implementation is in BluefruitLE_SPI_Stream.h to avoid linker issues.
*/

View File

@@ -0,0 +1,157 @@
/*
BluefruitLE_SPI_Stream.h
Documentation for the various AT commands used below is available at
https://learn.adafruit.com/adafruit-feather-m0-bluefruit-le/at-commands
*/
#ifndef _BLUEFRUIT_LE_SPI_STREAM_H_
#define _BLUEFRUIT_LE_SPI_STREAM_H_
#include <Adafruit_BluefruitLE_SPI.h>
class BluefruitLE_SPI_Stream : public Stream
{
public:
BluefruitLE_SPI_Stream(int8_t csPin, int8_t irqPin, int8_t rstPin);
void setLocalName(const char *localName);
void setConnectionInterval(unsigned short minConnInterval, unsigned short maxConnInterval);
void setFlushInterval(int flushInterval);
void begin();
bool poll();
void end();
// Print overrides
size_t write(uint8_t byte);
using Print::write; // Expose other write variants
// Stream overrides
int available();
int read();
int peek();
void flush();
private:
Adafruit_BluefruitLE_SPI ble;
String localName;
unsigned short minConnInterval;
unsigned short maxConnInterval;
uint8_t txBuffer[SDEP_MAX_PACKETSIZE];
size_t txCount;
};
BluefruitLE_SPI_Stream::BluefruitLE_SPI_Stream(int8_t csPin, int8_t irqPin, int8_t rstPin) :
ble(csPin, irqPin, rstPin),
minConnInterval(0),
maxConnInterval(0),
txCount(0)
{ }
void BluefruitLE_SPI_Stream::setLocalName(const char *localName)
{
this->localName = localName;
}
void BluefruitLE_SPI_Stream::setConnectionInterval(unsigned short minConnInterval, unsigned short maxConnInterval)
{
this->minConnInterval = minConnInterval;
this->maxConnInterval = maxConnInterval;
}
void BluefruitLE_SPI_Stream::setFlushInterval(int flushInterval)
{
// Not used
}
void BluefruitLE_SPI_Stream::begin()
{
// Initialize the SPI interface
ble.begin();
// Perform a factory reset to make sure everything is in a known state
ble.factoryReset();
// Disable command echo from Bluefruit
ble.echo(false);
// Change the MODE LED to indicate BLE UART activity
ble.println("AT+HWMODELED=BLEUART");
// Set local name
if (localName.length() > 0) {
ble.print("AT+GAPDEVNAME=");
ble.println(localName);
}
// Set connection interval
if (minConnInterval > 0 && maxConnInterval > 0) {
ble.print("AT+GAPINTERVALS=");
ble.print(minConnInterval);
ble.print(",");
ble.print(maxConnInterval);
ble.println(",,,");
}
// Disable real and simulated mode switch (i.e. "+++") command
ble.println("AT+MODESWITCHEN=local,0");
ble.enableModeSwitchCommand(false);
// Switch to data mode
ble.setMode(BLUEFRUIT_MODE_DATA);
}
bool BluefruitLE_SPI_Stream::poll()
{
// If there's outgoing data in the buffer, just send it. The firmware on
// the nRF51822 will decide when to transmit the data in its TX FIFO.
if (txCount) flush();
// In order to check for a connection, we would need to switch from data to
// command mode and back again. However, due to the internal workings of
// Adafruit_BluefruitLE_SPI, this can lead to unread incoming data being
// lost. Therefore, we always return true.
return true;
}
void BluefruitLE_SPI_Stream::end()
{
flush();
ble.end();
}
size_t BluefruitLE_SPI_Stream::write(uint8_t byte)
{
txBuffer[txCount++] = byte;
if (txCount == sizeof(txBuffer)) flush();
return 1;
}
int BluefruitLE_SPI_Stream::available()
{
return ble.available();
}
int BluefruitLE_SPI_Stream::read()
{
return ble.read();
}
int BluefruitLE_SPI_Stream::peek()
{
return ble.peek();
}
void BluefruitLE_SPI_Stream::flush()
{
ble.write(txBuffer, txCount);
txCount = 0;
}
#endif // _BLUEFRUIT_LE_SPI_STREAM_H_

View File

@@ -0,0 +1,3 @@
/*
* Implementation is in EthernetClientStream.h to avoid linker issues.
*/

View File

@@ -0,0 +1,141 @@
/*
EthernetClientStream.h
An Arduino-Stream that wraps an instance of Client reconnecting to
the remote-ip in a transparent way. A disconnected client may be
recognized by the returnvalues -1 from calls to peek or read and
a 0 from calls to write.
Copyright (C) 2013 Norbert Truchsess. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See file LICENSE.txt for further informations on licensing terms.
Last updated June 18th, 2016
*/
#ifndef ETHERNETCLIENTSTREAM_H
#define ETHERNETCLIENTSTREAM_H
#include <inttypes.h>
#include <Stream.h>
//#define SERIAL_DEBUG
#include "firmataDebug.h"
#define MILLIS_RECONNECT 5000
class EthernetClientStream : public Stream
{
public:
EthernetClientStream(Client &client, IPAddress localip, IPAddress ip, const char* host, uint16_t port);
int available();
int read();
int peek();
void flush();
size_t write(uint8_t);
void maintain(IPAddress localip);
private:
Client &client;
IPAddress localip;
IPAddress ip;
const char* host;
uint16_t port;
bool connected;
uint32_t time_connect;
bool maintain();
void stop();
};
/*
* EthernetClientStream.cpp
* Copied here as a hack to linker issues with 3rd party board packages that don't properly
* implement the Arduino network APIs.
*/
EthernetClientStream::EthernetClientStream(Client &client, IPAddress localip, IPAddress ip, const char* host, uint16_t port)
: client(client),
localip(localip),
ip(ip),
host(host),
port(port),
connected(false)
{
}
int
EthernetClientStream::available()
{
return maintain() ? client.available() : 0;
}
int
EthernetClientStream::read()
{
return maintain() ? client.read() : -1;
}
int
EthernetClientStream::peek()
{
return maintain() ? client.peek() : -1;
}
void EthernetClientStream::flush()
{
if (maintain())
client.flush();
}
size_t
EthernetClientStream::write(uint8_t c)
{
return maintain() ? client.write(c) : 0;
}
void
EthernetClientStream::maintain(IPAddress localip)
{
// ensure the local IP is updated in the case that it is changed by the DHCP server
if (this->localip != localip) {
this->localip = localip;
if (connected)
stop();
}
}
void
EthernetClientStream::stop()
{
client.stop();
connected = false;
time_connect = millis();
}
bool
EthernetClientStream::maintain()
{
if (client && client.connected())
return true;
if (connected) {
stop();
}
// if the client is disconnected, attempt to reconnect every 5 seconds
else if (millis() - time_connect >= MILLIS_RECONNECT) {
connected = host ? client.connect(host, port) : client.connect(ip, port);
if (!connected) {
time_connect = millis();
DEBUG_PRINTLN("Connection failed. Attempting to reconnect...");
} else {
DEBUG_PRINTLN("Connected");
}
}
return connected;
}
#endif /* ETHERNETCLIENTSTREAM_H */

View File

@@ -0,0 +1,3 @@
/*
* Implementation is in EthernetServerStream.h to avoid linker issues.
*/

View File

@@ -0,0 +1,147 @@
/*
EthernetServerStream.h
Copyright (C) 2017 Marc Josef Pees. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See file LICENSE.txt for further informations on licensing terms.
Last updated July 10th, 2017
*/
#ifndef ETHERNETSERVERSTREAM_H
#define ETHERNETSERVERSTREAM_H
#include <inttypes.h>
#include <Stream.h>
#include <Ethernet.h>
//#define SERIAL_DEBUG
#include "firmataDebug.h"
class EthernetServerStream : public Stream
{
public:
EthernetServerStream(IPAddress localip, uint16_t port);
int available();
int read();
int peek();
void flush();
size_t write(uint8_t);
void maintain(IPAddress localip);
private:
EthernetClient client;
IPAddress localip;
uint16_t port;
bool connected;
bool maintain();
void stop();
protected:
EthernetServer server = EthernetServer(3030);
bool listening = false;
bool connect_client();
};
/*
* EthernetServerStream.cpp
* Copied here as a hack to linker issues with 3rd party board packages that don't properly
* implement the Arduino network APIs.
*/
EthernetServerStream::EthernetServerStream(IPAddress localip, uint16_t port)
: localip(localip),
port(port),
connected(false)
{
}
bool EthernetServerStream::connect_client()
{
if ( connected )
{
if ( client && client.connected() ) return true;
stop();
}
EthernetClient newClient = server.available();
if ( !newClient ) return false;
client = newClient;
connected = true;
DEBUG_PRINTLN("Connected");
return true;
}
int
EthernetServerStream::available()
{
return maintain() ? client.available() : 0;
}
int
EthernetServerStream::read()
{
return maintain() ? client.read() : -1;
}
int
EthernetServerStream::peek()
{
return maintain() ? client.peek() : -1;
}
void EthernetServerStream::flush()
{
if (maintain())
client.flush();
}
size_t
EthernetServerStream::write(uint8_t c)
{
return maintain() ? client.write(c) : 0;
}
void
EthernetServerStream::maintain(IPAddress localip)
{
// ensure the local IP is updated in the case that it is changed by the DHCP server
if (this->localip != localip) {
this->localip = localip;
if (connected)
stop();
}
}
void
EthernetServerStream::stop()
{
if(client)
{
client.stop();
}
connected = false;
}
bool
EthernetServerStream::maintain()
{
if (connect_client()) return true;
stop();
if(!listening)
{
server = EthernetServer(port);
server.begin();
listening = true;
}
return false;
}
#endif /* ETHERNETSERVERSTREAM_H */

View File

@@ -0,0 +1,38 @@
/*
FirmataFeature.h
Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights reserved.
Copyright (C) 2010-2011 Paul Stoffregen. All rights reserved.
Copyright (C) 2009 Shigeru Kobayashi. All rights reserved.
Copyright (C) 2013 Norbert Truchsess. All rights reserved.
Copyright (C) 2009-2016 Jeff Hoefs. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
Interface for Firmata feature classes.
This version of FirmataFeature.h differs from the ConfigurableFirmata
version in the following ways:
- Imports Firmata.h rather than ConfigurableFirmata.h
See file LICENSE.txt for further informations on licensing terms.
*/
#ifndef FirmataFeature_h
#define FirmataFeature_h
#include <Firmata.h>
class FirmataFeature
{
public:
virtual void handleCapability(byte pin) = 0;
virtual boolean handlePinMode(byte pin, int mode) = 0;
virtual boolean handleSysex(byte command, byte argc, byte* argv) = 0;
virtual void reset() = 0;
};
#endif

View File

@@ -0,0 +1,342 @@
/*
SerialFirmata.cpp
Copyright (C) 2016 Jeff Hoefs. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See file LICENSE.txt for further informations on licensing terms.
This version of SerialFirmata.cpp differs from the ConfigurableFirmata
version in the following ways:
- handlePinMode calls Firmata::setPinMode
Last updated October 16th, 2016
*/
#include "SerialFirmata.h"
SerialFirmata::SerialFirmata()
{
#if defined(SoftwareSerial_h)
swSerial0 = NULL;
swSerial1 = NULL;
swSerial2 = NULL;
swSerial3 = NULL;
#endif
serialIndex = -1;
}
boolean SerialFirmata::handlePinMode(byte pin, int mode)
{
// used for both HW and SW serial
if (mode == PIN_MODE_SERIAL) {
Firmata.setPinMode(pin, PIN_MODE_SERIAL);
return true;
}
return false;
}
void SerialFirmata::handleCapability(byte pin)
{
if (IS_PIN_SERIAL(pin)) {
Firmata.write(PIN_MODE_SERIAL);
Firmata.write(getSerialPinType(pin));
}
}
boolean SerialFirmata::handleSysex(byte command, byte argc, byte *argv)
{
if (command == SERIAL_MESSAGE) {
Stream *serialPort;
byte mode = argv[0] & SERIAL_MODE_MASK;
byte portId = argv[0] & SERIAL_PORT_ID_MASK;
switch (mode) {
case SERIAL_CONFIG:
{
long baud = (long)argv[1] | ((long)argv[2] << 7) | ((long)argv[3] << 14);
serial_pins pins;
if (portId < 8) {
serialPort = getPortFromId(portId);
if (serialPort != NULL) {
pins = getSerialPinNumbers(portId);
if (pins.rx != 0 && pins.tx != 0) {
Firmata.setPinMode(pins.rx, PIN_MODE_SERIAL);
Firmata.setPinMode(pins.tx, PIN_MODE_SERIAL);
// Fixes an issue where some serial devices would not work properly with Arduino Due
// because all Arduino pins are set to OUTPUT by default in StandardFirmata.
pinMode(pins.rx, INPUT);
}
((HardwareSerial*)serialPort)->begin(baud);
}
} else {
#if defined(SoftwareSerial_h)
byte swTxPin, swRxPin;
if (argc > 4) {
swRxPin = argv[4];
swTxPin = argv[5];
} else {
// RX and TX pins must be specified when using SW serial
Firmata.sendString("Specify serial RX and TX pins");
return false;
}
switch (portId) {
case SW_SERIAL0:
if (swSerial0 == NULL) {
swSerial0 = new SoftwareSerial(swRxPin, swTxPin);
}
break;
case SW_SERIAL1:
if (swSerial1 == NULL) {
swSerial1 = new SoftwareSerial(swRxPin, swTxPin);
}
break;
case SW_SERIAL2:
if (swSerial2 == NULL) {
swSerial2 = new SoftwareSerial(swRxPin, swTxPin);
}
break;
case SW_SERIAL3:
if (swSerial3 == NULL) {
swSerial3 = new SoftwareSerial(swRxPin, swTxPin);
}
break;
}
serialPort = getPortFromId(portId);
if (serialPort != NULL) {
Firmata.setPinMode(swRxPin, PIN_MODE_SERIAL);
Firmata.setPinMode(swTxPin, PIN_MODE_SERIAL);
((SoftwareSerial*)serialPort)->begin(baud);
}
#endif
}
break; // SERIAL_CONFIG
}
case SERIAL_WRITE:
{
byte data;
serialPort = getPortFromId(portId);
if (serialPort == NULL) {
break;
}
for (byte i = 1; i < argc; i += 2) {
data = argv[i] + (argv[i + 1] << 7);
serialPort->write(data);
}
break; // SERIAL_WRITE
}
case SERIAL_READ:
if (argv[1] == SERIAL_READ_CONTINUOUSLY) {
if (serialIndex + 1 >= MAX_SERIAL_PORTS) {
break;
}
if (argc > 2) {
// maximum number of bytes to read from buffer per iteration of loop()
serialBytesToRead[portId] = (int)argv[2] | ((int)argv[3] << 7);
} else {
// read all available bytes per iteration of loop()
serialBytesToRead[portId] = 0;
}
serialIndex++;
reportSerial[serialIndex] = portId;
} else if (argv[1] == SERIAL_STOP_READING) {
byte serialIndexToSkip = 0;
if (serialIndex <= 0) {
serialIndex = -1;
} else {
for (byte i = 0; i < serialIndex + 1; i++) {
if (reportSerial[i] == portId) {
serialIndexToSkip = i;
break;
}
}
// shift elements over to fill space left by removed element
for (byte i = serialIndexToSkip; i < serialIndex + 1; i++) {
if (i < MAX_SERIAL_PORTS) {
reportSerial[i] = reportSerial[i + 1];
}
}
serialIndex--;
}
}
break; // SERIAL_READ
case SERIAL_CLOSE:
serialPort = getPortFromId(portId);
if (serialPort != NULL) {
if (portId < 8) {
((HardwareSerial*)serialPort)->end();
} else {
#if defined(SoftwareSerial_h)
((SoftwareSerial*)serialPort)->end();
if (serialPort != NULL) {
free(serialPort);
serialPort = NULL;
}
#endif
}
}
break; // SERIAL_CLOSE
case SERIAL_FLUSH:
serialPort = getPortFromId(portId);
if (serialPort != NULL) {
getPortFromId(portId)->flush();
}
break; // SERIAL_FLUSH
#if defined(SoftwareSerial_h)
case SERIAL_LISTEN:
// can only call listen() on software serial ports
if (portId > 7) {
serialPort = getPortFromId(portId);
if (serialPort != NULL) {
((SoftwareSerial*)serialPort)->listen();
}
}
break; // SERIAL_LISTEN
#endif
} // end switch
return true;
}
return false;
}
void SerialFirmata::update()
{
checkSerial();
}
void SerialFirmata::reset()
{
#if defined(SoftwareSerial_h)
Stream *serialPort;
// free memory allocated for SoftwareSerial ports
for (byte i = SW_SERIAL0; i < SW_SERIAL3 + 1; i++) {
serialPort = getPortFromId(i);
if (serialPort != NULL) {
free(serialPort);
serialPort = NULL;
}
}
#endif
serialIndex = -1;
for (byte i = 0; i < SERIAL_READ_ARR_LEN; i++) {
serialBytesToRead[i] = 0;
}
}
// get a pointer to the serial port associated with the specified port id
Stream* SerialFirmata::getPortFromId(byte portId)
{
switch (portId) {
case HW_SERIAL0:
// block use of Serial (typically pins 0 and 1) until ability to reclaim Serial is implemented
//return &Serial;
return NULL;
#if defined(PIN_SERIAL1_RX)
case HW_SERIAL1:
return &Serial1;
#endif
#if defined(PIN_SERIAL2_RX)
case HW_SERIAL2:
return &Serial2;
#endif
#if defined(PIN_SERIAL3_RX)
case HW_SERIAL3:
return &Serial3;
#endif
#if defined(PIN_SERIAL4_RX)
case HW_SERIAL4:
return &Serial4;
#endif
#if defined(PIN_SERIAL5_RX)
case HW_SERIAL5:
return &Serial5;
#endif
#if defined(PIN_SERIAL6_RX)
case HW_SERIAL6:
return &Serial6;
#endif
#if defined(SoftwareSerial_h)
case SW_SERIAL0:
if (swSerial0 != NULL) {
// instances of SoftwareSerial are already pointers so simply return the instance
return swSerial0;
}
break;
case SW_SERIAL1:
if (swSerial1 != NULL) {
return swSerial1;
}
break;
case SW_SERIAL2:
if (swSerial2 != NULL) {
return swSerial2;
}
break;
case SW_SERIAL3:
if (swSerial3 != NULL) {
return swSerial3;
}
break;
#endif
}
return NULL;
}
// Check serial ports that have READ_CONTINUOUS mode set and relay any data
// for each port to the device attached to that port.
void SerialFirmata::checkSerial()
{
byte portId, serialData;
int bytesToRead = 0;
int numBytesToRead = 0;
Stream* serialPort;
if (serialIndex > -1) {
// loop through all reporting (READ_CONTINUOUS) serial ports
for (byte i = 0; i < serialIndex + 1; i++) {
portId = reportSerial[i];
bytesToRead = serialBytesToRead[portId];
serialPort = getPortFromId(portId);
if (serialPort == NULL) {
continue;
}
#if defined(SoftwareSerial_h)
// only the SoftwareSerial port that is "listening" can read data
if (portId > 7 && !((SoftwareSerial*)serialPort)->isListening()) {
continue;
}
#endif
if (serialPort->available() > 0) {
Firmata.write(START_SYSEX);
Firmata.write(SERIAL_MESSAGE);
Firmata.write(SERIAL_REPLY | portId);
if (bytesToRead == 0 || (serialPort->available() <= bytesToRead)) {
numBytesToRead = serialPort->available();
} else {
numBytesToRead = bytesToRead;
}
// relay serial data to the serial device
while (numBytesToRead > 0) {
serialData = serialPort->read();
Firmata.write(serialData & 0x7F);
Firmata.write((serialData >> 7) & 0x7F);
numBytesToRead--;
}
Firmata.write(END_SYSEX);
}
}
}
}

View File

@@ -0,0 +1,208 @@
/*
SerialFirmata.h
Copyright (C) 2016 Jeff Hoefs. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See file LICENSE.txt for further informations on licensing terms.
This version of SerialFirmata.h differs from the ConfigurableFirmata
version in the following ways:
- Defines FIRMATA_SERIAL_FEATURE (could add to Configurable version as well)
- Imports Firmata.h rather than ConfigurableFirmata.h
Last updated October 16th, 2016
*/
#ifndef SerialFirmata_h
#define SerialFirmata_h
#include <Firmata.h>
#include "FirmataFeature.h"
// SoftwareSerial is currently only supported for AVR-based boards and the Arduino 101.
// Limited to Arduino 1.6.6 or higher because Arduino builder cannot find SoftwareSerial
// prior to this release.
#if (ARDUINO > 10605) && (defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_ARC32))
#include <SoftwareSerial.h>
#endif
#define FIRMATA_SERIAL_FEATURE
// Serial port Ids
#define HW_SERIAL0 0x00
#define HW_SERIAL1 0x01
#define HW_SERIAL2 0x02
#define HW_SERIAL3 0x03
#define HW_SERIAL4 0x04
#define HW_SERIAL5 0x05
#define HW_SERIAL6 0x06
// extensible up to 0x07
#define SW_SERIAL0 0x08
#define SW_SERIAL1 0x09
#define SW_SERIAL2 0x0A
#define SW_SERIAL3 0x0B
// extensible up to 0x0F
#define SERIAL_PORT_ID_MASK 0x0F
#define MAX_SERIAL_PORTS 8
#define SERIAL_READ_ARR_LEN 12
// map configuration query response resolution value to serial pin type
#define RES_RX1 0x02
#define RES_TX1 0x03
#define RES_RX2 0x04
#define RES_TX2 0x05
#define RES_RX3 0x06
#define RES_TX3 0x07
#define RES_RX4 0x08
#define RES_TX4 0x09
#define RES_RX5 0x0a
#define RES_TX5 0x0b
#define RES_RX6 0x0c
#define RES_TX6 0x0d
// Serial command bytes
#define SERIAL_CONFIG 0x10
#define SERIAL_WRITE 0x20
#define SERIAL_READ 0x30
#define SERIAL_REPLY 0x40
#define SERIAL_CLOSE 0x50
#define SERIAL_FLUSH 0x60
#define SERIAL_LISTEN 0x70
// Serial read modes
#define SERIAL_READ_CONTINUOUSLY 0x00
#define SERIAL_STOP_READING 0x01
#define SERIAL_MODE_MASK 0xF0
namespace {
struct serial_pins {
uint8_t rx;
uint8_t tx;
};
/*
* Get the serial serial pin type (RX1, TX1, RX2, TX2, etc) for the specified pin.
*/
inline uint8_t getSerialPinType(uint8_t pin) {
#if defined(PIN_SERIAL_RX)
// TODO when use of HW_SERIAL0 is enabled
#endif
#if defined(PIN_SERIAL1_RX)
if (pin == PIN_SERIAL1_RX) return RES_RX1;
if (pin == PIN_SERIAL1_TX) return RES_TX1;
#endif
#if defined(PIN_SERIAL2_RX)
if (pin == PIN_SERIAL2_RX) return RES_RX2;
if (pin == PIN_SERIAL2_TX) return RES_TX2;
#endif
#if defined(PIN_SERIAL3_RX)
if (pin == PIN_SERIAL3_RX) return RES_RX3;
if (pin == PIN_SERIAL3_TX) return RES_TX3;
#endif
#if defined(PIN_SERIAL4_RX)
if (pin == PIN_SERIAL4_RX) return RES_RX4;
if (pin == PIN_SERIAL4_TX) return RES_TX4;
#endif
#if defined(PIN_SERIAL5_RX)
if (pin == PIN_SERIAL5_RX) return RES_RX5;
if (pin == PIN_SERIAL5_TX) return RES_TX5;
#endif
#if defined(PIN_SERIAL6_RX)
if (pin == PIN_SERIAL6_RX) return RES_RX6;
if (pin == PIN_SERIAL6_TX) return RES_TX6;
#endif
return 0;
}
/*
* Get the RX and TX pins numbers for the specified HW serial port.
*/
inline serial_pins getSerialPinNumbers(uint8_t portId) {
serial_pins pins;
switch (portId) {
#if defined(PIN_SERIAL_RX)
// case HW_SERIAL0:
// // TODO when use of HW_SERIAL0 is enabled
// break;
#endif
#if defined(PIN_SERIAL1_RX)
case HW_SERIAL1:
pins.rx = PIN_SERIAL1_RX;
pins.tx = PIN_SERIAL1_TX;
break;
#endif
#if defined(PIN_SERIAL2_RX)
case HW_SERIAL2:
pins.rx = PIN_SERIAL2_RX;
pins.tx = PIN_SERIAL2_TX;
break;
#endif
#if defined(PIN_SERIAL3_RX)
case HW_SERIAL3:
pins.rx = PIN_SERIAL3_RX;
pins.tx = PIN_SERIAL3_TX;
break;
#endif
#if defined(PIN_SERIAL4_RX)
case HW_SERIAL4:
pins.rx = PIN_SERIAL4_RX;
pins.tx = PIN_SERIAL4_TX;
break;
#endif
#if defined(PIN_SERIAL5_RX)
case HW_SERIAL5:
pins.rx = PIN_SERIAL5_RX;
pins.tx = PIN_SERIAL5_TX;
break;
#endif
#if defined(PIN_SERIAL6_RX)
case HW_SERIAL6:
pins.rx = PIN_SERIAL6_RX;
pins.tx = PIN_SERIAL6_TX;
break;
#endif
default:
pins.rx = 0;
pins.tx = 0;
}
return pins;
}
} // end namespace
class SerialFirmata: public FirmataFeature
{
public:
SerialFirmata();
boolean handlePinMode(byte pin, int mode);
void handleCapability(byte pin);
boolean handleSysex(byte command, byte argc, byte* argv);
void update();
void reset();
void checkSerial();
private:
byte reportSerial[MAX_SERIAL_PORTS];
int serialBytesToRead[SERIAL_READ_ARR_LEN];
signed char serialIndex;
#if defined(SoftwareSerial_h)
Stream *swSerial0;
Stream *swSerial1;
Stream *swSerial2;
Stream *swSerial3;
#endif
Stream* getPortFromId(byte portId);
};
#endif /* SerialFirmata_h */

View File

@@ -0,0 +1,105 @@
/*
WiFiClientStream.h
An Arduino Stream that wraps an instance of a WiFiClient. For use
with legacy Arduino WiFi shield and other boards and shields that
are compatible with the Arduino WiFi library.
Copyright (C) 2016 Jens B. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See file LICENSE.txt for further informations on licensing terms.
Parts of this class are based on
- EthernetClientStream - Copyright (C) 2013 Norbert Truchsess. All rights reserved.
published under the same license.
Last updated April 23rd, 2016
*/
#ifndef WIFI_CLIENT_STREAM_H
#define WIFI_CLIENT_STREAM_H
#include "WiFiStream.h"
#define MILLIS_RECONNECT 5000
class WiFiClientStream : public WiFiStream
{
protected:
uint32_t _time_connect = 0;
/**
* check if TCP client is connected
* @return true if connected
*/
virtual inline bool connect_client()
{
if ( _connected )
{
if ( _client && _client.connected() ) return true;
stop();
}
// active TCP connect
if ( WiFi.status() == WL_CONNECTED )
{
// if the client is disconnected, try to reconnect every 5 seconds
if ( millis() - _time_connect >= MILLIS_RECONNECT )
{
_connected = _client.connect( _remote_ip, _port );
if ( !_connected )
{
_time_connect = millis();
}
else if ( _currentHostConnectionCallback )
{
(*_currentHostConnectionCallback)(HOST_CONNECTION_CONNECTED);
}
}
}
return _connected;
}
public:
/**
* create a WiFi stream with a TCP client
*/
WiFiClientStream(IPAddress server_ip, uint16_t server_port) : WiFiStream(server_ip, server_port) {}
/**
* maintain WiFi and TCP connection
* @return true if WiFi and TCP connection are established
*/
virtual inline bool maintain()
{
return connect_client();
}
/**
* stop client connection
*/
virtual inline void stop()
{
if ( _client)
{
_client.stop();
if ( _currentHostConnectionCallback )
{
(*_currentHostConnectionCallback)(HOST_CONNECTION_DISCONNECTED);
}
}
_connected = false;
_time_connect = millis();
}
};
#endif //WIFI_CLIENT_STREAM_H

View File

@@ -0,0 +1,107 @@
/*
WiFiServerStream.h
An Arduino Stream extension for a WiFiClient or WiFiServer to be used
with legacy Arduino WiFi shield and other boards and shields that
are compatible with the Arduino WiFi library.
Copyright (C) 2016 Jens B. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See file LICENSE.txt for further informations on licensing terms.
Parts of this class are based on
- WiFiStream - Copyright (C) 2015-2016 Jesse Frush. All rights reserved.
published under the same license.
Last updated April 23rd, 2016
*/
#ifndef WIFI_SERVER_STREAM_H
#define WIFI_SERVER_STREAM_H
#include "WiFiStream.h"
class WiFiServerStream : public WiFiStream
{
protected:
WiFiServer _server = WiFiServer(3030);
bool _listening = false;
/**
* check if TCP client is connected
* @return true if connected
*/
virtual inline bool connect_client()
{
if ( _connected )
{
if ( _client && _client.connected() ) return true;
stop();
}
// passive TCP connect (accept)
WiFiClient newClient = _server.available();
if ( !newClient ) return false;
_client = newClient;
_connected = true;
if ( _currentHostConnectionCallback )
{
(*_currentHostConnectionCallback)(HOST_CONNECTION_CONNECTED);
}
return true;
}
public:
/**
* create a WiFi stream with a TCP server
*/
WiFiServerStream(uint16_t server_port) : WiFiStream(server_port) {}
/**
* maintain WiFi and TCP connection
* @return true if WiFi and TCP connection are established
*/
virtual inline bool maintain()
{
if ( connect_client() ) return true;
stop();
if ( !_listening && WiFi.status() == WL_CONNECTED )
{
// start TCP server after first WiFi connect
_server = WiFiServer(_port);
_server.begin();
_listening = true;
}
return false;
}
/**
* stop client connection
*/
virtual inline void stop()
{
if ( _client)
{
_client.stop();
if ( _currentHostConnectionCallback )
{
(*_currentHostConnectionCallback)(HOST_CONNECTION_DISCONNECTED);
}
}
_connected = false;
}
};
#endif //WIFI_SERVER_STREAM_H

View File

@@ -0,0 +1,4 @@
/*
* Implementation is in WiFiStream.h to avoid linker issues. Legacy WiFi and modern WiFi101 both define WiFiClass which
* will cause linker errors whenever Firmata.h is included.
*/

View File

@@ -0,0 +1,226 @@
/*
WiFiStream.h
An Arduino Stream extension for a WiFiClient or WiFiServer to be used
with legacy Arduino WiFi shield and other boards and shields that
are compatible with the Arduino WiFi library.
Copyright (C) 2015-2016 Jesse Frush. All rights reserved.
Copyright (C) 2016 Jens B. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See file LICENSE.txt for further informations on licensing terms.
Last updated April 23rd, 2016
*/
#ifndef WIFI_STREAM_H
#define WIFI_STREAM_H
#include <inttypes.h>
#include <Stream.h>
#define HOST_CONNECTION_DISCONNECTED 0
#define HOST_CONNECTION_CONNECTED 1
extern "C" {
// callback function types
typedef void (*hostConnectionCallbackFunction)(byte);
}
class WiFiStream : public Stream
{
protected:
WiFiClient _client;
bool _connected = false;
hostConnectionCallbackFunction _currentHostConnectionCallback;
//configuration members
IPAddress _local_ip; // DHCP
IPAddress _subnet;
IPAddress _gateway;
IPAddress _remote_ip;
uint16_t _port;
uint8_t _key_idx; //WEP
const char *_key = nullptr; //WEP
const char *_passphrase = nullptr; //WPA
char *_ssid = nullptr;
/**
* check if TCP client is connected
* @return true if connected
*/
virtual bool connect_client() = 0;
public:
/** constructor for TCP server */
WiFiStream(uint16_t server_port) : _port(server_port) {}
/** constructor for TCP client */
WiFiStream(IPAddress server_ip, uint16_t server_port) : _remote_ip(server_ip), _port(server_port) {}
inline void attach( hostConnectionCallbackFunction newFunction ) { _currentHostConnectionCallback = newFunction; }
/******************************************************************************
* network configuration
******************************************************************************/
#ifndef ESP8266
/**
* configure a static local IP address without defining the local network
* DHCP will be used as long as local IP address is not defined
*/
inline void config(IPAddress local_ip)
{
_local_ip = local_ip;
WiFi.config( local_ip );
}
#endif
/**
* configure a static local IP address
* DHCP will be used as long as local IP address is not defined
*/
inline void config(IPAddress local_ip, IPAddress gateway, IPAddress subnet)
{
_local_ip = local_ip;
_subnet = subnet;
_gateway = gateway;
#ifndef ESP8266
WiFi.config( local_ip, IPAddress(0, 0, 0, 0), gateway, subnet );
#else
WiFi.config( local_ip, gateway, subnet );
#endif
}
/**
* @return local IP address
*/
inline IPAddress getLocalIP()
{
return WiFi.localIP();
}
/******************************************************************************
* network functions
******************************************************************************/
/**
* maintain WiFi and TCP connection
* @return true if WiFi and TCP connection are established
*/
virtual bool maintain() = 0;
#ifdef ESP8266
/**
* get status of TCP connection
* @return status of TCP connection
* CLOSED = 0 (typical)
* LISTEN = 1 (not used)
* SYN_SENT = 2
* SYN_RCVD = 3
* ESTABLISHED = 4 (typical)
* FIN_WAIT_1 = 5
* FIN_WAIT_2 = 6
* CLOSE_WAIT = 7
* CLOSING = 8
* LAST_ACK = 9
* TIME_WAIT = 10
*/
inline uint8_t status()
{
return _client.status();
}
#endif
/**
* close TCP client connection
*/
virtual void stop() = 0;
/******************************************************************************
* WiFi configuration
******************************************************************************/
/**
* initialize WiFi without security (open) and initiate client connection
* if WiFi connection is already established
* @return WL_CONNECTED if WiFi connection is established
*/
inline int begin(char *ssid)
{
_ssid = ssid;
WiFi.begin(ssid);
int result = WiFi.status();
return WiFi.status();
}
#ifndef ESP8266
/**
* initialize WiFi with WEP security and initiate client connection
* if WiFi connection is already established
* @return WL_CONNECTED if WiFi connection is established
*/
inline int begin(char *ssid, uint8_t key_idx, const char *key)
{
_ssid = ssid;
_key_idx = key_idx;
_key = key;
WiFi.begin( ssid, key_idx, key );
return WiFi.status();
}
#endif
/**
* initialize WiFi with WPA-PSK security and initiate client connection
* if WiFi connection is already established
* @return WL_CONNECTED if WiFi connection is established
*/
inline int begin(char *ssid, const char *passphrase)
{
_ssid = ssid;
_passphrase = passphrase;
WiFi.begin(ssid, passphrase);
return WiFi.status();
}
/******************************************************************************
* stream functions
******************************************************************************/
inline int available()
{
return connect_client() ? _client.available() : 0;
}
inline void flush()
{
if( _client ) _client.flush();
}
inline int peek()
{
return connect_client() ? _client.peek(): 0;
}
inline int read()
{
return connect_client() ? _client.read() : -1;
}
inline size_t write(uint8_t byte)
{
return connect_client() ? _client.write( byte ) : 0;
}
};
#endif //WIFI_STREAM_H

View File

@@ -0,0 +1,14 @@
#ifndef FIRMATA_DEBUG_H
#define FIRMATA_DEBUG_H
#ifdef SERIAL_DEBUG
#define DEBUG_BEGIN(baud) Serial.begin(baud); while(!Serial) {;}
#define DEBUG_PRINTLN(x) Serial.println (x); Serial.flush()
#define DEBUG_PRINT(x) Serial.print (x)
#else
#define DEBUG_BEGIN(baud)
#define DEBUG_PRINTLN(x)
#define DEBUG_PRINT(x)
#endif
#endif /* FIRMATA_DEBUG_H */