added arduino, modified build
This commit is contained in:
342
arduino/libraries/Firmata/utility/SerialFirmata.cpp
Normal file
342
arduino/libraries/Firmata/utility/SerialFirmata.cpp
Normal 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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user